@tanstack/db
Version:
A reactive client store for building super fast apps on sync
1 lines • 49.2 kB
Source Map (JSON)
{"version":3,"file":"group-by.cjs","sources":["../../../../src/query/compiler/group-by.ts"],"sourcesContent":["import {\n filter,\n groupBy,\n groupByOperators,\n map,\n serializeValue,\n} from '@tanstack/db-ivm'\nimport {\n ConditionalSelect,\n Func,\n PropRef,\n getHavingExpression,\n isExpressionLike,\n} from '../ir.js'\nimport {\n AggregateFunctionNotInSelectError,\n NonAggregateExpressionNotInGroupByError,\n UnknownHavingExpressionTypeError,\n UnsupportedAggregateFunctionError,\n} from '../../errors.js'\nimport {\n getEqualityValueIdentity,\n getParentContextIdentity,\n getParentContextValue,\n} from '../equality-value-identity.js'\nimport {\n compileExpression,\n isCaseWhenConditionTrue,\n toBooleanPredicate,\n} from './evaluators.js'\nimport {\n INCLUDES_PUBLIC_KEY,\n attachRouteMetadata,\n getNamespacedRouteMetadata,\n stripInternalCallbackMetadata,\n} from './route-metadata.js'\nimport type { ValueIdentity } from '../equality-value-identity.js'\nimport type { RouteMetadata } from './route-metadata.js'\nimport type {\n Aggregate,\n BasicExpression,\n GroupBy,\n Having,\n Select,\n SelectValueExpression,\n} from '../ir.js'\nimport type { NamespacedAndKeyedStream, NamespacedRow } from '../../types.js'\nimport type { VirtualOrigin } from '../../virtual-props.js'\n\nconst RAW_REPRESENTATIVE = Symbol(`raw_group_representative`)\n\ntype InternalGroupFields = ReturnType<typeof createInternalGroupFields>\n\nfunction createInternalGroupFields(groupCount: number, selectClause?: Select) {\n const aliases = Object.keys(selectClause ?? {})\n let prefix = `__tanstack_group_`\n while (aliases.some((alias) => alias.startsWith(prefix))) prefix += `_`\n\n return {\n virtual: `${prefix}virtual`,\n route: `${prefix}route`,\n correlationIdentity: `${prefix}correlation_identity`,\n parentContextIdentity: `${prefix}parent_context_identity`,\n singleGroup: `${prefix}single_group`,\n aggregatePrefix: `${prefix}aggregate_`,\n groupKeys: Array.from(\n { length: groupCount },\n (_, i) => `${prefix}key_${i}`,\n ),\n groupValues: Array.from(\n { length: groupCount },\n (_, i) => `${prefix}value_${i}`,\n ),\n groupKeyRefs: Array.from(\n { length: groupCount },\n (_, i) => `${prefix}key_ref_${i}`,\n ),\n }\n}\n\ntype RowVirtualMetadata = {\n synced: boolean\n hasLocal: boolean\n}\n\ntype Representative<T> = {\n key: string\n [RAW_REPRESENTATIVE]: T\n}\n\nfunction createPublicGroupKey(values: Array<unknown>): unknown {\n const identities = values.map(getEqualityValueIdentity)\n if (identities.length === 1) {\n const identity = identities[0]\n if (\n identity == null ||\n (typeof identity !== `object` &&\n typeof identity !== `function` &&\n typeof identity !== `symbol`)\n ) {\n return identity\n }\n }\n return serializeValue(identities)\n}\n\nfunction attachPublicGroupKey(\n row: Record<string, any>,\n publicKey: unknown,\n): void {\n const keyedRow = row as Record<PropertyKey, unknown>\n keyedRow[INCLUDES_PUBLIC_KEY] = publicKey\n}\n\nfunction createRepresentative<T>(\n rowKey: string,\n value: T,\n identity: unknown,\n): Representative<T> {\n // Encode once per contribution, not once per member on every group change.\n const representative = {\n key: serializeValue([rowKey, identity]),\n } as Representative<T>\n Object.defineProperty(representative, RAW_REPRESENTATIVE, { value })\n return representative\n}\n\nfunction getRepresentative<T>(\n values: Array<[Representative<T>, number]>,\n): Representative<T> | undefined {\n let selected: Representative<T> | undefined\n for (const [candidate, multiplicity] of values) {\n if (multiplicity <= 0) continue\n if (selected === undefined || candidate.key < selected.key) {\n selected = candidate\n }\n }\n return selected\n}\n\nfunction unwrapRepresentative<T>(\n value: Representative<T> | undefined,\n): T | undefined {\n return value?.[RAW_REPRESENTATIVE]\n}\n\nfunction addCorrelationRouteIdentityToGroupKey(\n key: Record<string, unknown>,\n row: NamespacedRow,\n mainSource: string,\n fields: InternalGroupFields,\n valueIdentity: ValueIdentity,\n): void {\n const route = getNamespacedRouteMetadata(row, mainSource)\n key[fields.correlationIdentity] = valueIdentity.equality(\n route?.correlationKey,\n )\n if (route?.parentContext != null) {\n key[fields.parentContextIdentity] = getParentContextIdentity(\n route.parentContext,\n )\n }\n}\n\n/** One representative carries the whole route so both parts come from one row. */\nfunction addCorrelationRouteAggregate(\n aggregates: Record<string, any>,\n mainSource: string,\n fields: InternalGroupFields,\n valueIdentity: ValueIdentity,\n): void {\n aggregates[fields.route] = {\n preMap: ([rowKey, row]: [string, NamespacedRow]) => {\n const route = getNamespacedRouteMetadata(row, mainSource)\n return createRepresentative(rowKey, route, [\n valueIdentity.exact(route?.correlationKey),\n getParentContextIdentity(route?.parentContext),\n ])\n },\n reduce: getRepresentative,\n postMap: unwrapRepresentative,\n }\n}\n\nfunction getGroupRoute(\n aggregatedRow: Record<string, unknown>,\n fields: InternalGroupFields,\n): RouteMetadata | undefined {\n return aggregatedRow[fields.route] as RouteMetadata | undefined\n}\n\nfunction getCorrelationRouteIdentity(\n aggregatedRow: Record<string, unknown>,\n fields: InternalGroupFields,\n): unknown {\n return getGroupRoute(aggregatedRow, fields)?.parentContext == null\n ? aggregatedRow[fields.correlationIdentity]\n : [\n aggregatedRow[fields.correlationIdentity],\n aggregatedRow[fields.parentContextIdentity],\n ]\n}\n\nfunction getGroupEvaluationRow(\n row: Record<string, unknown>,\n fields: InternalGroupFields,\n selected = row.$selected as Record<string, unknown>,\n): NamespacedRow {\n return {\n ...getParentContextValue(getGroupRoute(row, fields)?.parentContext),\n $selected: selected,\n }\n}\n\nfunction getRowVirtualMetadata(row: NamespacedRow): RowVirtualMetadata {\n let found = false\n let allSynced = true\n let hasLocal = false\n\n for (const [alias, value] of Object.entries(row as Record<string, unknown>)) {\n if (alias === `$selected`) continue\n if (value === null || typeof value !== `object`) continue\n const asRecord = value as Record<string, unknown>\n const hasSyncedProp = `$synced` in asRecord\n const hasOriginProp = `$origin` in asRecord\n if (!hasSyncedProp && !hasOriginProp) {\n continue\n }\n found = true\n if (asRecord.$synced === false) {\n allSynced = false\n }\n if (asRecord.$origin === `local`) {\n hasLocal = true\n }\n }\n\n return {\n synced: found ? allSynced : true,\n hasLocal,\n }\n}\n\nconst { sum, count, avg, min, max } = groupByOperators\n\n/**\n * Validates that all non-aggregate expressions in SELECT are present in GROUP BY\n * and creates a cached mapping for efficient lookup during processing\n */\nfunction validateAndCreateMapping(\n groupByClause: GroupBy,\n selectClause?: Select,\n): Map<string, number> {\n const selectToGroupByIndex = new Map<string, number>()\n\n if (!selectClause) {\n return selectToGroupByIndex\n }\n\n // Validate each SELECT expression\n for (const [alias, expr] of Object.entries(selectClause)) {\n if (expr.type === `agg` || containsAggregate(expr)) {\n // Aggregate expressions (plain or wrapped) are allowed and don't need to be in GROUP BY\n continue\n }\n\n // Non-aggregate expression must be in GROUP BY\n const groupIndex = groupByClause.findIndex((groupExpr) =>\n expressionsEqual(expr, groupExpr),\n )\n\n if (groupIndex === -1) {\n throw new NonAggregateExpressionNotInGroupByError(alias)\n }\n\n // Cache the mapping\n selectToGroupByIndex.set(alias, groupIndex)\n }\n\n return selectToGroupByIndex\n}\n\n/**\n * Processes the GROUP BY clause with optional HAVING and SELECT\n * Works with the new $selected structure from early SELECT processing\n */\nexport function processGroupBy(\n pipeline: NamespacedAndKeyedStream,\n groupByClause: GroupBy,\n valueIdentity: ValueIdentity,\n havingClauses?: Array<Having>,\n selectClause?: Select,\n fnHavingClauses?: Array<(row: any) => any>,\n aggregateCollectionId?: string,\n mainSource?: string,\n sanitizeCallbackRows = false,\n): NamespacedAndKeyedStream {\n const fields = createInternalGroupFields(groupByClause.length, selectClause)\n const virtualAggregates: Record<string, any> = {\n [fields.virtual]: {\n preMap: ([, row]: [string, NamespacedRow]) => getRowVirtualMetadata(row),\n reduce: (values: Array<[RowVirtualMetadata, number]>) => {\n const group: RowVirtualMetadata = { synced: true, hasLocal: false }\n for (const [metadata, multiplicity] of values) {\n if (multiplicity <= 0) continue\n if (!metadata.synced) group.synced = false\n if (metadata.hasLocal) group.hasLocal = true\n }\n return group\n },\n },\n }\n\n if (mainSource) {\n addCorrelationRouteAggregate(\n virtualAggregates,\n mainSource,\n fields,\n valueIdentity,\n )\n }\n\n const singleGroup = groupByClause.length === 0\n // Single-group aggregation accepts selections without grouping validation.\n const mapping = singleGroup\n ? undefined\n : validateAndCreateMapping(groupByClause, selectClause)\n\n // Pre-compile groupBy expressions\n const compiledGroupByExpressions = groupByClause.map((e) =>\n compileExpression(e),\n )\n\n // Include the complete route so distinct parent inputs stay apart.\n const keyExtractor = ([, row]: [\n string,\n NamespacedRow & { $selected?: any },\n ]) => {\n // Use the original namespaced row for GROUP BY expressions, not $selected\n const namespacedRow = singleGroup ? row : { ...row }\n if (!singleGroup) delete namespacedRow.$selected\n\n const key: Record<string, unknown> = singleGroup\n ? { [fields.singleGroup]: true }\n : {}\n\n // D2 must key groups by the same relation as the query evaluator. The raw\n // representative is retained separately as an aggregate for projection.\n for (let i = 0; i < groupByClause.length; i++) {\n const compiledExpr = compiledGroupByExpressions[i]!\n const value = compiledExpr(namespacedRow)\n key[fields.groupKeys[i]!] = valueIdentity.equality(value)\n }\n\n if (mainSource) {\n addCorrelationRouteIdentityToGroupKey(\n key,\n row,\n mainSource,\n fields,\n valueIdentity,\n )\n }\n\n return key\n }\n\n // Create aggregate functions for any aggregated columns in the SELECT clause\n const aggregates: Record<string, any> = virtualAggregates\n const wrappedAggExprs: Record<string, (data: any) => any> = {}\n const aggCounter = { value: 0 }\n\n for (let i = 0; i < compiledGroupByExpressions.length; i++) {\n const compiledExpr = compiledGroupByExpressions[i]!\n aggregates[fields.groupValues[i]!] = {\n preMap: ([rowKey, row]: [string, NamespacedRow]) => {\n const value = compiledExpr(row)\n return createRepresentative(rowKey, value, valueIdentity.exact(value))\n },\n reduce: getRepresentative,\n postMap: unwrapRepresentative,\n }\n }\n\n if (selectClause) {\n // Scan the SELECT clause for aggregate functions\n for (const [alias, expr] of Object.entries(selectClause)) {\n if (expr.type === `agg`) {\n aggregates[alias] = getAggregateFunction(expr)\n } else if (containsAggregate(expr)) {\n const { transformed, extracted } = extractAndReplaceAggregates(\n expr as SelectValueExpression,\n aggCounter,\n fields.aggregatePrefix,\n )\n for (const [syntheticAlias, aggExpr] of Object.entries(extracted)) {\n aggregates[syntheticAlias] = getAggregateFunction(aggExpr)\n }\n wrappedAggExprs[alias] = compileGroupedSelectValue(\n singleGroup\n ? transformed\n : replaceGroupByRefsInSelectValue(\n transformed,\n groupByClause,\n fields.groupKeyRefs,\n ),\n )\n }\n }\n }\n\n // Apply the groupBy operator\n pipeline = pipeline.pipe(groupBy(keyExtractor, aggregates))\n\n // Update $selected to handle GROUP BY results\n pipeline = pipeline.pipe(\n map(([, aggregatedRow]) => {\n // Start with the existing $selected from early SELECT processing\n const selectResults = (aggregatedRow as any).$selected || {}\n const finalResults: Record<string, any> = singleGroup\n ? { ...selectResults }\n : {}\n\n if (selectClause) {\n // First pass: populate group keys, plain aggregates, and synthetic aliases\n for (const [alias, expr] of Object.entries(selectClause)) {\n if (expr.type === `agg`) {\n finalResults[alias] = aggregatedRow[alias]\n } else if (!singleGroup && !wrappedAggExprs[alias]) {\n // Use cached mapping to get the corresponding __key_X for non-aggregates\n const groupIndex = mapping?.get(alias)\n if (groupIndex !== undefined) {\n finalResults[alias] =\n aggregatedRow[fields.groupValues[groupIndex]!]\n } else {\n // Fallback to original SELECT results\n finalResults[alias] = selectResults[alias]\n }\n }\n }\n evaluateWrappedAggregates(\n finalResults,\n aggregatedRow as Record<string, any>,\n wrappedAggExprs,\n fields,\n )\n } else {\n // No SELECT clause - just use the group keys\n for (let i = 0; i < groupByClause.length; i++) {\n finalResults[`__key_${i}`] = aggregatedRow[fields.groupValues[i]!]\n }\n }\n\n // Generate a simple key for the live collection using group values.\n // In includes mode, add the complete route so correlated groups do not\n // collide.\n const route = mainSource\n ? getGroupRoute(aggregatedRow, fields)\n : undefined\n const correlationKey = route?.correlationKey\n const correlationRoute = mainSource\n ? getCorrelationRouteIdentity(aggregatedRow, fields)\n : undefined\n const keyParts: Array<unknown> = []\n const publicKeyParts: Array<unknown> = []\n for (let i = 0; i < groupByClause.length; i++) {\n keyParts.push(aggregatedRow[fields.groupKeys[i]!])\n publicKeyParts.push(aggregatedRow[fields.groupValues[i]!])\n }\n if (correlationRoute !== undefined) {\n keyParts.push(correlationRoute)\n }\n const finalKey = singleGroup\n ? correlationRoute !== undefined\n ? `single_group_${serializeValue(correlationRoute)}`\n : `single_group`\n : keyParts.length === 1\n ? keyParts[0]\n : serializeValue(keyParts)\n const publicKey = singleGroup\n ? `single_group`\n : createPublicGroupKey(publicKeyParts)\n\n // When in includes mode, restore route metadata for output routing.\n const resultRow: Record<string, any> = {\n ...(aggregatedRow as Record<string, any>),\n $selected: finalResults,\n }\n const virtual = (aggregatedRow as Record<string, any>)[fields.virtual] as\n | RowVirtualMetadata\n | undefined\n resultRow.$synced = virtual?.synced ?? true\n resultRow.$origin = (\n virtual?.hasLocal ? `local` : `remote`\n ) satisfies VirtualOrigin\n resultRow.$key = publicKey\n resultRow.$collectionId = aggregateCollectionId ?? resultRow.$collectionId\n if (mainSource && correlationKey !== undefined) {\n attachPublicGroupKey(resultRow, publicKey)\n attachRouteMetadata(\n resultRow,\n correlationKey,\n route?.parentContext ?? null,\n )\n }\n return [mainSource ? finalKey : publicKey, resultRow] as [\n unknown,\n Record<string, any>,\n ]\n }),\n )\n\n // Apply HAVING clauses if present\n if (havingClauses && havingClauses.length > 0) {\n for (const havingClause of havingClauses) {\n const havingExpression = getHavingExpression(havingClause)\n const transformedHavingClause = replaceAggregatesByRefs(\n havingExpression,\n selectClause || {},\n )\n const compiledHaving = compileExpression(transformedHavingClause)\n\n pipeline = pipeline.pipe(\n filter(([, row]) => {\n const namespacedRow = getGroupEvaluationRow(row, fields)\n const result = compiledHaving(namespacedRow)\n // Preserve each path's coercion for unchecked nonboolean IR values.\n return singleGroup ? toBooleanPredicate(result) : result\n }),\n )\n }\n }\n\n // Apply functional HAVING clauses if present\n if (fnHavingClauses && fnHavingClauses.length > 0) {\n for (const fnHaving of fnHavingClauses) {\n pipeline = pipeline.pipe(\n filter(([, row]) => {\n const namespacedRow = getGroupEvaluationRow(row, fields)\n const callbackRow = sanitizeCallbackRows\n ? stripInternalCallbackMetadata(namespacedRow)\n : namespacedRow\n return toBooleanPredicate(fnHaving(callbackRow))\n }),\n )\n }\n }\n\n return pipeline\n}\n\n/**\n * Helper function to check if two expressions are equal\n */\nfunction expressionsEqual(expr1: any, expr2: any): boolean {\n if (!expr1 || !expr2) return false\n if (expr1.type !== expr2.type) return false\n\n switch (expr1.type) {\n case `ref`:\n // Compare paths as arrays\n if (!expr1.path || !expr2.path) return false\n if (expr1.path.length !== expr2.path.length) return false\n return expr1.path.every(\n (segment: string, i: number) => segment === expr2.path[i],\n )\n case `val`:\n return expr1.value === expr2.value\n case `func`:\n return (\n expr1.name === expr2.name &&\n expr1.args?.length === expr2.args?.length &&\n (expr1.args || []).every((arg: any, i: number) =>\n expressionsEqual(arg, expr2.args[i]),\n )\n )\n case `agg`:\n return (\n expr1.name === expr2.name &&\n expr1.args?.length === expr2.args?.length &&\n (expr1.args || []).every((arg: any, i: number) =>\n expressionsEqual(arg, expr2.args[i]),\n )\n )\n default:\n return false\n }\n}\n\n/**\n * Helper function to get an aggregate function based on the Agg expression\n */\nfunction getAggregateFunction(aggExpr: Aggregate) {\n // Pre-compile the value extractor expression\n const compiledExpr = compileExpression(aggExpr.args[0]!)\n\n // Create a value extractor function for the expression to aggregate\n const valueExtractor = ([, namespacedRow]: [string, NamespacedRow]) => {\n const value = compiledExpr(namespacedRow)\n // Ensure we return a number for numeric aggregate functions\n if (typeof value === `number`) {\n return value\n }\n return value != null ? Number(value) : 0\n }\n\n // Create a value extractor function for min/max that preserves comparable types\n const valueExtractorForMinMax = ([, namespacedRow]: [\n string,\n NamespacedRow,\n ]) => {\n const value = compiledExpr(namespacedRow)\n // Preserve strings, numbers, Dates, and bigints for comparison\n if (\n typeof value === `number` ||\n typeof value === `string` ||\n typeof value === `bigint` ||\n value instanceof Date\n ) {\n return value\n }\n return value != null ? Number(value) : 0\n }\n\n // Create a raw value extractor function for the expression to aggregate\n const rawValueExtractor = ([, namespacedRow]: [string, NamespacedRow]) => {\n return compiledExpr(namespacedRow)\n }\n\n // Return the appropriate aggregate function\n switch (aggExpr.name.toLowerCase()) {\n case `sum`:\n return sum(valueExtractor)\n case `count`:\n return count(rawValueExtractor)\n case `avg`:\n return avg(valueExtractor)\n case `min`:\n return min(valueExtractorForMinMax)\n case `max`:\n return max(valueExtractorForMinMax)\n default:\n throw new UnsupportedAggregateFunctionError(aggExpr.name)\n }\n}\n\n/**\n * Transforms expressions to replace aggregate functions with references to computed values.\n *\n * For aggregate expressions, finds matching aggregates in the SELECT clause and replaces them\n * with PropRef([resultAlias, alias]) to reference the computed aggregate value.\n *\n * Ref expressions (table columns and $selected fields) and value expressions are passed through unchanged.\n * Function expressions are recursively transformed.\n *\n * @param havingExpr - The expression to transform (can be aggregate, ref, func, or val)\n * @param selectClause - The SELECT clause containing aliases and aggregate definitions\n * @param resultAlias - The namespace alias for SELECT results (default: '$selected')\n * @returns A transformed BasicExpression that references computed values instead of raw expressions\n */\nexport function replaceAggregatesByRefs(\n havingExpr: BasicExpression | Aggregate,\n selectClause: Select,\n resultAlias: string = `$selected`,\n): BasicExpression {\n switch (havingExpr.type) {\n case `agg`: {\n const aggExpr = havingExpr\n // Find matching aggregate in SELECT clause\n for (const [alias, selectExpr] of Object.entries(selectClause)) {\n if (selectExpr.type === `agg` && aggregatesEqual(aggExpr, selectExpr)) {\n // Replace with a reference to the computed aggregate\n return new PropRef([resultAlias, alias])\n }\n }\n // If no matching aggregate found in SELECT, throw error\n throw new AggregateFunctionNotInSelectError(aggExpr.name)\n }\n\n case `func`: {\n const funcExpr = havingExpr\n // Transform function arguments recursively\n const transformedArgs = funcExpr.args.map(\n (arg: BasicExpression | Aggregate) =>\n replaceAggregatesByRefs(arg, selectClause),\n )\n return new Func(funcExpr.name, transformedArgs)\n }\n\n case `ref`:\n // Ref expressions are passed through unchanged - they reference either:\n // - $selected fields (which are already in the correct namespace)\n // - Table column references (which remain valid)\n return havingExpr as BasicExpression\n\n case `val`:\n // Return as-is\n return havingExpr as BasicExpression\n\n default:\n throw new UnknownHavingExpressionTypeError((havingExpr as any).type)\n }\n}\n\n/**\n * Evaluates wrapped-aggregate expressions against the aggregated row.\n * Copies synthetic __agg_N values into finalResults so the compiled wrapper\n * expressions can reference them, evaluates each wrapper, then removes the\n * synthetic keys so they don't leak onto user-visible result rows.\n */\nfunction evaluateWrappedAggregates(\n finalResults: Record<string, any>,\n aggregatedRow: Record<string, any>,\n wrappedAggExprs: Record<string, (data: any) => any>,\n fields: InternalGroupFields,\n): void {\n for (const key of Object.keys(aggregatedRow)) {\n if (key.startsWith(fields.aggregatePrefix)) {\n finalResults[key] = aggregatedRow[key]\n }\n }\n for (let i = 0; i < fields.groupKeyRefs.length; i++) {\n finalResults[fields.groupKeyRefs[i]!] =\n aggregatedRow[fields.groupValues[i]!]\n }\n for (const [alias, evaluator] of Object.entries(wrappedAggExprs)) {\n finalResults[alias] = evaluator(\n getGroupEvaluationRow(aggregatedRow, fields, finalResults),\n )\n }\n for (const key of Object.keys(finalResults)) {\n if (\n key.startsWith(fields.aggregatePrefix) ||\n fields.groupKeyRefs.includes(key)\n ) {\n delete finalResults[key]\n }\n }\n}\n\n/**\n * Checks whether an expression contains an aggregate anywhere in its tree.\n * Returns true for a top-level Aggregate, or a Func whose args (recursively)\n * contain an Aggregate. Safely returns false for nested Select objects.\n */\nexport function containsAggregate(\n expr: BasicExpression | Aggregate | Select | { type: string },\n): boolean {\n if (isConditionalSelect(expr)) {\n const branchHasAggregate = expr.branches.some(\n (branch) =>\n containsAggregate(branch.condition) || containsAggregate(branch.value),\n )\n\n return (\n branchHasAggregate ||\n (expr.defaultValue !== undefined && containsAggregate(expr.defaultValue))\n )\n }\n\n if (isNestedSelectObject(expr)) {\n return Object.values(expr).some((value) =>\n containsAggregate(value as BasicExpression | Aggregate | Select),\n )\n }\n\n if (!isExpressionLike(expr)) {\n return false\n }\n\n if (expr.type === `agg`) {\n return true\n }\n if (expr.type === `func` && `args` in expr) {\n return (expr.args as Array<BasicExpression | Aggregate>).some(\n (arg: BasicExpression | Aggregate) => containsAggregate(arg),\n )\n }\n return false\n}\n\n/**\n * Walks an expression tree containing nested aggregates.\n * Each Aggregate node is extracted, assigned a synthetic alias (__agg_N),\n * and replaced with PropRef([\"$selected\", \"__agg_N\"]) so the wrapper\n * expression can be compiled as a pure BasicExpression after groupBy\n * populates the synthetic values.\n */\nfunction extractAndReplaceAggregates(\n expr: SelectValueExpression,\n counter: { value: number },\n aggregatePrefix: string,\n): {\n transformed: SelectValueExpression\n extracted: Record<string, Aggregate>\n} {\n if (expr.type === `includesSubquery`) {\n return { transformed: expr, extracted: {} }\n }\n\n if (expr.type === `agg`) {\n const alias = `${aggregatePrefix}${counter.value++}`\n return {\n transformed: new PropRef([`$selected`, alias]),\n extracted: { [alias]: expr },\n }\n }\n\n if (expr.type === `func`) {\n const allExtracted: Record<string, Aggregate> = {}\n const newArgs = expr.args.map((arg: BasicExpression | Aggregate) => {\n const result = extractAndReplaceAggregates(arg, counter, aggregatePrefix)\n Object.assign(allExtracted, result.extracted)\n return result.transformed as BasicExpression\n })\n return {\n transformed: new Func(expr.name, newArgs),\n extracted: allExtracted,\n }\n }\n\n if (isConditionalSelect(expr)) {\n const allExtracted: Record<string, Aggregate> = {}\n const branches = expr.branches.map((branch) => {\n const condition = extractAndReplaceAggregates(\n branch.condition,\n counter,\n aggregatePrefix,\n )\n const value = extractAndReplaceAggregates(\n branch.value,\n counter,\n aggregatePrefix,\n )\n Object.assign(allExtracted, condition.extracted, value.extracted)\n return {\n condition: condition.transformed as BasicExpression,\n value: value.transformed,\n }\n })\n const defaultValue =\n expr.defaultValue === undefined\n ? undefined\n : extractAndReplaceAggregates(\n expr.defaultValue,\n counter,\n aggregatePrefix,\n )\n\n if (defaultValue) {\n Object.assign(allExtracted, defaultValue.extracted)\n }\n\n return {\n transformed: new ConditionalSelect(branches, defaultValue?.transformed),\n extracted: allExtracted,\n }\n }\n\n if (isNestedSelectObject(expr)) {\n const allExtracted: Record<string, Aggregate> = {}\n const transformed: Select = {}\n\n for (const [key, value] of Object.entries(expr)) {\n const result = extractAndReplaceAggregates(\n value as SelectValueExpression,\n counter,\n aggregatePrefix,\n )\n Object.assign(allExtracted, result.extracted)\n transformed[key] = result.transformed\n }\n\n return { transformed, extracted: allExtracted }\n }\n\n // ref / val – pass through unchanged\n return { transformed: expr, extracted: {} }\n}\n\nfunction replaceGroupByRefsInSelectValue(\n value: SelectValueExpression,\n groupByClause: GroupBy,\n groupKeyRefs: Array<string>,\n): SelectValueExpression {\n if (isConditionalSelect(value)) {\n return new ConditionalSelect(\n value.branches.map((branch) => ({\n condition: replaceGroupByRefsInExpression(\n branch.condition,\n groupByClause,\n groupKeyRefs,\n ),\n value: replaceGroupByRefsInSelectValue(\n branch.value,\n groupByClause,\n groupKeyRefs,\n ),\n })),\n value.defaultValue === undefined\n ? undefined\n : replaceGroupByRefsInSelectValue(\n value.defaultValue,\n groupByClause,\n groupKeyRefs,\n ),\n )\n }\n\n if (isNestedSelectObject(value)) {\n const transformed: Select = {}\n for (const [key, entry] of Object.entries(value)) {\n transformed[key] = replaceGroupByRefsInSelectValue(\n entry as SelectValueExpression,\n groupByClause,\n groupKeyRefs,\n )\n }\n return transformed\n }\n\n if (!isExpressionLike(value)) {\n return value\n }\n\n if (value.type === `includesSubquery` || value.type === `agg`) {\n return value\n }\n\n return replaceGroupByRefsInExpression(value, groupByClause, groupKeyRefs)\n}\n\nfunction replaceGroupByRefsInExpression(\n expr: BasicExpression,\n groupByClause: GroupBy,\n groupKeyRefs: Array<string>,\n): BasicExpression {\n if (expr.type === `ref`) {\n const groupIndex = groupByClause.findIndex((groupExpr) =>\n expressionsEqual(expr, groupExpr),\n )\n return groupIndex === -1\n ? expr\n : new PropRef([`$selected`, groupKeyRefs[groupIndex]!])\n }\n\n if (expr.type === `func`) {\n return new Func(\n expr.name,\n expr.args.map((arg) =>\n replaceGroupByRefsInExpression(arg, groupByClause, groupKeyRefs),\n ),\n )\n }\n\n return expr\n}\n\nfunction compileGroupedSelectValue(\n value: SelectValueExpression,\n): (row: NamespacedRow) => any {\n if (isConditionalSelect(value)) {\n return compileGroupedConditionalSelect(value)\n }\n\n if (value.type === `includesSubquery`) {\n return () => null\n }\n\n if (isNestedSelectObject(value)) {\n return compileGroupedSelectObject(value)\n }\n\n if (!isExpressionLike(value)) {\n return () => value\n }\n\n return compileExpression(value as BasicExpression)\n}\n\nfunction compileGroupedSelectObject(\n obj: Select,\n): (row: NamespacedRow) => Record<string, any> {\n const entries = Object.entries(obj).map(([key, value]) => {\n if (key.startsWith(`__SPREAD_SENTINEL__`)) {\n const rest = key.slice(`__SPREAD_SENTINEL__`.length)\n const splitIndex = rest.lastIndexOf(`__`)\n const pathStr = splitIndex >= 0 ? rest.slice(0, splitIndex) : rest\n const isRefExpr =\n typeof value === `object` && `type` in value && value.type === `ref`\n const expression = isRefExpr\n ? (value as BasicExpression)\n : (new PropRef(pathStr.split(`.`)) as BasicExpression)\n\n return {\n key,\n spread: true,\n value: compileExpression(expression),\n }\n }\n\n return {\n key,\n spread: false,\n value: compileGroupedSelectValue(value as SelectValueExpression),\n }\n })\n\n return (row) => {\n const result: Record<string, any> = {}\n for (const entry of entries) {\n const value = entry.value(row)\n if (entry.spread) {\n if (value && typeof value === `object`) {\n Object.assign(result, value)\n }\n } else {\n result[entry.key] = value\n }\n }\n return result\n }\n}\n\nfunction compileGroupedConditionalSelect(\n conditional: ConditionalSelect,\n): (row: NamespacedRow) => any {\n const branches = conditional.branches.map((branch) => ({\n condition: compileExpression(branch.condition),\n value: compileGroupedSelectValue(branch.value),\n }))\n const defaultValue =\n conditional.defaultValue === undefined\n ? undefined\n : compileGroupedSelectValue(conditional.defaultValue)\n\n return (row) => {\n for (const branch of branches) {\n if (isCaseWhenConditionTrue(branch.condition(row))) {\n return branch.value(row)\n }\n }\n\n return defaultValue !== undefined ? defaultValue(row) : null\n }\n}\n\nfunction isNestedSelectObject(value: unknown): value is Select {\n return (\n value != null &&\n typeof value === `object` &&\n !Array.isArray(value) &&\n !(value as any).__refProxy &&\n !isExpressionLike(value)\n )\n}\n\nfunction isConditionalSelect(value: unknown): value is ConditionalSelect {\n return (\n value instanceof ConditionalSelect ||\n (value != null &&\n typeof value === `object` &&\n (value as { type?: string }).type === `conditionalSelect`)\n )\n}\n\n/**\n * Checks if two aggregate expressions are equal\n */\nfunction aggregatesEqual(agg1: Aggregate, agg2: Aggregate): boolean {\n return (\n agg1.name === agg2.name &&\n agg1.args.length === agg2.args.length &&\n agg1.args.every((arg, i) => expressionsEqual(arg, agg2.args[i]))\n )\n}\n"],"names":["getEqualityValueIdentity","serializeValue","INCLUDES_PUBLIC_KEY","getNamespacedRouteMetadata","getParentContextIdentity","getParentContextValue","groupByOperators","NonAggregateExpressionNotInGroupByError","compileExpression","groupBy","map","attachRouteMetadata","getHavingExpression","filter","toBooleanPredicate","stripInternalCallbackMetadata","UnsupportedAggregateFunctionError","PropRef","AggregateFunctionNotInSelectError","Func","UnknownHavingExpressionTypeError","isExpressionLike","ConditionalSelect","isCaseWhenConditionTrue"],"mappings":"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"}