UNPKG

slonik-trpc

Version:
567 lines (566 loc) 39.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.makeQueryLoader = void 0; const slonik_1 = require("slonik"); const zod_1 = require("zod"); const zod_2 = require("../helpers/zod"); const cursors_1 = require("../helpers/cursors"); const buildView_1 = require("./buildView"); const orderDirection = zod_1.z.enum(["ASC", "DESC"]); function isBasicSortFieldOption(field) { var _a, _b; return !((_b = (_a = field) === null || _a === void 0 ? void 0 : _a.field) === null || _b === void 0 ? void 0 : _b.sql); } function getOrderFieldNullsLast(field) { return isBasicSortFieldOption(field) ? false : !!(field === null || field === void 0 ? void 0 : field.nullsLast); } function getOrderFieldNullable(field) { return isBasicSortFieldOption(field) ? false : !!(field === null || field === void 0 ? void 0 : field.nullable); } function getOrderByDirection(field, reverse) { if (getOrderFieldNullsLast(field[0])) { switch (field[1]) { case 'ASC': return reverse ? slonik_1.sql.fragment `DESC NULLS FIRST` : slonik_1.sql.fragment `ASC NULLS LAST`; case 'DESC': return reverse ? slonik_1.sql.fragment `ASC NULLS FIRST` : slonik_1.sql.fragment `DESC NULLS LAST`; } } switch (field[1]) { case 'ASC': return reverse ? slonik_1.sql.fragment `DESC` : slonik_1.sql.fragment `ASC`; case 'DESC': return reverse ? slonik_1.sql.fragment `ASC` : slonik_1.sql.fragment `DESC`; } } function interpretFieldFragment(field) { if (typeof field === 'string' || Array.isArray(field)) { return slonik_1.sql.fragment `${slonik_1.sql.identifier(Array.isArray(field) ? field : [field])}`; } return isBasicSortFieldOption(field) ? field : field.field; } function interpretOrderBy(field, reverse) { return slonik_1.sql.fragment `${interpretFieldFragment(field[0])} ${getOrderByDirection(field, reverse)}`; } const countQueryType = zod_1.z.object({ count: zod_1.z.number(), }); function getSelectedKeys(allKeys, selected) { const noneSelected = !(selected === null || selected === void 0 ? void 0 : selected.length); if (!noneSelected) { return allKeys.filter(key => selected.includes(key)); } else { return allKeys; } } function makeQueryLoader(options) { var _a, _b, _c, _d, _e, _f, _g; const queryComponents = options.query; const query = queryComponents.select; let view = queryComponents.view; const fromFragment = queryComponents.from || (view === null || view === void 0 ? void 0 : view.getFromFragment({})); if (((_a = options.filters) === null || _a === void 0 ? void 0 : _a.interpreters) && !view && fromFragment) { // backwards compatible if only filters are specified view = (0, buildView_1.buildView) `${fromFragment}` .addFilters(options.filters.interpreters); } else if (((_b = options.filters) === null || _b === void 0 ? void 0 : _b.interpreters) && view) { // Add filters to existing view if both are specified view = view.addFilters(options.filters.interpreters); } if (query.sql.match(/;\s*$/)) { // TODO: Add more checks for invalid queries console.warn("Your query includes semicolons at the end. Please refer to the documentation of slonik-trpc, and do not include semicolons in the query:\n " + query.sql); } if (!fromFragment) { console.warn("Deprecation warning: Specify query.from and query.select separately in makeQueryLoader", query === null || query === void 0 ? void 0 : query.sql); } if (fromFragment && ((_c = fromFragment.sql) === null || _c === void 0 ? void 0 : _c.length) > 5 && !((_e = (_d = fromFragment === null || fromFragment === void 0 ? void 0 : fromFragment.sql) === null || _d === void 0 ? void 0 : _d.match) === null || _e === void 0 ? void 0 : _e.call(_d, /^\s*FROM/i))) { throw new Error("query.from must begin with FROM"); } if (!((_g = (_f = query === null || query === void 0 ? void 0 : query.sql) === null || _f === void 0 ? void 0 : _f.match) === null || _g === void 0 ? void 0 : _g.call(_f, /^\s*(SELECT|WITH)/i))) { throw new Error("Your query must begin with SELECT or WITH"); } const type = options.type || query.parser; // @ts-expect-error accessing internal _any const isAnyType = type._any === true; if (!isAnyType && (!type || !type.keyof || !type.partial)) throw new Error('Invalid query type provided: ' + (type)); const interpretFilters = view ? view.getWhereConditions : null; const sortableAliases = Object.keys((options === null || options === void 0 ? void 0 : options.sortableColumns) || {}); const sortFields = sortableAliases.length ? zod_1.z.enum(sortableAliases) : // If unspecified, no field is allowed to be used for sorting zod_1.z.never(); const orderByWithoutTransform = zod_1.z.tuple([sortFields, orderDirection]); const cursorColumns = "cursorcolumns"; const sortFieldWithTransform = sortFields.transform(field => { var _a; return ((_a = options.sortableColumns) === null || _a === void 0 ? void 0 : _a[field]) || field; }); const orderByType = zod_1.z.tuple([sortFieldWithTransform, orderDirection]); const mapTransformRows = (rows, args) => __awaiter(this, void 0, void 0, function* () { var _h; if (!rows.length) return rows; if (options.virtualFields) { const keys = Object.keys(options.virtualFields); const selected = getSelectedKeys(keys, args.select); if (selected.length) { const { default: Nativebird } = yield Promise.resolve().then(() => __importStar(require('nativebird'))); yield Promise.all(selected.map((key) => __awaiter(this, void 0, void 0, function* () { var _j, _k, _l, _m, _o; const remoteLoad = yield ((_l = (_k = (_j = options.virtualFields) === null || _j === void 0 ? void 0 : _j[key]) === null || _k === void 0 ? void 0 : _k.load) === null || _l === void 0 ? void 0 : _l.call(_k, rows, args)); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const firstResolve = options.virtualFields[key].resolve(rows[0], Object.assign(Object.assign({}, args), { index: 0 }), remoteLoad); if (typeof ((_m = firstResolve) === null || _m === void 0 ? void 0 : _m.then) === 'function') { yield Nativebird.map(rows.slice(1), (row, index) => __awaiter(this, void 0, void 0, function* () { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion row[key] = yield options.virtualFields[key].resolve(row, Object.assign(Object.assign({}, args), { index }), remoteLoad); }), { concurrency: ((_o = options === null || options === void 0 ? void 0 : options.options) === null || _o === void 0 ? void 0 : _o.runConcurrency) || 50 }); rows[0][key] = yield firstResolve; } else { rows[0][key] = firstResolve; let index = 0; for (const row of rows.slice(1)) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion row[key] = options.virtualFields[key].resolve(row, Object.assign(Object.assign({}, args), { index: ++index }), remoteLoad); } } }))); } } if ((_h = options === null || options === void 0 ? void 0 : options.options) === null || _h === void 0 ? void 0 : _h.runtimeCheck) { const zodType = type.partial(); return rows.map(row => zodType.parse(row)); } else { return rows; } }); const getQuery = (allArgs) => __awaiter(this, void 0, void 0, function* () { var _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0; let { take, select, orderBy, } = allArgs; const { where, skip, distinctOn, ctx, cursor, takeCursors, searchAfter, selectGroups, } = allArgs; const context = ctx && ((_p = options.contextParser) === null || _p === void 0 ? void 0 : _p.parse) ? options.contextParser.parse(ctx) : ctx; const filtersCondition = yield (interpretFilters === null || interpretFilters === void 0 ? void 0 : interpretFilters({ where: where || {}, ctx: context, options: { orEnabled: !!((_q = options === null || options === void 0 ? void 0 : options.options) === null || _q === void 0 ? void 0 : _q.orFilterEnabled), } })); // Allows easier usage of cursor pagination with default sorting if (!(orderBy === null || orderBy === void 0 ? void 0 : orderBy.length) && ((_s = (_r = options.defaults) === null || _r === void 0 ? void 0 : _r.orderBy) === null || _s === void 0 ? void 0 : _s.length)) { orderBy = options.defaults.orderBy; } const authConditions = yield ((_t = options === null || options === void 0 ? void 0 : options.constraints) === null || _t === void 0 ? void 0 : _t.call(options, context)); const auth = Array.isArray(authConditions) ? authConditions : [authConditions].filter(zod_2.notEmpty); const allConditions = [...auth, ...(filtersCondition || [])].filter(zod_2.notEmpty); const whereCondition = allConditions.length ? slonik_1.sql.fragment `(${slonik_1.sql.join(allConditions, slonik_1.sql.fragment `) AND (`)})` : slonik_1.sql.fragment `TRUE`; let actualQuery = query; if (selectGroups === null || selectGroups === void 0 ? void 0 : selectGroups.length) { const groupFields = selectGroups.flatMap(group => { var _a; return ((_a = options.columnGroups) === null || _a === void 0 ? void 0 : _a[group]) || []; }); select = (select || []).concat(...groupFields); } const isPartial = (select === null || select === void 0 ? void 0 : select.length) || (selectGroups === null || selectGroups === void 0 ? void 0 : selectGroups.length); const reverse = !!take && take < 0; if (take && take < 0) take = -take; if (reverse && !(orderBy === null || orderBy === void 0 ? void 0 : orderBy.length)) { throw new Error("orderBy must be specified when take parameter is negative!"); } const noneSelected = !(select === null || select === void 0 ? void 0 : select.length); const distinctFields = Array.isArray(distinctOn) ? distinctOn === null || distinctOn === void 0 ? void 0 : distinctOn.map(distinct => sortFields.parse(distinct)) : (distinctOn === null || distinctOn === void 0 ? void 0 : distinctOn.length) ? [sortFields.parse(distinctOn)] : null; const orderExpressions = Array.isArray(orderBy === null || orderBy === void 0 ? void 0 : orderBy[0]) ? orderBy === null || orderBy === void 0 ? void 0 : orderBy.map(order => orderByWithoutTransform.parse(order)) : (orderBy === null || orderBy === void 0 ? void 0 : orderBy.length) ? [orderByWithoutTransform.parse(orderBy)] : (distinctFields === null || distinctFields === void 0 ? void 0 : distinctFields.length) ? [] : null; if ((distinctFields === null || distinctFields === void 0 ? void 0 : distinctFields.length) && !((_u = options === null || options === void 0 ? void 0 : options.options) === null || _u === void 0 ? void 0 : _u.useSqlite)) { const distinctExpressions = distinctFields.map(field => interpretFieldFragment(sortFieldWithTransform.parse(field))); const distinctQuery = slonik_1.sql.fragment `SELECT DISTINCT ON (${slonik_1.sql.join(distinctExpressions, slonik_1.sql.fragment `, `)})`; // Hacky way to add DISTINCT ON (must be done towards the end...) actualQuery = Object.assign(Object.assign({}, actualQuery), { sql: query.sql.replace(/^\n*(\W\n?)*SELECT(\s*DISTINCT)?/i, distinctQuery.sql) }); for (const expression of distinctFields.reverse()) { // Reverse to make sure unshift is done in the correct order const orderPosition = orderExpressions === null || orderExpressions === void 0 ? void 0 : orderExpressions.findIndex(([field]) => field === expression); if (typeof orderPosition === 'number' && orderPosition >= 0) { orderExpressions === null || orderExpressions === void 0 ? void 0 : orderExpressions.unshift((_v = orderExpressions === null || orderExpressions === void 0 ? void 0 : orderExpressions.splice(orderPosition, 1)) === null || _v === void 0 ? void 0 : _v[0]); } else { orderExpressions === null || orderExpressions === void 0 ? void 0 : orderExpressions.unshift([expression, 'ASC']); } } } const conditions = [whereCondition].filter(zod_2.notEmpty); const cursorsEnabled = takeCursors && (orderExpressions === null || orderExpressions === void 0 ? void 0 : orderExpressions.length); const zodType = isAnyType ? type : cursorsEnabled ? (isPartial ? type.partial() : type).merge(zod_1.z.object({ [cursorColumns]: zod_1.z.any(), })) : (isPartial ? type.partial() : type); const fields = Object.keys(((_x = (_w = type === null || type === void 0 ? void 0 : type.keyof) === null || _w === void 0 ? void 0 : _w.call(type)) === null || _x === void 0 ? void 0 : _x.Values) || {}); const selectable = options === null || options === void 0 ? void 0 : options.selectableColumns; select = (select || []) .filter(field => !(selectable === null || selectable === void 0 ? void 0 : selectable.length) || selectable.indexOf(field) >= 0) // Add dependencies from selected fields. .flatMap((field) => { var _a, _b; return [ field, ...(((_b = (_a = options === null || options === void 0 ? void 0 : options.virtualFields) === null || _a === void 0 ? void 0 : _a[field]) === null || _b === void 0 ? void 0 : _b.dependencies) || []), ]; }) .filter((field) => !(fields === null || fields === void 0 ? void 0 : fields.length) || (fields === null || fields === void 0 ? void 0 : fields.indexOf(field)) >= 0); const hasTransformColumns = typeof ((_y = options === null || options === void 0 ? void 0 : options.options) === null || _y === void 0 ? void 0 : _y.transformColumns) === 'function'; if (hasTransformColumns) { select = select.map((field) => { var _a, _b, _c; return (_c = (_b = (_a = options === null || options === void 0 ? void 0 : options.options) === null || _a === void 0 ? void 0 : _a.transformColumns) === null || _b === void 0 ? void 0 : _b.call(_a, field)) !== null && _c !== void 0 ? _c : field; }); } const sqlFields = hasTransformColumns ? fields.map(field => { var _a, _b, _c; return (_c = (_b = (_a = options === null || options === void 0 ? void 0 : options.options) === null || _a === void 0 ? void 0 : _a.transformColumns) === null || _b === void 0 ? void 0 : _b.call(_a, field)) !== null && _c !== void 0 ? _c : field; }) : fields; const finalKeys = Array.from(new Set(sqlFields .filter(zod_2.notEmpty) .filter((column) => noneSelected || (select === null || select === void 0 ? void 0 : select.includes(column)))).values()).map(a => slonik_1.sql.identifier([a])); const lateralExpressions = []; const extraSelects = []; if (takeCursors && (orderExpressions === null || orderExpressions === void 0 ? void 0 : orderExpressions.length)) { if ((_z = options.options) === null || _z === void 0 ? void 0 : _z.useSqlite) { finalKeys.push(slonik_1.sql.fragment `json_object(${orderExpressions.length ? slonik_1.sql.join(orderExpressions.flatMap((expression) => [slonik_1.sql.literalValue(expression[0]), interpretFieldFragment(orderByType.parse(expression)[0])]), slonik_1.sql.fragment `,`) : slonik_1.sql.fragment ``}) ${slonik_1.sql.identifier([cursorColumns])}`); } else { if (!query.sql.includes("lateralcolumns.cursorjson")) { // Hacky way to get access to internal FROM tables for sorting expressions... extraSelects.push(slonik_1.sql.fragment `lateralcolumns.cursorjson ${slonik_1.sql.identifier([cursorColumns])}`); } lateralExpressions.push(slonik_1.sql.fragment `jsonb_build_object(${orderExpressions.length ? slonik_1.sql.join(orderExpressions.flatMap((expression) => [slonik_1.sql.literalValue(expression[0]), interpretFieldFragment(orderByType.parse(expression)[0])]), slonik_1.sql.fragment `,`) : slonik_1.sql.fragment ``}) cursorjson`); } } if ((searchAfter || cursor) && (orderExpressions === null || orderExpressions === void 0 ? void 0 : orderExpressions.length)) { const orderByExpressions = orderExpressions.map(parsed => [interpretFieldFragment(orderByType.parse(parsed)[0]), parsed[1], parsed[0], parsed]); const cursorValues = cursor ? (0, cursors_1.fromCursor)(cursor) : {}; conditions.push(slonik_1.sql.fragment `(${slonik_1.sql.join(orderByExpressions.map((_, outerIndex) => { const expressions = orderByExpressions.slice(0, outerIndex + 1); return slonik_1.sql.fragment `(${slonik_1.sql.join(expressions.map(([expression, direction, columnAlias], innerIndex) => { var _a; let operator = slonik_1.sql.fragment `=`; let nullFragment = slonik_1.sql.fragment `TRUE`; const orderField = (_a = options.sortableColumns) === null || _a === void 0 ? void 0 : _a[columnAlias]; const value = searchAfter ? searchAfter[columnAlias] : cursorValues[columnAlias]; const isNullable = getOrderFieldNullable(orderField) || value === null; const nullsLast = getOrderFieldNullsLast(orderField); let isNull = false; const ascending = direction === (reverse ? "DESC" : "ASC"); if (innerIndex === expressions.length - 1) { operator = ascending ? slonik_1.sql.fragment `>` : slonik_1.sql.fragment `<`; if (isNullable) { nullFragment = ascending || nullsLast ? slonik_1.sql.fragment `${expression} IS NULL` : slonik_1.sql.fragment `${expression} IS NOT NULL`; isNull = ascending || nullsLast; } } else if (value === null) { nullFragment = ascending !== nullsLast ? slonik_1.sql.fragment `${expression} IS NOT NULL` : slonik_1.sql.fragment `${expression} IS NULL`; isNull = ascending === nullsLast; } return value !== null && value !== undefined ? isNullable && isNull ? slonik_1.sql.fragment `(${expression} ${operator} ${value} OR ${nullFragment})` : slonik_1.sql.fragment `${expression} ${operator} ${value}` : nullFragment; }), slonik_1.sql.fragment ` AND `)})`; }), slonik_1.sql.fragment ` OR `)})`); } const groupExpression = (queryComponents.groupBy) ? [ ...(typeof queryComponents.groupBy === 'function' ? [queryComponents.groupBy(allArgs)] : []), ...(((_0 = queryComponents.groupBy) === null || _0 === void 0 ? void 0 : _0.sql) ? [queryComponents.groupBy] : []), lateralExpressions[0] ? slonik_1.sql.fragment `lateralcolumns.cursorjson` : null ].filter(zod_2.notEmpty) : []; const extraSelectFields = extraSelects.length ? slonik_1.sql.fragment `, ${slonik_1.sql.join(extraSelects, slonik_1.sql.fragment `, `)}` : slonik_1.sql.fragment ``; const realFromFragment = view ? view.getFromFragment(context) : fromFragment; const baseQuery = slonik_1.sql.type(zodType) `${actualQuery} ${extraSelectFields} ${realFromFragment !== null && realFromFragment !== void 0 ? realFromFragment : slonik_1.sql.fragment ``} ${lateralExpressions[0] ? slonik_1.sql.fragment `, LATERAL (SELECT ${slonik_1.sql.join(lateralExpressions, slonik_1.sql.fragment `, `)}) lateralcolumns` : slonik_1.sql.fragment ``} ${conditions.length ? slonik_1.sql.fragment `WHERE (${slonik_1.sql.join(conditions, slonik_1.sql.fragment `)\n AND (`)})` : slonik_1.sql.fragment ``} ${(groupExpression === null || groupExpression === void 0 ? void 0 : groupExpression.length) ? slonik_1.sql.fragment `GROUP BY ${slonik_1.sql.join(groupExpression, slonik_1.sql.fragment `, `)}` : slonik_1.sql.fragment ``} ${orderExpressions ? slonik_1.sql.fragment `ORDER BY ${slonik_1.sql.join(orderExpressions.map(parsed => interpretOrderBy(orderByType.parse(parsed), reverse)), slonik_1.sql.fragment `, `)}` : slonik_1.sql.fragment ``} ${typeof take === 'number' ? slonik_1.sql.fragment `LIMIT ${take}` : slonik_1.sql.fragment ``} ${typeof skip === 'number' ? slonik_1.sql.fragment `OFFSET ${skip}` : slonik_1.sql.fragment ``} `; if (!(select === null || select === void 0 ? void 0 : select.length) && !(selectGroups === null || selectGroups === void 0 ? void 0 : selectGroups.length) && !fields.length) { finalKeys.push(slonik_1.sql.fragment `*`); } else if (takeCursors && (lateralExpressions === null || lateralExpressions === void 0 ? void 0 : lateralExpressions.length)) { finalKeys.push(slonik_1.sql.identifier(["root_query", cursorColumns])); } // Run another root query, that only selects the column names that aren't excluded, or only ones that are included. const finalQuery = slonik_1.sql.type(zodType) `WITH root_query AS (${baseQuery}) SELECT ${slonik_1.sql.join(finalKeys, slonik_1.sql.fragment `, `)} FROM root_query`; for (const plugin of (options.plugins || [])) { if (plugin.onGetQuery) { plugin.onGetQuery({ args: Object.assign(Object.assign({}, allArgs), { take, select }), query: finalQuery, }); } } return finalQuery; }); const getSelectableFields = () => { var _a, _b; const selectable = options === null || options === void 0 ? void 0 : options.selectableColumns; const columns = Object.keys((options === null || options === void 0 ? void 0 : options.virtualFields) || {}).concat(Object.keys(((_b = (_a = type === null || type === void 0 ? void 0 : type.keyof) === null || _a === void 0 ? void 0 : _a.call(type)) === null || _b === void 0 ? void 0 : _b.Values) || {})); if (selectable === null || selectable === void 0 ? void 0 : selectable.length) { return columns.filter(column => selectable.indexOf(column) >= 0); } return columns; }; const getLoadArgs = ({ sortableColumns = Object.keys((options === null || options === void 0 ? void 0 : options.sortableColumns) || {}), selectableColumns = options === null || options === void 0 ? void 0 : options.selectableColumns, disabledFilters, transformSortColumns, } = {}) => { var _a, _b, _c; const sortFields = (sortableColumns === null || sortableColumns === void 0 ? void 0 : sortableColumns.length) ? zod_1.z.enum(sortableColumns) : // If unspecified, no field is allowed to be used for sorting zod_1.z.never(); const orderTuple = zod_1.z.tuple([sortFields, orderDirection]); const selectColumns = (selectableColumns || options.selectableColumns); const fields = (selectColumns === null || selectColumns === void 0 ? void 0 : selectColumns.length) ? zod_1.z.enum(selectColumns) : // If unspecified, any field is allowed to be selected zod_1.z.string(); const groups = Object.keys(options.columnGroups || {}); const groupsEnum = groups.length ? zod_1.z.enum(groups) : zod_1.z.never(); const orderUnion = zod_1.z.union([zod_1.z.array(orderTuple), orderTuple]).nullish(); const orderBy = zod_1.z.preprocess((typeof transformSortColumns === 'function' ? (columns => { if (Array.isArray(columns)) { if (Array.isArray(columns[0]) || columns[0] === undefined) { return transformSortColumns(columns) || columns; } else { return transformSortColumns([columns].filter(zod_2.notEmpty)) || columns; } } }) : (a) => (Array.isArray(a) && (Array.isArray(a[0]) || a[0] === undefined) ? a : [a].filter(zod_2.notEmpty))), orderUnion); const filterKeys = Object.keys(((_a = options.query.view) === null || _a === void 0 ? void 0 : _a.getFilters()) || {}) .concat(Object.keys(((_b = options === null || options === void 0 ? void 0 : options.filters) === null || _b === void 0 ? void 0 : _b.filters) || {})); const hasFilters = !!filterKeys.length; const filterType = zod_1.z.lazy(() => { var _a; return zod_1.z.object(Object.assign(Object.assign(Object.assign(Object.assign({}, (filterKeys.reduce((acc, key) => { var _a, _b; acc[key] = ((_b = (_a = options === null || options === void 0 ? void 0 : options.filters) === null || _a === void 0 ? void 0 : _a.filters) === null || _b === void 0 ? void 0 : _b[key]) || zod_1.z.any(); return acc; }, {}))), (hasFilters && !(disabledFilters === null || disabledFilters === void 0 ? void 0 : disabledFilters.OR) && ((_a = options === null || options === void 0 ? void 0 : options.options) === null || _a === void 0 ? void 0 : _a.orFilterEnabled) && { OR: zod_1.z.array(filterType) })), (hasFilters && !(disabledFilters === null || disabledFilters === void 0 ? void 0 : disabledFilters.AND) && { AND: zod_1.z.array(filterType) })), (hasFilters && !(disabledFilters === null || disabledFilters === void 0 ? void 0 : disabledFilters.NOT) && { NOT: filterType }))).partial(); }).nullish(); return zod_1.z.object({ /** The fields that should be included. If unspecified, all fields are returned. */ select: zod_1.z.array(fields).optional(), take: zod_1.z.number().optional(), skip: zod_1.z.number().optional().default(0), takeCount: zod_1.z.boolean().optional(), takeCursors: zod_1.z.boolean().optional(), cursor: zod_1.z.string().optional(), takeNextPages: zod_1.z.number().optional(), selectGroups: zod_1.z.array(groupsEnum).optional(), searchAfter: sortableColumns.length ? zod_1.z.object(sortableColumns.reduce((acc, column) => { acc[column] = zod_1.z.any(); return acc; }, {})).partial().optional() : zod_1.z.null(), orderBy: ((_c = options === null || options === void 0 ? void 0 : options.defaults) === null || _c === void 0 ? void 0 : _c.orderBy) ? orderBy.default(options.defaults.orderBy) : orderBy, where: filterType, }).partial(); }; const self = { _columnGroups: options.columnGroups, getSelectableFields, getLoadArgs, getQuery, // By default, select all fields (string covers all), and don't exclude any fields load(args, database) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { if ((_a = args.selectGroups) === null || _a === void 0 ? void 0 : _a.length) { const groupFields = args.selectGroups.flatMap(group => { var _a; return ((_a = options.columnGroups) === null || _a === void 0 ? void 0 : _a[group]) || []; }); args.select = (args.select || []).concat(...groupFields); } if (typeof options.contextFactory === 'function') { args.ctx = options.contextFactory(args.ctx); } const db = database || (options === null || options === void 0 ? void 0 : options.db); const reverse = !!args.take && args.take < 0; if (!(db === null || db === void 0 ? void 0 : db.any)) throw new Error("Database not provided"); const finalQuery = yield getQuery(Object.assign(Object.assign({}, args), { take: typeof args.take === 'number' ? args.take : ((_b = options === null || options === void 0 ? void 0 : options.defaults) === null || _b === void 0 ? void 0 : _b.take), takeCursors: false })); let result = null; const onLoadOptions = { args, query: finalQuery, setResultAndStopExecution(newResult) { result = newResult; }, }; const afterCalls = []; for (const plugin of options.plugins || []) { if (plugin.onLoad) { const done = plugin.onLoad(onLoadOptions); if (done === null || done === void 0 ? void 0 : done.onLoadDone) { afterCalls.push(done.onLoadDone); } if (result) break; } } const load = () => db.any(finalQuery).then((rows) => __awaiter(this, void 0, void 0, function* () { return mapTransformRows(reverse ? rows.reverse() : rows, args); })).then((rows) => __awaiter(this, void 0, void 0, function* () { // Call the onLoadDone method of each plugin for (const onLoadDone of afterCalls) { onLoadDone({ result: rows, setResult: (newResult) => { result = newResult; }, }); } if (result) return result; return rows; })); if (result) return result; return load(); }); }, /** * Returns the data in a pagination-convenient form. * Specify takeCount: true to query the overall count as if no limit had been specified. * Otherwise, count will be null. * `take` is limited to 1000 items when using loadPagination, as it's meant to be used for loading only a few pages at a time. * */ loadPagination(args, database) { var _a, _b, _c, _d, _e, _f; return __awaiter(this, void 0, void 0, function* () { if ((_a = args.selectGroups) === null || _a === void 0 ? void 0 : _a.length) { const groupFields = args.selectGroups.flatMap(group => { var _a; return ((_a = options.columnGroups) === null || _a === void 0 ? void 0 : _a[group]) || []; }); args.select = (args.select || []).concat(...groupFields); } if (typeof options.contextFactory === 'function') { args.ctx = options.contextFactory(args.ctx); } if (typeof args.take !== 'number' && ((_b = options === null || options === void 0 ? void 0 : options.defaults) === null || _b === void 0 ? void 0 : _b.take)) { args.take = options.defaults.take; } const allArgs = args; const db = database || (options === null || options === void 0 ? void 0 : options.db); if (!(db === null || db === void 0 ? void 0 : db.any)) throw new Error("Database not provided"); const reverse = !!args.take && args.take < 0 ? -1 : 1; const take = (typeof args.take === 'number' && args.take < 0) ? -args.take : args.take; if (reverse === -1 && !((_c = allArgs.orderBy) === null || _c === void 0 ? void 0 : _c.length) && !((_e = (_d = options === null || options === void 0 ? void 0 : options.defaults) === null || _d === void 0 ? void 0 : _d.orderBy) === null || _e === void 0 ? void 0 : _e.length)) { throw new Error("orderBy must be specified when take parameter is negative!"); } const extraItems = Math.max(Math.min(3, ((args === null || args === void 0 ? void 0 : args.takeNextPages) || 0) - 1), 0) * (take !== null && take !== void 0 ? take : 25) + 1; const finalQuery = yield getQuery(Object.assign(Object.assign({}, args), { take: // Query an extra row to see if the next page exists (Math.min(Math.max(0, take !== null && take !== void 0 ? take : 100), (((_f = options.options) === null || _f === void 0 ? void 0 : _f.maxLimit) || 1000)) + extraItems) * reverse })); const countQuery = args.takeCount ? slonik_1.sql.type(countQueryType) `SELECT COUNT(*) FROM (${yield getQuery(Object.assign(Object.assign({}, args), { skip: undefined, searchAfter: undefined, cursor: undefined, takeCursors: false, take: undefined }))}) allrows` : null; // Count is null by default let countPromise = Promise.resolve(null); let countSet = false; let result = null; const afterCalls = []; for (const plugin of options.plugins || []) { if (plugin.onLoadPagination) { const done = plugin.onLoadPagination({ args, query: finalQuery, countQuery, setCount(newCount) { countPromise = Promise.resolve(newCount); countSet = true; }, setResultAndStopExecution(newResult) { result = newResult; }, }); if (done === null || done === void 0 ? void 0 : done.onLoadDone) { afterCalls.push(done.onLoadDone); } if (result) break; } } const load = () => db .any(finalQuery) .then((nodes) => __awaiter(this, void 0, void 0, function* () { var _g, _h; const slicedNodes = nodes.slice(0, take !== null && take !== void 0 ? take : undefined); const rows = reverse === -1 ? slicedNodes.reverse() : slicedNodes; const cursors = allArgs.takeCursors && { startCursor: (0, cursors_1.toCursor)((_g = rows[0]) === null || _g === void 0 ? void 0 : _g[cursorColumns]), endCursor: (0, cursors_1.toCursor)((_h = rows[rows.length - 1]) === null || _h === void 0 ? void 0 : _h[cursorColumns]), cursors: rows.map((row) => { if (row[cursorColumns]) { const cursorcolumns = row[cursorColumns]; delete row[cursorColumns]; return (0, cursors_1.toCursor)(cursorcolumns); } }), }; const hasMore = nodes.length > slicedNodes.length; const hasPrevious = !!args.skip || (!!allArgs.cursor || !!allArgs.searchAfter); const allRows = yield mapTransformRows(rows, Object.assign(Object.assign({}, args.ctx), args)); return Object.assign(Object.assign({ nodes: allRows }, (cursors && { cursors: cursors.cursors })), { pageInfo: Object.assign(Object.assign({ hasPreviousPage: reverse === -1 ? hasMore : hasPrevious, hasNextPage: reverse === -1 ? hasPrevious : hasMore, minimumCount: (args.skip || 0) + nodes.length }, (cursors && { startCursor: cursors.startCursor, endCursor: cursors.endCursor, })), { count: yield countPromise }) }); })).then((rows) => { // Call the onLoadDone method of each plugin for (const onLoadDone of afterCalls) { onLoadDone({ result: rows, setResult: (newResult) => { result = newResult; }, }); } if (result) return result; return rows; }); if (result) return result; if (args.takeCount && !countSet) { countPromise = db .any(countQuery) .then((res) => { var _a; return (_a = res === null || res === void 0 ? void 0 : res[0]) === null || _a === void 0 ? void 0 : _a.count; }); } return load(); }); }, }; return self; } exports.makeQueryLoader = makeQueryLoader;