@iamthes/query-builder
Version:
Builds sql query for RDBMS
450 lines • 16.4 kB
JavaScript
;
var query_type_enum_1 = require("./query-type.enum");
var lodash_1 = require("lodash");
var isNumber = require("is-number");
var Sql = (function () {
function Sql() {
this.reset();
}
Sql.prototype.reset = function () {
this._queryKind = undefined;
this._selects = [];
this._tables = [];
this._wheres = [];
this._whereConcat = "and";
this._whereConcatDefault = "and";
this._sets = [];
this._limit = undefined;
this._offset = undefined;
this._orderBys = [];
this._joins = [];
this._groupBys = [];
this._whereGroupCount = 0;
this._openWhereGroupCount = 0;
this._havings = [];
return this;
};
Sql.prototype.select = function (field, alias, func) {
var _this = this;
this._queryKind = query_type_enum_1.QueryKind.SELECT;
switch (arguments.length) {
case 0:
this._selects.push({ "field": "*" });
break;
case 1:
if (!lodash_1.isArray(field))
field = String(field).split(",");
field.map(function (f) { return lodash_1.trim(f); }).filter(Boolean).forEach(function (f) {
var _a = f.split(/\s*as\s*/i), field = _a[0], alias = _a[1];
_this._selects.push({ field: field, alias: alias });
});
break;
case 2:
if (lodash_1.isString(field)) {
this._selects.push({ field: field, alias: alias });
}
break;
default:
var args = Array.prototype.slice.call(arguments);
func = args.shift(); // First parameter
alias = args.pop(); // Last parameter
args = args.map(function (f) { return lodash_1.isArray(f) ? f.join(", ") : f; }); // Do flatten array.
this._selects.push({ func: func, alias: alias, "field": args.join(", ") });
}
return this;
};
Sql.prototype.between = function (field, value, otherValue) {
if (otherValue === undefined) {
var split = value.split("..");
if (split.length > 1) {
value = split[0], otherValue = split[1];
}
}
var sql = field + " between " + this._wrap(value) + " and " + this._wrap(otherValue);
this._where(sql);
return this;
};
Sql.prototype.table = function (table) {
var _this = this;
if (!lodash_1.isArray(table)) {
table = [table];
}
table.forEach(function (t) { return _this._tables.push(t); });
return this;
};
Sql.prototype.from = function (table) {
return this.table(table);
};
Sql.prototype.into = function (table) {
return this.table(table);
};
Sql.prototype._conditionExpr = function (field, value, operator) {
// console.log('_conditionExpr', arguments);
var wrapValue = true;
if (!operator) {
operator = lodash_1.find(Sql._operators, function (o) { return lodash_1.endsWith(field, o); });
if (operator) {
field = field.slice(0, -operator.length).trim();
}
}
switch (operator) {
case "is null":
operator = "is";
value = "@null";
break;
case "is not null":
operator = "is not";
value = "@null";
break;
default:
if (!operator) {
operator = "=";
}
}
if (value === null) {
value = "@null";
}
if (lodash_1.isString(value) && value.substr(0, 1) === "@") {
wrapValue = false;
value = value.substr(1);
}
if (wrapValue && value !== undefined) {
value = this._wrap(value);
}
return { field: field, operator: operator, value: value };
};
Sql.prototype.where = function (field, operator, value) {
if (typeof field === "object") {
for (var i in field) {
this.where(i, field[i]);
}
return this;
}
if (value === undefined) {
value = operator;
operator = undefined;
}
// console.log("field, value, operator ", field, value, operator);
var expr = this._conditionExpr(field, value, operator);
// console.log("expr ", expr);
switch (expr.operator) {
case "@": return this.whereIn(field.slice(0, -1), value);
case "!@": return this.whereNotIn(field.slice(0, -2), value);
case "!%": return this.notLike(field.slice(0, -2), value, "both");
case "%": return this.like(field.slice(0, -1), value, "both");
case "^%": return this.like(field.slice(0, -2), value, "right");
case "%$": return this.like(field.slice(0, -2), value, "left");
}
this._where(expr.field + " " + expr.operator + " " + expr.value);
return this;
};
Sql.prototype.whereNotIn = function (field, values) {
return this.whereIn(field, values, "not in");
};
Sql.prototype.whereIn = function (field, values, op) {
if (op === void 0) { op = "in"; }
if (!lodash_1.isArray(values))
values = [String(values)];
values = values.map(this._wrap);
var value = "(" + values.join(",") + ")";
var where = field + " " + op + " " + value;
this._where(where);
return this;
};
Sql.prototype.limit = function (limit, offset) {
this._limit = limit;
if (offset !== undefined) {
this._offset = offset;
}
return this;
};
Sql.prototype.top = function (n) {
return this.limit(n);
};
Sql.prototype.offset = function (offset) {
this._offset = offset;
return this;
};
Sql.prototype.skip = function (n) {
return this.offset(n);
};
Sql.prototype.notLike = function (field, match, side) {
return this.like(field, match, side, "not like");
};
Sql.prototype.like = function (field, match, side, op) {
if (match === void 0) { match = ""; }
if (side === void 0) { side = "both"; }
if (op === void 0) { op = "like"; }
field = lodash_1.trim(field);
switch (side) {
case "left":
match = "%" + match;
break;
case "right":
match += "%";
break;
case "both":
{
if (lodash_1.isString(match) && match.length === 0) {
match = "%";
}
else {
match = "%" + match + "%";
}
}
break;
default:
throw new Error("Unknown side " + side);
}
// console.log('field', JSON.stringify(field));
// console.log('op', JSON.stringify(op));
// console.log('match', JSON.stringify(match));
// console.log(JSON.stringify(`${field} ${op} ${this._wrap(match)}`));
this._where(field + " " + op + " " + this._wrap(match));
return this;
};
Sql.prototype.groupBy = function (fields) {
var _this = this;
if (!lodash_1.isArray(fields)) {
fields = String(fields).split(",");
}
fields
.map(function (f) { return lodash_1.trim(f); })
.filter(function (f) { return f.length > 0; })
.forEach(function (f) {
_this._groupBys.push(f);
});
return this;
};
Sql.prototype.andOp = function () {
this._whereConcat = "and";
return this;
};
Sql.prototype.orOp = function () {
this._whereConcat = "or";
return this;
};
Sql.prototype.beginWhereGroup = function () {
this._whereGroupCount++;
this._openWhereGroupCount++;
return this;
};
Sql.prototype.endWhereGroup = function () {
if (this._whereGroupCount > 0) {
var whereCount = this._wheres.length;
if (this._openWhereGroupCount >= this._whereGroupCount) {
this._openWhereGroupCount--;
}
else if (whereCount > 0) {
this._wheres[whereCount - 1] += ")";
}
this._whereGroupCount--;
}
return this;
};
Sql.prototype._endQuery = function () {
while (this._whereGroupCount > 0) {
this.endWhereGroup();
}
};
Sql.prototype.join = function (table, on, join) {
if (!lodash_1.includes(Sql._joinTypes, join))
join = "";
var expr = lodash_1.trim(join + " join " + table + " on " + on);
this._joins.push(expr);
return this;
};
Sql.prototype.leftJoin = function (table, on) {
return this.join(table, on, "left");
};
Sql.prototype.having = function (field, value) {
var expr = this._conditionExpr(field, value);
this._havings.push(expr.field + " " + expr.operator + " " + expr.value);
return this;
};
Sql.prototype.orderBy = function (field, direction) {
if (direction === void 0) { direction = "asc"; }
direction = direction.toLowerCase();
if (direction !== "asc")
direction = "desc";
var expr = field + " " + direction;
this._orderBys.push(expr);
return this;
};
Sql.prototype.get = function () {
switch (this._queryKind) {
case query_type_enum_1.QueryKind.SELECT: return this.getSelect();
case query_type_enum_1.QueryKind.DELETE: return this.getDelete();
case query_type_enum_1.QueryKind.INSERT: return this.getInsert();
case query_type_enum_1.QueryKind.UPDATE: return this.getUpdate();
default:
throw new TypeError("Unknown kind of query " + this._queryKind);
}
};
Sql.prototype.getSelect = function () {
this._endQuery();
var sql = "select ";
var selects = this._selects
.map(function (item) {
var field = item.field;
if (item.func)
field = item.func + "(" + field + ")";
if (item.alias)
field = field + " as " + item.alias;
return field;
})
.join(", ");
if (selects === "")
selects = "*";
sql += selects;
if (this._tables.length > 0)
sql += " " + "from " + this._tables.join(", ");
if (this._joins.length > 0)
sql += " " + this._joins.join(" ");
if (this._wheres.length > 0)
sql += " " + "where " + this._wheres.join(" ");
if (this._groupBys.length > 0)
sql += " " + "group by " + this._groupBys.join(", ");
if (this._havings.length > 0)
sql += " " + "having " + this._havings.join(" ");
if (this._orderBys.length > 0)
sql += " " + "order by " + this._orderBys.join(", ");
if (isNumber(this._limit)) {
sql += " ";
sql = this.getLimit(sql, this._limit, this._offset);
}
this.reset();
return sql;
};
Sql.prototype.delete = function (table) {
this._queryKind = query_type_enum_1.QueryKind.DELETE;
if (table) {
this._tables.push(table);
}
return this;
};
Sql.prototype.getDelete = function () {
var table = this._tables[0];
var result = "delete " + table;
if (this._wheres.length > 0) {
result += " " + "where " + this._wheres.join(" ");
}
this.reset();
return result;
};
Sql.prototype.update = function (table) {
this._queryKind = query_type_enum_1.QueryKind.UPDATE;
if (table) {
this._tables.push(table);
}
return this;
};
Sql.prototype.getUpdate = function () {
var _this = this;
this._endQuery();
var table = this._tables[0];
var result = "update " + table + " set ";
result += this._sets
.map(function (item) {
var value = item.value;
if (item.wrapValue)
value = _this._wrap(value);
return item.name + " = " + value;
})
.join(", ");
if (this._wheres.length > 0) {
result += " where " + this._wheres.join(" ");
}
this.reset();
return result;
};
Sql.prototype.insert = function () {
this._queryKind = query_type_enum_1.QueryKind.INSERT;
return this;
};
Sql.prototype.set = function (name, value, wrapValue) {
if (wrapValue === void 0) { wrapValue = true; }
if (arguments.length === 1) {
for (var i in name) {
this.set(i, name[i], true);
}
return this;
}
if (value === null || value === undefined) {
value = "null";
wrapValue = false;
}
this._sets.push({
name: name,
value: value,
wrapValue: wrapValue
});
return this;
};
Sql.prototype.getInsert = function () {
var _this = this;
var table = this._tables[0];
var result = "insert into " + table;
var names = this._sets.map(function (item) { return item.name; });
var values = this._sets.map(function (item) {
var value = item.value;
if (item.wrapValue)
value = _this._wrap(value);
return value;
});
result += "(" + names.join(", ") + ") values(" + values.join(", ") + ")";
this.reset();
return result;
};
Sql.prototype.getLimit = function (sql, limit, offset) {
throw "getLimit() not supported.";
};
Sql.prototype._where = function (sql) {
var concat = "";
if (this._wheres.length > 0) {
concat = this._whereConcat + " ";
}
while (this._openWhereGroupCount > 0) {
concat += "(";
this._openWhereGroupCount--;
}
// console.log("concat _w ", JSON.stringify(concat));
// console.log("sql _w ", JSON.stringify(sql));
this._whereConcat = this._whereConcatDefault;
this._wheres.push(concat + sql);
// console.log("this._wheres ", this._wheres);
};
Sql.prototype._wrap = function (value) {
// console.log("_wrap ", value);
if (!isNumber(value)) {
value = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
}
return value;
};
Sql.prototype._quote = function (value, wrapInQuotes) {
console.log("_quote ", value);
if (isNumber(value)) {
return value;
}
value = value
.replace("\\", "\\\\")
.replace("\0", "\\0")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("'", "\\'")
.replace("\"", "\\\"")
.replace("\x1a", "\\Z");
if (wrapInQuotes) {
value = "'" + value + "'";
}
return value;
};
Sql._operators = [">=", "<=", "!=", "<>", ">", "<", "!@", "@", "%$", "^%", "%", "like", "not like", "is", "is null", "is not null"];
Sql._joinTypes = ["inner", "outer", "left", "right", "left outer", "right outer"];
return Sql;
}());
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Sql;
//# sourceMappingURL=sql.js.map