Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@wmfs/pg-model

Package Overview
Dependencies
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wmfs/pg-model - npm Package Compare versions

Comparing version 1.22.0 to 1.22.1

31

CHANGELOG.md

@@ -0,1 +1,32 @@

## [1.22.1](https://github.com/wmfs/pg-model/compare/v1.22.0...v1.22.1) (2020-04-30)
### 🐛 Bug Fixes
* check rows has elements before attempting to access entries ([00858c1](https://github.com/wmfs/pg-model/commit/00858c12aa1670e0111dfc81d1a44e7cd05560a9))
### 🛠 Builds
* **deps-dev:** bump [@wmfs](https://github.com/wmfs)/pg-diff-sync from 1.18.0 to 1.19.0 ([2f84cfb](https://github.com/wmfs/pg-model/commit/2f84cfb9c5b7d201ae0199670453089b131bf42b))
* **deps-dev:** bump mocha from 7.1.1 to 7.1.2 ([ae69a57](https://github.com/wmfs/pg-model/commit/ae69a5743f9fe87b30e6e0fa54c6a5fe69977442))
### 📦 Code Refactoring
* **Creator:** Prefer builtins to lodash methods ([88e16ec](https://github.com/wmfs/pg-model/commit/88e16ecddd6aa79d38e2ec94ca3104b7aef05977))
* **Destroyer:** Use Array.map in preference to a for loop ([0f7635a](https://github.com/wmfs/pg-model/commit/0f7635a60681672b7d705013c4b240e9abb4b384))
* **Finder:** Added findOne and findAll to Finder, simplify model ([89262e8](https://github.com/wmfs/pg-model/commit/89262e80ac043a889cda6e6d13b84069d05daa50))
* **Finder:** Eliminate use of async package. Move to async/await ([a0be44a](https://github.com/wmfs/pg-model/commit/a0be44a7721de1dfd253af58bc8025f5992c81e5))
* **Finder:** Replaced lodash methods with builtins. ([d12ce1c](https://github.com/wmfs/pg-model/commit/d12ce1cc6338382dcf1eb8c9f20750d26132be63))
* **Model:** Switch implementation from callback first to promise first. ([feb1304](https://github.com/wmfs/pg-model/commit/feb1304dd3f1614c6cd3515b2e51b8775e770ae6))
* **pre-statement-hook:** Prefer builtins to lodash methods ([3b9244f](https://github.com/wmfs/pg-model/commit/3b9244ff338101929bf6e77bc8ee5ae412a3325d))
* **tests:** Remove use of 'async' package ([6a8dc49](https://github.com/wmfs/pg-model/commit/6a8dc49320744d3b84e86e3f460b53fc30b9db8c))
* **Updater:** Prefer builtins to lodash methods. Split out named functions to clarify flow. ([3cf1b8b](https://github.com/wmfs/pg-model/commit/3cf1b8b6d4304234412ed10d83a55095f3d30276))
### 💎 Styles
* **Updater:** Lint fixes ([35cf1bc](https://github.com/wmfs/pg-model/commit/35cf1bc8b124e91914ea8cc5b18a7f4b165eac3f))
# [1.22.0](https://github.com/wmfs/pg-model/compare/v1.21.0...v1.22.0) (2020-04-22)

@@ -2,0 +33,0 @@

14

lib/Model/actions/Creator.js

@@ -54,3 +54,3 @@ 'use strict'

_.forOwn(parsedDoc.subDocs, (subDoc, propertyId) => {
for (const propertyId of Object.keys(parsedDoc.subDocs)) {
const subModel = this.model.subModels[propertyId]

@@ -64,3 +64,3 @@

script.push(...subScript)
})
}
} // addInsertStatementsToScript

@@ -136,5 +136,9 @@

const returnValue = {}
_.forOwn(result.rows[0], (value, columnName) => {
returnValue[_.camelCase(columnName)] = value
})
if (result.rows.length > 0) {
for (const [columnName, value] of Object.entries(result.rows[0])) {
returnValue[_.camelCase(columnName)] = value
}
}
ctx.returnValue = {

@@ -141,0 +145,0 @@ idProperties: returnValue

@@ -7,10 +7,4 @@ 'use strict'

const where = []
let i = 0
model.pkColumnNames.forEach(
function (columnName) {
i++
where.push(columnName + '=$' + i)
}
)
const where = model.pkColumnNames.map((name, index) => `${name}=$${index + 1}`)
this.sql = `DELETE FROM ${this.fullTableName} WHERE ${where.join(' AND ')}`

@@ -17,0 +11,0 @@ }

'use strict'
const _ = require('lodash')
const async = require('async')
const optionParser = require('./../../utils/option-parser')

@@ -18,71 +15,38 @@

static removeTopLevelDoc (doc) {
const topLevelKeys = _.keys(doc)
if (topLevelKeys.length === 1) {
return doc[topLevelKeys[0]]
}
}
async findAll (options) {
const doc = await this.find({}, options)
return removeTopLevelDoc(doc)
} // findAll
static removeTopLevelDocAndFlatten (doc) {
const topLevelDocs = Finder.removeTopLevelDoc(doc)
if (_.isArray(topLevelDocs) && topLevelDocs.length === 1) {
return topLevelDocs[0]
}
}
async findOne (options) {
const doc = await this.find({}, options)
return removeTopLevelDocAndFlatten(doc)
} // findOne
find (targetRoot, options, callback) {
const _this = this
async find (targetRoot, options) {
const sqlSelect = this.createSqlSelect(options)
const parsedOptions = optionParser(sqlSelect, this.propertyIdToColumn, options)
this.client.query(
const result = await this.client.query(
parsedOptions.sql,
parsedOptions.values,
function (err, result) {
if (err) {
callback(err)
} else {
targetRoot[_this.modelId] = result.rows
parsedOptions.values
)
async.eachOfSeries(
_this.subModels,
function (subModel, subModelId, cb) {
async.everySeries(
targetRoot[_this.modelId],
function (row, cb2) {
const where = {}
let i = -1
subModel.sourceProperties.forEach(
function (sourcePropertyId) {
i++
const targetPropertyId = subModel.targetProperties[i]
where[sourcePropertyId] = { equals: row[targetPropertyId] }
}
)
targetRoot[this.modelId] = result.rows
subModel.model.finder.find(
row,
{
where: where
},
function (err) {
if (err) {
cb2(err)
} else {
cb(null)
}
}
)
},
cb
)
},
callback
)
}
// search for submodels
for (const subModel of Object.values(this.subModels)) {
for (const row of targetRoot[this.modelId]) {
const where = makeSubModelWhere(subModel, row)
await subModel.model.finder.find(
row,
{ where: where }
)
}
)
}
} // for ...
return targetRoot
} // find
createSqlSelect (options) {

@@ -99,5 +63,30 @@ const filter = Array.isArray(options.fields)

return `SELECT ${columnNamesWithPropertyAliases} FROM ${this.model.fullTableName}`
} // createSqlStatement
} // class Finder
function makeSubModelWhere (subModel, row) {
const where = {}
subModel.sourceProperties.forEach(
(sourcePropertyId, index) => {
const targetPropertyId = subModel.targetProperties[index]
where[sourcePropertyId] = { equals: row[targetPropertyId] }
}
)
return where
} // makeSubModelWhere
function removeTopLevelDoc (doc) {
const topLevelKeys = Object.keys(doc)
if (topLevelKeys.length === 1) {
return doc[topLevelKeys[0]]
}
}
function removeTopLevelDocAndFlatten (doc) {
const topLevelDocs = removeTopLevelDoc(doc)
if (Array.isArray(topLevelDocs) && topLevelDocs.length === 1) {
return topLevelDocs[0]
}
}
module.exports = Finder

@@ -1,3 +0,1 @@

const _ = require('lodash')
module.exports = function getPreStatementHookFunction (parentFullTableName, columnJoin) {

@@ -7,19 +5,16 @@ return function preStatementHook (scriptEntry, ctx) {

const fkValuesToAutoFill = {}
_.forOwn(
columnJoin,
function (childColumnName, parentColumnName) {
fkValuesToAutoFill[parentColumnName] = parentPkValues[childColumnName]
}
)
for (const [parentColumnName, childColumnName] of Object.entries(columnJoin)) {
fkValuesToAutoFill[parentColumnName] = parentPkValues[childColumnName]
}
const scriptEntryColumnNames = scriptEntry.columnNames
const scriptEntryValues = scriptEntry.params
let scriptEntryColumnName
for (let i = 0; i < scriptEntryColumnNames.length; i++) {
scriptEntryColumnName = scriptEntryColumnNames[i]
if (Object.prototype.hasOwnProperty.call(fkValuesToAutoFill, scriptEntryColumnName)) {
scriptEntryValues[i] = fkValuesToAutoFill[scriptEntryColumnName]
scriptEntryColumnNames.forEach((columnName, index) => {
if (Object.prototype.hasOwnProperty.call(fkValuesToAutoFill, columnName)) {
scriptEntryValues[index] = fkValuesToAutoFill[columnName]
}
}
})
}
}
'use strict'
const _ = require('lodash')
const getPreStatementHookFunction = require('./get-pre-statement-hook-function')

@@ -23,15 +22,33 @@

makeStatements (jsonData, options) {
const _this = this
const script = []
this.makeUpdateStatement(jsonData, script, options)
this.makeSubDocsStatements(jsonData, script, options)
return script
} // makeStatements
addModifiedBy (parsedDoc) {
if (this.model.modifiedByField) {
parsedDoc.attributeColumns.push(this.model.modifiedByField)
parsedDoc.attributeValues.push(this.model.currentUserFn())
}
} // addModifiedBy
makeUpdateStatement (
jsonData,
script,
options
) {
const values = []
const parsedDoc = _this.model.parseDoc(jsonData)
const parsedDoc = this.model.parseDoc(jsonData)
this.addModifiedBy(parsedDoc)
const set = []
let i = 0
parsedDoc.attributeColumns.forEach(
function (column) {
i++
set.push(column + '=$' + i)
values.push(parsedDoc.attributeValues[i - 1])
(column, index) => {
values.push(parsedDoc.attributeValues[index])
set.push(`${column}=$${index + 1}`)
}

@@ -42,5 +59,3 @@ )

parsedDoc.missingAttributeColumnNames.forEach(
function (column) {
set.push(column + '=null')
}
column => set.push(`${column}=null`)
)

@@ -50,15 +65,10 @@ }

const key = []
let j = 0
parsedDoc.keyColumns.forEach(
function (column) {
j++
i++
key.push(column + '=$' + i)
values.push(parsedDoc.keyValues[j - 1])
(column, index) => {
values.push(parsedDoc.keyValues[index])
key.push(`${column}=$${index + values.length}`)
}
)
let sql = _this.prefix + set.join(', ')
sql += ' WHERE ' + key.join(' AND ')
const sql = this.prefix + set.join(', ') + ' WHERE ' + key.join(' AND ')
script.push(

@@ -71,65 +81,74 @@ {

)
} // makeUpdateStatement
_.forOwn(
this.model.subModels,
function (subModel, subModelId) {
const subDocPkValues = []
makeSubDocsStatements (
jsonData,
script,
options
) {
for (const [subModelId, subModel] of Object.entries(this.model.subModels)) {
if (!Array.isArray(jsonData[subModelId])) {
continue
}
if (Object.prototype.hasOwnProperty.call(jsonData, subModelId)) {
jsonData[subModelId].forEach(
function (row) {
subDocPkValues.push(subModel.model.extractPkValuesFromDoc(row))
makeSubDocUpsertsStatements(
subModelId,
subModel,
jsonData,
this.fullTableName,
script,
options
)
// Add inferred FK columns
_.forOwn(
subModel.columnJoin,
function (parentColumnsName, childColumnsName) {
row[childColumnsName] = jsonData[parentColumnsName]
}
)
const subDocPkValues = jsonData[subModelId].map(row => subModel.model.extractPkValuesFromDoc(row))
destroyMissingSubDocsStatement(subModel, subDocPkValues, script, options)
} // for ...
} // makeSubDocsStatements
} // class Updater
options.upsert = true
options.destroyMissingSubDocs = true
const subScript = subModel.model.creator.makeStatements(
row,
options,
getPreStatementHookFunction(_this.fullTableName, subModel.columnJoin)
)
script.push(...subScript)
}
)
function makeSubDocUpsertsStatements (
subModelId,
subModel,
jsonData,
parentTableName,
script,
options
) {
for (const row of jsonData[subModelId]) {
// Add inferred FK columns
for (const [childColumnsName, parentColumnsName] of Object.entries(subModel.columnJoin)) {
row[childColumnsName] = jsonData[parentColumnsName]
}
if (Object.prototype.hasOwnProperty.call(options, 'destroyMissingSubDocs') && options.destroyMissingSubDocs) {
if (subDocPkValues[0].length === 1) {
const firstPkValues = []
subDocPkValues.forEach(
function (pkValue) {
firstPkValues.push(pkValue[0])
}
)
script.push(
{
sql: subModel.model.deleteMissingSql,
params: [firstPkValues]
}
)
} else {
// TODO: Composite subdoc keys!
throw new Error('Composite subdoc keys not supported!')
}
}
}
}
options.upsert = true
options.destroyMissingSubDocs = true
const subScript = subModel.model.creator.makeStatements(
row,
options,
getPreStatementHookFunction(parentTableName, subModel.columnJoin)
)
return script
script.push(...subScript)
}
}
addModifiedBy (parsedDoc) {
if (this.model.modifiedByField) {
parsedDoc.attributeColumns.push(this.model.modifiedByField)
parsedDoc.attributeValues.push(this.model.currentUserFn())
}
function destroyMissingSubDocsStatement (
subModel,
subDocPkValues,
script,
options
) {
if (!options.destroyMissingSubDocs) return
if (subDocPkValues[0].length !== 1) {
// TODO: Composite subdoc keys!
throw new Error('Composite subdoc keys not supported!')
}
}
const firstPkValues = subDocPkValues.map(pkValues => pkValues[0])
script.push({
sql: subModel.model.deleteMissingSql,
params: [firstPkValues]
})
} // destroyMissingSubDocsStatement
module.exports = Updater

@@ -11,13 +11,7 @@ 'use strict'

function promised (obj, fn, ...args) {
return new Promise((resolve, reject) => {
fn.call(obj, ...args, (err, result) => {
if (err) {
reject(err)
} else {
resolve(result)
}
})
})
} // promised
function callbackify (promise, callback) {
promise
.then(result => callback(null, result))
.catch(err => callback(err))
}

@@ -85,4 +79,2 @@ class Model {

}
this.promised = (...args) => promised(this, ...args)
}

@@ -98,4 +90,4 @@

create (jsonData, options = {}, callback = NotSet) {
if (callback === NotSet) {
return this.promised(this.create, jsonData, options)
if (callback !== NotSet) {
return callbackify(this.create(jsonData, options), callback)
} // if ...

@@ -105,66 +97,30 @@

const script = this.creator.makeStatements(jsonData, options)
this.client.run(script, callback)
return this.client.run(script)
}
findById (id, callback = NotSet) {
if (callback === NotSet) {
return this.promised(this.findById, id)
if (callback !== NotSet) {
return callbackify(this.findById(id), callback)
}
if (!_.isArray(id)) {
id = [id]
}
const doc = {}
this.finder.find(
doc,
{
where: this.makeWhereFromId(id)
},
function (err) {
if (err) {
callback(err)
} else {
callback(null, Finder.removeTopLevelDocAndFlatten(doc))
}
}
)
return this.finder.findOne({
where: this.makeWhereFromId(id)
})
}
find (options, callback = NotSet) {
if (callback === NotSet) {
return this.promised(this.find, options)
if (callback !== NotSet) {
return callbackify(this.find(options), callback)
} // if ...
const doc = {}
this.finder.find(
doc,
options,
function (err) {
if (err) {
callback(err)
} else {
callback(null, Finder.removeTopLevelDoc(doc))
}
}
)
return this.finder.findAll(options)
}
findOne (options, callback = NotSet) {
if (callback === NotSet) {
return this.promised(this.findOne, options)
if (callback !== NotSet) {
return callbackify(this.findOne(options), callback)
} // if ...
options.limit = 1
const doc = {}
this.finder.find(
doc,
options,
function (err) {
if (err) {
callback(err)
} else {
callback(null, Finder.removeTopLevelDocAndFlatten(doc))
}
}
)
return this.finder.findOne(options)
}

@@ -183,4 +139,4 @@

update (doc, options, callback = NotSet) {
if (callback === NotSet) {
return this.promised(this.update, doc, options)
if (callback !== NotSet) {
return callbackify(this.update(doc, options), callback)
} // if ...

@@ -190,9 +146,10 @@

if (!Object.prototype.hasOwnProperty.call(options, 'setMissingPropertiesToNull')) options.setMissingPropertiesToNull = true
const script = this.updater.makeStatements(doc, options)
this.client.run(script, callback)
return this.client.run(script)
}
patch (doc, options, callback = NotSet) {
if (callback === NotSet) {
return this.promised(this.patch, doc, options)
if (callback !== NotSet) {
return callbackify(this.patch(doc, options), callback)
} // if ...

@@ -204,24 +161,22 @@

const script = this.updater.makeStatements(doc, options)
this.client.run(script, callback)
return this.client.run(script)
}
upsert (jsonData, options, callback = NotSet) {
if (callback === NotSet) {
return this.promised(this.upsert, jsonData, options)
if (callback !== NotSet) {
return callbackify(this.upsert(jsonData, options), callback)
}
options.upsert = true
const script = this.creator.makeStatements(jsonData, options)
this.client.run(script, callback)
return this.client.run(script)
}
destroyById (id, callback = NotSet) {
if (callback === NotSet) {
return this.promised(this.destroyById, id)
if (callback !== NotSet) {
return callbackify(this.destroyById(id), callback)
}
if (!_.isArray(id)) {
id = [id]
}
const script = this.destroyer.makeStatements(id)
this.client.run(script, callback)
const ids = Array.isArray(id) ? id : [id]
const script = this.destroyer.makeStatements(ids)
return this.client.run(script)
}

@@ -231,11 +186,5 @@

// Parse options
let includeNullFks
if (options) {
if (Object.prototype.hasOwnProperty.call(options, 'includeNullFks')) {
includeNullFks = options.includeNullFks
} else {
includeNullFks = false
}
} else {
includeNullFks = false
let includeNullFks = false
if (options && Object.prototype.hasOwnProperty.call(options, 'includeNullFks')) {
includeNullFks = options.includeNullFks
}

@@ -313,8 +262,7 @@

makeWhereFromId (id) {
let i = -1
const ids = Array.isArray(id) ? id : [id]
const where = {}
this.pkPropertyIds.forEach(
function (propertyId) {
i++
where[propertyId] = { equals: id[i] }
(propertyId, index) => {
where[propertyId] = { equals: ids[index] }
}

@@ -328,3 +276,3 @@ )

this.pkPropertyIds.forEach(
function (propertyId) {
(propertyId) => {
pkValues.push(doc[propertyId])

@@ -331,0 +279,0 @@ }

{
"name": "@wmfs/pg-model",
"version": "1.22.0",
"version": "1.22.1",
"description": "Takes a relational database structure and returns model objects for noSQL-like abilities.",

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

"cz-conventional-changelog": "3.1.0",
"mocha": "7.1.1",
"mocha": "7.1.2",
"nyc": "15.0.1",

@@ -41,3 +41,3 @@ "semantic-release": "17.0.7",

"@wmfs/hl-pg-client": "1.20.0",
"@wmfs/pg-diff-sync": "1.18.0"
"@wmfs/pg-diff-sync": "1.19.0"
},

@@ -44,0 +44,0 @@ "scripts": {

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

for (const filename of ['uninstall.sql', 'install.sql']) {
await client.runFile(path.resolve(__dirname, path.join('fixtures', 'scripts', filename)))
await client.runFile(
path.resolve(__dirname, path.join('fixtures', 'scripts', filename))
)
}

@@ -45,0 +47,0 @@ })

@@ -11,3 +11,2 @@ /* eslint-env mocha */

const pgDiffSync = require('@wmfs/pg-diff-sync')
const async = require('async')
const path = require('path')

@@ -38,29 +37,15 @@ const chai = require('chai')

it('initially drop-cascade the pg_model_test schema, if one exists', async () => {
for (const filename of ['uninstall.sql', 'install.sql']) { await client.runFile(path.resolve(__dirname, path.join('fixtures', 'scripts', filename))) }
it('drop-cascade the pg_model_test schema, if one exists', async () => {
for (const filename of ['uninstall.sql', 'install.sql']) {
await client.runFile(
path.resolve(__dirname, path.join('fixtures', 'scripts', filename))
)
}
})
it('install test database objects', function (done) {
async.eachSeries(
pgDiffSync(
empty,
planets
),
function (statement, cb) {
client.query(
statement,
function (e) {
if (e) {
console.error(statement)
cb(e)
} else {
cb()
}
}
)
},
function (err) {
expect(err).to.equal(null)
done()
}
)
it('install test database objects', async () => {
const statements = pgDiffSync(empty, planets)
for (const s of statements) {
await client.query(s)
}
})

@@ -67,0 +52,0 @@

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