@wmfs/pg-model
Version:
Takes a relational database structure and returns model objects for noSQL-like abilities.
159 lines (134 loc) • 3.99 kB
JavaScript
const getPreStatementHookFunction = require('./get-pre-statement-hook-function')
function getPostHookFunction (fullTableName, pk) {
return function (result, ctx) {
if (!Object.prototype.hasOwnProperty.call(ctx, 'lastCreatedPrimaryKey')) {
ctx.lastCreatedPrimaryKey = {}
}
ctx.lastCreatedPrimaryKey[fullTableName] = pk
}
}
class Updater {
constructor (model) {
this.model = model
this.fullTableName = model.fullTableName
this.prefix = 'UPDATE ' + this.fullTableName + ' SET '
}
makeStatements (jsonData, options) {
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
addModified (parsedDoc) {
if (this.model.modifiedField) {
parsedDoc.attributeColumns.push(this.model.modifiedField)
parsedDoc.attributeValues.push(new Date())
}
} // addModified
makeUpdateStatement (
jsonData,
script,
options
) {
const parsedDoc = this.model.parseDoc(jsonData)
this.addModifiedBy(parsedDoc)
this.addModified(parsedDoc)
const values = []
const set = []
const key = []
parsedDoc.attributeColumns.forEach(
(column, index) => {
values.push(parsedDoc.attributeValues[index])
set.push(`${column}=$${values.length}`)
}
)
if (options.setMissingPropertiesToNull) {
parsedDoc.missingAttributeColumnNames.forEach(
column => set.push(`${column}=null`)
)
}
parsedDoc.keyColumns.forEach(
(column, index) => {
values.push(parsedDoc.keyValues[index])
key.push(`${column}=$${values.length}`)
}
)
const sql = this.prefix + set.join(', ') + ' WHERE ' + key.join(' AND ')
script.push(
{
sql: sql,
params: values,
postStatementHook: getPostHookFunction(this.fullTableName, parsedDoc.primaryKeyValues)
}
)
} // makeUpdateStatement
makeSubDocsStatements (
jsonData,
script,
options
) {
for (const [subModelId, subModel] of Object.entries(this.model.subModels)) {
if (!Array.isArray(jsonData[subModelId])) {
continue
}
makeSubDocUpsertsStatements(
subModelId,
subModel,
jsonData,
this.fullTableName,
script,
options
)
const subDocPkValues = jsonData[subModelId].map(row => subModel.model.extractPkValuesFromDoc(row))
destroyMissingSubDocsStatement(subModel, subDocPkValues, script, options)
} // for ...
} // makeSubDocsStatements
} // class Updater
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]
}
options.upsert = true
options.destroyMissingSubDocs = true
const subScript = subModel.model.creator.makeStatements(
row,
options,
getPreStatementHookFunction(parentTableName, subModel.columnJoin)
)
script.push(...subScript)
}
}
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