UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

174 lines (173 loc) 5.88 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const dbIvm = require("@tanstack/db-ivm"); const errors = require("../../errors.cjs"); const evaluators = require("./evaluators.cjs"); const index = require("./index.cjs"); function processJoins(pipeline, joinClauses, tables, mainTableAlias, allInputs, cache, queryMapping) { let resultPipeline = pipeline; for (const joinClause of joinClauses) { resultPipeline = processJoin( resultPipeline, joinClause, tables, mainTableAlias, allInputs, cache, queryMapping ); } return resultPipeline; } function processJoin(pipeline, joinClause, tables, mainTableAlias, allInputs, cache, queryMapping) { const { alias: joinedTableAlias, input: joinedInput } = processJoinSource( joinClause.from, allInputs, cache, queryMapping ); tables[joinedTableAlias] = joinedInput; const joinType = joinClause.type === `cross` ? `inner` : joinClause.type === `outer` ? `full` : joinClause.type; const { mainExpr, joinedExpr } = analyzeJoinExpressions( joinClause.left, joinClause.right, mainTableAlias, joinedTableAlias ); const compiledMainExpr = evaluators.compileExpression(mainExpr); const compiledJoinedExpr = evaluators.compileExpression(joinedExpr); const mainPipeline = pipeline.pipe( dbIvm.map(([currentKey, namespacedRow]) => { const mainKey = compiledMainExpr(namespacedRow); return [mainKey, [currentKey, namespacedRow]]; }) ); const joinedPipeline = joinedInput.pipe( dbIvm.map(([currentKey, row]) => { const namespacedRow = { [joinedTableAlias]: row }; const joinedKey = compiledJoinedExpr(namespacedRow); return [joinedKey, [currentKey, namespacedRow]]; }) ); if (![`inner`, `left`, `right`, `full`].includes(joinType)) { throw new errors.UnsupportedJoinTypeError(joinClause.type); } return mainPipeline.pipe( dbIvm.join(joinedPipeline, joinType), dbIvm.consolidate(), processJoinResults(joinClause.type) ); } function analyzeJoinExpressions(left, right, mainTableAlias, joinedTableAlias) { const leftTableAlias = getTableAliasFromExpression(left); const rightTableAlias = getTableAliasFromExpression(right); if (leftTableAlias === mainTableAlias && rightTableAlias === joinedTableAlias) { return { mainExpr: left, joinedExpr: right }; } if (leftTableAlias === joinedTableAlias && rightTableAlias === mainTableAlias) { return { mainExpr: right, joinedExpr: left }; } if (leftTableAlias === rightTableAlias) { throw new errors.InvalidJoinConditionSameTableError(leftTableAlias || `unknown`); } if (!leftTableAlias || !rightTableAlias) { throw new errors.InvalidJoinConditionTableMismatchError( mainTableAlias, joinedTableAlias ); } throw new errors.InvalidJoinConditionWrongTablesError( leftTableAlias, rightTableAlias, mainTableAlias, joinedTableAlias ); } function getTableAliasFromExpression(expr) { switch (expr.type) { case `ref`: return expr.path[0] || null; case `func`: { const tableAliases = /* @__PURE__ */ new Set(); for (const arg of expr.args) { const alias = getTableAliasFromExpression(arg); if (alias) { tableAliases.add(alias); } } return tableAliases.size === 1 ? Array.from(tableAliases)[0] : null; } default: return null; } } function processJoinSource(from, allInputs, cache, queryMapping) { switch (from.type) { case `collectionRef`: { const input = allInputs[from.collection.id]; if (!input) { throw new errors.CollectionInputNotFoundError(from.collection.id); } return { alias: from.alias, input }; } case `queryRef`: { const originalQuery = queryMapping.get(from.query) || from.query; const subQueryResult = index.compileQuery( originalQuery, allInputs, cache, queryMapping ); const subQueryInput = subQueryResult.pipeline; const extractedInput = subQueryInput.pipe( dbIvm.map((data) => { const [key, [value, _orderByIndex]] = data; return [key, value]; }) ); return { alias: from.alias, input: extractedInput }; } default: throw new errors.UnsupportedJoinSourceTypeError(from.type); } } function processJoinResults(joinType) { return function(pipeline) { return pipeline.pipe( // Process the join result and handle nulls dbIvm.filter((result) => { const [_key, [main, joined]] = result; const mainNamespacedRow = main == null ? void 0 : main[1]; const joinedNamespacedRow = joined == null ? void 0 : joined[1]; if (joinType === `inner`) { return !!(mainNamespacedRow && joinedNamespacedRow); } if (joinType === `left`) { return !!mainNamespacedRow; } if (joinType === `right`) { return !!joinedNamespacedRow; } return true; }), dbIvm.map((result) => { const [_key, [main, joined]] = result; const mainKey = main == null ? void 0 : main[0]; const mainNamespacedRow = main == null ? void 0 : main[1]; const joinedKey = joined == null ? void 0 : joined[0]; const joinedNamespacedRow = joined == null ? void 0 : joined[1]; const mergedNamespacedRow = {}; if (mainNamespacedRow) { Object.assign(mergedNamespacedRow, mainNamespacedRow); } if (joinedNamespacedRow) { Object.assign(mergedNamespacedRow, joinedNamespacedRow); } const resultKey = `[${mainKey},${joinedKey}]`; return [resultKey, mergedNamespacedRow]; }) ); }; } exports.processJoins = processJoins; //# sourceMappingURL=joins.cjs.map