UNPKG

pg-diff-api

Version:

PostgreSQL migration strategy for NodeJS

875 lines (797 loc) 28.8 kB
const objectType = require("./enums/objectType"); const hints = { addColumnNotNullableWithoutDefaultValue: " --WARN: Add a new column not nullable without a default value can occure in a sql error during execution!", changeColumnDataType: " --WARN: Change column data type can occure in a casting error, the suggested casting expression is the default one and may not fit your needs!", dropColumn: " --WARN: Drop column can occure in data loss!", potentialRoleMissing: " --WARN: Grant\\Revoke privileges to a role can occure in a sql error during execution if role is missing to the target database!", identityColumnDetected: " --WARN: Identity column has been detected, an error can occure because constraints violation!", dropTable: " --WARN: Drop table can occure in data loss!", extensionNotInstalled: " -- WARN: Extension must be firstly installed at server level otherwise an error can occure during patch execution!", extensionToUpdate: " -- WARN: Extension must be firstly updated at server level otherwise an error can occure during patch execution!", }; var helper = { /** * * @param {Object} columnSchema */ __generateColumnDataTypeDefinition: function (columnSchema) { let dataType = columnSchema.datatype; if (columnSchema.precision) { let dataTypeScale = columnSchema.scale ? `,${columnSchema.scale}` : ""; dataType += `(${columnSchema.precision}${dataTypeScale})`; } return dataType; }, /** * * @param {String} column * @param {Object} columnSchema */ __generateColumnDefinition: function (column, columnSchema) { let nullableExpression = columnSchema.nullable ? "NULL" : "NOT NULL"; let defaultValue = ""; if (columnSchema.default) defaultValue = `DEFAULT ${columnSchema.default}`; let identityValue = ""; if (columnSchema.identity) identityValue = `GENERATED ${columnSchema.identity} AS IDENTITY`; if (columnSchema.generatedColumn) { nullableExpression = ""; defaultValue = `GENERATED ALWAYS AS ${columnSchema.default} STORED`; identityValue = ""; } let dataType = this.__generateColumnDataTypeDefinition(columnSchema); return `${column} ${dataType} ${nullableExpression} ${defaultValue} ${identityValue}`; }, /** * * @param {String} table * @param {String} role * @param {Object} privileges */ __generateTableGrantsDefinition: function (table, role, privileges) { let definitions = []; if (privileges.select) definitions.push(`GRANT SELECT ON TABLE ${table} TO ${role};${hints.potentialRoleMissing}`); if (privileges.insert) definitions.push(`GRANT INSERT ON TABLE ${table} TO ${role};${hints.potentialRoleMissing}`); if (privileges.update) definitions.push(`GRANT UPDATE ON TABLE ${table} TO ${role};${hints.potentialRoleMissing}`); if (privileges.delete) definitions.push(`GRANT DELETE ON TABLE ${table} TO ${role};${hints.potentialRoleMissing}`); if (privileges.truncate) definitions.push(`GRANT TRUNCATE ON TABLE ${table} TO ${role};${hints.potentialRoleMissing}`); if (privileges.references) definitions.push(`GRANT REFERENCES ON TABLE ${table} TO ${role};${hints.potentialRoleMissing}`); if (privileges.trigger) definitions.push(`GRANT TRIGGER ON TABLE ${table} TO ${role};${hints.potentialRoleMissing}`); return definitions; }, /** * * @param {String} procedure * @param {String} argTypes * @param {String} role * @param {Object} privileges * @param {"f"|"p"} type */ __generateProcedureGrantsDefinition: function (procedure, argTypes, role, privileges, type) { const procedureType = type === "f" ? "FUNCTION" : "PROCEDURE"; let definitions = []; if (privileges.execute) definitions.push(`GRANT EXECUTE ON ${procedureType} ${procedure}(${argTypes}) TO ${role};${hints.potentialRoleMissing}`); return definitions; }, /** * * @param {String} sequence * @param {String} role * @param {Object} privileges */ __generateSequenceGrantsDefinition: function (sequence, role, privileges) { let definitions = []; if (privileges.select) definitions.push(`GRANT SELECT ON SEQUENCE ${sequence} TO ${role};${hints.potentialRoleMissing}`); if (privileges.usage) definitions.push(`GRANT USAGE ON SEQUENCE ${sequence} TO ${role};${hints.potentialRoleMissing}`); if (privileges.update) definitions.push(`GRANT UPDATE ON SEQUENCE ${sequence} TO ${role};${hints.potentialRoleMissing}`); return definitions; }, /** * * @param {String} objectType * @param {String} objectName * @param {String} comment * @param {String} parentObjectName */ generateChangeCommentScript: function (objectType, objectName, comment, parentObjectName = null) { const description = comment ? `'${comment.replaceAll("'", "''")}'` : "NULL"; const parentObject = parentObjectName ? `ON ${parentObjectName}` : ""; let script = `\nCOMMENT ON ${objectType} ${objectName} ${parentObject} IS ${description};\n`; return script; }, /** * * @param {String} schema * @param {String} owner */ generateCreateSchemaScript: function (schema, owner) { let script = `\nCREATE SCHEMA IF NOT EXISTS ${schema} AUTHORIZATION ${owner};\n`; return script; }, /** * * @param {String} table */ generateDropTableScript: function (table) { let script = `\nDROP TABLE IF EXISTS ${table}; ${hints.dropTable}\n`; return script; }, /** * * @param {String} table * @param {Object} schema */ generateCreateTableScript: function (table, schema) { //Generate columns script let columns = []; for (let column in schema.columns) { columns.push(this.__generateColumnDefinition(column, schema.columns[column])); } //Generate constraints script for (let constraint in schema.constraints) { columns.push(`CONSTRAINT ${constraint} ${schema.constraints[constraint].definition} `); } //Generate options script let options = ""; if (schema.options && schema.options.withOids) options = `\nWITH ( OIDS=${schema.options.withOids.toString().toUpperCase()} )`; //Generate indexes script let indexes = []; for (let index in schema.indexes) { let definition = schema.indexes[index].definition; definition = definition.replace("CREATE INDEX", "CREATE INDEX IF NOT EXISTS"); definition = definition.replace("CREATE UNIQUE INDEX", "CREATE UNIQUE INDEX IF NOT EXISTS"); indexes.push(`\n${definition};\n`); } //Generate privileges script let privileges = []; privileges.push(`ALTER TABLE IF EXISTS ${table} OWNER TO ${schema.owner};\n`); for (let role in schema.privileges) { privileges = privileges.concat(this.__generateTableGrantsDefinition(table, role, schema.privileges[role])); } let columnsComment = []; for (let column in schema.columns) { columnsComment.push(this.generateChangeCommentScript(objectType.COLUMN, `${table}.${column}`, schema.columns[column].comment)); } let constraintsComment = []; for (let constraint in schema.constraints) { constraintsComment.push( this.generateChangeCommentScript(objectType.CONSTRAINT, constraint, schema.constraints[constraint].comment, table) ); } let indexesComment = []; for (let index in schema.indexes) { indexesComment.push( this.generateChangeCommentScript(objectType.INDEX, `"${schema.indexes[index].schema}"."${index}"`, schema.indexes[index].comment) ); } let script = `\nCREATE TABLE IF NOT EXISTS ${table} (\n\t${columns.join(",\n\t")}\n)${options};\n${indexes.join("\n")}\n${privileges.join( "\n" )}\n${columnsComment.join("\n")}${constraintsComment.join("\n")}${indexesComment.join("\n")}`; return script; }, /** * * @param {String} table * @param {String} column * @param {Object} schema */ generateAddTableColumnScript: function (table, column, schema) { let script = `\nALTER TABLE IF EXISTS ${table} ADD COLUMN IF NOT EXISTS ${this.__generateColumnDefinition(column, schema)};`; if (script.includes("NOT NULL") && !script.includes("DEFAULT")) script += hints.addColumnNotNullableWithoutDefaultValue; script += "\n"; return script; }, /** * * @param {String} table * @param {String} column * @param {Object} changes */ generateChangeTableColumnScript: function (table, column, changes) { let definitions = []; if (Object.prototype.hasOwnProperty.call(changes, "nullable")) definitions.push(`ALTER COLUMN ${column} ${changes.nullable ? "DROP NOT NULL" : "SET NOT NULL"}`); if (changes.datatype) { definitions.push(`${hints.changeColumnDataType}`); let dataTypeDefinition = this.__generateColumnDataTypeDefinition(changes); definitions.push(`ALTER COLUMN ${column} SET DATA TYPE ${dataTypeDefinition} USING ${column}::${dataTypeDefinition}`); } if (Object.prototype.hasOwnProperty.call(changes, "default")) definitions.push(`ALTER COLUMN ${column} ${changes.default ? "SET" : "DROP"} DEFAULT ${changes.default || ""}`); if (Object.prototype.hasOwnProperty.call(changes, "identity") && Object.prototype.hasOwnProperty.call(changes, "isNewIdentity")) { let identityDefinition = ""; if (changes.identity) { //truly values identityDefinition = `${changes.isNewIdentity ? "ADD" : "SET"} GENERATED ${changes.identity} ${ changes.isNewIdentity ? "AS IDENTITY" : "" }`; } else { //falsy values identityDefinition = "DROP IDENTITY IF EXISTS"; } definitions.push(`ALTER COLUMN ${column} ${identityDefinition}`); } let script = `\nALTER TABLE IF EXISTS ${table}\n\t${definitions.join(",\n\t")};\n`; //TODO: Should we include COLLATE when change column data type? return script; }, /** * * @param {String} table * @param {String} column */ generateDropTableColumnScript: function (table, column, withoutHint = false) { let script = `\nALTER TABLE IF EXISTS ${table} DROP COLUMN IF EXISTS ${column} CASCADE;${withoutHint ? "" : hints.dropColumn}\n`; return script; }, /** * * @param {String} table * @param {String} constraint * @param {Object} schema */ generateAddTableConstraintScript: function (table, constraint, schema) { let script = `\nALTER TABLE IF EXISTS ${table} ADD CONSTRAINT ${constraint} ${schema.definition};\n`; return script; }, /** * * @param {String} table * @param {String} constraint */ generateDropTableConstraintScript: function (table, constraint) { let script = `\nALTER TABLE IF EXISTS ${table} DROP CONSTRAINT IF EXISTS ${constraint};\n`; return script; }, /** * * @param {String} table * @param {Object} options */ generateChangeTableOptionsScript: function (table, options) { let script = `\nALTER TABLE IF EXISTS ${table} SET ${options.withOids ? "WITH" : "WITHOUT"} OIDS;\n`; return script; }, generateChangeIndexScript: function (index, definition) { let script = `\nDROP INDEX IF EXISTS ${index};\n${definition};\n`; return script; }, /** * * @param {String} index */ generateDropIndexScript: function (index) { let script = `\nDROP INDEX IF EXISTS ${index};\n`; return script; }, /** * * @param {String} table * @param {String} role * @param {Object} privileges */ generateTableRoleGrantsScript: function (table, role, privileges) { let script = `\n${this.__generateTableGrantsDefinition(table, role, privileges).join("\n")}\n`; return script; }, /** * * @param {String} table * @param {String} role * @param {Object} changes */ generateChangesTableRoleGrantsScript: function (table, role, changes) { let privileges = []; if (Object.prototype.hasOwnProperty.call(changes, "select")) privileges.push( `${changes.select ? "GRANT" : "REVOKE"} SELECT ON TABLE ${table} ${changes.select ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); if (Object.prototype.hasOwnProperty.call(changes, "insert")) privileges.push( `${changes.insert ? "GRANT" : "REVOKE"} INSERT ON TABLE ${table} ${changes.insert ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); if (Object.prototype.hasOwnProperty.call(changes, "update")) privileges.push( `${changes.update ? "GRANT" : "REVOKE"} UPDATE ON TABLE ${table} ${changes.update ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); if (Object.prototype.hasOwnProperty.call(changes, "delete")) privileges.push( `${changes.delete ? "GRANT" : "REVOKE"} DELETE ON TABLE ${table} ${changes.delete ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); if (Object.prototype.hasOwnProperty.call(changes, "truncate")) privileges.push( `${changes.truncate ? "GRANT" : "REVOKE"} TRUNCATE ON TABLE ${table} ${changes.truncate ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); if (Object.prototype.hasOwnProperty.call(changes, "references")) privileges.push( `${changes.references ? "GRANT" : "REVOKE"} REFERENCES ON TABLE ${table} ${changes.references ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); if (Object.prototype.hasOwnProperty.call(changes, "trigger")) privileges.push( `${changes.trigger ? "GRANT" : "REVOKE"} TRIGGER ON TABLE ${table} ${changes.trigger ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); let script = `\n${privileges.join("\n")}\n`; return script; }, /** * * @param {String} table * @param {String} owner */ generateChangeTableOwnerScript: function (table, owner) { let script = `\nALTER TABLE IF EXISTS ${table} OWNER TO ${owner};\n`; return script; }, /** * * @param {String} view * @param {Object} schema */ generateCreateViewScript: function (view, schema) { //Generate privileges script let privileges = []; privileges.push(`ALTER VIEW IF EXISTS ${view} OWNER TO ${schema.owner};`); for (let role in schema.privileges) { privileges = privileges.concat(this.__generateTableGrantsDefinition(view, role, schema.privileges[role])); } let script = `\nCREATE OR REPLACE VIEW ${view} AS ${schema.definition}\n${privileges.join("\n")}\n`; return script; }, /** * * @param {String} view */ generateDropViewScript: function (view) { let script = `\nDROP VIEW IF EXISTS ${view};`; return script; }, /** * * @param {String} view * @param {Object} schema */ generateCreateMaterializedViewScript: function (view, schema) { //Generate indexes script let indexes = []; for (let index in schema.indexes) { indexes.push(`\n${schema.indexes[index].definition};\n`); } //Generate privileges script let privileges = []; privileges.push(`ALTER MATERIALIZED VIEW IF EXISTS ${view} OWNER TO ${schema.owner};\n`); for (let role in schema.privileges) { privileges = privileges.concat(this.__generateTableGrantsDefinition(view, role, schema.privileges[role])); } let script = `\nCREATE MATERIALIZED VIEW IF NOT EXISTS ${view} AS ${schema.definition}\n${indexes.join("\n")}\n${privileges.join("\n")}\n`; return script; }, /** * * @param {String} view */ generateDropMaterializedViewScript: function (view) { let script = `\nDROP MATERIALIZED VIEW IF EXISTS ${view};`; return script; }, /** * * @param {String} procedure * @param {Object} schema * @param {"f"|"p"} type */ generateCreateProcedureScript: function (procedure, schema) { const procedureType = schema.type === "f" ? "FUNCTION" : "PROCEDURE"; //Generate privileges script let privileges = []; privileges.push(`ALTER ${procedureType} ${procedure}(${schema.argTypes}) OWNER TO ${schema.owner};`); for (let role in schema.privileges) { privileges = privileges.concat( this.__generateProcedureGrantsDefinition(procedure, schema.argTypes, role, schema.privileges[role], schema.type) ); } let script = `\n${schema.definition};\n${privileges.join("\n")}\n`; return script; }, /** * * @param {String} aggregate * @param {Object} schema */ generateCreateAggregateScript: function (aggregate, schema) { //Generate privileges script let privileges = []; privileges.push(`ALTER AGGREGATE ${aggregate}(${schema.argTypes}) OWNER TO ${schema.owner};`); for (let role in schema.privileges) { privileges = privileges.concat(this.__generateProcedureGrantsDefinition(aggregate, schema.argTypes, role, schema.privileges[role], "f")); } let script = `\nCREATE AGGREGATE ${aggregate} (${schema.argTypes}) (\n${schema.definition}\n);\n${privileges.join("\n")}\n`; return script; }, /** * * @param {String} procedure * @param {Object} schema */ generateChangeProcedureScript: function (procedure, schema) { const procedureType = schema.type === "f" ? "FUNCTION" : "PROCEDURE"; let script = `\nDROP ${procedureType} IF EXISTS ${procedure}(${schema.argTypes});\n${this.generateCreateProcedureScript(procedure, schema)}`; return script; }, /** * * @param {String} aggregate * @param {Object} schema */ generateChangeAggregateScript: function (aggregate, schema) { let script = `\nDROP AGGREGATE IF EXISTS ${aggregate}(${schema.argTypes});\n${this.generateCreateAggregateScript(aggregate, schema)}`; return script; }, /** * * @param {String} procedure * @param {String} procedureArgs */ generateDropProcedureScript: function (procedure, procedureArgs) { let script = `\nDROP FUNCTION IF EXISTS ${procedure}(${procedureArgs});\n`; return script; }, /** * * @param {String} aggregate * @param {String} aggregateArgs */ generateDropAggregateScript: function (aggregate, aggregateArgs) { let script = `\nDROP AGGREGATE IF EXISTS ${aggregate}(${aggregateArgs});\n`; return script; }, /** * * @param {String} procedure * @param {String} argTypes * @param {String} role * @param {Object} privileges * @param {"f"|"p"} type */ generateProcedureRoleGrantsScript: function (procedure, argTypes, role, privileges, type) { let script = `\n${this.__generateProcedureGrantsDefinition(procedure, argTypes, role, privileges, type).join("\n")}`; return script; }, /** * * @param {String} procedure * @param {String} argTypes * @param {String} role * @param {Object} changes * @param {"f"|"p"} type */ generateChangesProcedureRoleGrantsScript: function (procedure, argTypes, role, changes, type) { const procedureType = type === "f" ? "FUNCTION" : "PROCEDURE"; let privileges = []; if (Object.prototype.hasOwnProperty.call(changes, "execute")) privileges.push( `${changes.execute ? "GRANT" : "REVOKE"} EXECUTE ON ${procedureType} ${procedure}(${argTypes}) ${ changes.execute ? "TO" : "FROM" } ${role};${hints.potentialRoleMissing}` ); let script = `\n${privileges.join("\n")}`; return script; }, /** * * @param {String} procedure * @param {String} argTypes * @param {String} owner * @param {"p"!"f"} type */ generateChangeProcedureOwnerScript: function (procedure, argTypes, owner, type) { const procedureType = type === "f" ? "FUNCTION" : "PROCEDURE"; let script = `\nALTER ${procedureType} ${procedure}(${argTypes}) OWNER TO ${owner};`; return script; }, /** * * @param {String} aggregate * @param {String} argTypes * @param {String} owner */ generateChangeAggregateOwnerScript: function (aggregate, argTypes, owner) { let script = `\nALTER AGGREGATE ${aggregate}(${argTypes}) OWNER TO ${owner};`; return script; }, /** * * @param {String} table * @param {Object} fields * @param {Object} filterConditions * @param {Object} changes */ generateUpdateTableRecordScript: function (table, fields, filterConditions, changes) { let updates = []; for (let field in changes) { updates.push(`"${field}" = ${this.__generateSqlFormattedValue(field, fields, changes[field])}`); } let conditions = []; for (let condition in filterConditions) { conditions.push(`"${condition}" = ${this.__generateSqlFormattedValue(condition, fields, filterConditions[condition])}`); } let script = `\nUPDATE ${table} SET ${updates.join(", ")} WHERE ${conditions.join(" AND ")};\n`; return script; }, /** * * @param {String} table * @param {Object} record * @param {Array} fields * @param {Boolean} isIdentityValuesAllowed */ generateInsertTableRecordScript: function (table, record, fields, isIdentityValuesAllowed) { let fieldNames = []; let fieldValues = []; for (let field in record) { fieldNames.push(`"${field}"`); fieldValues.push(this.__generateSqlFormattedValue(field, fields, record[field])); } let script = `\nINSERT INTO ${table} (${fieldNames.join(", ")}) ${ isIdentityValuesAllowed ? "" : "OVERRIDING SYSTEM VALUE" } VALUES (${fieldValues.join(", ")});\n`; if (!isIdentityValuesAllowed) script = `\n${hints.identityColumnDetected}` + script; return script; }, /** * * @param {String} table * @param {Array} fields * @param {Object} keyFieldsMap */ generateDeleteTableRecordScript: function (table, fields, keyFieldsMap) { let conditions = []; for (let condition in keyFieldsMap) { conditions.push(`"${condition}" = ${this.__generateSqlFormattedValue(condition, fields, keyFieldsMap[condition])}`); } let script = `\nDELETE FROM ${table} WHERE ${conditions.join(" AND ")};\n`; return script; }, /** * * @param {String} fieldName * @param {Array} fields * @param {Object} value */ __generateSqlFormattedValue: function (fieldName, fields, value) { if (value === undefined) throw new Error(`The field "${fieldName}" contains an "undefined" value!`); if (value === null) return "NULL"; let dataTypeName = ""; let dataTypeCategory = "X"; let dataTypeIndex = fields.findIndex((field) => { return fieldName === field.name; }); if (dataTypeIndex >= 0) { dataTypeName = fields[dataTypeIndex].datatype; dataTypeCategory = fields[dataTypeIndex].dataTypeCategory; if (fields[dataTypeIndex].isGeneratedColumn) return "DEFAULT"; } switch (dataTypeCategory) { case "D": //DATE TIME return `'${value.toISOString()}'`; case "V": //BIT case "S": //STRING return `'${value.replace(/'/g, "''")}'`; // return `'${value}'`; case "A": //ARRAY return `'{${value.join()}}'`; case "R": //RANGE return `'${value}'`; case "B": //BOOL case "E": //ENUM case "G": //GEOMETRIC case "I": //NETWORK ADDRESS case "N": //NUMERIC case "T": //TIMESPAN return value; case "U": { //USER TYPE switch (dataTypeName) { case "jsonb": case "json": return `'${JSON.stringify(value).replace(/'/g, "''")}'`; default: //like XML, UUID, GEOMETRY, etc. return `'${value.replace(/'/g, "''")}'`; } } case "X": //UNKNOWN case "P": //PSEUDO TYPE case "C": //COMPOSITE TYPE default: throw new Error(`The data type category '${dataTypeCategory}' is not implemented yet!`); } }, generateMergeTableRecord(table, fields, changes, options) { let fieldNames = []; let fieldValues = []; let updates = []; for (let field in changes) { fieldNames.push(`"${field}"`); fieldValues.push(this.__generateSqlFormattedValue(field, fields, changes[field])); updates.push(`"${field}" = ${this.__generateSqlFormattedValue(field, fields, changes[field])}`); } let conflictDefinition = ""; if (options.constraintName) conflictDefinition = `ON CONSTRAINT ${options.constraintName}`; else if (options.uniqueFields && options.uniqueFields.length > 0) conflictDefinition = `("${options.uniqueFields.join('", "')}")`; else throw new Error(`Impossible to generate conflict definition for table ${table} record to merge!`); let script = `\nINSERT INTO ${table} (${fieldNames.join(", ")}) VALUES (${fieldValues.join( ", " )})\nON CONFLICT ${conflictDefinition}\nDO UPDATE SET ${updates.join(", ")}`; return script; }, /** * * @param {String} tableName * @param {Object} sequence */ generateSetSequenceValueScript(tableName, sequence) { let script = `\nSELECT setval(pg_get_serial_sequence('${tableName}', '${sequence.attname}'), max("${sequence.attname}"), true) FROM ${tableName};\n`; return script; }, /** * * @param {String} sequence * @param {String} property * @param {Number} value */ generateChangeSequencePropertyScript(sequence, property, value) { var definition = ""; switch (property) { case "startValue": definition = `START WITH ${value}`; break; case "minValue": definition = `MINVALUE ${value}`; break; case "maxValue": definition = `MAXVALUE ${value}`; break; case "increment": definition = `INCREMENT BY ${value}`; break; case "cacheSize": definition = `CACHE ${value}`; break; case "isCycle": definition = `${value ? "" : "NO"} CYCLE`; break; case "owner": definition = `OWNER TO ${value}`; break; } let script = `\nALTER SEQUENCE IF EXISTS ${sequence} ${definition};\n`; return script; }, /** * * @param {String} sequence * @param {String} role * @param {Object} changes */ generateChangesSequenceRoleGrantsScript: function (sequence, role, changes) { let privileges = []; if (Object.prototype.hasOwnProperty.call(changes, "select")) privileges.push( `${changes.select ? "GRANT" : "REVOKE"} SELECT ON SEQUENCE ${sequence} ${changes.select ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); if (Object.prototype.hasOwnProperty.call(changes, "usage")) privileges.push( `${changes.usage ? "GRANT" : "REVOKE"} USAGE ON SEQUENCE ${sequence} ${changes.usage ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); if (Object.prototype.hasOwnProperty.call(changes, "update")) privileges.push( `${changes.update ? "GRANT" : "REVOKE"} UPDATE ON SEQUENCE ${sequence} ${changes.update ? "TO" : "FROM"} ${role};${ hints.potentialRoleMissing }` ); let script = `\n${privileges.join("\n")}`; return script; }, /** * * @param {String} sequence * @param {String} role * @param {Object} privileges */ generateSequenceRoleGrantsScript: function (sequence, role, privileges) { let script = `\n${this.__generateSequenceGrantsDefinition(sequence, role, privileges).join("\n")}`; return script; }, /** * * @param {String} sequence * @param {Object} schema */ generateCreateSequenceScript: function (sequence, schema) { //Generate privileges script let privileges = []; privileges.push(`ALTER SEQUENCE ${sequence} OWNER TO ${schema.owner};`); for (let role in schema.privileges) { privileges = privileges.concat(this.__generateSequenceGrantsDefinition(sequence, role, schema.privileges[role])); } let script = `\n CREATE SEQUENCE IF NOT EXISTS ${sequence} \tINCREMENT BY ${schema.increment} \tMINVALUE ${schema.minValue} \tMAXVALUE ${schema.maxValue} \tSTART WITH ${schema.startValue} \tCACHE ${schema.cacheSize} \t${schema.isCycle ? "" : "NO "}CYCLE; \n${privileges.join("\n")}\n`; return script; }, /** * * @param {String} old_name * @param {String} new_name */ generateRenameSequenceScript: function (old_name, new_name) { let script = `\nALTER SEQUENCE IF EXISTS ${old_name} RENAME TO ${new_name};\n`; return script; }, /** * * @param {String} tableName * @param {Object} trigger * @returns */ generateDropTriggerScript: function (tableName, trigger) { let script = `\nDROP TRIGGER ${trigger} ON ${tableName};\n`; return script; }, /** * * @param {Object} trigger * @returns */ generateCreateTriggerScript: function (trigger) { let script = `\n${trigger.definition};\n`; return script; }, /** * * @param {String} name * @returns */ generateCreateExtensionScript: function (name) { let script = `\nCREATE EXTENSION IF NOT EXISTS "${name}";${hints.extensionNotInstalled}\n`; return script; }, /** * * @param {String} name * @param {String} version * @returns */ generateUpdateExtensionScript: function (name, version) { let script = `\nALTER EXTENSION "${name}" UPDATE TO '${version}';${hints.extensionToUpdate}\n`; return script; }, }; module.exports = helper;