@tanstack/db 0.0.14 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/dist/cjs/collection.cjs +117 -104
  2. package/dist/cjs/collection.cjs.map +1 -1
  3. package/dist/cjs/collection.d.cts +18 -21
  4. package/dist/cjs/index.cjs +35 -13
  5. package/dist/cjs/index.cjs.map +1 -1
  6. package/dist/cjs/index.d.cts +0 -1
  7. package/dist/cjs/query/builder/functions.cjs +107 -0
  8. package/dist/cjs/query/builder/functions.cjs.map +1 -0
  9. package/dist/cjs/query/builder/functions.d.cts +38 -0
  10. package/dist/cjs/query/builder/index.cjs +499 -0
  11. package/dist/cjs/query/builder/index.cjs.map +1 -0
  12. package/dist/cjs/query/builder/index.d.cts +324 -0
  13. package/dist/cjs/query/builder/ref-proxy.cjs +96 -0
  14. package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -0
  15. package/dist/cjs/query/builder/ref-proxy.d.cts +28 -0
  16. package/dist/cjs/query/builder/types.d.cts +80 -0
  17. package/dist/cjs/query/compiler/evaluators.cjs +261 -0
  18. package/dist/cjs/query/compiler/evaluators.cjs.map +1 -0
  19. package/dist/cjs/query/compiler/evaluators.d.cts +11 -0
  20. package/dist/cjs/query/compiler/group-by.cjs +271 -0
  21. package/dist/cjs/query/compiler/group-by.cjs.map +1 -0
  22. package/dist/cjs/query/compiler/group-by.d.cts +7 -0
  23. package/dist/cjs/query/compiler/index.cjs +181 -0
  24. package/dist/cjs/query/compiler/index.cjs.map +1 -0
  25. package/dist/cjs/query/compiler/index.d.cts +15 -0
  26. package/dist/cjs/query/compiler/joins.cjs +116 -0
  27. package/dist/cjs/query/compiler/joins.cjs.map +1 -0
  28. package/dist/cjs/query/compiler/joins.d.cts +11 -0
  29. package/dist/cjs/query/compiler/order-by.cjs +89 -0
  30. package/dist/cjs/query/compiler/order-by.cjs.map +1 -0
  31. package/dist/cjs/query/compiler/order-by.d.cts +9 -0
  32. package/dist/cjs/query/compiler/select.cjs +57 -0
  33. package/dist/cjs/query/compiler/select.cjs.map +1 -0
  34. package/dist/cjs/query/compiler/select.d.cts +15 -0
  35. package/dist/cjs/query/index.d.cts +6 -5
  36. package/dist/cjs/query/ir.cjs +57 -0
  37. package/dist/cjs/query/ir.cjs.map +1 -0
  38. package/dist/cjs/query/ir.d.cts +81 -0
  39. package/dist/cjs/query/live-query-collection.cjs +224 -0
  40. package/dist/cjs/query/live-query-collection.cjs.map +1 -0
  41. package/dist/cjs/query/live-query-collection.d.cts +124 -0
  42. package/dist/cjs/transactions.cjs +20 -13
  43. package/dist/cjs/transactions.cjs.map +1 -1
  44. package/dist/cjs/transactions.d.cts +10 -1
  45. package/dist/cjs/types.d.cts +13 -0
  46. package/dist/esm/collection.d.ts +18 -21
  47. package/dist/esm/collection.js +118 -105
  48. package/dist/esm/collection.js.map +1 -1
  49. package/dist/esm/index.d.ts +0 -1
  50. package/dist/esm/index.js +34 -12
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/query/builder/functions.d.ts +38 -0
  53. package/dist/esm/query/builder/functions.js +107 -0
  54. package/dist/esm/query/builder/functions.js.map +1 -0
  55. package/dist/esm/query/builder/index.d.ts +324 -0
  56. package/dist/esm/query/builder/index.js +499 -0
  57. package/dist/esm/query/builder/index.js.map +1 -0
  58. package/dist/esm/query/builder/ref-proxy.d.ts +28 -0
  59. package/dist/esm/query/builder/ref-proxy.js +96 -0
  60. package/dist/esm/query/builder/ref-proxy.js.map +1 -0
  61. package/dist/esm/query/builder/types.d.ts +80 -0
  62. package/dist/esm/query/compiler/evaluators.d.ts +11 -0
  63. package/dist/esm/query/compiler/evaluators.js +261 -0
  64. package/dist/esm/query/compiler/evaluators.js.map +1 -0
  65. package/dist/esm/query/compiler/group-by.d.ts +7 -0
  66. package/dist/esm/query/compiler/group-by.js +271 -0
  67. package/dist/esm/query/compiler/group-by.js.map +1 -0
  68. package/dist/esm/query/compiler/index.d.ts +15 -0
  69. package/dist/esm/query/compiler/index.js +181 -0
  70. package/dist/esm/query/compiler/index.js.map +1 -0
  71. package/dist/esm/query/compiler/joins.d.ts +11 -0
  72. package/dist/esm/query/compiler/joins.js +116 -0
  73. package/dist/esm/query/compiler/joins.js.map +1 -0
  74. package/dist/esm/query/compiler/order-by.d.ts +9 -0
  75. package/dist/esm/query/compiler/order-by.js +89 -0
  76. package/dist/esm/query/compiler/order-by.js.map +1 -0
  77. package/dist/esm/query/compiler/select.d.ts +15 -0
  78. package/dist/esm/query/compiler/select.js +57 -0
  79. package/dist/esm/query/compiler/select.js.map +1 -0
  80. package/dist/esm/query/index.d.ts +6 -5
  81. package/dist/esm/query/ir.d.ts +81 -0
  82. package/dist/esm/query/ir.js +57 -0
  83. package/dist/esm/query/ir.js.map +1 -0
  84. package/dist/esm/query/live-query-collection.d.ts +124 -0
  85. package/dist/esm/query/live-query-collection.js +224 -0
  86. package/dist/esm/query/live-query-collection.js.map +1 -0
  87. package/dist/esm/transactions.d.ts +10 -1
  88. package/dist/esm/transactions.js +20 -13
  89. package/dist/esm/transactions.js.map +1 -1
  90. package/dist/esm/types.d.ts +13 -0
  91. package/package.json +3 -4
  92. package/src/collection.ts +152 -129
  93. package/src/index.ts +0 -1
  94. package/src/query/builder/functions.ts +267 -0
  95. package/src/query/builder/index.ts +648 -0
  96. package/src/query/builder/ref-proxy.ts +156 -0
  97. package/src/query/builder/types.ts +278 -0
  98. package/src/query/compiler/evaluators.ts +315 -0
  99. package/src/query/compiler/group-by.ts +428 -0
  100. package/src/query/compiler/index.ts +276 -0
  101. package/src/query/compiler/joins.ts +228 -0
  102. package/src/query/compiler/order-by.ts +139 -0
  103. package/src/query/compiler/select.ts +173 -0
  104. package/src/query/index.ts +64 -5
  105. package/src/query/ir.ts +128 -0
  106. package/src/query/live-query-collection.ts +509 -0
  107. package/src/transactions.ts +27 -16
  108. package/src/types.ts +15 -0
  109. package/dist/cjs/query/compiled-query.cjs +0 -160
  110. package/dist/cjs/query/compiled-query.cjs.map +0 -1
  111. package/dist/cjs/query/compiled-query.d.cts +0 -20
  112. package/dist/cjs/query/evaluators.cjs +0 -161
  113. package/dist/cjs/query/evaluators.cjs.map +0 -1
  114. package/dist/cjs/query/evaluators.d.cts +0 -14
  115. package/dist/cjs/query/extractors.cjs +0 -122
  116. package/dist/cjs/query/extractors.cjs.map +0 -1
  117. package/dist/cjs/query/extractors.d.cts +0 -22
  118. package/dist/cjs/query/functions.cjs +0 -152
  119. package/dist/cjs/query/functions.cjs.map +0 -1
  120. package/dist/cjs/query/functions.d.cts +0 -21
  121. package/dist/cjs/query/group-by.cjs +0 -88
  122. package/dist/cjs/query/group-by.cjs.map +0 -1
  123. package/dist/cjs/query/group-by.d.cts +0 -40
  124. package/dist/cjs/query/joins.cjs +0 -141
  125. package/dist/cjs/query/joins.cjs.map +0 -1
  126. package/dist/cjs/query/joins.d.cts +0 -14
  127. package/dist/cjs/query/order-by.cjs +0 -185
  128. package/dist/cjs/query/order-by.cjs.map +0 -1
  129. package/dist/cjs/query/order-by.d.cts +0 -3
  130. package/dist/cjs/query/pipeline-compiler.cjs +0 -89
  131. package/dist/cjs/query/pipeline-compiler.cjs.map +0 -1
  132. package/dist/cjs/query/pipeline-compiler.d.cts +0 -10
  133. package/dist/cjs/query/query-builder.cjs +0 -307
  134. package/dist/cjs/query/query-builder.cjs.map +0 -1
  135. package/dist/cjs/query/query-builder.d.cts +0 -225
  136. package/dist/cjs/query/schema.d.cts +0 -100
  137. package/dist/cjs/query/select.cjs +0 -130
  138. package/dist/cjs/query/select.cjs.map +0 -1
  139. package/dist/cjs/query/select.d.cts +0 -3
  140. package/dist/cjs/query/types.d.cts +0 -189
  141. package/dist/cjs/query/utils.cjs +0 -154
  142. package/dist/cjs/query/utils.cjs.map +0 -1
  143. package/dist/cjs/query/utils.d.cts +0 -37
  144. package/dist/cjs/utils.cjs +0 -17
  145. package/dist/cjs/utils.cjs.map +0 -1
  146. package/dist/cjs/utils.d.cts +0 -3
  147. package/dist/esm/query/compiled-query.d.ts +0 -20
  148. package/dist/esm/query/compiled-query.js +0 -160
  149. package/dist/esm/query/compiled-query.js.map +0 -1
  150. package/dist/esm/query/evaluators.d.ts +0 -14
  151. package/dist/esm/query/evaluators.js +0 -161
  152. package/dist/esm/query/evaluators.js.map +0 -1
  153. package/dist/esm/query/extractors.d.ts +0 -22
  154. package/dist/esm/query/extractors.js +0 -122
  155. package/dist/esm/query/extractors.js.map +0 -1
  156. package/dist/esm/query/functions.d.ts +0 -21
  157. package/dist/esm/query/functions.js +0 -152
  158. package/dist/esm/query/functions.js.map +0 -1
  159. package/dist/esm/query/group-by.d.ts +0 -40
  160. package/dist/esm/query/group-by.js +0 -88
  161. package/dist/esm/query/group-by.js.map +0 -1
  162. package/dist/esm/query/joins.d.ts +0 -14
  163. package/dist/esm/query/joins.js +0 -141
  164. package/dist/esm/query/joins.js.map +0 -1
  165. package/dist/esm/query/order-by.d.ts +0 -3
  166. package/dist/esm/query/order-by.js +0 -185
  167. package/dist/esm/query/order-by.js.map +0 -1
  168. package/dist/esm/query/pipeline-compiler.d.ts +0 -10
  169. package/dist/esm/query/pipeline-compiler.js +0 -89
  170. package/dist/esm/query/pipeline-compiler.js.map +0 -1
  171. package/dist/esm/query/query-builder.d.ts +0 -225
  172. package/dist/esm/query/query-builder.js +0 -307
  173. package/dist/esm/query/query-builder.js.map +0 -1
  174. package/dist/esm/query/schema.d.ts +0 -100
  175. package/dist/esm/query/select.d.ts +0 -3
  176. package/dist/esm/query/select.js +0 -130
  177. package/dist/esm/query/select.js.map +0 -1
  178. package/dist/esm/query/types.d.ts +0 -189
  179. package/dist/esm/query/utils.d.ts +0 -37
  180. package/dist/esm/query/utils.js +0 -154
  181. package/dist/esm/query/utils.js.map +0 -1
  182. package/dist/esm/utils.d.ts +0 -3
  183. package/dist/esm/utils.js +0 -17
  184. package/dist/esm/utils.js.map +0 -1
  185. package/src/query/compiled-query.ts +0 -234
  186. package/src/query/evaluators.ts +0 -250
  187. package/src/query/extractors.ts +0 -214
  188. package/src/query/functions.ts +0 -297
  189. package/src/query/group-by.ts +0 -139
  190. package/src/query/joins.ts +0 -260
  191. package/src/query/order-by.ts +0 -264
  192. package/src/query/pipeline-compiler.ts +0 -149
  193. package/src/query/query-builder.ts +0 -902
  194. package/src/query/schema.ts +0 -268
  195. package/src/query/select.ts +0 -208
  196. package/src/query/types.ts +0 -418
  197. package/src/query/utils.ts +0 -245
  198. package/src/utils.ts +0 -15
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref-proxy.js","sources":["../../../../src/query/builder/ref-proxy.ts"],"sourcesContent":["import { Ref, Value } from \"../ir.js\"\nimport type { BasicExpression } from \"../ir.js\"\n\nexport interface RefProxy<T = any> {\n /** @internal */\n readonly __refProxy: true\n /** @internal */\n readonly __path: Array<string>\n /** @internal */\n readonly __type: T\n}\n\n/**\n * Creates a proxy object that records property access paths\n * Used in callbacks like where, select, etc. to create type-safe references\n */\nexport function createRefProxy<T extends Record<string, any>>(\n aliases: Array<string>\n): RefProxy<T> & T {\n const cache = new Map<string, any>()\n const spreadSentinels = new Set<string>() // Track which aliases have been spread\n\n function createProxy(path: Array<string>): any {\n const pathKey = path.join(`.`)\n if (cache.has(pathKey)) {\n return cache.get(pathKey)\n }\n\n const proxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return path\n if (prop === `__type`) return undefined // Type is only for TypeScript inference\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const newPath = [...path, String(prop)]\n return createProxy(newPath)\n },\n\n has(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`)\n return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(target) {\n // If this is a table-level proxy (path length 1), mark it as spread\n if (path.length === 1) {\n const aliasName = path[0]!\n spreadSentinels.add(aliasName)\n }\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {\n return { enumerable: false, configurable: true }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n })\n\n cache.set(pathKey, proxy)\n return proxy\n }\n\n // Create the root proxy with all aliases as top-level properties\n const rootProxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return []\n if (prop === `__type`) return undefined // Type is only for TypeScript inference\n if (prop === `__spreadSentinels`) return spreadSentinels // Expose spread sentinels\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const propStr = String(prop)\n if (aliases.includes(propStr)) {\n return createProxy([propStr])\n }\n\n return undefined\n },\n\n has(target, prop) {\n if (\n prop === `__refProxy` ||\n prop === `__path` ||\n prop === `__type` ||\n prop === `__spreadSentinels`\n )\n return true\n if (typeof prop === `string` && aliases.includes(prop)) return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(_target) {\n return [...aliases, `__refProxy`, `__path`, `__type`, `__spreadSentinels`]\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (\n prop === `__refProxy` ||\n prop === `__path` ||\n prop === `__type` ||\n prop === `__spreadSentinels`\n ) {\n return { enumerable: false, configurable: true }\n }\n if (typeof prop === `string` && aliases.includes(prop)) {\n return { enumerable: true, configurable: true }\n }\n return undefined\n },\n })\n\n return rootProxy\n}\n\n/**\n * Converts a value to an Expression\n * If it's a RefProxy, creates a Ref, otherwise creates a Value\n */\nexport function toExpression<T = any>(value: T): BasicExpression<T>\nexport function toExpression(value: RefProxy<any>): BasicExpression<any>\nexport function toExpression(value: any): BasicExpression<any> {\n if (isRefProxy(value)) {\n return new Ref(value.__path)\n }\n // If it's already an Expression (Func, Ref, Value) or Agg, return it directly\n if (\n value &&\n typeof value === `object` &&\n `type` in value &&\n (value.type === `func` ||\n value.type === `ref` ||\n value.type === `val` ||\n value.type === `agg`)\n ) {\n return value\n }\n return new Value(value)\n}\n\n/**\n * Type guard to check if a value is a RefProxy\n */\nexport function isRefProxy(value: any): value is RefProxy {\n return value && typeof value === `object` && value.__refProxy === true\n}\n\n/**\n * Helper to create a Value expression from a literal\n */\nexport function val<T>(value: T): BasicExpression<T> {\n return new Value(value)\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { CollectionImpl } from '../../collection.js';
2
+ import { Aggregate, BasicExpression } from '../ir.js';
3
+ import { QueryBuilder } from './index.js';
4
+ export interface Context {
5
+ baseSchema: ContextSchema;
6
+ schema: ContextSchema;
7
+ fromSourceName: string;
8
+ hasJoins?: boolean;
9
+ joinTypes?: Record<string, `inner` | `left` | `right` | `full` | `outer` | `cross`>;
10
+ result?: any;
11
+ }
12
+ export type ContextSchema = Record<string, unknown>;
13
+ export type Source = {
14
+ [alias: string]: CollectionImpl<any, any> | QueryBuilder<Context>;
15
+ };
16
+ export type InferCollectionType<T> = T extends CollectionImpl<infer U> ? U : never;
17
+ export type SchemaFromSource<T extends Source> = Prettify<{
18
+ [K in keyof T]: T[K] extends CollectionImpl<infer U> ? U : T[K] extends QueryBuilder<infer TContext> ? GetResult<TContext> : never;
19
+ }>;
20
+ export type GetAliases<TContext extends Context> = keyof TContext[`schema`];
21
+ export type WhereCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
22
+ export type SelectObject<T extends Record<string, BasicExpression | Aggregate | RefProxy | RefProxyFor<any>> = Record<string, BasicExpression | Aggregate | RefProxy | RefProxyFor<any>>> = T;
23
+ export type ResultTypeFromSelect<TSelectObject> = {
24
+ [K in keyof TSelectObject]: TSelectObject[K] extends RefProxy<infer T> ? T : TSelectObject[K] extends BasicExpression<infer T> ? T : TSelectObject[K] extends Aggregate<infer T> ? T : TSelectObject[K] extends RefProxyFor<infer T> ? T : never;
25
+ };
26
+ export type OrderByCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
27
+ export type GroupByCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
28
+ export type JoinOnCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
29
+ export type RefProxyForContext<TContext extends Context> = {
30
+ [K in keyof TContext[`schema`]]: RefProxyFor<TContext[`schema`][K]>;
31
+ };
32
+ type IsExactlyUndefined<T> = [T] extends [undefined] ? true : false;
33
+ type IsOptional<T> = undefined extends T ? true : false;
34
+ type NonUndefined<T> = T extends undefined ? never : T;
35
+ export type RefProxyFor<T> = OmitRefProxy<IsExactlyUndefined<T> extends true ? RefProxy<T> : IsOptional<T> extends true ? NonUndefined<T> extends Record<string, any> ? {
36
+ [K in keyof NonUndefined<T>]: NonUndefined<T>[K] extends Record<string, any> ? RefProxyFor<NonUndefined<T>[K] | undefined> & RefProxy<NonUndefined<T>[K] | undefined> : RefProxy<NonUndefined<T>[K] | undefined>;
37
+ } & RefProxy<T> : RefProxy<T> : T extends Record<string, any> ? {
38
+ [K in keyof T]: T[K] extends Record<string, any> ? RefProxyFor<T[K]> & RefProxy<T[K]> : RefProxy<T[K]>;
39
+ } & RefProxy<T> : RefProxy<T>>;
40
+ type OmitRefProxy<T> = Omit<T, `__refProxy` | `__path` | `__type`>;
41
+ export interface RefProxy<T = any> {
42
+ /** @internal */
43
+ readonly __refProxy: true;
44
+ /** @internal */
45
+ readonly __path: Array<string>;
46
+ /** @internal */
47
+ readonly __type: T;
48
+ }
49
+ export type MergeContextWithJoinType<TContext extends Context, TNewSchema extends ContextSchema, TJoinType extends `inner` | `left` | `right` | `full` | `outer` | `cross`> = {
50
+ baseSchema: TContext[`baseSchema`];
51
+ schema: ApplyJoinOptionalityToMergedSchema<TContext[`schema`], TNewSchema, TJoinType, TContext[`fromSourceName`]>;
52
+ fromSourceName: TContext[`fromSourceName`];
53
+ hasJoins: true;
54
+ joinTypes: (TContext[`joinTypes`] extends Record<string, any> ? TContext[`joinTypes`] : {}) & {
55
+ [K in keyof TNewSchema & string]: TJoinType;
56
+ };
57
+ result: TContext[`result`];
58
+ };
59
+ export type ApplyJoinOptionalityToMergedSchema<TExistingSchema extends ContextSchema, TNewSchema extends ContextSchema, TJoinType extends `inner` | `left` | `right` | `full` | `outer` | `cross`, TFromSourceName extends string> = {
60
+ [K in keyof TExistingSchema]: K extends TFromSourceName ? TJoinType extends `right` | `full` ? TExistingSchema[K] | undefined : TExistingSchema[K] : TExistingSchema[K];
61
+ } & {
62
+ [K in keyof TNewSchema]: TJoinType extends `left` | `full` ? // New table becomes optional for left and full joins
63
+ TNewSchema[K] | undefined : TNewSchema[K];
64
+ };
65
+ export type GetResult<TContext extends Context> = Prettify<TContext[`result`] extends object ? TContext[`result`] : TContext[`hasJoins`] extends true ? TContext[`schema`] : TContext[`schema`][TContext[`fromSourceName`]]>;
66
+ export type ApplyJoinOptionalityToSchema<TSchema extends ContextSchema, TJoinTypes extends Record<string, string>, TFromSourceName extends string> = {
67
+ [K in keyof TSchema]: K extends TFromSourceName ? HasJoinType<TJoinTypes, `right` | `full`> extends true ? TSchema[K] | undefined : TSchema[K] : K extends keyof TJoinTypes ? TJoinTypes[K] extends `left` | `full` ? TSchema[K] | undefined : IsTableMadeOptionalBySubsequentJoins<K, TJoinTypes, TFromSourceName> extends true ? TSchema[K] | undefined : TSchema[K] : TSchema[K];
68
+ };
69
+ type IsTableMadeOptionalBySubsequentJoins<TTableAlias extends string | number | symbol, TJoinTypes extends Record<string, string>, TFromSourceName extends string> = TTableAlias extends TFromSourceName ? HasJoinType<TJoinTypes, `right` | `full`> : false;
70
+ export type HasJoinType<TJoinTypes extends Record<string, string>, TTargetTypes extends string> = true extends {
71
+ [K in keyof TJoinTypes]: TJoinTypes[K] extends TTargetTypes ? true : false;
72
+ }[keyof TJoinTypes] ? true : false;
73
+ export type MergeContext<TContext extends Context, TNewSchema extends ContextSchema> = MergeContextWithJoinType<TContext, TNewSchema, `left`>;
74
+ export type WithResult<TContext extends Context, TResult> = Prettify<Omit<TContext, `result`> & {
75
+ result: Prettify<TResult>;
76
+ }>;
77
+ export type Prettify<T> = {
78
+ [K in keyof T]: T[K];
79
+ } & {};
80
+ export {};
@@ -0,0 +1,11 @@
1
+ import { BasicExpression } from '../ir.js';
2
+ import { NamespacedRow } from '../../types.js';
3
+ /**
4
+ * Compiled expression evaluator function type
5
+ */
6
+ export type CompiledExpression = (namespacedRow: NamespacedRow) => any;
7
+ /**
8
+ * Compiles an expression into an optimized evaluator function.
9
+ * This eliminates branching during evaluation by pre-compiling the expression structure.
10
+ */
11
+ export declare function compileExpression(expr: BasicExpression): CompiledExpression;
@@ -0,0 +1,261 @@
1
+ function compileExpression(expr) {
2
+ switch (expr.type) {
3
+ case `val`: {
4
+ const value = expr.value;
5
+ return () => value;
6
+ }
7
+ case `ref`: {
8
+ return compileRef(expr);
9
+ }
10
+ case `func`: {
11
+ return compileFunction(expr);
12
+ }
13
+ default:
14
+ throw new Error(`Unknown expression type: ${expr.type}`);
15
+ }
16
+ }
17
+ function compileRef(ref) {
18
+ const [tableAlias, ...propertyPath] = ref.path;
19
+ if (!tableAlias) {
20
+ throw new Error(`Reference path cannot be empty`);
21
+ }
22
+ if (propertyPath.length === 0) {
23
+ return (namespacedRow) => namespacedRow[tableAlias];
24
+ } else if (propertyPath.length === 1) {
25
+ const prop = propertyPath[0];
26
+ return (namespacedRow) => {
27
+ const tableData = namespacedRow[tableAlias];
28
+ return tableData == null ? void 0 : tableData[prop];
29
+ };
30
+ } else {
31
+ return (namespacedRow) => {
32
+ const tableData = namespacedRow[tableAlias];
33
+ if (tableData === void 0) {
34
+ return void 0;
35
+ }
36
+ let value = tableData;
37
+ for (const prop of propertyPath) {
38
+ if (value == null) {
39
+ return value;
40
+ }
41
+ value = value[prop];
42
+ }
43
+ return value;
44
+ };
45
+ }
46
+ }
47
+ function compileFunction(func) {
48
+ const compiledArgs = func.args.map(compileExpression);
49
+ switch (func.name) {
50
+ // Comparison operators
51
+ case `eq`: {
52
+ const argA = compiledArgs[0];
53
+ const argB = compiledArgs[1];
54
+ return (namespacedRow) => {
55
+ const a = argA(namespacedRow);
56
+ const b = argB(namespacedRow);
57
+ return a === b;
58
+ };
59
+ }
60
+ case `gt`: {
61
+ const argA = compiledArgs[0];
62
+ const argB = compiledArgs[1];
63
+ return (namespacedRow) => {
64
+ const a = argA(namespacedRow);
65
+ const b = argB(namespacedRow);
66
+ return a > b;
67
+ };
68
+ }
69
+ case `gte`: {
70
+ const argA = compiledArgs[0];
71
+ const argB = compiledArgs[1];
72
+ return (namespacedRow) => {
73
+ const a = argA(namespacedRow);
74
+ const b = argB(namespacedRow);
75
+ return a >= b;
76
+ };
77
+ }
78
+ case `lt`: {
79
+ const argA = compiledArgs[0];
80
+ const argB = compiledArgs[1];
81
+ return (namespacedRow) => {
82
+ const a = argA(namespacedRow);
83
+ const b = argB(namespacedRow);
84
+ return a < b;
85
+ };
86
+ }
87
+ case `lte`: {
88
+ const argA = compiledArgs[0];
89
+ const argB = compiledArgs[1];
90
+ return (namespacedRow) => {
91
+ const a = argA(namespacedRow);
92
+ const b = argB(namespacedRow);
93
+ return a <= b;
94
+ };
95
+ }
96
+ // Boolean operators
97
+ case `and`:
98
+ return (namespacedRow) => {
99
+ for (const compiledArg of compiledArgs) {
100
+ if (!compiledArg(namespacedRow)) {
101
+ return false;
102
+ }
103
+ }
104
+ return true;
105
+ };
106
+ case `or`:
107
+ return (namespacedRow) => {
108
+ for (const compiledArg of compiledArgs) {
109
+ if (compiledArg(namespacedRow)) {
110
+ return true;
111
+ }
112
+ }
113
+ return false;
114
+ };
115
+ case `not`: {
116
+ const arg = compiledArgs[0];
117
+ return (namespacedRow) => !arg(namespacedRow);
118
+ }
119
+ // Array operators
120
+ case `in`: {
121
+ const valueEvaluator = compiledArgs[0];
122
+ const arrayEvaluator = compiledArgs[1];
123
+ return (namespacedRow) => {
124
+ const value = valueEvaluator(namespacedRow);
125
+ const array = arrayEvaluator(namespacedRow);
126
+ if (!Array.isArray(array)) {
127
+ return false;
128
+ }
129
+ return array.includes(value);
130
+ };
131
+ }
132
+ // String operators
133
+ case `like`: {
134
+ const valueEvaluator = compiledArgs[0];
135
+ const patternEvaluator = compiledArgs[1];
136
+ return (namespacedRow) => {
137
+ const value = valueEvaluator(namespacedRow);
138
+ const pattern = patternEvaluator(namespacedRow);
139
+ return evaluateLike(value, pattern, false);
140
+ };
141
+ }
142
+ case `ilike`: {
143
+ const valueEvaluator = compiledArgs[0];
144
+ const patternEvaluator = compiledArgs[1];
145
+ return (namespacedRow) => {
146
+ const value = valueEvaluator(namespacedRow);
147
+ const pattern = patternEvaluator(namespacedRow);
148
+ return evaluateLike(value, pattern, true);
149
+ };
150
+ }
151
+ // String functions
152
+ case `upper`: {
153
+ const arg = compiledArgs[0];
154
+ return (namespacedRow) => {
155
+ const value = arg(namespacedRow);
156
+ return typeof value === `string` ? value.toUpperCase() : value;
157
+ };
158
+ }
159
+ case `lower`: {
160
+ const arg = compiledArgs[0];
161
+ return (namespacedRow) => {
162
+ const value = arg(namespacedRow);
163
+ return typeof value === `string` ? value.toLowerCase() : value;
164
+ };
165
+ }
166
+ case `length`: {
167
+ const arg = compiledArgs[0];
168
+ return (namespacedRow) => {
169
+ const value = arg(namespacedRow);
170
+ if (typeof value === `string`) {
171
+ return value.length;
172
+ }
173
+ if (Array.isArray(value)) {
174
+ return value.length;
175
+ }
176
+ return 0;
177
+ };
178
+ }
179
+ case `concat`:
180
+ return (namespacedRow) => {
181
+ return compiledArgs.map((evaluator) => {
182
+ const arg = evaluator(namespacedRow);
183
+ try {
184
+ return String(arg ?? ``);
185
+ } catch {
186
+ try {
187
+ return JSON.stringify(arg) || ``;
188
+ } catch {
189
+ return `[object]`;
190
+ }
191
+ }
192
+ }).join(``);
193
+ };
194
+ case `coalesce`:
195
+ return (namespacedRow) => {
196
+ for (const evaluator of compiledArgs) {
197
+ const value = evaluator(namespacedRow);
198
+ if (value !== null && value !== void 0) {
199
+ return value;
200
+ }
201
+ }
202
+ return null;
203
+ };
204
+ // Math functions
205
+ case `add`: {
206
+ const argA = compiledArgs[0];
207
+ const argB = compiledArgs[1];
208
+ return (namespacedRow) => {
209
+ const a = argA(namespacedRow);
210
+ const b = argB(namespacedRow);
211
+ return (a ?? 0) + (b ?? 0);
212
+ };
213
+ }
214
+ case `subtract`: {
215
+ const argA = compiledArgs[0];
216
+ const argB = compiledArgs[1];
217
+ return (namespacedRow) => {
218
+ const a = argA(namespacedRow);
219
+ const b = argB(namespacedRow);
220
+ return (a ?? 0) - (b ?? 0);
221
+ };
222
+ }
223
+ case `multiply`: {
224
+ const argA = compiledArgs[0];
225
+ const argB = compiledArgs[1];
226
+ return (namespacedRow) => {
227
+ const a = argA(namespacedRow);
228
+ const b = argB(namespacedRow);
229
+ return (a ?? 0) * (b ?? 0);
230
+ };
231
+ }
232
+ case `divide`: {
233
+ const argA = compiledArgs[0];
234
+ const argB = compiledArgs[1];
235
+ return (namespacedRow) => {
236
+ const a = argA(namespacedRow);
237
+ const b = argB(namespacedRow);
238
+ const divisor = b ?? 0;
239
+ return divisor !== 0 ? (a ?? 0) / divisor : null;
240
+ };
241
+ }
242
+ default:
243
+ throw new Error(`Unknown function: ${func.name}`);
244
+ }
245
+ }
246
+ function evaluateLike(value, pattern, caseInsensitive) {
247
+ if (typeof value !== `string` || typeof pattern !== `string`) {
248
+ return false;
249
+ }
250
+ const searchValue = caseInsensitive ? value.toLowerCase() : value;
251
+ const searchPattern = caseInsensitive ? pattern.toLowerCase() : pattern;
252
+ let regexPattern = searchPattern.replace(/[.*+?^${}()|[\]\\]/g, `\\$&`);
253
+ regexPattern = regexPattern.replace(/%/g, `.*`);
254
+ regexPattern = regexPattern.replace(/_/g, `.`);
255
+ const regex = new RegExp(`^${regexPattern}$`);
256
+ return regex.test(searchValue);
257
+ }
258
+ export {
259
+ compileExpression
260
+ };
261
+ //# sourceMappingURL=evaluators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluators.js","sources":["../../../../src/query/compiler/evaluators.ts"],"sourcesContent":["import type { BasicExpression, Func, Ref } from \"../ir.js\"\nimport type { NamespacedRow } from \"../../types.js\"\n\n/**\n * Compiled expression evaluator function type\n */\nexport type CompiledExpression = (namespacedRow: NamespacedRow) => any\n\n/**\n * Compiles an expression into an optimized evaluator function.\n * This eliminates branching during evaluation by pre-compiling the expression structure.\n */\nexport function compileExpression(expr: BasicExpression): CompiledExpression {\n switch (expr.type) {\n case `val`: {\n // For constant values, return a function that just returns the value\n const value = expr.value\n return () => value\n }\n\n case `ref`: {\n // For references, pre-compile the property path navigation\n return compileRef(expr)\n }\n\n case `func`: {\n // For functions, pre-compile the function and its arguments\n return compileFunction(expr)\n }\n\n default:\n throw new Error(`Unknown expression type: ${(expr as any).type}`)\n }\n}\n\n/**\n * Compiles a reference expression into an optimized evaluator\n */\nfunction compileRef(ref: Ref): CompiledExpression {\n const [tableAlias, ...propertyPath] = ref.path\n\n if (!tableAlias) {\n throw new Error(`Reference path cannot be empty`)\n }\n\n // Pre-compile the property path navigation\n if (propertyPath.length === 0) {\n // Simple table reference\n return (namespacedRow) => namespacedRow[tableAlias]\n } else if (propertyPath.length === 1) {\n // Single property access - most common case\n const prop = propertyPath[0]!\n return (namespacedRow) => {\n const tableData = namespacedRow[tableAlias]\n return tableData?.[prop]\n }\n } else {\n // Multiple property navigation\n return (namespacedRow) => {\n const tableData = namespacedRow[tableAlias]\n if (tableData === undefined) {\n return undefined\n }\n\n let value: any = tableData\n for (const prop of propertyPath) {\n if (value == null) {\n return value\n }\n value = value[prop]\n }\n return value\n }\n }\n}\n\n/**\n * Compiles a function expression into an optimized evaluator\n */\nfunction compileFunction(func: Func): CompiledExpression {\n // Pre-compile all arguments\n const compiledArgs = func.args.map(compileExpression)\n\n switch (func.name) {\n // Comparison operators\n case `eq`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a === b\n }\n }\n case `gt`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a > b\n }\n }\n case `gte`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a >= b\n }\n }\n case `lt`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a < b\n }\n }\n case `lte`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return a <= b\n }\n }\n\n // Boolean operators\n case `and`:\n return (namespacedRow) => {\n for (const compiledArg of compiledArgs) {\n if (!compiledArg(namespacedRow)) {\n return false\n }\n }\n return true\n }\n case `or`:\n return (namespacedRow) => {\n for (const compiledArg of compiledArgs) {\n if (compiledArg(namespacedRow)) {\n return true\n }\n }\n return false\n }\n case `not`: {\n const arg = compiledArgs[0]!\n return (namespacedRow) => !arg(namespacedRow)\n }\n\n // Array operators\n case `in`: {\n const valueEvaluator = compiledArgs[0]!\n const arrayEvaluator = compiledArgs[1]!\n return (namespacedRow) => {\n const value = valueEvaluator(namespacedRow)\n const array = arrayEvaluator(namespacedRow)\n if (!Array.isArray(array)) {\n return false\n }\n return array.includes(value)\n }\n }\n\n // String operators\n case `like`: {\n const valueEvaluator = compiledArgs[0]!\n const patternEvaluator = compiledArgs[1]!\n return (namespacedRow) => {\n const value = valueEvaluator(namespacedRow)\n const pattern = patternEvaluator(namespacedRow)\n return evaluateLike(value, pattern, false)\n }\n }\n case `ilike`: {\n const valueEvaluator = compiledArgs[0]!\n const patternEvaluator = compiledArgs[1]!\n return (namespacedRow) => {\n const value = valueEvaluator(namespacedRow)\n const pattern = patternEvaluator(namespacedRow)\n return evaluateLike(value, pattern, true)\n }\n }\n\n // String functions\n case `upper`: {\n const arg = compiledArgs[0]!\n return (namespacedRow) => {\n const value = arg(namespacedRow)\n return typeof value === `string` ? value.toUpperCase() : value\n }\n }\n case `lower`: {\n const arg = compiledArgs[0]!\n return (namespacedRow) => {\n const value = arg(namespacedRow)\n return typeof value === `string` ? value.toLowerCase() : value\n }\n }\n case `length`: {\n const arg = compiledArgs[0]!\n return (namespacedRow) => {\n const value = arg(namespacedRow)\n if (typeof value === `string`) {\n return value.length\n }\n if (Array.isArray(value)) {\n return value.length\n }\n return 0\n }\n }\n case `concat`:\n return (namespacedRow) => {\n return compiledArgs\n .map((evaluator) => {\n const arg = evaluator(namespacedRow)\n try {\n return String(arg ?? ``)\n } catch {\n try {\n return JSON.stringify(arg) || ``\n } catch {\n return `[object]`\n }\n }\n })\n .join(``)\n }\n case `coalesce`:\n return (namespacedRow) => {\n for (const evaluator of compiledArgs) {\n const value = evaluator(namespacedRow)\n if (value !== null && value !== undefined) {\n return value\n }\n }\n return null\n }\n\n // Math functions\n case `add`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return (a ?? 0) + (b ?? 0)\n }\n }\n case `subtract`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return (a ?? 0) - (b ?? 0)\n }\n }\n case `multiply`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n return (a ?? 0) * (b ?? 0)\n }\n }\n case `divide`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (namespacedRow) => {\n const a = argA(namespacedRow)\n const b = argB(namespacedRow)\n const divisor = b ?? 0\n return divisor !== 0 ? (a ?? 0) / divisor : null\n }\n }\n\n default:\n throw new Error(`Unknown function: ${func.name}`)\n }\n}\n\n/**\n * Evaluates LIKE/ILIKE patterns\n */\nfunction evaluateLike(\n value: any,\n pattern: any,\n caseInsensitive: boolean\n): boolean {\n if (typeof value !== `string` || typeof pattern !== `string`) {\n return false\n }\n\n const searchValue = caseInsensitive ? value.toLowerCase() : value\n const searchPattern = caseInsensitive ? pattern.toLowerCase() : pattern\n\n // Convert SQL LIKE pattern to regex\n // First escape all regex special chars except % and _\n let regexPattern = searchPattern.replace(/[.*+?^${}()|[\\]\\\\]/g, `\\\\$&`)\n\n // Then convert SQL wildcards to regex\n regexPattern = regexPattern.replace(/%/g, `.*`) // % matches any sequence\n regexPattern = regexPattern.replace(/_/g, `.`) // _ matches any single char\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(searchValue)\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { GroupBy, Having, Select } from '../ir.js';
2
+ import { NamespacedAndKeyedStream } from '../../types.js';
3
+ /**
4
+ * Processes the GROUP BY clause with optional HAVING and SELECT
5
+ * Works with the new __select_results structure from early SELECT processing
6
+ */
7
+ export declare function processGroupBy(pipeline: NamespacedAndKeyedStream, groupByClause: GroupBy, havingClauses?: Array<Having>, selectClause?: Select, fnHavingClauses?: Array<(row: any) => any>): NamespacedAndKeyedStream;
@@ -0,0 +1,271 @@
1
+ import { groupBy, map, filter, groupByOperators } from "@electric-sql/d2mini";
2
+ import { Ref, Func } from "../ir.js";
3
+ import { compileExpression } from "./evaluators.js";
4
+ const { sum, count, avg, min, max } = groupByOperators;
5
+ function validateAndCreateMapping(groupByClause, selectClause) {
6
+ const selectToGroupByIndex = /* @__PURE__ */ new Map();
7
+ const groupByExpressions = [...groupByClause];
8
+ if (!selectClause) {
9
+ return { selectToGroupByIndex, groupByExpressions };
10
+ }
11
+ for (const [alias, expr] of Object.entries(selectClause)) {
12
+ if (expr.type === `agg`) {
13
+ continue;
14
+ }
15
+ const groupIndex = groupByExpressions.findIndex(
16
+ (groupExpr) => expressionsEqual(expr, groupExpr)
17
+ );
18
+ if (groupIndex === -1) {
19
+ throw new Error(
20
+ `Non-aggregate expression '${alias}' in SELECT must also appear in GROUP BY clause`
21
+ );
22
+ }
23
+ selectToGroupByIndex.set(alias, groupIndex);
24
+ }
25
+ return { selectToGroupByIndex, groupByExpressions };
26
+ }
27
+ function processGroupBy(pipeline, groupByClause, havingClauses, selectClause, fnHavingClauses) {
28
+ if (groupByClause.length === 0) {
29
+ const aggregates2 = {};
30
+ if (selectClause) {
31
+ for (const [alias, expr] of Object.entries(selectClause)) {
32
+ if (expr.type === `agg`) {
33
+ const aggExpr = expr;
34
+ aggregates2[alias] = getAggregateFunction(aggExpr);
35
+ }
36
+ }
37
+ }
38
+ const keyExtractor2 = () => ({ __singleGroup: true });
39
+ pipeline = pipeline.pipe(
40
+ groupBy(keyExtractor2, aggregates2)
41
+ );
42
+ pipeline = pipeline.pipe(
43
+ map(([, aggregatedRow]) => {
44
+ const selectResults = aggregatedRow.__select_results || {};
45
+ const finalResults = { ...selectResults };
46
+ if (selectClause) {
47
+ for (const [alias, expr] of Object.entries(selectClause)) {
48
+ if (expr.type === `agg`) {
49
+ finalResults[alias] = aggregatedRow[alias];
50
+ }
51
+ }
52
+ }
53
+ return [
54
+ `single_group`,
55
+ {
56
+ ...aggregatedRow,
57
+ __select_results: finalResults
58
+ }
59
+ ];
60
+ })
61
+ );
62
+ if (havingClauses && havingClauses.length > 0) {
63
+ for (const havingClause of havingClauses) {
64
+ const transformedHavingClause = transformHavingClause(
65
+ havingClause,
66
+ selectClause || {}
67
+ );
68
+ const compiledHaving = compileExpression(transformedHavingClause);
69
+ pipeline = pipeline.pipe(
70
+ filter(([, row]) => {
71
+ const namespacedRow = { result: row.__select_results };
72
+ return compiledHaving(namespacedRow);
73
+ })
74
+ );
75
+ }
76
+ }
77
+ if (fnHavingClauses && fnHavingClauses.length > 0) {
78
+ for (const fnHaving of fnHavingClauses) {
79
+ pipeline = pipeline.pipe(
80
+ filter(([, row]) => {
81
+ const namespacedRow = { result: row.__select_results };
82
+ return fnHaving(namespacedRow);
83
+ })
84
+ );
85
+ }
86
+ }
87
+ return pipeline;
88
+ }
89
+ const mapping = validateAndCreateMapping(groupByClause, selectClause);
90
+ const compiledGroupByExpressions = groupByClause.map(compileExpression);
91
+ const keyExtractor = ([, row]) => {
92
+ const namespacedRow = { ...row };
93
+ delete namespacedRow.__select_results;
94
+ const key = {};
95
+ for (let i = 0; i < groupByClause.length; i++) {
96
+ const compiledExpr = compiledGroupByExpressions[i];
97
+ const value = compiledExpr(namespacedRow);
98
+ key[`__key_${i}`] = value;
99
+ }
100
+ return key;
101
+ };
102
+ const aggregates = {};
103
+ if (selectClause) {
104
+ for (const [alias, expr] of Object.entries(selectClause)) {
105
+ if (expr.type === `agg`) {
106
+ const aggExpr = expr;
107
+ aggregates[alias] = getAggregateFunction(aggExpr);
108
+ }
109
+ }
110
+ }
111
+ pipeline = pipeline.pipe(groupBy(keyExtractor, aggregates));
112
+ pipeline = pipeline.pipe(
113
+ map(([, aggregatedRow]) => {
114
+ const selectResults = aggregatedRow.__select_results || {};
115
+ const finalResults = {};
116
+ if (selectClause) {
117
+ for (const [alias, expr] of Object.entries(selectClause)) {
118
+ if (expr.type !== `agg`) {
119
+ const groupIndex = mapping.selectToGroupByIndex.get(alias);
120
+ if (groupIndex !== void 0) {
121
+ finalResults[alias] = aggregatedRow[`__key_${groupIndex}`];
122
+ } else {
123
+ finalResults[alias] = selectResults[alias];
124
+ }
125
+ } else {
126
+ finalResults[alias] = aggregatedRow[alias];
127
+ }
128
+ }
129
+ } else {
130
+ for (let i = 0; i < groupByClause.length; i++) {
131
+ finalResults[`__key_${i}`] = aggregatedRow[`__key_${i}`];
132
+ }
133
+ }
134
+ let finalKey;
135
+ if (groupByClause.length === 1) {
136
+ finalKey = aggregatedRow[`__key_0`];
137
+ } else {
138
+ const keyParts = [];
139
+ for (let i = 0; i < groupByClause.length; i++) {
140
+ keyParts.push(aggregatedRow[`__key_${i}`]);
141
+ }
142
+ finalKey = JSON.stringify(keyParts);
143
+ }
144
+ return [
145
+ finalKey,
146
+ {
147
+ ...aggregatedRow,
148
+ __select_results: finalResults
149
+ }
150
+ ];
151
+ })
152
+ );
153
+ if (havingClauses && havingClauses.length > 0) {
154
+ for (const havingClause of havingClauses) {
155
+ const transformedHavingClause = transformHavingClause(
156
+ havingClause,
157
+ selectClause || {}
158
+ );
159
+ const compiledHaving = compileExpression(transformedHavingClause);
160
+ pipeline = pipeline.pipe(
161
+ filter(([, row]) => {
162
+ const namespacedRow = { result: row.__select_results };
163
+ return compiledHaving(namespacedRow);
164
+ })
165
+ );
166
+ }
167
+ }
168
+ if (fnHavingClauses && fnHavingClauses.length > 0) {
169
+ for (const fnHaving of fnHavingClauses) {
170
+ pipeline = pipeline.pipe(
171
+ filter(([, row]) => {
172
+ const namespacedRow = { result: row.__select_results };
173
+ return fnHaving(namespacedRow);
174
+ })
175
+ );
176
+ }
177
+ }
178
+ return pipeline;
179
+ }
180
+ function expressionsEqual(expr1, expr2) {
181
+ var _a, _b, _c, _d;
182
+ if (!expr1 || !expr2) return false;
183
+ if (expr1.type !== expr2.type) return false;
184
+ switch (expr1.type) {
185
+ case `ref`:
186
+ if (!expr1.path || !expr2.path) return false;
187
+ if (expr1.path.length !== expr2.path.length) return false;
188
+ return expr1.path.every(
189
+ (segment, i) => segment === expr2.path[i]
190
+ );
191
+ case `val`:
192
+ return expr1.value === expr2.value;
193
+ case `func`:
194
+ return expr1.name === expr2.name && ((_a = expr1.args) == null ? void 0 : _a.length) === ((_b = expr2.args) == null ? void 0 : _b.length) && (expr1.args || []).every(
195
+ (arg, i) => expressionsEqual(arg, expr2.args[i])
196
+ );
197
+ case `agg`:
198
+ return expr1.name === expr2.name && ((_c = expr1.args) == null ? void 0 : _c.length) === ((_d = expr2.args) == null ? void 0 : _d.length) && (expr1.args || []).every(
199
+ (arg, i) => expressionsEqual(arg, expr2.args[i])
200
+ );
201
+ default:
202
+ return false;
203
+ }
204
+ }
205
+ function getAggregateFunction(aggExpr) {
206
+ const compiledExpr = compileExpression(aggExpr.args[0]);
207
+ const valueExtractor = ([, namespacedRow]) => {
208
+ const value = compiledExpr(namespacedRow);
209
+ return typeof value === `number` ? value : value != null ? Number(value) : 0;
210
+ };
211
+ switch (aggExpr.name.toLowerCase()) {
212
+ case `sum`:
213
+ return sum(valueExtractor);
214
+ case `count`:
215
+ return count();
216
+ // count() doesn't need a value extractor
217
+ case `avg`:
218
+ return avg(valueExtractor);
219
+ case `min`:
220
+ return min(valueExtractor);
221
+ case `max`:
222
+ return max(valueExtractor);
223
+ default:
224
+ throw new Error(`Unsupported aggregate function: ${aggExpr.name}`);
225
+ }
226
+ }
227
+ function transformHavingClause(havingExpr, selectClause) {
228
+ switch (havingExpr.type) {
229
+ case `agg`: {
230
+ const aggExpr = havingExpr;
231
+ for (const [alias, selectExpr] of Object.entries(selectClause)) {
232
+ if (selectExpr.type === `agg` && aggregatesEqual(aggExpr, selectExpr)) {
233
+ return new Ref([`result`, alias]);
234
+ }
235
+ }
236
+ throw new Error(
237
+ `Aggregate function in HAVING clause must also be in SELECT clause: ${aggExpr.name}`
238
+ );
239
+ }
240
+ case `func`: {
241
+ const funcExpr = havingExpr;
242
+ const transformedArgs = funcExpr.args.map(
243
+ (arg) => transformHavingClause(arg, selectClause)
244
+ );
245
+ return new Func(funcExpr.name, transformedArgs);
246
+ }
247
+ case `ref`: {
248
+ const refExpr = havingExpr;
249
+ if (refExpr.path.length === 1) {
250
+ const alias = refExpr.path[0];
251
+ if (selectClause[alias]) {
252
+ return new Ref([`result`, alias]);
253
+ }
254
+ }
255
+ return havingExpr;
256
+ }
257
+ case `val`:
258
+ return havingExpr;
259
+ default:
260
+ throw new Error(
261
+ `Unknown expression type in HAVING clause: ${havingExpr.type}`
262
+ );
263
+ }
264
+ }
265
+ function aggregatesEqual(agg1, agg2) {
266
+ return agg1.name === agg2.name && agg1.args.length === agg2.args.length && agg1.args.every((arg, i) => expressionsEqual(arg, agg2.args[i]));
267
+ }
268
+ export {
269
+ processGroupBy
270
+ };
271
+ //# sourceMappingURL=group-by.js.map