refql
Version:
A Node.js and Deno library for composing and running SQL queries.
129 lines (128 loc) • 5.31 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const consts_1 = require("../common/consts");
const Raw_1 = __importDefault(require("../SQLTag/Raw"));
const sql_1 = require("../SQLTag/sql");
const Values_1 = __importDefault(require("../SQLTag/Values"));
const Table_1 = require("../Table");
const RefField_1 = __importDefault(require("./RefField"));
const RQLNode_1 = require("./RQLNode");
const type = "refql/RefNode";
const prototype = Object.assign({}, RQLNode_1.rqlNodePrototype, {
[consts_1.refqlType]: type,
joinLateral
});
function RefNode(tag, refProp, parent, options) {
let refNode = Object.create(prototype);
const { as, rel, child, refInput } = refProp;
const refOf = RefField_1.default.refFieldOf(as);
let info = { parent, as };
let single = false;
function getRef(refs, table, type, fallback) {
return refs && refs.length > 0
? refs.map((ref, idx) => refOf(table, type + (idx + 1), ref))
: [refOf(table, type + "1", options.toCase(fallback))];
}
switch (rel) {
case "BelongsTo":
info.lRef = getRef(refInput.lRef, parent, "lref", `${child.name}_id`);
info.rRef = getRef(refInput.rRef, child, "rref", "id");
single = true;
break;
case "HasOne":
info.lRef = getRef(refInput.lRef, parent, "lref", "id");
info.rRef = getRef(refInput.rRef, child, "rref", `${parent.name}_id`);
single = true;
break;
case "HasMany":
info.lRef = getRef(refInput.lRef, parent, "lref", "id");
info.rRef = getRef(refInput.rRef, child, "rref", `${parent.name}_id`);
break;
case "BelongsToMany":
const btmInput = refInput;
const xTable = typeof btmInput.xTable === "undefined"
? (0, Table_1.TableX)(parent.name < child.name ? `${parent.name}_${child.name}` : `${child.name}_${parent.name}`, [])
: (0, Table_1.TableX)(btmInput.xTable, []);
Object.assign(info, {
xTable,
lRef: getRef(btmInput.lRef, parent, "lref", "id"),
rRef: getRef(btmInput.rRef, child, "rref", "id"),
lxRef: getRef(btmInput.lxRef, xTable, "lxref", `${parent.name}_id`),
rxRef: getRef(btmInput.rxRef, xTable, "rxref", `${child.name}_id`)
});
break;
}
refNode.info = info;
refNode.single = single;
refNode.tag = tag;
return refNode;
}
function joinLateral() {
if (this.info.xTable) {
const { rRef, lRef, xTable, rxRef, lxRef, parent } = this.info;
const l1 = lRef.reduce((acc, lr, idx) => {
const kw = idx === 0 ? "where" : "and";
return acc.concat((0, sql_1.sqlX) `
${(0, Raw_1.default)(`${kw} ${lr.name}`)}
in ${(0, Values_1.default)(p => [...new Set(p.refQLRows.map(r => r[lr.as]))])}
`);
}, (0, sql_1.sqlX) `
select distinct ${(0, Raw_1.default)(lRef.join(", "))}
from ${(0, Raw_1.default)(parent)}
`);
const l2Join = rRef.reduce((acc, rr, idx) => {
const kw = idx === 0 ? "on" : "and";
const rxr = rxRef[idx];
return acc.concat((0, sql_1.sqlX) `
${(0, Raw_1.default)(`${kw} ${rxr.name} = ${rr.name}`)}
`);
}, (0, sql_1.sqlX) `join ${(0, Raw_1.default)(xTable)}`);
const l2where = lRef.reduce((acc, lr, idx) => {
const kw = idx === 0 ? "where" : "and";
const lxr = lxRef[idx];
return acc.concat((0, sql_1.sqlX) `
${(0, Raw_1.default)(`${kw} ${lxr.name} = refqll1.${lr.as}`)}
`);
}, (0, sql_1.sqlX) ``);
const { tag: l2, next } = this.tag.interpret(l2Join.concat(l2where));
const joined = (0, sql_1.sqlX) `
select * from (${l1}) refqll1,
lateral (${l2}) refqll2
`;
this.tag.interpreted = { tag: joined, next };
return this.tag;
}
else {
const { rRef, lRef, parent } = this.info;
const l1 = lRef.reduce((acc, lr, idx) => {
const kw = idx === 0 ? "where" : "and";
return acc.concat((0, sql_1.sqlX) `
${(0, Raw_1.default)(`${kw} ${lr.name}`)}
in ${(0, Values_1.default)(p => [...new Set(p.refQLRows.map(r => r[lr.as]))])}
`);
}, (0, sql_1.sqlX) `
select distinct ${(0, Raw_1.default)(lRef.join(", "))}
from ${(0, Raw_1.default)(parent)}
`);
const { tag: l2, next } = this.tag.interpret(lRef.reduce((acc, lr, idx) => {
const rr = rRef[idx];
const kw = idx === 0 ? "where" : "and";
return acc.concat((0, sql_1.sqlX) `
${(0, Raw_1.default)(`${kw} ${rr.name} = refqll1.${lr.as}`)}
`);
}, (0, sql_1.sqlX) ``));
const joined = (0, sql_1.sqlX) `
select * from (${l1}) refqll1,
lateral (${l2}) refqll2
`;
this.tag.interpreted = { tag: joined, next };
return this.tag;
}
}
RefNode.isRefNode = function (x) {
return x != null && x[consts_1.refqlType] === type;
};
exports.default = RefNode;
;