fxsql
Version:
Functional query builder based on fxjs
213 lines (186 loc) • 8.96 kB
JavaScript
;
var _mapInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/map");
var _filterInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/filter");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = load_ljoin;
var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat"));
var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
var _indexOf = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/index-of"));
var _fxjs = require("fxjs");
var _pluralize = _interopRequireDefault(require("pluralize"));
const {
singular
} = _pluralize.default;
async function load_ljoin({
ready_sqls,
add_column,
tag,
connection_info,
QUERY,
IN,
EQ,
COLUMN,
CL,
TB,
SQL,
SQLS
}) {
const table_columns = {};
const add_as_join = (me, as) => {
var _context;
return COLUMN(...(0, _fxjs.go)((0, _concat.default)(_context = me.column.originals).call(_context, (0, _fxjs.pluck)('left_key', me.left_joins)), (0, _mapInstanceProperty(_fxjs))(c => me.as + '.' + c + ' AS ' + `${as}>_<${c}`), _fxjs.uniq));
};
(0, _assign.default)(table_columns, await (0, _fxjs.go)(QUERY`
SELECT table_name, column_name
FROM information_schema.columns
WHERE
table_name in (
SELECT tablename
FROM pg_tables
WHERE
tableowner=${connection_info.user || process.env.PGUSER}
) ORDER BY table_name;`, (0, _fxjs.groupBy)(v => v.table_name), (0, _mapInstanceProperty(_fxjs))(v => (0, _fxjs.pluck)('column_name', v))), await (0, _fxjs.go)(QUERY`
SELECT *
FROM INFORMATION_SCHEMA.view_column_usage
WHERE view_catalog=${connection_info.database || process.env.PGDATABASE}
;`, (0, _fxjs.groupBy)(v => v.view_name), (0, _mapInstanceProperty(_fxjs))(v => (0, _fxjs.pluck)('column_name', v))));
function where_in_query(left, where_in, QUERY) {
var _context2;
const colums = (0, _fxjs.uniq)((0, _concat.default)(_context2 = add_column(left).originals).call(_context2, left.key));
const query = left.query();
if (query && query.text) query.text = query.text.replace(/^\s*WHERE/i, 'AND');
return left.row_number.length == 2 ? QUERY`
SELECT *
FROM (
SELECT
${COLUMN(...colums)},
ROW_NUMBER() OVER (PARTITION BY ${CL(left.key)} ORDER BY ${left.row_number[1]}) as "--row_number--"
FROM ${TB(left.table)} AS ${TB(left.as)}
${where_in || tag()}
) AS "--row_number_table--"
WHERE "--row_number_table--"."--row_number--"<=${left.row_number[0]}` : QUERY`
SELECT ${CL(...colums)}
FROM ${TB(left.table)} AS ${TB(left.as)}
${where_in || tag()}
${tag(query)}
`;
}
function left_join_query(left, where_in, QUERY) {
var _context3;
let i = 0;
left.lj_as = 'lj' + i++ + '//' + left.depth;
const first_col = (0, _concat.default)(_context3 = add_as_join(left, left.lj_as).originals).call(_context3, left.as + '.id' + ' AS ' + `${left.lj_as}>_<id`);
if (left.key) first_col.push(left.as + '.' + left.key + ' AS ' + `${left.lj_as}>_<${left.key}`);
const join_columns = [first_col];
const join_sqls = [];
return (0, _fxjs.go)(left, function recur(me) {
me.left_join_over = true;
(0, _fxjs.each)(right => {
var _context4, _context5;
const query = right.query();
right.lj_as = 'lj' + i++ + '//' + right.depth;
if (query && query.text) query.text = query.text.replace(/^\s*WHERE/i, 'AND');
join_columns.push((0, _fxjs.uniq)((0, _concat.default)(_context4 = (0, _concat.default)(_context5 = add_as_join(right, right.lj_as).originals).call(_context5, right.as + '.' + right.key + ' AS ' + `${right.lj_as}>_<${right.key}`)).call(_context4, right.as + '.id' + ' AS ' + `${right.lj_as}>_<id`)));
join_sqls.push(SQL`
LEFT JOIN
${TB(right.table)} AS ${TB(right.as)}
ON
${EQ({
[me.as + '.' + right.left_key]: COLUMN(right.as + '.' + right.key)
})}
${tag(query)}
`);
recur(right);
}, me.left_joins);
}, () => {
const query = left.query();
if (!query) return query;
query.text = query.text.replace(/^\s*WHERE/i, where_in ? 'AND' : 'WHERE');
return query;
}, query => left.row_number.length == 2 ? QUERY`
SELECT "--row_number_table--".*
FROM (
SELECT
${COLUMN(...(0, _fxjs.flatten)(join_columns))},
ROW_NUMBER() OVER (PARTITION BY ${CL(left.as + '.' + left.key)} ORDER BY ${left.row_number[1]}) as "--row_number--"
FROM ${TB(left.table)} AS ${TB(left.as)}
${SQLS(join_sqls)}
${where_in || tag()}
${tag(query)}
) AS "--row_number_table--"
WHERE "--row_number_table--"."--row_number--"<=${left.row_number[0]}` : QUERY`
SELECT ${COLUMN(...(0, _fxjs.flatten)(join_columns))}
FROM ${TB(left.table)} AS ${TB(left.as)}
${SQLS(join_sqls)}
${where_in || tag()}
${tag(query)}`, left.row_number.length == 2 ? (0, _mapInstanceProperty(_fxjs))(r => delete r['--row_number--'] && r) : r => r, (0, _mapInstanceProperty(_fxjs))(row => {
const before_result_obj = {};
const result_obj = {};
for (const as in row) {
if ((0, _indexOf.default)(as).call(as, '>_<') == -1) return;
const split_as = as.split('>_<');
var tas = split_as[0];
before_result_obj[tas] = before_result_obj[tas] || {
_: {}
};
before_result_obj[tas][split_as[1]] = row[as];
}
!function recur(me, memo) {
memo[me.as] = before_result_obj[me.lj_as];
(0, _fxjs.each)(right => recur(right, memo[me.as]._), me.left_joins);
}(left, result_obj);
return result_obj[left.as];
}));
}
return function (QUERY) {
return async function ljoin(strs, ...tails) {
return (0, _fxjs.go)(ready_sqls(strs, tails), _fxjs.flatten, (0, _filterInstanceProperty(_fxjs))(t => t.as), (0, _fxjs.each)(option => {
option.query = option.query || tag();
option.table = option.table || (option.rel_type == '-' ? option.as + 's' : option.as);
option.column = option.column || CL(...table_columns[option.table]);
option.left_joins = [];
option.rels = [];
option.row_number = option.row_number || [];
}), ([left, ...rest]) => {
const cur = [left];
(0, _fxjs.each)(me => {
while (!((0, _fxjs.last)(cur).depth < me.depth)) cur.pop();
const left = (0, _fxjs.last)(cur);
if (me.rel_type == '-') {
me.left_key = me.left_key || (me.is_poly ? 'id' : singular(me.table) + '_id');
me.key = me.key || (me.is_poly ? 'attached_id' : 'id');
left.left_joins.push(me);
} else {
me.left_key = me.left_key || 'id';
me.key = me.key || (me.is_poly ? 'attached_id' : singular(left.table) + '_id');
}
left.rels.push(me);
me.poly_type = me.is_poly ? SQL`AND ${EQ((0, _fxjs.isString)(me.poly_type) ? {
attached_type: me.poly_type || left.table
} : me.poly_type)}` : tag();
cur.push(me);
}, rest);
return left;
}, async left => [left, left.left_joins.length ? await left_join_query(left, null, QUERY) : await QUERY`
SELECT ${add_column(left)}
FROM ${TB(left.table)} AS ${TB(left.as)} ${left.query}`], function recur([left, results]) {
if ((0, _fxjs.reject)(r => r, results).length) return;
return (0, _fxjs.go)(left.rels, (0, _fxjs.mapC)(async function (me) {
const f_key_ids = (0, _fxjs.uniq)((0, _filterInstanceProperty(_fxjs))(r => !!r, (0, _fxjs.pluck)(me.left_key, results)));
if (me.rel_type == '-' || !f_key_ids.length) return recur([me, (0, _fxjs.flatten)((0, _mapInstanceProperty(_fxjs))(r => r._ ? r._[me.as] : null, results))]);
return (0, _fxjs.go)((!me.left_join_over && me.left_joins.length ? left_join_query : where_in_query)(me, SQL`WHERE ${IN(me.as + '.' + me.key, f_key_ids)}`, QUERY), (0, _fxjs.groupBy)(v => v[me.key]), function (groups) {
(0, _fxjs.each)(function (result) {
result._ = result._ || {};
result._[me.as] = groups[result[me.left_key]] || [];
}, results);
return recur([me, (0, _fxjs.flatten)((0, _mapInstanceProperty(_fxjs))(r => r._ ? r._[me.as] : null, results))]);
});
}), () => results);
});
};
};
}