@wener/miniquery
Version:
SQL Where like **safe** filter expression for ORM.
334 lines (333 loc) • 11.3 kB
JavaScript
/* eslint-disable @typescript-eslint/no-non-null-assertion */ function _array_like_to_array(arr, len) {
if (len == null || len > arr.length)
len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++)
arr2[i] = arr[i];
return arr2;
}
function _array_without_holes(arr) {
if (Array.isArray(arr))
return _array_like_to_array(arr);
}
function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
}
else {
obj[key] = value;
}
return obj;
}
function _iterable_to_array(iter) {
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null)
return Array.from(iter);
}
function _non_iterable_spread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _object_spread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function (key) {
_define_property(target, key, source[key]);
});
}
return target;
}
function _to_consumable_array(arr) {
return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
}
function _unsupported_iterable_to_array(o, minLen) {
if (!o)
return;
if (typeof o === "string")
return _array_like_to_array(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor)
n = o.constructor.name;
if (n === "Map" || n === "Set")
return Array.from(n);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
return _array_like_to_array(o, minLen);
}
import { col, DataTypes, fn, Op, where } from "@sequelize/core";
import { toMiniQueryAST } from "../ast.js";
export function toSequelizeWhere(s, o) {
var _ctx_include;
var ctx = _object_spread({
functions: DefaultFunctions,
include: [],
associations: []
}, o);
if (!s) {
return {
where: {},
include: []
};
}
var where = toWhere(toMiniQueryAST(s), ctx);
(_ctx_include = ctx.include).push.apply(_ctx_include, _to_consumable_array(ctx.associations));
return {
where: where,
include: ctx.include
};
}
var DefaultFunctions = {
date: {
arity: 1
},
length: {
arity: 1
}
};
function checkFunctions(name) {
var args = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : [], o = arguments.length > 2 ? arguments[2] : void 0;
if (!o.functions[name]) {
throw new Error("Invalid function: ".concat(name));
}
}
function isSameType(a, b) {
return a === b || keyOfDataType(a) === keyOfDataType(b);
}
function keyOfDataType(d) {
if (typeof d === "string") {
return d.toUpperCase();
}
return d;
// if ('key' in d) {
// // v7 removed
// // return d.key;
// // return d.usageContext?.model.name
// return d
// }
// // fixme
// return d.name;
}
function resolve(parts, c) {
var Model = c.Model;
var M = Model;
var rest = _to_consumable_array(parts);
var all = [];
var isAssoc = false;
var include;
while (rest.length) {
var first = rest.shift();
var attr = M.getAttributes()[first];
if (attr) {
if (isSameType(attr.type, DataTypes.JSON) || isSameType(attr.type, DataTypes.JSONB)) {
var _all;
all.push(attr.field);
(_all = all).push.apply(_all, _to_consumable_array(rest));
break;
}
else if (rest.length === 0) {
all.push(attr.field);
break;
}
else {
throw new SyntaxError("Invalid ref of attr: ".concat(parts.join("."), " type of ").concat(attr.field, " is ").concat(attr.type));
}
}
else if (rest.length === parts.length - 1) {
// first
// User.createdAt
if (first === M.name) {
continue;
}
}
var assoc = M.associations[first];
if (assoc) {
if (assoc.isMultiAssociation) {
throw new Error("Use has for multi association: ".concat(parts.join(".")));
}
if (!include) {
include = {
association: assoc,
required: true
};
c.include.push(include);
}
else {
// nested
include.include = [
{
association: assoc,
required: true
}
];
}
all.push(first);
M = assoc.target;
if (!rest.length) {
throw new SyntaxError("Invalid ref of an association: ".concat(parts.join(".")));
}
isAssoc = true;
continue;
}
throw new SyntaxError("Invalid ref: ".concat(parts.join("."), " of model ").concat(M.name));
}
if (isAssoc) {
return "$".concat(all.join("."), "$");
}
return all.join(".");
}
function toWhere(ast, o) {
var _o_current;
var current = (_o_current = o.current) !== null && _o_current !== void 0 ? _o_current : {};
var Model = o.Model;
function attrOfIdentifier(name) {
// can support auto case convert
var attr = Model.getAttributes()[name];
if (!(attr === null || attr === void 0 ? void 0 : attr.field)) {
throw new Error("Invalid attribute: ".concat(name));
}
return attr;
}
var setOp = function (left, op, val) {
if (typeof op === "string") {
op = opOf(op);
}
var v;
switch (left.type) {
case "identifier":
var _current, _attrOfIdentifier_field;
var _;
v = (_ = (_current = current)[_attrOfIdentifier_field = attrOfIdentifier(left.name).field]) !== null && _ !== void 0 ? _ : _current[_attrOfIdentifier_field] = {};
break;
case "call":
{
var first = left.value[0];
if (left.value.length !== 1) {
throw new SyntaxError("Expected 1 call args, got ".concat(left.value.length));
}
var cn;
switch (first.type) {
case "identifier":
cn = attrOfIdentifier(first.name).field;
break;
case "ref":
// fixme hack replace
cn = resolve(first.name, o).replaceAll("$", "`");
break;
default:
throw new SyntaxError("Expected identifier or ref for call, got ".concat(first.type));
}
var name = left.name.toLowerCase();
checkFunctions(name, [
first
], o);
current = where(fn(name, col(cn)), _define_property({}, op, val));
return;
}
case "ref":
var _current1, _resolve;
var _1;
// 依然无法 escape `.`
// https://sequelize.org/docs/v7/core-concepts/model-querying-basics/#querying-json
// v = _.get(current, left.name);
// if (!v) {
// v = {};
// _.set(current, left.name, v);
// }
v = (_1 = (_current1 = current)[_resolve = resolve(left.name, o)]) !== null && _1 !== void 0 ? _1 : _current1[_resolve] = {};
break;
default:
throw new SyntaxError("Expected identifier, ref or call for left side, got ".concat(left.type));
}
v[op] = val;
};
switch (ast.type) {
case "rel":
{
setOp(ast.a, ast.op, toWhere(ast.b, _object_spread({}, o)));
}
break;
case "between":
{
setOp(ast.a, ast.op, [
toWhere(ast.b, _object_spread({}, o)),
toWhere(ast.c, _object_spread({}, o))
]);
}
break;
case "logic":
{
var _current, _op;
var op = opOf(ast.op);
var _;
var c = (_ = (_current = current)[_op = op]) !== null && _ !== void 0 ? _ : _current[_op] = [];
// collect - flat - optimize
var a = toWhere(ast.a, _object_spread({}, o));
if (a[op]) {
var _c;
(_c = c).push.apply(_c, _to_consumable_array(a[op]));
}
else {
c.push(a);
}
var b = toWhere(ast.b, _object_spread({}, o));
if (b[op]) {
var _c1;
(_c1 = c).push.apply(_c1, _to_consumable_array(b[op]));
}
else {
c.push(b);
}
}
break;
case "paren":
return [
toWhere(ast.value, _object_spread({}, o))
];
case "int":
case "string":
case "float":
return ast.value;
case "null":
return null;
case "call":
{
var name = ast.name.toLowerCase();
checkFunctions(name, ast.value, o);
return fn.apply(void 0, [
name
].concat(_to_consumable_array(ast.value.map(function (v) {
return toWhere(v, _object_spread({}, o));
}))));
}
case "identifier":
{
var attr = attrOfIdentifier(ast.name);
return col(attr.field);
}
default:
throw new SyntaxError("Invalid type: ".concat(ast.type));
}
return current;
}
var OpMap = {
"not between": "notBetween",
"not like": "notLike",
ilike: "iLike",
"not ilike": "notILike",
"not in": "notIn",
"is not": "not"
};
function opOf(v) {
var op = Op[OpMap[v] || v];
if (!op) {
throw new SyntaxError("Unsupported operator: ".concat(v));
}
return op;
}