UNPKG

@sequeljs/ast

Version:

A SQL AST manager for JavaScript

1,006 lines 34.4 kB
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