@sequeljs/ast
Version:
A SQL AST manager for JavaScript
246 lines • 7.5 kB
JavaScript
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