UNPKG

ddl-manager

Version:

store postgres procedures and triggers in files

183 lines 7.45 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FileParser = void 0; const psql_lang_1 = require("psql-lang"); const ast_1 = require("../ast"); const CacheParser_1 = require("./CacheParser"); const Comment_1 = require("../database/schema/Comment"); const DatabaseFunction_1 = require("../database/schema/DatabaseFunction"); const DatabaseTrigger_1 = require("../database/schema/DatabaseTrigger"); const TableID_1 = require("../database/schema/TableID"); const defaults_1 = require("./defaults"); const FileSyntax_1 = require("./FileSyntax"); const assert_1 = __importDefault(require("assert")); class FileParser { static parse(sql) { const parser = new FileParser(); return parser.parseSql(sql); } static parseFile(filePath) { const parser = new FileParser(); return parser.parseFile(filePath); } static parseFunction(sql) { const fileContent = FileParser.parse(sql); assert_1.default.ok(fileContent, "should be not empty sql"); const func = (fileContent.functions || [])[0]; assert_1.default.ok(func instanceof DatabaseFunction_1.DatabaseFunction, "sql should contain function"); return func; } static parseCache(sql) { const fileContent = FileParser.parse(sql); assert_1.default.ok(fileContent, "should be not empty sql"); const cache = (fileContent.cache || [])[0]; assert_1.default.ok(cache instanceof ast_1.Cache, "sql should contain cache"); return cache; } parseFile(filePath) { const { cursor } = psql_lang_1.Sql.file(filePath); return this.parse(cursor); } parseSql(sql) { const { cursor } = psql_lang_1.Sql.code(sql); return this.parse(cursor); } parse(cursor) { const content = cursor.parse(FileSyntax_1.FileSyntax); const state = { functions: [], triggers: [], cache: content.row.caches.map(buildCache) }; for (const funcNode of content.row.functions) { addFunction(cursor, state, funcNode); } for (const triggerNode of content.row.triggers) { addTrigger(cursor, state, triggerNode); } return state; } } exports.FileParser = FileParser; function addFunction(cursor, state, funcNode) { const func = buildFunction(funcNode); // check duplicate const isDuplicate = state.functions.some((prevFunc) => prevFunc.getSignature() === func.getSignature()); if (isDuplicate) { cursor.throwError("duplicated function: " + func.getSignature(), funcNode); } // two function inside file, can be with only same name and schema const isWrongName = state.functions.some((prevFunc) => prevFunc.name !== func.name || prevFunc.schema !== func.schema); if (isWrongName) { cursor.throwError("two function inside file, can be with only same name and schema", funcNode); } state.functions.push(func); } function addTrigger(cursor, state, triggerNode) { const trigger = buildTrigger(triggerNode); // validate function name and trigger procedure const firstFunc = state.functions[0]; if (firstFunc) { if (firstFunc.schema !== trigger.procedure.schema || firstFunc.name !== trigger.procedure.name) { const wrongName = `${trigger.procedure.schema}.${trigger.procedure.name}`; cursor.throwError(`wrong procedure name ${wrongName}`, triggerNode); } // validate function returns type const hasTriggerFunc = state.functions.some((func) => func.returns.type === "trigger"); if (!hasTriggerFunc) { cursor.throwError("file must contain function with returns type trigger", triggerNode); } } // check duplicate const isDuplicate = state.triggers.some((prevTrigger) => prevTrigger.getSignature() === trigger.getSignature()); if (isDuplicate) { cursor.throwError("duplicated trigger: " + trigger.getSignature(), triggerNode); } state.triggers.push(trigger); } function buildFunction(funcNode) { var _a, _b; return new DatabaseFunction_1.DatabaseFunction({ schema: ((_a = funcNode.row.schema) === null || _a === void 0 ? void 0 : _a.toString()) || defaults_1.DEFAULT_SCHEMA, name: funcNode.row.name.toString(), args: funcNode.row.args.map(parseArg), returns: parseReturns(funcNode), body: funcNode.row.body.row.string, language: funcNode.row.language, immutable: funcNode.row.immutability === "immutable", returnsNullOnNull: funcNode.row.inputNullsRule === "returns null on null input", stable: funcNode.row.immutability === "stable", strict: funcNode.row.inputNullsRule === "strict", parallel: funcNode.row.parallel ? [funcNode.row.parallel] : undefined, cost: Number((_b = funcNode.row.cost) === null || _b === void 0 ? void 0 : _b.toString()) || undefined, comment: Comment_1.Comment.fromFs({ objectType: "function" }) }); } function buildTrigger(triggerNode) { var _a, _b, _c; return new DatabaseTrigger_1.DatabaseTrigger({ name: triggerNode.row.name.toString(), table: TableID_1.TableID.fromString(triggerNode.row.table.toString()), procedure: { schema: ((_a = triggerNode.row.procedure.row.schema) === null || _a === void 0 ? void 0 : _a.toString()) || defaults_1.DEFAULT_SCHEMA, name: (_b = triggerNode.row.procedure.row.name) === null || _b === void 0 ? void 0 : _b.toString(), args: [] }, before: triggerNode.row.events.before, after: !triggerNode.row.events.before, insert: triggerNode.row.events.insert, update: !!triggerNode.row.events.update, updateOf: Array.isArray(triggerNode.row.events.update) ? triggerNode.row.events.update .map(name => name.toValue()) .sort() : undefined, delete: triggerNode.row.events.delete, when: (_c = triggerNode.row.when) === null || _c === void 0 ? void 0 : _c.toString(), constraint: triggerNode.row.constraint, deferrable: triggerNode.row.deferrable, statement: triggerNode.row.statement, initially: triggerNode.row.initially, comment: Comment_1.Comment.fromFs({ objectType: "trigger" }) }); } function buildCache(cacheSyntax) { return CacheParser_1.CacheParser.parse(cacheSyntax); } function parseReturns(funcNode) { const returns = funcNode.row.returns.row; if ("table" in returns) { return { setof: returns.setOf, table: returns.table.map(parseArg) }; } return { setof: returns.setOf, type: returns.type.toString() }; } function parseArg(argNode) { var _a, _b; return { out: argNode.row.out, in: argNode.row.in, name: (_a = argNode.row.name) === null || _a === void 0 ? void 0 : _a.toString(), type: argNode.row.type.toString(), default: (_b = argNode.row.default) === null || _b === void 0 ? void 0 : _b.toString() }; } //# sourceMappingURL=FileParser.js.map