ts-sql
Version:
An SQL builder in Typescript. This project is heavily inspired by [XQL](/extjs/xql). A big shout out to @exjs and @kobalicek for this amazing project.
242 lines • 9.02 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ast = require("./astsql");
class QueryableImpl {
constructor(queryBuilder) {
this.queryBuilder = queryBuilder;
this.select = (element, ...moreElements) => {
const all = "*";
let query = this.statement.query.query;
if (element === all) {
query.selectAll = all;
query.elements = moreElements;
}
else {
query.elements = [typeof element === "string" ? this.queryBuilder.column(element) : element].concat(moreElements);
}
return this;
};
this.from = (table, alias) => {
let query = this.statement.query.query;
let tableSourceItems = [];
if (typeof table === "string") {
let tableSpec = new ast.TableSpec(table);
tableSourceItems.push(alias ? new ast.AliasedTerm(tableSpec, alias) : tableSpec);
}
else {
if (!alias) {
throw Error("Alias required for nested select statements");
}
else {
tableSourceItems.push(new ast.AliasedTerm(table, alias));
}
}
query.from = new ast.FromClause(tableSourceItems.map(item => new ast.TableSource(item)));
return this;
};
this.join = (table, alias, on) => {
return this.buildJoinClause(table, alias, on, "INNER");
};
this.lefJoin = (table, alias, on) => {
return this.buildJoinClause(table, alias, on, "LEFT OUTER");
};
this.rightJoin = (table, alias, on) => {
return this.buildJoinClause(table, alias, on, "RIGHT OUTER");
};
this.where = (expression) => {
let query = this.statement.query.query;
if (query.from) {
query.from.where = new ast.WhereClause(expression);
}
return this;
};
this.groupBy = (...fields) => {
let groupByClause = new ast.GroupByClause(fields.map(f => typeof f === "string" ? new ast.GroupByItem(new ast.ColumnName(f)) : f));
if (this.statement.query.query.from) {
this.statement.query.query.from.groupBy = groupByClause;
}
else {
throw Error("Can't group anything");
}
return this;
};
this.having = (condition) => {
if (this.statement.query.query.from) {
this.statement.query.query.from.having = condition;
}
else {
throw Error("Invalid use of 'having'");
}
return this;
};
this.orderBy = (...expressions) => {
this.statement.query.query.orderBy = new ast.OrderByClause(expressions);
return this;
};
this.limit = (limit, offset) => {
this.statement.query.query.limit = new ast.LimitClause(limit, offset);
return this;
};
this.into = (...fields) => {
throw Error("Into is not yet implemented");
};
this.toSelect = () => {
return this.statement;
};
this.build = () => {
return new ast.SqlRoot(this.queryBuilder.dialect, [this.toSelect()]);
};
this.statement = new ast.SelectStatement(new ast.QueryIntoExpression(new ast.QueryExpression()));
}
buildJoinClause(table, alias, on, joinType) {
let tableSpec = new ast.AliasedTerm(typeof table === "string" ? new ast.TableSpec(table) : table, alias);
let joinPart = new ast.JoinClause(tableSpec);
joinPart.joinType = joinType;
joinPart.on = on;
if (this.statement.query.query.from !== undefined) {
let tables = this.statement.query.query.from.tables;
let lastTable = tables[tables.length - 1];
lastTable.joins = lastTable.joins ? lastTable.joins.concat(joinPart) : [joinPart];
}
else {
throw Error("Can't join with anything meaningful");
}
return this;
}
}
class QueryBuilderBase {
constructor(dialect) {
this.dialect = dialect;
this.equals = (left, right) => {
return this.buildBinaryPredicate(left, "=", right);
};
this.greater = (left, right) => {
return this.buildBinaryPredicate(left, ">", right);
};
this.less = (left, right) => {
return this.buildBinaryPredicate(left, "<", right);
};
this.greaterOrEquals = (left, right) => {
return this.buildBinaryPredicate(left, ">=", right);
};
this.lessOrEquals = (left, right) => {
return this.buildBinaryPredicate(left, "<=", right);
};
this.notEquals = (left, right) => {
return this.buildBinaryPredicate(left, "!=", right);
};
this.nullSafeEquals = (left, right) => {
return this.buildBinaryPredicate(left, "<=>", right);
};
}
alias(node, aliasName) {
return new ast.AliasedTerm(node, aliasName);
}
func(name, ...funcArgs) {
return new ast.SimpleFunctionCall(name, funcArgs.map(f => typeof f === "string" ? this.column(f) : f));
}
column(name, table) {
let lastDot = name.lastIndexOf(".");
if (lastDot !== -1) {
if (table) {
throw Error("Invalid syntax for column name");
}
else {
table = name.substr(0, lastDot);
name = name.substr(lastDot + 1);
if (!name || name === "") {
throw Error("Invalid syntax for column name");
}
}
}
return new ast.ColumnName(name, table);
}
literal(value, alias) {
let constant = new ast.Constant(value);
return alias ? new ast.AliasedTerm(constant, alias) : constant;
}
variable(name) {
return new ast.Variable(name);
}
exists(statement) {
return new ast.ExistsSelectStatement(statement);
}
nested(statement) {
return new ast.NestedSelectStatement(statement);
}
not(expression) {
return new ast.NotExpression(expression);
}
and(left, right, ...more) {
let result = new ast.BinaryExpression(left, "AND", right);
for (let expr of more) {
result = new ast.BinaryExpression(result, "AND", expr);
}
return result;
}
or(left, right, ...more) {
let result = new ast.BinaryExpression(left, "OR", right);
for (let expr of more) {
result = new ast.BinaryExpression(result, "OR", expr);
}
return result;
}
xor(left, right) {
return new ast.BinaryExpression(left, "XOR", right);
}
isTrue(predicate) {
return new ast.TruthyPredicate(predicate, false, true);
}
isFalse(predicate) {
return new ast.TruthyPredicate(predicate, false, false);
}
isUnknown(predicate) {
throw new Error("Method not implemented.");
}
in(predicate, target) {
return new ast.InPredicate(predicate, target);
}
notIn(predicate, target) {
return new ast.InPredicate(predicate, target, true);
}
isNull(predicate) {
return new ast.IsNullNotNullPredicate(predicate, "NULL");
}
isNotNull(predicate) {
return new ast.IsNullNotNullPredicate(predicate, "NOT NULL");
}
binaryPredicate(left, operator, right) {
return new ast.BinaryExpression(left, operator, right);
}
between(operand, start, end) {
return new ast.BetweenPredicate(operand, start, end);
}
notBetween(operand, left, right) {
return new ast.BetweenPredicate(operand, left, right, true);
}
soundsLike(left, right) {
return new ast.SoundsLikePredicate(left, right);
}
like(left, right) {
return new ast.LikePredicate(left, right);
}
notLike(left, right) {
return new ast.LikePredicate(left, right, true);
}
query() {
return new QueryableImpl(this);
}
buildBinaryPredicate(left, operator, right) {
let lp = typeof left === "string" ? this.column(left) : left;
let rp = typeof right === "string" ? this.column(right) : right;
return new ast.BinaryPredicate(lp, operator, rp);
}
}
exports.QueryBuilderBase = QueryBuilderBase;
class MySQLQueryBuilder extends QueryBuilderBase {
constructor() {
super("MySQL");
}
}
exports.MySQLQueryBuilder = MySQLQueryBuilder;
//# sourceMappingURL=queryBuilder.js.map