UNPKG

@sequeljs/ast

Version:

A SQL AST manager for JavaScript

246 lines 7.5 kB
import SQLString from '../collectors/SQLString'; import EmptyJoinError from '../errors/EmptyJoinError'; import EngineNotSetError from '../errors/EngineNotSetError'; import VisitorNotSetError from '../errors/VisitorNotSetError'; import Comment from '../nodes/Comment'; import Distinct from '../nodes/Distinct'; import DistinctOn from '../nodes/DistinctOn'; import Except from '../nodes/Except'; import Exists from '../nodes/Exists'; import Group from '../nodes/Group'; import InnerJoin from '../nodes/InnerJoin'; import Intersect from '../nodes/Intersect'; import Join from '../nodes/Join'; import Lateral from '../nodes/Lateral'; import Limit from '../nodes/Limit'; import Lock from '../nodes/Lock'; import NamedWindow from '../nodes/NamedWindow'; import Offset from '../nodes/Offset'; import On from '../nodes/On'; import OptimizerHints from '../nodes/OptimizerHints'; import OuterJoin from '../nodes/OuterJoin'; import SQLLiteral from '../nodes/SQLLiteral'; import SelectStatement from '../nodes/SelectStatement'; import StringJoin from '../nodes/StringJoin'; import Union from '../nodes/Union'; import UnionAll from '../nodes/UnionAll'; import With from '../nodes/With'; import WithRecursive from '../nodes/WithRecursive'; import WhereSQL from '../visitors/WhereSQL'; import SequelAST from '../SequelAST'; import TreeManager from './TreeManager'; class SelectManager extends TreeManager { get constraints() { return this.ctx.wheres; } get froms() { return this.ast.cores.map((c) => c.from).filter(Boolean); } get joinSources() { return this.ctx.source.right; } get limit() { return this.ast.limit && this.ast.limit.expr; } set limit(limit) { this.take(limit); } get locked() { return this.ast.lock; } get offset() { return this.ast.offset && this.ast.offset.expr; } set offset(amount) { this.skip(amount); } get orders() { return this.ast.orders; } get projections() { return this.ctx.projections; } set projections(projections) { this.ctx.projections = projections; } get source() { return this.ctx.source; } get taken() { return this.limit; } constructor(table = null) { super(new SelectStatement()); this.ctx = this.ast.cores[this.ast.cores.length - 1]; this.from(table); } collapse(exprs) { let expressions = exprs; expressions = expressions.filter(Boolean).map((expr) => { if (typeof expr === 'string') { return new SQLLiteral(expr); } return expr; }); if (expressions.length === 1) { return expressions[0]; } return this.createAnd(expressions); } as(other) { return this.createTableAlias(this.grouping(this.ast), new SQLLiteral(other)); } comment(...values) { this.ctx.comment = new Comment(values); return this; } distinct(value = true) { this.ctx.setQuantifier = value ? new Distinct() : null; return this; } distinctOn(value) { this.ctx.setQuantifier = value ? new DistinctOn(value) : null; return this; } except(other) { return new Except(this.ast, other.ast); } exists() { return new Exists(this.ast); } from(table) { if (table instanceof Join) { this.ctx.source.right.push(table); } else if (typeof table === 'string') { this.ctx.source.left = new SQLLiteral(table); } else { this.ctx.source.left = table; } return this; } group(...columns) { columns.forEach((column) => { let col = column; if (typeof col === 'string') { col = new SQLLiteral(col); } this.ctx.groups.push(new Group(col)); }); return this; } having(expr) { this.ctx.havings.push(expr); return this; } intersect(other) { return new Intersect(this.ast, other.ast); } join(relation, klass = InnerJoin) { if (relation === null) { return this; } let Klass = klass; let rel = relation; if (typeof rel === 'string' || rel instanceof SQLLiteral) { rel = new SQLLiteral(rel); if (rel.length <= 0) { throw new EmptyJoinError(); } Klass = StringJoin; } this.ctx.source.right.push(this.createJoin(rel, null, Klass)); return this; } lateral(tableName = null) { const base = tableName ? this.as(tableName) : this.ast; return new Lateral(base); } lock(locking = new SQLLiteral('FOR UPDATE')) { let lock = locking; if (lock === true) { lock = new SQLLiteral('FOR UPDATE'); } else if (typeof lock === 'string' || lock instanceof SQLLiteral) { lock = new SQLLiteral(lock); } this.ast.lock = new Lock(lock); return this; } minus(other) { return this.except(other); } on(...exprs) { this.ctx.source.right[this.ctx.source.right.length - 1].right = new On(this.collapse(exprs)); return this; } optimizerHints(...hints) { if (hints.length > 0) { this.ctx.optimizerHints = new OptimizerHints(hints); } return this; } order(...expr) { this.ast.orders.push(...expr.map((e) => (typeof e === 'string' ? new SQLLiteral(e) : e))); return this; } outerJoin(relation) { return this.join(relation, OuterJoin); } project(...projections) { this.ctx.projections.push(...projections.map((p) => typeof p === 'string' ? new SQLLiteral(p) : p)); return this; } skip(amount) { this.ast.offset = amount ? new Offset(amount) : null; return this; } take(limit) { if (limit) { this.ast.limit = new Limit(limit); } else { this.ast.limit = null; } return this; } union(other) { return new Union(this.ast, other.ast); } unionAll(other) { return new UnionAll(this.ast, other.ast); } whereSQL(engine = undefined) { let currentEngine = engine; if (typeof currentEngine === 'undefined') { currentEngine = SequelAST.engine; } if (!currentEngine) { throw new EngineNotSetError(); } if (this.ctx.wheres.length <= 0) { return null; } if (!currentEngine.connection.visitor) { throw new VisitorNotSetError(); } const visitor = new WhereSQL(currentEngine.connection.visitor, currentEngine.connection); return new SQLLiteral(visitor.accept(this.ctx, new SQLString()).value); } window(name) { const window = new NamedWindow(name); this.ctx.windows.push(window); return window; } with(...subqueries) { this.ast.with = new With(subqueries.reduce((acc, val) => acc.concat(val), [])); return this; } withRecursive(...subqueries) { this.ast.with = new WithRecursive(subqueries.reduce((acc, val) => acc.concat(val), [])); return this; } } export default SelectManager; //# sourceMappingURL=SelectManager.js.map