UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

1,252 lines (1,251 loc) 41.4 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const dbIvm = require("@tanstack/db-ivm"); const optimizer = require("../optimizer.cjs"); const errors = require("../../errors.cjs"); const virtualProps = require("../../virtual-props.cjs"); const ir = require("../ir.cjs"); const autoIndex = require("../../indexes/auto-index.cjs"); const functions = require("../builder/functions.cjs"); const evaluators = require("./evaluators.cjs"); const joins = require("./joins.cjs"); const groupBy = require("./group-by.cjs"); const lazyTargets = require("./lazy-targets.cjs"); const orderBy = require("./order-by.cjs"); const select = require("./select.cjs"); const INCLUDES_ROUTING = /* @__PURE__ */ Symbol(`includesRouting`); const FN_SELECT_STATE = /* @__PURE__ */ Symbol(`fnSelectState`); const SKIP_INCLUDE = /* @__PURE__ */ Symbol(`skipInclude`); function compileQuery(rawQuery, inputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache = /* @__PURE__ */ new WeakMap(), queryMapping = /* @__PURE__ */ new WeakMap(), parentKeyStream, childCorrelationField) { const cachedResult = cache.get(rawQuery); if (cachedResult) { return cachedResult; } validateQueryStructure(rawQuery); const { optimizedQuery, sourceWhereClauses } = optimizer.optimizeQuery(rawQuery); let query = optimizedQuery; queryMapping.set(query, rawQuery); mapNestedQueries(query, rawQuery, queryMapping); const allInputs = { ...inputs }; const aliasToCollectionId = {}; const aliasRemapping = {}; const sources = {}; const { alias: mainSource, collectionId: mainCollectionId, pipeline: initialPipeline, sources: fromSources, sourceIncludes, directIncludes, isUnionFrom } = processFromClause( query.from, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping, aliasToCollectionId, aliasRemapping, sourceWhereClauses ); Object.assign(sources, fromSources); let pipeline = initialPipeline; if (!isUnionFrom && parentKeyStream && childCorrelationField) { const mainInput = sources[mainSource]; let filteredMainInput = mainInput; const childFieldPath = childCorrelationField.path.slice(1); const childRekeyed = mainInput.pipe( dbIvm.map(([key, row]) => { const correlationValue = getNestedValue(row, childFieldPath); return [correlationValue, [key, row]]; }) ); const joined = childRekeyed.pipe(dbIvm.join(parentKeyStream, `inner`)); filteredMainInput = joined.pipe( dbIvm.filter(([_correlationValue, [childSide]]) => { return childSide != null; }), dbIvm.map(([correlationValue, [childSide, parentSide]]) => { const [childKey, childRow] = childSide; const tagged = { ...childRow, __correlationKey: correlationValue }; if (parentSide != null) { tagged.__parentContext = parentSide; } const effectiveKey = parentSide != null ? `${String(childKey)}::${JSON.stringify(parentSide)}` : childKey; return [effectiveKey, tagged]; }) ); sources[mainSource] = filteredMainInput; pipeline = wrapInputWithAlias(filteredMainInput, mainSource); } if (query.join && query.join.length > 0) { pipeline = joins.processJoins( pipeline, query.join, sources, mainCollectionId, mainSource, allInputs, cache, queryMapping, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, rawQuery, compileQuery, aliasToCollectionId, aliasRemapping, sourceWhereClauses ); } if (query.where && query.where.length > 0) { for (const where of query.where) { const whereExpression = ir.getWhereExpression(where); const compiledWhere = evaluators.compileExpression(whereExpression); pipeline = pipeline.pipe( dbIvm.filter(([_key, namespacedRow]) => { return evaluators.toBooleanPredicate(compiledWhere(namespacedRow)); }) ); } } if (query.fnWhere && query.fnWhere.length > 0) { for (const fnWhere of query.fnWhere) { pipeline = pipeline.pipe( dbIvm.filter(([_key, namespacedRow]) => { return evaluators.toBooleanPredicate(fnWhere(namespacedRow)); }) ); } } const includesResults = !query.select ? [...directIncludes] : []; const includesRoutingFns = []; for (const { sourceAlias, include } of sourceIncludes) { const projectedPaths = query.select != null ? findProjectedSourceIncludePaths( query.select, sourceAlias, include.resultPath ) : query.fnSelect ? [] : [ { path: [sourceAlias, ...include.resultPath], guards: [] } ]; if (projectedPaths.length === 0) { continue; } for (const { path: resultPath, guards } of projectedPaths) { const fieldName = getUniqueIncludesRoutingKey( `${sourceAlias}.${resultPath.join(`.`)}`, includesRoutingFns ); const compiledGuards = guards.map((guard) => ({ condition: evaluators.compileExpression(guard.condition), expected: guard.expected })); includesResults.push({ ...include, fieldName, resultPath }); includesRoutingFns.push({ fieldName, getRouting: (nsRow) => { if (!matchesConditionalSelectGuards(compiledGuards, nsRow)) { return { correlationKey: null, parentContext: null }; } return nsRow[sourceAlias]?.[INCLUDES_ROUTING]?.[include.fieldName] ?? { correlationKey: null, parentContext: null }; } }); } } if (query.select && directIncludes.length > 0) { for (const include of directIncludes) { const projectedPaths = findProjectedResultIncludePaths( query.select, include.resultPath ); for (const { path: resultPath, guards } of projectedPaths) { const fieldName = getUniqueIncludesRoutingKey( resultPath.join(`.`), includesRoutingFns ); const compiledGuards = guards.map((guard) => ({ condition: evaluators.compileExpression(guard.condition), expected: guard.expected })); includesResults.push({ ...include, fieldName, resultPath }); includesRoutingFns.push({ fieldName, getRouting: (nsRow) => { if (!matchesConditionalSelectGuards(compiledGuards, nsRow)) { return { correlationKey: null, parentContext: null }; } return nsRow[INCLUDES_ROUTING]?.[include.fieldName] ?? { correlationKey: null, parentContext: null }; } }); } } } if (query.select) { const includesEntries = extractIncludesFromSelect(query.select); if (includesEntries.length > 0) { query = { ...query, select: { ...query.select } }; } for (const { key, path, subquery, guards } of includesEntries) { const fieldName = getUniqueIncludesRoutingKey(key, includesRoutingFns); const compiledCorrelation = evaluators.compileExpression(subquery.correlationField); const compiledGuards = guards.map((guard) => ({ condition: evaluators.compileExpression(guard.condition), expected: guard.expected })); let parentKeys; if (subquery.parentProjection && subquery.parentProjection.length > 0) { const compiledProjections = subquery.parentProjection.map((ref) => ({ alias: ref.path[0], field: ref.path.slice(1), compiled: evaluators.compileExpression(ref) })); parentKeys = pipeline.pipe( dbIvm.map(([_key, nsRow]) => { if (!matchesConditionalSelectGuards(compiledGuards, nsRow)) { return [SKIP_INCLUDE, null]; } const parentContext = {}; for (const proj of compiledProjections) { if (!parentContext[proj.alias]) { parentContext[proj.alias] = {}; } const value = proj.compiled(nsRow); let target = parentContext[proj.alias]; for (let i = 0; i < proj.field.length - 1; i++) { if (!target[proj.field[i]]) { target[proj.field[i]] = {}; } target = target[proj.field[i]]; } target[proj.field[proj.field.length - 1]] = value; } return [compiledCorrelation(nsRow), parentContext]; }) ); } else { parentKeys = pipeline.pipe( dbIvm.map(([_key, nsRow]) => { if (!matchesConditionalSelectGuards(compiledGuards, nsRow)) { return [SKIP_INCLUDE, null]; } return [compiledCorrelation(nsRow), null]; }) ); } parentKeys = parentKeys.pipe( dbIvm.filter(([correlationValue]) => correlationValue !== SKIP_INCLUDE) ); parentKeys = parentKeys.pipe( dbIvm.reduce( (values) => values.map(([v, mult]) => [v, mult > 0 ? 1 : 0]) ) ); const childCorrelationAlias = subquery.childCorrelationField.path[0]; const directChildCollection = subquery.query.from.type === `collectionRef` ? subquery.query.from.collection : void 0; const lazyTargets$1 = lazyTargets.getLazyLoadTargets( subquery.query, subquery.query.from, childCorrelationAlias, subquery.childCorrelationField, directChildCollection, aliasRemapping ); if (lazyTargets$1.length > 0) { for (const target of lazyTargets$1) { lazySources.add(target.alias); } for (const target of lazyTargets$1) { const targetFieldName = target.path[0]; if (targetFieldName) { autoIndex.ensureIndexForField(targetFieldName, target.path, target.collection); } } parentKeys = parentKeys.pipe( dbIvm.tap((data) => { const joinKeys = [ ...new Set( data.getInner().map( ([[correlationValue]]) => correlationValue ).filter((joinKey) => joinKey != null) ) ]; if (joinKeys.length === 0) { return; } for (const target of lazyTargets$1) { const lazySourceSubscription = subscriptions[target.alias]; if (!lazySourceSubscription) { continue; } if (lazySourceSubscription.hasLoadedInitialState()) { continue; } const lazyJoinRef = new ir.PropRef(target.path); lazySourceSubscription.requestSnapshot({ where: functions.inArray(lazyJoinRef, joinKeys) }); } }) ); } const childQuery = subquery.parentFilters && subquery.parentFilters.length > 0 ? { ...subquery.query, where: [ ...subquery.query.where || [], ...subquery.parentFilters ] } : subquery.query; const childResult = compileQuery( childQuery, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping, parentKeys, subquery.childCorrelationField ); Object.assign(aliasToCollectionId, childResult.aliasToCollectionId); Object.assign(aliasRemapping, childResult.aliasRemapping); for (const [alias, whereClause] of childResult.sourceWhereClauses) { sourceWhereClauses.set(alias, whereClause); } includesResults.push({ pipeline: childResult.pipeline, fieldName, resultPath: path, correlationField: subquery.correlationField, childCorrelationField: subquery.childCorrelationField, hasOrderBy: !!(subquery.query.orderBy && subquery.query.orderBy.length > 0), childCompilationResult: childResult, parentProjection: subquery.parentProjection, materialization: subquery.materialization, scalarField: subquery.scalarField }); if (subquery.parentProjection && subquery.parentProjection.length > 0) { const compiledProjs = subquery.parentProjection.map((ref) => ({ alias: ref.path[0], field: ref.path.slice(1), compiled: evaluators.compileExpression(ref) })); const compiledCorr = compiledCorrelation; const compiledRoutingGuards = compiledGuards; includesRoutingFns.push({ fieldName, getRouting: (nsRow) => { if (!matchesConditionalSelectGuards(compiledRoutingGuards, nsRow)) { return { correlationKey: null, parentContext: null }; } const parentContext = {}; for (const proj of compiledProjs) { if (!parentContext[proj.alias]) { parentContext[proj.alias] = {}; } const value = proj.compiled(nsRow); let target = parentContext[proj.alias]; for (let i = 0; i < proj.field.length - 1; i++) { if (!target[proj.field[i]]) { target[proj.field[i]] = {}; } target = target[proj.field[i]]; } target[proj.field[proj.field.length - 1]] = value; } return { correlationKey: compiledCorr(nsRow), parentContext }; } }); } else { const compiledRoutingGuards = compiledGuards; includesRoutingFns.push({ fieldName, getRouting: (nsRow) => { if (!matchesConditionalSelectGuards(compiledRoutingGuards, nsRow)) { return { correlationKey: null, parentContext: null }; } return { correlationKey: compiledCorrelation(nsRow), parentContext: null }; } }); } query = { ...query, select: replaceIncludesInSelect(query.select, path) }; } } if (query.distinct && !query.fnSelect && !query.select && query.from.type !== `unionAll`) { throw new errors.DistinctRequiresSelectError(); } if (query.fnSelect && query.groupBy && query.groupBy.length > 0) { throw new errors.FnSelectWithGroupByError(); } if (query.fnSelect) { pipeline = pipeline.pipe( dbIvm.map(([key, namespacedRow]) => { const selectResults = query.fnSelect(namespacedRow); if (selectResults && typeof selectResults === `object`) { const routing = namespacedRow[INCLUDES_ROUTING]; if (routing) { selectResults[INCLUDES_ROUTING] = routing; } if (directIncludes.length > 0) { Object.defineProperty(selectResults, FN_SELECT_STATE, { value: { sourceRow: namespacedRow, fnSelect: query.fnSelect }, enumerable: true, configurable: true }); } } return [ key, { ...namespacedRow, $selected: selectResults } ]; }) ); } else if (query.select) { pipeline = select.processSelect(pipeline, query.select); } else { pipeline = pipeline.pipe( dbIvm.map(([key, namespacedRow]) => { const selectResults = !isUnionFrom && !query.join && !query.groupBy ? namespacedRow[mainSource] : namespacedRow; return [ key, { ...namespacedRow, $selected: selectResults } ]; }) ); } if (includesRoutingFns.length > 0) { pipeline = pipeline.pipe( dbIvm.map(([key, namespacedRow]) => { const routing = {}; for (const { fieldName, getRouting } of includesRoutingFns) { routing[fieldName] = getRouting(namespacedRow); } namespacedRow.$selected[INCLUDES_ROUTING] = routing; return [key, namespacedRow]; }) ); } const groupByMainSource = parentKeyStream ? mainSource : void 0; if (query.groupBy && query.groupBy.length > 0) { pipeline = groupBy.processGroupBy( pipeline, query.groupBy, query.having, query.select, query.fnHaving, mainCollectionId, groupByMainSource ); } else if (query.select) { const hasAggregates = Object.values(query.select).some( (expr) => expr.type === `agg` || groupBy.containsAggregate(expr) ); if (hasAggregates) { pipeline = groupBy.processGroupBy( pipeline, [], // Empty group by means single group query.having, query.select, query.fnHaving, mainCollectionId, groupByMainSource ); } } if (query.having && (!query.groupBy || query.groupBy.length === 0)) { const hasAggregates = query.select ? Object.values(query.select).some((expr) => expr.type === `agg`) : false; if (!hasAggregates) { throw new errors.HavingRequiresGroupByError(); } } if (query.fnHaving && query.fnHaving.length > 0 && (!query.groupBy || query.groupBy.length === 0)) { for (const fnHaving of query.fnHaving) { pipeline = pipeline.pipe( dbIvm.filter(([_key, namespacedRow]) => { return fnHaving(namespacedRow); }) ); } } if (query.distinct) { pipeline = pipeline.pipe(dbIvm.distinct(([_key, row]) => row.$selected)); } if (query.orderBy && query.orderBy.length > 0) { const includesGroupKeyFn = parentKeyStream && (query.limit !== void 0 || query.offset !== void 0) ? (_key, row) => { const correlationKey = row?.[mainSource]?.__correlationKey; const parentContext = row?.__parentContext; if (parentContext != null) { return JSON.stringify([correlationKey, parentContext]); } return correlationKey; } : void 0; const orderedPipeline = orderBy.processOrderBy( rawQuery, pipeline, query.orderBy, query.select || {}, collections[mainCollectionId], optimizableOrderByCollections, setWindowFn, query.limit, query.offset, includesGroupKeyFn ); const resultPipeline2 = orderedPipeline.pipe( dbIvm.map(([key, [row, orderByIndex]]) => { const raw = row.$selected; const finalResults = attachVirtualPropsToSelected( unwrapValue(raw), row ); if (parentKeyStream) { const correlationKey = row[mainSource]?.__correlationKey; const parentContext = row.__parentContext ?? null; delete finalResults.__correlationKey; delete finalResults.__parentContext; return [ key, [finalResults, orderByIndex, correlationKey, parentContext] ]; } return [key, [finalResults, orderByIndex]]; }) ); const result2 = resultPipeline2; const compilationResult2 = { collectionId: mainCollectionId, pipeline: result2, sourceWhereClauses, aliasToCollectionId, aliasRemapping, includes: includesResults.length > 0 ? includesResults : void 0 }; cache.set(rawQuery, compilationResult2); return compilationResult2; } else if (query.limit !== void 0 || query.offset !== void 0) { throw new errors.LimitOffsetRequireOrderByError(); } const resultPipeline = pipeline.pipe( dbIvm.map(([key, row]) => { const raw = row.$selected; const finalResults = attachVirtualPropsToSelected( unwrapValue(raw), row ); if (parentKeyStream) { const correlationKey = row[mainSource]?.__correlationKey; const parentContext = row.__parentContext ?? null; delete finalResults.__correlationKey; delete finalResults.__parentContext; return [ key, [finalResults, void 0, correlationKey, parentContext] ]; } return [key, [finalResults, void 0]]; }) ); const result = resultPipeline; const compilationResult = { collectionId: mainCollectionId, pipeline: result, sourceWhereClauses, aliasToCollectionId, aliasRemapping, includes: includesResults.length > 0 ? includesResults : void 0 }; cache.set(rawQuery, compilationResult); return compilationResult; } function collectDirectCollectionAliases(query) { const aliases = /* @__PURE__ */ new Set(); for (const source of getFromSources(query.from)) { if (source.type === `collectionRef`) { aliases.add(source.alias); } } if (query.join) { for (const joinClause of query.join) { if (joinClause.from.type === `collectionRef`) { aliases.add(joinClause.from.alias); } } } return aliases; } function validateQueryStructure(query, parentCollectionAliases = /* @__PURE__ */ new Set()) { const currentLevelAliases = collectDirectCollectionAliases(query); for (const alias of currentLevelAliases) { if (parentCollectionAliases.has(alias)) { throw new errors.DuplicateAliasInSubqueryError( alias, Array.from(parentCollectionAliases) ); } } const combinedAliases = /* @__PURE__ */ new Set([ ...parentCollectionAliases, ...currentLevelAliases ]); if (query.from.type === `unionAll`) { for (const branch of query.from.queries) { validateQueryStructure(branch, combinedAliases); } } else { for (const source of getFromSources(query.from)) { if (source.type === `queryRef`) { validateQueryStructure(source.query, combinedAliases); } } } if (query.join) { for (const joinClause of query.join) { if (joinClause.from.type === `queryRef`) { validateQueryStructure(joinClause.from.query, combinedAliases); } } } } function processFromClause(from, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping, aliasToCollectionId, aliasRemapping, sourceWhereClauses) { if (from.type === `unionAll`) { return processUnionAll( from, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping, aliasToCollectionId, aliasRemapping, sourceWhereClauses ); } if (from.type !== `unionFrom`) { const { alias, input, collectionId, sourceIncludes: sourceIncludes2 } = processFrom( from, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping, aliasToCollectionId, aliasRemapping, sourceWhereClauses ); return { alias, pipeline: wrapInputWithAlias(input, alias), collectionId, sources: { [alias]: input }, sourceIncludes: sourceIncludes2, directIncludes: [], isUnionFrom: false }; } if (from.sources.length === 0) { throw new errors.UnsupportedFromTypeError(`empty unionFrom`); } const sources = {}; const sourceIncludes = []; let pipeline; let mainAlias = ``; let mainCollectionId = ``; for (const source of from.sources) { const { alias, input, collectionId, sourceIncludes: childSourceIncludes } = processFrom( source, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping, aliasToCollectionId, aliasRemapping, sourceWhereClauses ); if (!mainAlias) { mainAlias = alias; mainCollectionId = collectionId; } sources[alias] = input; sourceIncludes.push(...childSourceIncludes); const branch = wrapInputWithAlias(input, alias).pipe( dbIvm.map(([key, row]) => { return [`${alias}:${encodeKeyForUnionBranch(key)}`, row]; }) ); pipeline = pipeline ? pipeline.pipe(dbIvm.concat(branch)) : branch; } return { alias: mainAlias, pipeline, collectionId: mainCollectionId, sources, sourceIncludes, directIncludes: [], isUnionFrom: true }; } function processUnionAll(from, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping, aliasToCollectionId, aliasRemapping, sourceWhereClauses) { if (from.queries.length === 0) { throw new errors.UnsupportedFromTypeError(`empty unionAll`); } const sources = {}; const sourceIncludes = []; const directIncludes = []; let pipeline; let mainCollectionId = ``; const branchAliases = /* @__PURE__ */ new Set(); for (let index = 0; index < from.queries.length; index++) { const branch = from.queries[index]; for (const source of getAllSources(branch)) { if (branchAliases.has(source.alias)) { throw new Error( `Duplicate source alias "${source.alias}" in unionAll query branches. Use distinct aliases in each branch before passing them to unionAll().` ); } branchAliases.add(source.alias); } const branchResult = compileQuery( branch, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping ); if (!mainCollectionId) { mainCollectionId = branchResult.collectionId; } Object.assign(aliasToCollectionId, branchResult.aliasToCollectionId); Object.assign(aliasRemapping, branchResult.aliasRemapping); directIncludes.push(...branchResult.includes ?? []); Object.assign(sources, allInputs); for (const [alias, where] of branchResult.sourceWhereClauses) { sourceWhereClauses.set(alias, where); } const branchPipeline = branchResult.pipeline.pipe( dbIvm.map(([key, [row]]) => { return [`${index}:${encodeKeyForUnionBranch(key)}`, row]; }) ); pipeline = pipeline ? pipeline.pipe(dbIvm.concat(branchPipeline)) : branchPipeline; } return { alias: ``, pipeline, collectionId: mainCollectionId, sources, sourceIncludes, directIncludes, isUnionFrom: true }; } function wrapInputWithAlias(input, alias) { return input.pipe( dbIvm.map(([key, row]) => { const { __parentContext, ...cleanRow } = row; const nsRow = { [alias]: cleanRow }; if (__parentContext) { Object.assign(nsRow, __parentContext); nsRow.__parentContext = __parentContext; } return [key, nsRow]; }) ); } function encodeKeyForUnionBranch(key) { if (typeof key === `string`) { return `string:${key}`; } if (typeof key === `number`) { return `number:${String(key)}`; } if (typeof key === `bigint`) { return `bigint:${String(key)}`; } return `${typeof key}:${JSON.stringify(key)}`; } function processFrom(from, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping, aliasToCollectionId, aliasRemapping, sourceWhereClauses) { switch (from.type) { case `collectionRef`: { const input = allInputs[from.alias]; if (!input) { throw new errors.CollectionInputNotFoundError( from.alias, from.collection.id, Object.keys(allInputs) ); } aliasToCollectionId[from.alias] = from.collection.id; return { alias: from.alias, input, collectionId: from.collection.id, sourceIncludes: [] }; } case `queryRef`: { const originalQuery = queryMapping.get(from.query) || from.query; const subQueryResult = compileQuery( originalQuery, allInputs, collections, subscriptions, callbacks, lazySources, optimizableOrderByCollections, setWindowFn, cache, queryMapping ); Object.assign(aliasToCollectionId, subQueryResult.aliasToCollectionId); Object.assign(aliasRemapping, subQueryResult.aliasRemapping); const isUserDefinedSubquery = queryMapping.has(from.query); const subqueryFromAlias = getFirstFromAlias(from.query.from); const isOptimizerCreated = !isUserDefinedSubquery && from.alias === subqueryFromAlias; if (!isOptimizerCreated) { for (const [alias, whereClause] of subQueryResult.sourceWhereClauses) { sourceWhereClauses.set(alias, whereClause); } } const innerAlias = Object.keys(subQueryResult.aliasToCollectionId).find( (alias) => subQueryResult.aliasToCollectionId[alias] === subQueryResult.collectionId ); if (innerAlias && innerAlias !== from.alias) { aliasRemapping[from.alias] = innerAlias; } const subQueryInput = subQueryResult.pipeline; const extractedInput = subQueryInput.pipe( dbIvm.map((data) => { const [key, [value, _orderByIndex]] = data; const unwrapped = unwrapValue(value); return [key, unwrapped]; }) ); return { alias: from.alias, input: extractedInput, collectionId: subQueryResult.collectionId, sourceIncludes: subQueryResult.includes?.map((include) => ({ sourceAlias: from.alias, include })) ?? [] }; } default: throw new errors.UnsupportedFromTypeError(from.type); } } function isValue(raw) { return raw instanceof ir.Value || raw && typeof raw === `object` && `type` in raw && raw.type === `val`; } function unwrapValue(value) { return isValue(value) ? value.value : value; } function attachVirtualPropsToSelected(selected, row) { if (!selected || typeof selected !== `object`) { return selected; } let needsMerge = false; for (const prop of virtualProps.VIRTUAL_PROP_NAMES) { if (selected[prop] == null && prop in row) { needsMerge = true; break; } } if (!needsMerge) { return selected; } for (const prop of virtualProps.VIRTUAL_PROP_NAMES) { if (selected[prop] == null && prop in row) { selected[prop] = row[prop]; } } return selected; } function mapNestedQueries(optimizedQuery, originalQuery, queryMapping) { mapNestedFromQueries(optimizedQuery.from, originalQuery.from, queryMapping); if (optimizedQuery.join && originalQuery.join) { for (let i = 0; i < optimizedQuery.join.length && i < originalQuery.join.length; i++) { const optimizedJoin = optimizedQuery.join[i]; const originalJoin = originalQuery.join[i]; if (optimizedJoin.from.type === `queryRef` && originalJoin.from.type === `queryRef`) { queryMapping.set(optimizedJoin.from.query, originalJoin.from.query); mapNestedQueries( optimizedJoin.from.query, originalJoin.from.query, queryMapping ); } } } } function getFromSources(from) { if (from.type === `unionFrom`) { return from.sources; } if (from.type === `unionAll`) { return []; } return [from]; } function getAllSources(query) { return [ ...getFromSources(query.from), ...query.join?.map((join) => join.from) ?? [] ]; } function getFirstFromAlias(from) { return getFromSources(from)[0]?.alias ?? ``; } function findProjectedSourceIncludePaths(select2, sourceAlias, sourcePath) { const targetPath = [sourceAlias, ...sourcePath]; return findProjectedIncludePaths(select2, targetPath); } function findProjectedResultIncludePaths(select2, resultPath) { return findProjectedIncludePaths(select2, resultPath); } function findProjectedIncludePaths(select2, targetPath) { const resultPaths = []; const visitSelectObject = (obj, prefix, guards) => { for (const [key, value] of Object.entries(obj)) { if (key.startsWith(`__SPREAD_SENTINEL__`)) { visitSpreadSentinel(key, value, prefix, guards); continue; } visitSelectValue(value, [...prefix, key], guards); } }; const visitSpreadSentinel = (key, value, path, guards) => { const rest = key.slice(`__SPREAD_SENTINEL__`.length); const splitIndex = rest.lastIndexOf(`__`); const pathStr = splitIndex >= 0 ? rest.slice(0, splitIndex) : rest; const isRefExpr = value && typeof value === `object` && `type` in value && value.type === `ref`; const sourcePath = isRefExpr ? value.path : pathStr.split(`.`).filter(Boolean); if (pathStartsWith(targetPath, sourcePath)) { resultPaths.push({ path: [...path, ...targetPath.slice(sourcePath.length)], guards }); } }; const visitSelectValue = (value, path, guards) => { if (value instanceof ir.PropRef && pathStartsWith(targetPath, value.path)) { resultPaths.push({ path: [...path, ...targetPath.slice(value.path.length)], guards }); return; } if (value instanceof ir.ConditionalSelect) { const previousBranchGuards = []; for (const branch of value.branches) { visitSelectValue(branch.value, path, [ ...guards, ...previousBranchGuards, { condition: branch.condition, expected: true } ]); previousBranchGuards.push({ condition: branch.condition, expected: false }); } if (value.defaultValue !== void 0) { visitSelectValue(value.defaultValue, path, [ ...guards, ...previousBranchGuards ]); } return; } if (isNestedSelectObject(value)) { visitSelectObject(value, path, guards); } }; visitSelectObject(select2, [], []); return resultPaths; } function pathStartsWith(path, prefix) { return prefix.length <= path.length && prefix.every((part, i) => path[i] === part); } function mapNestedFromQueries(optimizedFrom, originalFrom, queryMapping) { if (optimizedFrom.type === `unionAll` && originalFrom.type === `unionAll`) { for (let i = 0; i < optimizedFrom.queries.length && i < originalFrom.queries.length; i++) { const optimizedBranch = optimizedFrom.queries[i]; const originalBranch = originalFrom.queries[i]; queryMapping.set(optimizedBranch, originalBranch); mapNestedQueries(optimizedBranch, originalBranch, queryMapping); } return; } const optimizedSources = getFromSources(optimizedFrom); const originalSources = getFromSources(originalFrom); for (let i = 0; i < optimizedSources.length && i < originalSources.length; i++) { const optimizedSource = optimizedSources[i]; const originalSource = originalSources[i]; if (optimizedSource.type === `queryRef` && originalSource.type === `queryRef`) { queryMapping.set(optimizedSource.query, originalSource.query); mapNestedQueries( optimizedSource.query, originalSource.query, queryMapping ); } } } function extractIncludesFromSelect(select2) { const results = []; for (const [key, value] of Object.entries(select2)) { if (key.startsWith(`__SPREAD_SENTINEL__`)) continue; if (value instanceof ir.IncludesSubquery) { results.push({ key: getIncludesRoutingKey([key], results), path: [key], subquery: value, guards: [] }); } else if (value instanceof ir.ConditionalSelect) { collectIncludesFromConditionalSelect(value, [key], [], results); } else if (isNestedSelectObject(value)) { assertNoNestedIncludes(value, key); } } return results; } function collectIncludesFromConditionalSelect(conditional, prefixPath, guards, results) { const previousBranchGuards = []; for (const branch of conditional.branches) { collectIncludesFromSelectValue( branch.value, prefixPath, [ ...guards, ...previousBranchGuards, { condition: branch.condition, expected: true } ], results ); previousBranchGuards.push({ condition: branch.condition, expected: false }); } if (conditional.defaultValue !== void 0) { collectIncludesFromSelectValue( conditional.defaultValue, prefixPath, [...guards, ...previousBranchGuards], results ); } } function collectIncludesFromSelectValue(value, prefixPath, guards, results) { if (value instanceof ir.IncludesSubquery) { const key = getIncludesRoutingKey(prefixPath, results); results.push({ key, path: prefixPath, subquery: value, guards }); return; } if (value instanceof ir.ConditionalSelect) { collectIncludesFromConditionalSelect(value, prefixPath, guards, results); return; } if (!isNestedSelectObject(value)) { return; } for (const [key, child] of Object.entries(value)) { if (key.startsWith(`__SPREAD_SENTINEL__`)) continue; collectIncludesFromSelectValue(child, [...prefixPath, key], guards, results); } } function getIncludesRoutingKey(path, entries) { return getUniqueIncludesRoutingKey(path.join(`.`), entries); } function getUniqueIncludesRoutingKey(baseKey, entries) { const hasKey = (key2) => entries.some((entry) => (entry.key ?? entry.fieldName) === key2); if (!hasKey(baseKey)) { return baseKey; } let suffix = entries.length; let key = `${baseKey}#${suffix}`; while (hasKey(key)) { suffix++; key = `${baseKey}#${suffix}`; } return key; } function isNestedSelectObject(value) { return value != null && typeof value === `object` && !Array.isArray(value) && !ir.isExpressionLike(value); } function assertNoNestedIncludes(obj, parentPath) { for (const [key, value] of Object.entries(obj)) { if (key.startsWith(`__SPREAD_SENTINEL__`)) continue; if (value instanceof ir.IncludesSubquery) { throw new Error( `Includes subqueries must be at the top level of select(). Found nested includes at "${parentPath}.${key}".` ); } if (isNestedSelectObject(value)) { assertNoNestedIncludes(value, `${parentPath}.${key}`); } } } function replaceIncludesInSelect(select2, path) { return replaceIncludesInSelectValue(select2, path, new ir.Value(null)).value; } function replaceIncludesInSelectValue(value, path, replacement) { if (path.length === 0) { return replaceIncludesValue(value, replacement); } if (value instanceof ir.ConditionalSelect) { return replaceIncludesInConditionalSelect(value, path, replacement); } if (!isNestedSelectObject(value)) { return { value, replaced: false }; } if (path.length === 1) { const field = path[0]; const result2 = replaceIncludesValue(value[field], replacement); if (!result2.replaced) { return { value, replaced: false }; } return { value: { ...value, [field]: result2.value }, replaced: true }; } const [head, ...rest] = path; const result = replaceIncludesInSelectValue(value[head], rest, replacement); if (!result.replaced) { return { value, replaced: false }; } return { value: { ...value, [head]: result.value }, replaced: true }; } function replaceIncludesValue(value, replacement) { if (value instanceof ir.IncludesSubquery) { return { value: replacement, replaced: true }; } if (value instanceof ir.ConditionalSelect) { return replaceIncludesInConditionalSelect(value, [], replacement); } return { value, replaced: false }; } function replaceIncludesInConditionalSelect(conditional, path, replacement) { let replaced = false; const branches = conditional.branches.map((branch) => { const result = path.length === 0 ? replaceIncludesValue(branch.value, replacement) : replaceIncludesInSelectValue(branch.value, path, replacement); if (!result.replaced) { return branch; } replaced = true; return { ...branch, value: result.value }; }); let defaultValue = conditional.defaultValue; if (conditional.defaultValue !== void 0) { const result = path.length === 0 ? replaceIncludesValue(conditional.defaultValue, replacement) : replaceIncludesInSelectValue( conditional.defaultValue, path, replacement ); if (result.replaced) { replaced = true; defaultValue = result.value; } } if (!replaced) { return { value: conditional, replaced: false }; } return { value: new ir.ConditionalSelect(branches, defaultValue), replaced: true }; } function getNestedValue(obj, path) { let value = obj; for (const segment of path) { if (value == null) return value; value = value[segment]; } return value; } function matchesConditionalSelectGuards(guards, row) { return guards.every( (guard) => evaluators.isCaseWhenConditionTrue(guard.condition(row)) === guard.expected ); } exports.FN_SELECT_STATE = FN_SELECT_STATE; exports.INCLUDES_ROUTING = INCLUDES_ROUTING; exports.compileQuery = compileQuery; //# sourceMappingURL=index.cjs.map