New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@wmfs/tymly-pg-plugin

Package Overview
Dependencies
Maintainers
1
Versions
329
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wmfs/tymly-pg-plugin - npm Package Compare versions

Comparing version 1.224.0 to 1.225.0

lib/blueprints/tymly-blueprint/pg-scripts/audit-delete-processor.sql

20

lib/components/services/audit/generate-trigger-statement.js

@@ -5,15 +5,15 @@ 'use strict'

module.exports = function generateTriggerStatement (options) {
const namespace = _.snakeCase(options.model.namespace)
const name = _.snakeCase(options.model.name)
const pk = options.model.primaryKey.map(_.snakeCase).join(',')
function generateTriggerStatement (model, triggerName, func, action) {
const namespace = _.snakeCase(model.namespace)
const name = _.snakeCase(model.name)
const pk = model.primaryKey.map(_.snakeCase).join(',')
switch (options.action) {
switch (action) {
case 'ADD':
return `CREATE TRIGGER ${namespace}_${name}_auditor
BEFORE UPDATE ON ${namespace}.${name}
return `CREATE TRIGGER ${triggerName}
${func.when} ON ${namespace}.${name}
FOR EACH ROW EXECUTE PROCEDURE
tymly.${_.snakeCase(options.function)}('${namespace}.${name}', '{${pk}}');`
tymly.${_.snakeCase(func.name)}('${namespace}.${name}', '{${pk}}');`
case 'REMOVE':
return `DROP TRIGGER IF EXISTS ${namespace}_${name}_auditor
return `DROP TRIGGER IF EXISTS ${triggerName}
ON ${namespace}.${name};`

@@ -24,1 +24,3 @@ default:

}
module.exports = generateTriggerStatement

@@ -16,37 +16,28 @@ 'use strict'

this.auditLog = options.bootedServices.storage.models.tymly_rewind
this.schemaNames = options.bootedServices.storage.schemaNames
const pgScripts = options.blueprintComponents.pgScripts || {}
this.auditFunctions = Object.keys(pgScripts)
.map(script => path.parse(pgScripts[script].filename).name)
.filter(filename => filename.split('-')[0] === 'audit')
.map(filename => {
debug(`Found audit function: ${filename.substring(filename.indexOf('-') + 1)}`)
return filename.substring(filename.indexOf('-') + 1)
})
const auditFunctions = gatherAuditFunctions(pgScripts)
const schemaNames = options.bootedServices.storage.schemaNames
await this.updateTriggers(options.messages)
await this.updateTriggers(auditFunctions, schemaNames, options.messages)
} // boot
async updateTriggers (messages) {
async updateTriggers (auditFunctions, schemaNames, messages) {
const currentDbStructure = await pgInfo({
client: this.client,
schemas: this.schemaNames
schemas: schemaNames
})
const allInstallers = this.auditFunctions
.map(func => {
messages.info(`Applying ${func} function`)
const installers = Object.keys(this.models)
.map(model => this.installTrigger(func, model, currentDbStructure, messages))
.filter(p => !!p)
for (const func of auditFunctions) {
messages.info(`Applying ${func.name} function`)
const installers = Object.keys(this.models)
.map(model => this.installTrigger(func, model, currentDbStructure, messages))
.filter(p => !!p)
if (installers.length === 0) {
messages.detail('Already in place')
return
}
return Promise.all(installers)
})
return Promise.all(allInstallers)
if (installers.length) {
await Promise.all(installers)
} else {
messages.detail('Already in place')
}
}
} // updateTriggers

@@ -59,3 +50,3 @@

const name = _.snakeCase(this.models[model].name)
const triggerName = `${namespace}_${name}_auditor`
const triggerName = `${namespace}_${name}_auditor${func.triggerSuffix}`

@@ -68,7 +59,8 @@ const modelTriggers = currentDbStructure.schemas[namespace].tables[name].triggers

const triggerSQL = generateTriggerStatement({
model: this.models[model],
function: func,
action: action
})
const triggerSQL = generateTriggerStatement(
this.models[model],
triggerName,
func,
action
)

@@ -108,4 +100,39 @@ if (!triggerSQL) {

function gatherAuditFunctions (pgScripts) {
return Object.keys(pgScripts)
.map(script => path.parse(pgScripts[script].filename).name)
.filter(filename => filename.split('-')[0] === 'audit')
.map(filename => {
const functionName = filename.substring(filename.indexOf('-') + 1)
debug(`Found audit function: ${functionName}`)
return auditFunctionProperties(functionName)
})
} // gatherAuditFunctions
const whenTrigger = {
insert: 'AFTER INSERT',
update: 'BEFORE UPDATE',
delete: 'BEFORE DELETE'
}
const triggerSuffix = {
insert: '_insert',
update: '',
delete: '_delete'
}
function auditFunctionProperties (functionName) {
const type = functionName.split('-')[0]
return {
name: functionName,
triggerSuffix: triggerSuffix[type],
when: whenTrigger[type]
}
} // auditFunctionProperties
function formatLog (log, model, additionalFields) {
const diffs = formatDiffs(log.diff, model)
const action = (typeof log.diff.action === 'string')
const diffs = action ? formatAction(log.diff.action, log.oldValues, model) : formatDiffs(log.diff, model)
const when = formatDate(log.modified)

@@ -124,2 +151,13 @@

function formatAction (action, record, model) {
const actionText = _.capitalize(action)
if (!model.label) return [actionText]
const labelFields = Array.isArray(model.label) ? model.label : [model.label]
return labelFields.map((field, index) => {
const label = record[field]
return (index === 0) ? `${actionText} ${label}` : label
}).filter(l => l)
}
function formatDiffs (diffs, model) {

@@ -126,0 +164,0 @@ return Object.entries(diffs)

@@ -16,2 +16,4 @@ /**

this.multicopy = resourceConfig.multicopy || false
this.schemaName = resourceConfig.schemaName || false
this.quote = resourceConfig.quote || null
}

@@ -45,4 +47,5 @@

client: this.client,
schemaName: context.stateMachineMeta.schemaName,
schemaName: this.schemaName || context.stateMachineMeta.schemaName,
truncateTables: this.truncateTables,
quote: this.quote,
debug: true

@@ -49,0 +52,0 @@ })

{
"name": "@wmfs/tymly-pg-plugin",
"version": "1.224.0",
"version": "1.225.0",
"description": "Replace Tymly's out-the-box memory storage with PostgreSQL",

@@ -33,5 +33,5 @@ "author": "West Midlands Fire Service",

"@wmfs/pg-model": "1.24.0",
"@wmfs/pg-telepods": "1.78.0",
"@wmfs/pg-telepods": "1.79.0",
"@wmfs/relationize": "1.24.0",
"@wmfs/supercopy": "1.38.0"
"@wmfs/supercopy": "1.39.0"
},

@@ -43,4 +43,5 @@ "devDependencies": {

"conventional-changelog-metahub": "4.0.1",
"cz-conventional-changelog": "3.2.0",
"mocha": "8.1.1",
"cz-conventional-changelog": "3.3.0",
"dirty-chai": "2.0.1",
"mocha": "8.1.3",
"nyc": "15.1.0",

@@ -53,3 +54,3 @@ "rimraf": "3.0.2",

"@semantic-release/exec": "5.0.0",
"@wmfs/tymly": "1.157.0"
"@wmfs/tymly": "1.160.0"
},

@@ -56,0 +57,0 @@ "scripts": {

{
"name": "pg",
"version": "1.224.0",
"version": "1.225.0",
"label": "PG",

@@ -5,0 +5,0 @@ "author": "Tim Needham",

@@ -5,3 +5,5 @@ /* eslint-env mocha */

const expect = require('chai').expect
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const tymly = require('@wmfs/tymly')

@@ -15,3 +17,3 @@ const path = require('path')

let tymlyService, models, rewindIdToDestroy, client
let tymlyService, models, client

@@ -25,4 +27,4 @@ before(function () {

it('create some tymly services', (done) => {
tymly.boot(
before('create some tymly services', async () => {
const tymlyServices = await tymly.boot(
{

@@ -36,108 +38,173 @@ pluginPaths: [

config: {}
},
(err, tymlyServices) => {
expect(err).to.eql(null)
tymlyService = tymlyServices.tymly
client = tymlyServices.storage.client
models = tymlyServices.storage.models
done(err)
}
)
tymlyService = tymlyServices.tymly
client = tymlyServices.storage.client
models = tymlyServices.storage.models
})
it('insert a dog to animal-with-age', async () => {
await models.tymlyTest_animalWithAge.create({
animal: 'dog',
colour: 'brown'
describe('Audited table', () => {
function dogChanges () {
return models.tymly_rewind.find({
where: {
modelName: { equals: 'tymly_test.animal_with_age' }
},
orderBy: ['-modified']
})
}
async function dog () {
const res = await models.tymlyTest_animalWithAge.find({})
return res.length ? res[0] : null
}
describe('insert', () => {
it('insert a dog to animal-with-age', async () => {
await models.tymlyTest_animalWithAge.create({
animal: 'dog',
colour: 'brown'
})
})
it('row in table', async () => {
const res = await dog()
expect(res.colour).to.eql('brown')
})
it('insert captured in tymly.rewind', async () => {
const res = await dogChanges()
expect(res.length).to.eql(1)
expect(res[0].modelName).to.eql('tymly_test.animal_with_age')
expect(res[0].keyString).to.eql('dog')
expect(res[0].diff.action).to.eql('insert')
})
})
})
it('check the dog is brown', async () => {
const res = await models.tymlyTest_animalWithAge.find({})
describe('update record', () => {
it('update the dog\'s colour to black', async () => {
await models.tymlyTest_animalWithAge.update({
animal: 'dog',
colour: 'black'
}, {})
})
expect(res[0].colour).to.eql('brown')
})
it('change committed', async () => {
const res = await dog()
it('update the dog\'s colour to black', async () => {
await models.tymlyTest_animalWithAge.update({
animal: 'dog',
colour: 'black'
}, {})
})
expect(res.colour).to.eql('black')
})
it('confirm dog is black', async () => {
const res = await models.tymlyTest_animalWithAge.find({})
it('update captured in tymly.rewind', async () => {
const res = await dogChanges()
expect(res[0].colour).to.eql('black')
})
expect(res.length).to.eql(2)
expect(res[0].modelName).to.eql('tymly_test.animal_with_age')
expect(res[0].keyString).to.eql('dog')
expect(res[0].diff.colour.from).to.eql('brown')
expect(res[0].diff.colour.to).to.eql('black')
})
})
it('check the change has been documented in tymly.rewind', async () => {
const res = await models.tymly_rewind.find({
where: {
modelName: { equals: 'tymly_test.animal_with_age' }
}
describe('update again', () => {
it('update the dog\'s colour to piebald', async () => {
await models.tymlyTest_animalWithAge.update({
animal: 'dog',
colour: 'piebald'
}, {})
})
it('confirm row changed again', async () => {
const res = await dog()
expect(res.colour).to.eql('piebald')
})
it('second change captured in tymly.rewind', async () => {
const res = await dogChanges()
expect(res.length).to.eql(3)
expect(res[0].modelName).to.eql('tymly_test.animal_with_age')
expect(res[0].keyString).to.eql('dog')
expect(res[0].diff.colour.from).to.eql('black')
expect(res[0].diff.colour.to).to.eql('piebald')
})
})
rewindIdToDestroy = res[0].id
expect(res[0].modelName).to.eql('tymly_test.animal_with_age')
expect(res[0].keyString).to.eql('dog')
expect(res[0].diff.colour.from).to.eql('brown')
expect(res[0].diff.colour.to).to.eql('black')
})
describe('delete record', () => {
it('delete row', async () => {
await models.tymlyTest_animalWithAge.destroyById('dog')
})
it('insert a cat to animal-with-year', async () => {
await models.tymlyTest_animalWithYear.create({
animal: 'cat',
colour: 'ginger'
it('row is gone', async () => {
const res = await dog()
expect(res).to.be.null()
})
it('delete is captured in tymly.rewind', async () => {
const res = await dogChanges()
expect(res.length).to.eql(4)
expect(res[0].modelName).to.eql('tymly_test.animal_with_age')
expect(res[0].keyString).to.eql('dog')
expect(res[0].diff.action).to.eql('delete')
})
})
})
it('check the cat is ginger', async () => {
const res = await models.tymlyTest_animalWithYear.find({})
describe('Unaudited table', () => {
it('insert a cat to animal-with-year', async () => {
await models.tymlyTest_animalWithYear.create({
animal: 'cat',
colour: 'ginger'
})
})
expect(res[0].colour).to.eql('ginger')
})
it('check the cat is ginger', async () => {
const res = await models.tymlyTest_animalWithYear.find({})
it('update the cat update the cat\'s colour to white', async () => {
await models.tymlyTest_animalWithYear.update({
animal: 'cat',
colour: 'white'
}, {})
})
expect(res[0].colour).to.eql('ginger')
})
it('check the cat is white', async () => {
const res = await models.tymlyTest_animalWithYear.find({})
it('update the cat update the cat\'s colour to white', async () => {
await models.tymlyTest_animalWithYear.update({
animal: 'cat',
colour: 'white'
}, {})
})
expect(res[0].colour).to.eql('white')
})
it('check the cat is white', async () => {
const res = await models.tymlyTest_animalWithYear.find({})
it('check the change has NOT been documented in tymly.rewind', async () => {
const res = await models.tymly_rewind.find({
where: {
modelName: { equals: 'tymly_test.animal_with_year' }
}
expect(res[0].colour).to.eql('white')
})
expect(res.length).to.eql(0)
})
it('check the change has NOT been documented in tymly.rewind', async () => {
const res = await models.tymly_rewind.find({
where: {
modelName: { equals: 'tymly_test.animal_with_year' }
}
})
it('clean up animal-with-age', async () => {
await models.tymlyTest_animalWithAge.destroyById('dog')
expect(res.length).to.eql(0)
})
})
it('clean up animal-with-year', async () => {
after('clean up animal-with-year', async () => {
await models.tymlyTest_animalWithYear.destroyById('cat')
})
it('clean up rewind', async () => {
await models.tymly_rewind.destroyById(rewindIdToDestroy)
after('clean up rewind', async () => {
await client.query("delete from tymly.rewind where model_name = 'tymly_test.animal_with_age'")
})
it('uninstall test schemas', async () => {
after('uninstall test schemas', async () => {
await sqlScriptRunner.uninstall(client)
})
it('shutdown Tymly', async () => {
after('shutdown Tymly', async () => {
await tymlyService.shutdown()
})
})

@@ -19,2 +19,23 @@ /* eslint-env mocha */

diff: {
action: 'insert'
},
modifiedBy: 'bob',
modified: DateTime.fromObject({
year: 2018,
month: 12,
day: 1,
hour: 10,
minute: 0
}).toJSDate()
},
{
modelName: 'test_animal',
keyString: 'dog_henry',
oldValues: {
name: 'henry',
colour: null,
size: 'small',
animal: 'dog'
},
diff: {
colour: {

@@ -85,2 +106,23 @@ from: '',

}).toJSDate()
},
{
modelName: 'test_animal',
keyString: 'dog_henry',
oldValues: {
name: 'henry',
colour: null,
size: 'small',
animal: 'dog'
},
diff: {
action: 'delete'
},
modifiedBy: 'bob',
modified: DateTime.fromObject({
year: 2028,
month: 12,
day: 1,
hour: 10,
minute: 0
}).toJSDate()
}

@@ -91,2 +133,7 @@ ]

{
change: 'Delete henry',
modifiedBy: 'bob',
modified: '10:00 Dec 1, 2028'
},
{
change: 'Size "small" was cleared',

@@ -105,2 +152,7 @@ modifiedBy: 'bill',

modified: '11:00 Dec 1, 2018'
},
{
change: 'Insert henry',
modifiedBy: 'bob',
modified: '10:00 Dec 1, 2018'
}

@@ -144,3 +196,4 @@ ]

}
}
},
label: 'name'
}

@@ -147,0 +200,0 @@ },

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc