@sequeljs/ast
Version:
A SQL AST manager for JavaScript
1,006 lines • 34.4 kB
JavaScript
import Attribute from '../attributes/Attribute';
import SQLString from '../collectors/SQLString';
import VisitorNotImplementedError from '../errors/VisitorNotImplementedError';
import VisitorNotSupportedError from '../errors/VisitorNotSupportedError';
import BindParam from '../nodes/BindParam';
import DeleteStatement from '../nodes/DeleteStatement';
import Grouping from '../nodes/Grouping';
import In from '../nodes/In';
import JoinSource from '../nodes/JoinSource';
import Node from '../nodes/Node';
import SQLLiteral from '../nodes/SQLLiteral';
import SelectStatement from '../nodes/SelectStatement';
import TableAlias from '../nodes/TableAlias';
import UpdateStatement from '../nodes/UpdateStatement';
import Visitor from './Visitor';
/**
* @internal
*/
function buildSubselect(key, thing) {
const stmt = new SelectStatement();
const [core] = stmt.cores;
core.from = thing.relation;
core.wheres = thing.wheres;
core.projections = [key];
stmt.limit = thing.limit;
stmt.offset = thing.offset;
stmt.orders = thing.orders;
return stmt;
}
/**
* @internal
*/
function chunkedArray(arr, chunksSize) {
const chunkedArr = [];
let index = 0;
while (index < arr.length) {
chunkedArr.push(arr.slice(index, chunksSize + index));
index += chunksSize;
}
return chunkedArr;
}
export default class ToSQL extends Visitor {
constructor(connection) {
super();
this.connection = connection;
}
compile(node, collector = new SQLString()) {
return this.accept(node, collector).value;
}
aggregate(name, thing, col) {
let collector = col;
collector.append(`${name}(`);
if (thing.distinct) {
collector.append(`${'DISTINCT'} `);
}
collector = this.injectJoin(thing.expressions, collector, ', ');
collector.append(')');
if (thing.alias) {
collector.append(' AS ');
collector = this.visit(thing.alias, collector);
}
return collector;
}
collectInClause(left, right, col) {
let collector = col;
collector = this.visit(left, collector);
collector.append(' IN (');
collector = this.visit(right, collector);
collector.append(')');
return collector;
}
collectNodesFor(nodes, col, spacer, connector = ', ') {
let collector = col;
if (nodes.length > 0) {
collector.append(spacer);
collector = this.injectJoin(nodes, collector, connector);
}
return collector;
}
collectNotInClause(left, right, col) {
let collector = col;
collector = this.visit(left, collector);
collector.append(' NOT IN (');
collector = this.visit(right, collector);
collector.append(')');
return collector;
}
collectOptimizerHints(thing, col) {
let collector = col;
collector = this.maybeVisit(thing.optimizerHints, collector);
return collector;
}
hasJoinSources(thing) {
return (thing.relation instanceof JoinSource && thing.relation.right.length > 0);
}
hasLimitOrOffsetOrOrders(thing) {
return thing.limit || thing.offset || thing.orders.length > 0;
}
infixValue(thing, col, value) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(value);
collector = this.visit(thing.right, collector);
return collector;
}
infixValueWithParen(thing, col, value, suppressParens = false) {
let collector = col;
if (!suppressParens) {
collector.append('( ');
}
if (thing.left.constructor === thing.constructor) {
collector = this.infixValueWithParen(thing.left, collector, value, true);
}
else {
collector = this.visit(thing.left, collector);
}
collector.append(value);
if (thing.right.constructor === thing.constructor) {
collector = this.infixValueWithParen(thing.right, collector, value, true);
}
else {
collector = this.visit(thing.right, collector);
}
if (!suppressParens) {
collector.append(' )');
}
return collector;
}
injectJoin(things, col, joinStr) {
let collector = col;
things.forEach((thing, i) => {
if (i !== 0) {
collector.append(joinStr);
}
collector = this.visit(thing, collector);
});
return collector;
}
isDistinctFrom(thing, col) {
let collector = col;
collector.append('CASE WHEN ');
collector = this.visit(thing.left, collector);
collector.append(' = ');
collector = this.visit(thing.right, collector);
collector.append(' OR (');
collector = this.visit(thing.left, collector);
collector.append(' IS NULL AND ');
collector = this.visit(thing.right, collector);
collector.append(' IS NULL)');
collector.append(' THEN 0 ELSE 1 END');
return collector;
}
isUnboundable(value) {
var _a;
return (_a = value === null || value === void 0 ? void 0 : value.isUnboundable) === null || _a === void 0 ? void 0 : _a.call(value);
}
literal(thing, col) {
return col.append(String(thing));
}
maybeVisit(thing, col) {
let collector = col;
if (!thing) {
return collector;
}
collector.append(' ');
collector = this.visit(thing, collector);
return collector;
}
prepareDeleteUpdateStatement(thing) {
if (thing.key &&
(this.hasLimitOrOffsetOrOrders(thing) || this.hasJoinSources(thing))) {
let stmt;
if (thing instanceof DeleteStatement) {
stmt = new DeleteStatement(thing.left, thing.right);
stmt.left = thing.left;
stmt.right = thing.right;
}
else {
stmt = new UpdateStatement();
stmt.relation = thing.relation;
stmt.values = thing.values;
}
stmt.key = thing.key;
stmt.limit = null;
stmt.offset = null;
stmt.orders = [];
stmt.wheres = [new In(thing.key, [buildSubselect(thing.key, thing)])];
if (this.hasJoinSources(thing)) {
stmt.relation = thing.relation.left;
}
return stmt;
}
return thing;
}
prepareDeleteStatement(thing) {
return this.prepareDeleteUpdateStatement(thing);
}
prepareUpdateStatement(thing) {
return this.prepareDeleteUpdateStatement(thing);
}
quote(value) {
if (value instanceof SQLLiteral) {
return String(value);
}
return this.connection.quote(value);
}
quoteColumnName(name) {
if (name instanceof SQLLiteral) {
return String(name);
}
return this.connection.quoteColumnName(name);
}
quoteTableName(name) {
if (name instanceof SQLLiteral) {
return String(name);
}
return this.connection.quoteTableName(name);
}
quoted(val, attribute) {
if (attribute &&
attribute instanceof Attribute &&
attribute.isAbleToTypeCast()) {
return this.quote(attribute.typeCastForDatabase(val));
}
return this.quote(val);
}
sanitizeAsSQLComment(value) {
if (value instanceof SQLLiteral) {
return value;
}
return this.connection.sanitizeAsSQLComment(value);
}
unsupported(thing, _) {
throw new VisitorNotSupportedError(typeof thing);
}
visitAddition(thing, col) {
return this.visitInfixOperation(thing, col);
}
visitAnd(thing, col) {
return this.injectJoin(thing.children, col, ' AND ');
}
visitArray(things, col) {
return this.injectJoin(things, col, ', ');
}
visitAs(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' AS ');
collector = this.visit(thing.right, collector);
return collector;
}
visitAscending(thing, col) {
return this.visit(thing.expr, col).append(' ASC');
}
visitAssignment(thing, col) {
let collector = col;
if (thing.right instanceof Attribute || thing.right instanceof Node) {
collector = this.visit(thing.left, collector);
collector.append(' = ');
collector = this.visit(thing.right, collector);
return collector;
}
collector = this.visit(thing.left, collector);
collector.append(' = ');
collector.append(String(this.quote(thing.right)));
return collector;
}
visitAttributesAttribute(thing, col) {
const collector = col;
let joinName;
if (thing.relation.tableAlias) {
if (thing.relation.tableAlias instanceof TableAlias) {
joinName = thing.relation.tableAlias.name;
}
else {
joinName = thing.relation.tableAlias;
}
}
else {
joinName = thing.relation.name;
}
collector.append(this.quoteTableName(joinName));
collector.append('.');
collector.append(this.quoteColumnName(thing.name));
return collector;
}
visitAttributesBoolean(thing, col) {
return this.visitAttributesAttribute(thing, col);
}
visitAttributesDecimal(thing, col) {
return this.visitAttributesAttribute(thing, col);
}
visitAttributesFloat(thing, col) {
return this.visitAttributesAttribute(thing, col);
}
visitAttributesInteger(thing, col) {
return this.visitAttributesAttribute(thing, col);
}
visitAttributesString(thing, col) {
return this.visitAttributesAttribute(thing, col);
}
visitAttributesTime(thing, col) {
return this.visitAttributesAttribute(thing, col);
}
visitAvg(thing, col) {
return this.aggregate('AVG', thing, col);
}
visitBetween(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' BETWEEN ');
collector = this.visit(thing.right, collector);
return collector;
}
visitBigInt(thing, col) {
return this.literal(thing, col);
}
visitBin(thing, col) {
return this.visit(thing.expr, col);
}
visitBindParam(thing, col) {
return col.addBind(thing.value, (_) => '?');
}
visitBoolean(thing, col) {
return this.unsupported(thing, col);
}
visitCase(thing, col) {
let collector = col;
collector.append('CASE ');
if (thing.case) {
collector = this.visit(thing.case, collector);
collector.append(' ');
}
thing.conditions.forEach((condition) => {
collector = this.visit(condition, collector);
collector.append(' ');
});
if (thing.default) {
collector = this.visit(thing.default, collector);
collector.append(' ');
}
collector.append('END');
return collector;
}
visitCasted(thing, col) {
return col.append(String(this.quoted(thing.value, thing.attribute)));
}
visitComment(thing, col) {
const collector = col;
const comment = thing.values
.map((value) => `/* ${this.sanitizeAsSQLComment(value)} */`)
.join(' ');
collector.append(comment);
return collector;
}
visitCount(thing, col) {
return this.aggregate('COUNT', thing, col);
}
visitCurrentRow(_, col) {
return col.append('CURRENT ROW');
}
visitDate(thing, col) {
return this.unsupported(thing, col);
}
visitDeleteStatement(thing, col) {
let collector = col;
const obj = this.prepareDeleteStatement(thing);
collector.append('DELETE FROM ');
collector = this.visit(obj.relation, collector);
collector = this.collectNodesFor(obj.wheres, collector, ' WHERE ', ' AND ');
collector = this.collectNodesFor(obj.orders, collector, ' ORDER BY ');
collector = this.maybeVisit(obj.limit, collector);
return collector;
}
visitDescending(thing, col) {
return this.visit(thing.expr, col).append(' DESC');
}
visitDistinct(thing, col) {
return col.append('DISTINCT');
}
visitDistinctOn(_1, _2) {
throw new VisitorNotImplementedError('DISTINCT ON not implemented for this db');
}
visitDivision(thing, col) {
return this.visitInfixOperation(thing, col);
}
visitDoesNotMatch(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' NOT LIKE ');
collector = this.visit(thing.right, collector);
if (thing.escape) {
collector.append(' ESCAPE ');
collector = this.visit(thing.escape, collector);
}
return collector;
}
visitElse(thing, col) {
let collector = col;
collector.append('ELSE ');
collector = this.visit(thing.expr, collector);
return collector;
}
visitEquality(thing, col) {
let collector = col;
if (this.isUnboundable(thing.right)) {
collector.append('1 = 0');
return collector;
}
collector = this.visit(thing.left, collector);
if (thing.right === null ||
('value' in thing.right && thing.right.value === null)) {
collector.append(' IS NULL');
return collector;
}
collector.append(' = ');
collector = this.visit(thing.right, collector);
return collector;
}
visitExcept(thing, col) {
let collector = col;
collector.append('( ');
collector = this.infixValue(thing, col, ' EXCEPT ');
collector.append(' )');
return collector;
}
visitExists(thing, col) {
let collector = col;
collector.append(`${'EXISTS '}(`);
collector = this.visit(thing.expressions, collector);
collector.append(')');
if (thing.alias) {
collector.append(' AS ');
collector = this.visit(thing.alias, collector);
}
return collector;
}
visitExtract(thing, col) {
let collector = col;
collector.append(`${'EXTRACT'}(${String(thing.field).toUpperCase()}${' FROM '}`);
collector = this.visit(thing.expr, collector);
collector.append(')');
return collector;
}
visitFalse(_, col) {
return col.append('FALSE');
}
visitFollowing(thing, col) {
let collector = col;
collector = thing.expr
? this.visit(thing.expr, collector)
: collector.append('UNBOUNDED');
collector.append(' FOLLOWING');
return collector;
}
visitFullOuterJoin(thing, col) {
let collector = col;
collector.append('FULL OUTER JOIN ');
collector = this.visit(thing.left, collector);
collector.append(' ');
collector = this.visit(thing.right, collector);
return collector;
}
visitGreaterThan(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' > ');
collector = this.visit(thing.right, collector);
return collector;
}
visitGreaterThanOrEqual(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' >= ');
collector = this.visit(thing.right, collector);
return collector;
}
visitGroup(thing, col) {
return this.visit(thing.expr, col);
}
visitGrouping(thing, col) {
let collector = col;
if (thing.expr instanceof Grouping) {
return this.visit(thing.expr, collector);
}
collector.append('(');
collector = this.visit(thing.expr, collector);
collector.append(')');
return collector;
}
visitIn(thing, col) {
const obj = thing;
let collector = col;
if (!Array.isArray(obj.right)) {
collector = this.collectInClause(obj.left, obj.right, collector);
return collector;
}
if (obj.right.length > 0) {
obj.right = obj.right.filter((value) => !this.isUnboundable(value));
}
if (obj.right.length <= 0) {
collector.append('1 = 0');
return collector;
}
const { inClauseLength } = this.connection;
if (!inClauseLength || obj.right.length <= inClauseLength) {
collector = this.collectInClause(obj.left, obj.right, collector);
}
else {
collector.append('(');
chunkedArray(obj.right, inClauseLength).forEach((value, i) => {
if (i !== 0) {
collector.append(' OR ');
}
collector = this.collectInClause(obj.left, value, collector);
});
collector.append(')');
}
return collector;
}
visitInfixOperation(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(` ${thing.operator} `);
collector = this.visit(thing.right, collector);
return collector;
}
visitInnerJoin(thing, col) {
let collector = col;
collector.append('INNER JOIN ');
collector = this.visit(thing.left, collector);
if (thing.right) {
collector.append(' ');
collector = this.visit(thing.right, collector);
}
return collector;
}
visitInsertStatement(thing, col) {
let collector = col;
collector.append('INSERT INTO ');
collector = this.visit(thing.relation, collector);
if (thing.columns.length > 0) {
collector.append(' (');
thing.columns.forEach((column, index) => {
if (index !== 0) {
collector.append(', ');
}
collector.append(this.quoteColumnName(column.name));
});
collector.append(')');
}
if (thing.values) {
collector = this.maybeVisit(thing.values, collector);
return collector;
}
if (thing.select) {
collector = this.maybeVisit(thing.select, collector);
return collector;
}
return collector;
}
visitIntersect(thing, col) {
let collector = col;
collector.append('( ');
collector = this.infixValue(thing, col, ' INTERSECT ');
collector.append(' )');
return collector;
}
visitIsDistinctFrom(thing, col) {
let collector = col;
if (thing.right === null ||
(thing.right &&
typeof thing.right === 'object' &&
'value' in thing.right &&
thing.right.value === null)) {
collector = this.visit(thing.left, collector);
collector.append(' IS NOT NULL');
}
else {
collector = this.isDistinctFrom(thing, collector);
collector.append(' = 1');
}
return collector;
}
visitIsNotDistinctFrom(thing, col) {
let collector = col;
if (thing.right === null ||
(thing.right &&
typeof thing.right === 'object' &&
'value' in thing.right &&
thing.right.value === null)) {
collector = this.visit(thing.left, collector);
collector.append(' IS NULL');
}
else {
collector = this.isDistinctFrom(thing, collector);
collector.append(' = 0');
}
return collector;
}
visitJoinSource(thing, col) {
let collector = col;
if (thing.left) {
collector = this.visit(thing.left, collector);
}
if (thing.right.length > 0) {
if (thing.left) {
collector.append(' ');
}
collector = this.injectJoin(thing.right, collector, ' ');
}
return collector;
}
visitLessThan(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' < ');
collector = this.visit(thing.right, collector);
return collector;
}
visitLessThanOrEqual(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' <= ');
collector = this.visit(thing.right, collector);
return collector;
}
visitLimit(thing, col) {
let collector = col;
collector.append('LIMIT ');
collector = this.visit(thing.expr, col);
return collector;
}
visitLock(thing, col) {
return this.visit(thing.expr, col);
}
visitMatches(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' LIKE ');
collector = this.visit(thing.right, collector);
if (thing.escape) {
collector.append(' ESCAPE ');
collector = this.visit(thing.escape, collector);
}
return collector;
}
visitMax(thing, col) {
return this.aggregate('MAX', thing, col);
}
visitMin(thing, col) {
return this.aggregate('MIN', thing, col);
}
visitMultiplication(thing, col) {
return this.visitInfixOperation(thing, col);
}
visitNamedSQLFunction(thing, col) {
let collector = col;
collector.append(thing.name);
collector.append('(');
if (thing.distinct) {
collector.append(`${'DISTINCT'} `);
}
collector = this.injectJoin(thing.expressions, collector, ', ');
collector.append(')');
if (thing.alias) {
collector.append(' AS ');
collector = this.visit(thing.alias, collector);
}
return collector;
}
visitNamedWindow(thing, col) {
let collector = col;
collector.append(this.quoteColumnName(thing.name));
collector.append(' AS ');
collector = this.visitWindow(thing, collector);
return collector;
}
visitNot(thing, col) {
let collector = col;
collector.append(`${'NOT '}(`);
collector = this.visit(thing.expr, collector);
collector.append(')');
return collector;
}
visitNotEqual(thing, col) {
let collector = col;
if (this.isUnboundable(thing.right)) {
collector.append('1 = 1');
return collector;
}
collector = this.visit(thing.left, collector);
if (thing.right === null ||
('value' in thing.right && thing.right.value === null)) {
collector.append(' IS NOT NULL');
return collector;
}
collector.append(' != ');
collector = this.visit(thing.right, collector);
return collector;
}
visitNotIn(thing, col) {
const obj = thing;
let collector = col;
if (!Array.isArray(obj.right)) {
collector = this.collectNotInClause(obj.left, obj.right, collector);
return collector;
}
if (obj.right.length > 0) {
obj.right = obj.right.filter((value) => !this.isUnboundable(value));
}
if (obj.right.length <= 0) {
collector.append('1 = 1');
return collector;
}
const { inClauseLength } = this.connection;
if (!inClauseLength || obj.right.length <= inClauseLength) {
collector = this.collectNotInClause(obj.left, obj.right, collector);
}
else {
collector.append('(');
chunkedArray(obj.right, inClauseLength).forEach((value, i) => {
if (i !== 0) {
collector.append(' AND ');
}
collector = this.collectNotInClause(obj.left, value, collector);
});
collector.append(')');
}
return collector;
}
visitNotRegexp(_1, _2) {
throw new VisitorNotImplementedError('!~ not implemented for this db');
}
visitNumber(thing, col) {
return this.literal(thing, col);
}
visitNull(thing, col) {
return this.unsupported(thing, col);
}
visitOffset(thing, col) {
let collector = col;
collector.append('OFFSET ');
collector = this.visit(thing.expr, col);
return collector;
}
visitOn(thing, col) {
let collector = col;
collector.append('ON ');
collector = this.visit(thing.expr, collector);
return collector;
}
visitOptimizerHints(thing, col) {
const collector = col;
const hints = thing.expr
.map((value) => this.sanitizeAsSQLComment(value))
.join(' ');
collector.append(`/*+ ${hints} */`);
return collector;
}
visitOr(thing, col) {
let collector = col;
collector = this.visit(thing.left, collector);
collector.append(' OR ');
collector = this.visit(thing.right, collector);
return collector;
}
visitOuterJoin(thing, col) {
let collector = col;
collector.append('LEFT OUTER JOIN ');
collector = this.visit(thing.left, collector);
collector.append(' ');
collector = this.visit(thing.right, collector);
return collector;
}
visitOver(thing, col) {
if (!thing.right) {
return this.visit(thing.left, col).append(`${' OVER '}()`);
}
if (thing.right instanceof SQLLiteral) {
return this.infixValue(thing, col, ' OVER ');
}
if (typeof thing.right === 'string') {
return this.visit(thing.left, col).append(`${' OVER '}${this.quoteColumnName(thing.right)}`);
}
return this.infixValue(thing, col, ' OVER ');
}
visitPreceding(thing, col) {
let collector = col;
collector = thing.expr
? this.visit(thing.expr, collector)
: collector.append('UNBOUNDED');
collector.append(' PRECEDING');
return collector;
}
visitQuoted(thing, col) {
return col.append(String(this.quoted(thing.expr, null)));
}
visitRange(thing, col) {
let collector = col;
if (thing.expr) {
collector.append(`${'RANGE'} `);
collector = this.visit(thing.expr, collector);
return collector;
}
collector.append('RANGE');
return collector;
}
visitRegexp(_1, _2) {
throw new VisitorNotImplementedError('~ not implemented for this db');
}
visitRightOuterJoin(thing, col) {
let collector = col;
collector.append('RIGHT OUTER JOIN ');
collector = this.visit(thing.left, collector);
collector.append(' ');
collector = this.visit(thing.right, collector);
return collector;
}
visitRows(thing, col) {
let collector = col;
if (thing.expr) {
collector.append(`${'ROWS'} `);
collector = this.visit(thing.expr, collector);
return collector;
}
collector.append('ROWS');
return collector;
}
visitSelectCore(thing, col) {
let collector = col;
collector.append('SELECT');
collector = this.collectOptimizerHints(thing, collector);
collector = this.maybeVisit(thing.setQuantifier, collector);
collector = this.collectNodesFor(thing.projections, collector, ' ');
if (thing.source &&
(thing.source.left ||
(thing.source.right && thing.source.right.filter(Boolean).length > 0))) {
collector.append(' FROM ');
collector = this.visit(thing.source, collector);
}
collector = this.collectNodesFor(thing.wheres, collector, ' WHERE ', ' AND ');
collector = this.collectNodesFor(thing.groups, collector, ' GROUP BY ');
collector = this.collectNodesFor(thing.havings, collector, ' HAVING ', ' AND ');
collector = this.collectNodesFor(thing.windows, collector, ' WINDOW ');
collector = this.maybeVisit(thing.comment, collector);
return collector;
}
visitSelectManager(thing, col) {
let collector = col;
collector.append('(');
collector = this.visit(thing.ast, collector);
collector.append(')');
return collector;
}
visitSelectStatement(thing, col) {
let collector = col;
if (thing.with) {
collector = this.visit(thing.with, collector);
collector.append(' ');
}
collector = thing.cores.reduce((coreCol, core) => this.visitSelectCore(core, coreCol), collector);
if (thing.orders.length > 0) {
collector.append(' ORDER BY ');
thing.orders.forEach((order, i) => {
if (i !== 0) {
collector.append(', ');
}
collector = this.visit(order, collector);
});
}
collector = this.maybeVisit(thing.limit, collector);
collector = this.maybeVisit(thing.offset, collector);
collector = this.maybeVisit(thing.lock, collector);
return collector;
}
visitSQLLiteral(thing, col) {
return this.literal(thing, col);
}
visitString(thing, col) {
return this.unsupported(thing, col);
}
visitStringJoin(thing, col) {
return this.visit(thing.left, col);
}
visitSubtraction(thing, col) {
return this.visitInfixOperation(thing, col);
}
visitSum(thing, col) {
return this.aggregate('SUM', thing, col);
}
visitSymbol(thing, col) {
return this.unsupported(thing, col);
}
visitTable(thing, col) {
if (thing.tableAlias) {
return col.append(`${this.quoteTableName(String(thing.name))} ${this.quoteTableName(String(thing.tableAlias))}`);
}
return col.append(this.quoteTableName(String(thing.name)));
}
visitTableAlias(thing, col) {
let collector = col;
collector = this.visit(thing.relation, collector);
collector.append(' ');
collector.append(this.quoteTableName(thing.name));
return collector;
}
visitTrue(_, col) {
return col.append('TRUE');
}
visitUnaryOperation(thing, col) {
let collector = col;
collector.append(` ${thing.operator} `);
collector = this.visit(thing.expr, collector);
return collector;
}
visitUnion(thing, col) {
let collector = col;
collector = this.infixValueWithParen(thing, collector, ' UNION ');
return collector;
}
visitUnionAll(thing, col) {
let collector = col;
collector = this.infixValueWithParen(thing, col, ' UNION ALL ');
return collector;
}
visitUnqualifiedColumn(thing, col) {
return col.append(this.quoteColumnName(thing.name));
}
visitUpdateStatement(thing, col) {
let collector = col;
const obj = this.prepareUpdateStatement(thing);
collector.append('UPDATE ');
collector = this.visit(obj.relation, collector);
collector = this.collectNodesFor(obj.values, collector, ' SET ');
collector = this.collectNodesFor(obj.wheres, collector, ' WHERE ', ' AND ');
collector = this.collectNodesFor(obj.orders, collector, ' ORDER BY ');
collector = this.maybeVisit(obj.limit, collector);
return collector;
}
visitValuesList(thing, col) {
let collector = col;
collector.append('VALUES ');
thing.rows.forEach((row, i) => {
const values = Object.entries(row);
if (i !== 0) {
collector.append(', ');
}
collector.append('(');
values.forEach(([_, value], k) => {
if (k !== 0) {
collector.append(', ');
}
if (value instanceof BindParam || value instanceof SQLLiteral) {
collector = this.visit(value, collector);
}
else {
collector.append(String(this.quote(value)));
}
});
collector.append(')');
});
return collector;
}
visitWhen(thing, col) {
let collector = col;
collector.append('WHEN ');
collector = this.visit(thing.left, collector);
collector.append(' THEN ');
collector = this.visit(thing.right, collector);
return collector;
}
visitWindow(thing, col) {
let collector = col;
collector.append('(');
collector = this.collectNodesFor(thing.partitions, collector, 'PARTITION BY ');
if (thing.orders.length > 0) {
if (thing.partitions.length > 0) {
collector.append(' ');
}
collector.append('ORDER BY ');
collector = this.injectJoin(thing.orders, collector, ', ');
}
if (thing.framing) {
if (thing.partitions.length > 0 || thing.orders.length > 0) {
collector.append(' ');
}
collector = this.visit(thing.framing, collector);
}
collector.append(')');
return collector;
}
visitWith(thing, col) {
let collector = col;
collector.append('WITH ');
collector = this.injectJoin(thing.children, collector, ', ');
return collector;
}
visitWithRecursive(thing, col) {
let collector = col;
collector.append('WITH RECURSIVE ');
collector = this.injectJoin(thing.children, collector, ', ');
return collector;
}
}
//# sourceMappingURL=ToSQL.js.map