ddl-manager
Version:
store postgres procedures and triggers in files
302 lines • 11.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Expression = void 0;
const Operator_1 = require("./Operator");
const FuncCall_1 = require("./FuncCall");
const AbstractExpressionElement_1 = require("./AbstractExpressionElement");
const UnknownExpressionElement_1 = require("./UnknownExpressionElement");
const ColumnReference_1 = require("./ColumnReference");
const Exists_1 = require("./Exists");
class Expression extends AbstractExpressionElement_1.AbstractExpressionElement {
constructor(elements = [], brackets = false) {
super();
this.elements = elements;
this.brackets = brackets;
}
static and(conditions) {
return Expression.condition("and", conditions);
}
static or(conditions) {
return Expression.condition("or", conditions);
}
static unknown(sql, columnsMap = {}) {
const unknownElement = UnknownExpressionElement_1.UnknownExpressionElement.fromSql(sql, columnsMap);
return new Expression([unknownElement]);
}
static funcCall(name, args) {
const funcElem = new FuncCall_1.FuncCall(name, args);
return new Expression([funcElem]);
}
static condition(operator, conditions) {
const elements = [];
for (let i = 0, n = conditions.length; i < n; i++) {
if (i > 0) {
elements.push(new Operator_1.Operator(operator));
}
const sql = conditions[i];
if (typeof sql === "string") {
elements.push(UnknownExpressionElement_1.UnknownExpressionElement.fromSql(sql));
}
else {
elements.push(sql);
}
}
return new Expression(elements).extrude();
}
children() {
return this.elements;
}
and(otherExpression) {
if (!otherExpression) {
return this;
}
const canCombineToPlainCondition = (this.onlyOperators("and") &&
otherExpression.onlyOperators("and"));
if (canCombineToPlainCondition) {
return new Expression([
...this.elements,
new Operator_1.Operator("and"),
...otherExpression.elements
]);
}
return new Expression([
this,
new Operator_1.Operator("and"),
otherExpression
]);
}
getExplicitCastType() {
const twoLastElements = this.elements.slice(-2);
const isCasting = (twoLastElements.length === 2 &&
twoLastElements[0].toString() === "::");
if (isCasting) {
return twoLastElements[1].toString();
}
}
isCoalesce() {
if (!this.isFuncCall()) {
return false;
}
const funcCall = this.getFuncCalls()[0];
return funcCall.name === "coalesce";
}
isFuncCall() {
const elements = this.getElementsWithoutCasts();
const firstElem = elements[0];
return (elements.length === 1 &&
(firstElem instanceof FuncCall_1.FuncCall
||
firstElem instanceof Expression &&
firstElem.isFuncCall()));
}
isThatFuncCall(funcName) {
const elements = this.getElementsWithoutCasts();
const firstElem = elements[0];
return (elements.length === 1 &&
(firstElem instanceof FuncCall_1.FuncCall &&
firstElem.name === funcName
||
firstElem instanceof Expression &&
firstElem.isThatFuncCall(funcName)));
}
isColumnReference() {
return (this.elements.length === 1 &&
this.elements[0] instanceof ColumnReference_1.ColumnReference);
}
isArrayItemOfColumnReference() {
return (this.elements.length === 2 &&
this.elements[0] instanceof ColumnReference_1.ColumnReference &&
/^\[\s*\d+\s*\]$/.test(this.elements[1].toString().trim()));
}
isIn() {
return (this.elements.length === 2 &&
/^\s*in\s*\([^\)]+\)\s*$/.test(this.elements[1].toString()));
}
isNotExists() {
return (this.elements.length === 2 &&
this.elements[0].toString() === "not" &&
this.elements[1] instanceof Exists_1.Exists);
}
isPrimitive() {
const elements = this.getElementsWithoutCasts();
return (elements.length === 1 &&
elements[0] instanceof UnknownExpressionElement_1.UnknownExpressionElement &&
/^(\d+|'.*')$/.test(elements[0].toString()));
}
hasArraySearchOperator() {
return this.elements.some(element => element instanceof Operator_1.Operator &&
element.toString() === "&&");
}
isBinary(operator) {
const elems = (operator === "::" ?
this.elements :
this.getElementsWithoutCasts());
const isBinaryExpression = (elems.length === 3 &&
elems[1] instanceof Operator_1.Operator &&
elems[1].toString() === operator);
return isBinaryExpression;
}
isEqualAny() {
const elems = this.getElementsWithoutCasts();
const isEqualAnyExpression = (elems.length === 3 &&
elems[1] instanceof Operator_1.Operator &&
elems[1].toString() === "=" &&
/^\s*any\s*\(/i.test(elems[2].toString()));
return isEqualAnyExpression;
}
getOperands() {
const operands = [];
for (let i = 0, n = this.elements.length; i < n; i++) {
const elem = this.elements[i];
const nextElem = this.elements[i + 1];
if (nextElem instanceof Operator_1.Operator && nextElem.toString() === "::") {
const castOperator = nextElem;
const castType = this.elements[i + 2];
const elemWithCasting = new Expression([
elem,
castOperator,
castType
]);
operands.push(elemWithCasting);
i += 2;
continue;
}
if (elem instanceof Operator_1.Operator) {
continue;
}
operands.push(elem);
}
return operands;
}
getElementsWithoutCasts() {
const expressionElementsWithoutCasts = this.elements.slice();
for (let i = 0, n = expressionElementsWithoutCasts.length; i < n; i++) {
const elem = expressionElementsWithoutCasts[i];
if (elem instanceof Operator_1.Operator && elem.toString() === "::") {
expressionElementsWithoutCasts.splice(i, 2);
n -= 2;
i--;
}
}
return expressionElementsWithoutCasts;
}
isEmpty() {
if (this.elements.length === 0) {
return true;
}
if (this.elements.length === 1) {
const firstElem = this.elements[0];
if (firstElem instanceof Expression) {
return firstElem.isEmpty();
}
}
return false;
}
replaceFuncCall(replaceFunc, toSql) {
const newElements = this.elements.map(elem => elem.replaceFuncCall(replaceFunc, toSql));
return this.clone(newElements);
}
replaceTable(replaceTable, toTable) {
const newElements = this.elements.map(elem => elem.replaceTable(replaceTable, toTable));
return this.clone(newElements);
}
replaceColumn(replaceColumn, toSql) {
const newElements = this.elements.map(elem => elem.replaceColumn(replaceColumn, toSql));
return this.clone(newElements);
}
splitBy(operator) {
const conditions = [];
let currentCondition = [];
for (const element of this.elements) {
if (element instanceof Operator_1.Operator) {
if (element.toString() === operator) {
if (currentCondition.length) {
const condition = new Expression(currentCondition);
conditions.push(condition);
}
currentCondition = [];
continue;
}
}
currentCondition.push(element);
}
if (currentCondition.length) {
const condition = new Expression(currentCondition);
conditions.push(condition);
}
return conditions;
}
extrude() {
const singleElement = this.elements[0];
if (this.elements.length === 1 && singleElement instanceof Expression) {
return singleElement.extrude();
}
return this;
}
clone(newElements) {
return new Expression(newElements || this.elements.map(elem => elem.clone()), this.brackets);
}
needWrapToBrackets() {
return (/^case\s/.test(this.toString().trim()));
}
template(spaces) {
let lines = [];
let line = "";
for (let i = 0, n = this.elements.length; i < n; i++) {
const elem = this.elements[i];
if (elem instanceof Operator_1.Operator && elem.toString() === "::") {
const nextElem = this.elements[i + 1];
line += "::" + nextElem.toString();
i++;
continue;
}
const isConditionOperator = (elem instanceof Operator_1.Operator &&
["and", "or"].includes(elem.toString()));
if (isConditionOperator) {
lines.push(spaces + line.trim());
lines.push(spaces + elem.toString());
line = "";
continue;
}
if (elem instanceof Expression) {
if (line.trim()) {
lines.push(spaces + line.trim());
}
line = "";
if (elem.hasOperator("or")) {
lines.push(spaces + "(");
lines.push(...elem.template(spaces.plusOneLevel()));
lines.push(spaces + ")");
}
else {
lines.push(...elem.template(spaces));
}
continue;
}
else {
line += " " + elem.toSQL(spaces);
}
}
if (line.trim()) {
lines.push(spaces + line.trim());
}
lines = lines.filter(someLine => !!someLine.trim());
if (this.brackets) {
const n = lines.length;
lines[0] = spaces + "(" + lines[0].trim();
lines[n - 1] = lines[n - 1] + ")";
}
return lines;
}
onlyOperators(onlyOperator) {
const operators = this.elements.filter(elem => elem instanceof Operator_1.Operator);
return (operators.length &&
operators.every(operator => operator.toString() === onlyOperator));
}
hasOperator(operator) {
return this.elements.some(elem => elem instanceof Operator_1.Operator &&
elem.toString() === operator);
}
}
exports.Expression = Expression;
//# sourceMappingURL=Expression.js.map