UNPKG

ddl-manager

Version:

store postgres procedures and triggers in files

213 lines 8.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExpressionParser = void 0; const psql_lang_1 = require("psql-lang"); const ast_1 = require("../ast"); const UnknownExpressionElementParser_1 = require("./UnknownExpressionElementParser"); const ColumnReferenceParser_1 = require("./ColumnReferenceParser"); const ArrayElement_1 = require("../ast/expression/ArrayElement"); const assert_1 = require("assert"); const funcsWithoutOrderBy = [ // 1 + 1 = 1 + 1 "count", // a + b = b + a "sum", // Math.max(a, b) = Math.max(b, a) "max", // Math.min(a, b) = Math.max(b, a) "min", // x || y = y || x "bool_or", // x && y = y && x "bool_and" ]; class ExpressionParser { constructor() { this.columnReferenceParser = new ColumnReferenceParser_1.ColumnReferenceParser(); this.unknownExpressionElementParser = new UnknownExpressionElementParser_1.UnknownExpressionElementParser(); } parse(input) { const sql = toOperand(input); const elements = this.parseElements(sql); if (elements.length === 1 && elements[0] instanceof ast_1.Expression) { return elements[0]; } return new ast_1.Expression(elements); } parseElements(elemSyntax) { if (elemSyntax instanceof psql_lang_1.SubExpression) { return [new ast_1.Expression(this.parseElements(elemSyntax.row.subExpression), true)]; } return this.tryParseBinaryOperator(elemSyntax) || [ this.tryParseFunctionCall(elemSyntax) || this.tryParsePgArray(elemSyntax) || this.tryParseExtract(elemSyntax) || this.tryParseCaseWhen(elemSyntax) || this.tryParseColumnRef(elemSyntax) || this.parseUnknown(elemSyntax) ]; } tryParseBinaryOperator(elemSyntax) { if (elemSyntax instanceof psql_lang_1.BinaryOperator) { return [ ...this.parseElements(elemSyntax.row.left), new ast_1.Operator(elemSyntax.row.operator), ...this.parseElements(elemSyntax.row.right) ]; } if (elemSyntax instanceof psql_lang_1.PreUnaryOperator) { return [ new ast_1.Operator(elemSyntax.row.preOperator), ...this.parseElements(elemSyntax.row.operand) ]; } if (elemSyntax instanceof psql_lang_1.PostUnaryOperator) { return [ ...this.parseElements(elemSyntax.row.operand), new ast_1.Operator(elemSyntax.row.postOperator) ]; } if (elemSyntax instanceof psql_lang_1.CastTo) { return [ ...this.parseElements(elemSyntax.row.cast), new ast_1.Operator("::"), ast_1.UnknownExpressionElement.fromSql(elemSyntax.row.to.toString()) ]; } if (elemSyntax instanceof psql_lang_1.SquareBrackets) { return [ ...this.parseElements(elemSyntax.row.operand), ast_1.UnknownExpressionElement.fromSql("[" + elemSyntax.row.index.toString() + "]") ]; } if (elemSyntax instanceof psql_lang_1.EqualAny) { return [ ...this.parseElements(elemSyntax.row.operand), new ast_1.Operator("="), ast_1.UnknownExpressionElement.fromSql("any(" + elemSyntax.row.equalAny.toString() + ")", this.unknownExpressionElementParser.buildColumnsMap(elemSyntax.row.equalAny)) ]; } if (elemSyntax instanceof psql_lang_1.In) { const unknownSql = Array.isArray(elemSyntax.row.in) ? `in (${elemSyntax.row.in.join(", ")})` : `in (${elemSyntax.row.in})`; return [ ...this.parseElements(elemSyntax.row.operand), ast_1.UnknownExpressionElement.fromSql(unknownSql, this.unknownExpressionElementParser.buildColumnsMap(elemSyntax.row.in)) ]; } } tryParseFunctionCall(funcCallSyntax) { if (!(funcCallSyntax instanceof psql_lang_1.FunctionCall)) { return; } const funcNameSyntax = funcCallSyntax.row.call; const funcName = funcNameSyntax.toString(); let args = funcCallSyntax.row.arguments.map(argSql => this.parseFunctionCallArgument(funcName, argSql)); let where; if (funcCallSyntax.row.filter) { where = this.parse(funcCallSyntax.row.filter); } let orderByItems = []; if (funcCallSyntax.row.orderBy) { funcCallSyntax.row.orderBy.forEach(itemSyntax => { const nulls = itemSyntax.row.nulls; const vector = itemSyntax.row.vector; const expression = this.parse(itemSyntax.row.expression); const item = new ast_1.OrderByItem({ type: vector, expression, nulls }); orderByItems.push(item); }); } let distinct = funcCallSyntax.row.form == "distinct"; if (funcsWithoutOrderBy.includes(funcName)) { orderByItems = []; } if (funcName === "sum") { orderByItems = []; } // min(distinct x) = min(x) // max(distinct x) = max(x) // bool_or(distinct x) = bool_or(x) // bool_and(distinct x) = bool_and(x) const funcsWithoutDistinct = [ "max", "min", "bool_or", "bool_and" ]; if (funcsWithoutDistinct.includes(funcName)) { distinct = false; } // count(id_client) = count(id_partner) = count(*) // count(distinct id_client) != count(id_partner) if (funcName === "count" && !distinct) { args = [ast_1.Expression.unknown("*")]; } const funcCall = new ast_1.FuncCall(funcName, args, where, distinct, orderByItems.length ? new ast_1.OrderBy(orderByItems) : undefined); return funcCall; } tryParsePgArray(elemSyntax) { if (!(elemSyntax instanceof psql_lang_1.ArrayLiteral)) { return; } const content = elemSyntax.row.array.map(expression => this.parse(expression)); return new ArrayElement_1.ArrayElement(content); } tryParseExtract(elemSyntax) { if (!(elemSyntax instanceof psql_lang_1.Extract)) { return; } const extract = elemSyntax.row.extract; const from = this.parse(elemSyntax.row.from); return new ast_1.Extract(extract, from); } tryParseCaseWhen(elemSyntax) { if (!(elemSyntax instanceof psql_lang_1.CaseWhen)) { return; } return new ast_1.CaseWhen({ cases: elemSyntax.row.case.map(caseSyntax => ({ when: this.parse(caseSyntax.row.when), then: this.parse(caseSyntax.row.then) })), else: elemSyntax.row.else ? this.parse(elemSyntax.row.else) : undefined }); } tryParseColumnRef(elemSyntax) { if (!(elemSyntax instanceof psql_lang_1.ColumnReference)) { return; } assert_1.strict.ok(!elemSyntax.row.allColumns); return this.columnReferenceParser.parse(elemSyntax); } parseUnknown(elemSyntax) { return this.unknownExpressionElementParser.parse(elemSyntax); } parseFunctionCallArgument(funcName, argSql) { if (funcName === "count" && (argSql.toString()).trim() === "*") { return new ast_1.Expression([ new ast_1.UnknownExpressionElement(new psql_lang_1.ColumnReference({ row: { column: [] } })) ]); } return this.parse(argSql); } } exports.ExpressionParser = ExpressionParser; function toOperand(input) { if (typeof input === "string") { return psql_lang_1.Sql.code(input).parse(psql_lang_1.Expression).operand(); } if (input instanceof psql_lang_1.Expression) { return input.operand(); } return input; } //# sourceMappingURL=ExpressionParser.js.map