@tanstack/db 0.0.4 → 0.0.5

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 (102) hide show
  1. package/dist/cjs/collection.cjs +113 -94
  2. package/dist/cjs/collection.cjs.map +1 -1
  3. package/dist/cjs/collection.d.cts +38 -11
  4. package/dist/cjs/index.cjs +1 -0
  5. package/dist/cjs/index.cjs.map +1 -1
  6. package/dist/cjs/proxy.cjs +87 -248
  7. package/dist/cjs/proxy.cjs.map +1 -1
  8. package/dist/cjs/proxy.d.cts +5 -5
  9. package/dist/cjs/query/compiled-query.cjs +23 -14
  10. package/dist/cjs/query/compiled-query.cjs.map +1 -1
  11. package/dist/cjs/query/compiled-query.d.cts +3 -1
  12. package/dist/cjs/query/evaluators.cjs +20 -20
  13. package/dist/cjs/query/evaluators.cjs.map +1 -1
  14. package/dist/cjs/query/evaluators.d.cts +3 -2
  15. package/dist/cjs/query/extractors.cjs +20 -20
  16. package/dist/cjs/query/extractors.cjs.map +1 -1
  17. package/dist/cjs/query/extractors.d.cts +3 -3
  18. package/dist/cjs/query/group-by.cjs +12 -15
  19. package/dist/cjs/query/group-by.cjs.map +1 -1
  20. package/dist/cjs/query/group-by.d.cts +7 -7
  21. package/dist/cjs/query/joins.cjs +41 -55
  22. package/dist/cjs/query/joins.cjs.map +1 -1
  23. package/dist/cjs/query/joins.d.cts +3 -3
  24. package/dist/cjs/query/order-by.cjs +37 -84
  25. package/dist/cjs/query/order-by.cjs.map +1 -1
  26. package/dist/cjs/query/order-by.d.cts +2 -2
  27. package/dist/cjs/query/pipeline-compiler.cjs +13 -18
  28. package/dist/cjs/query/pipeline-compiler.cjs.map +1 -1
  29. package/dist/cjs/query/pipeline-compiler.d.cts +2 -1
  30. package/dist/cjs/query/query-builder.cjs +0 -12
  31. package/dist/cjs/query/query-builder.cjs.map +1 -1
  32. package/dist/cjs/query/query-builder.d.cts +4 -8
  33. package/dist/cjs/query/schema.d.cts +1 -6
  34. package/dist/cjs/query/select.cjs +35 -24
  35. package/dist/cjs/query/select.cjs.map +1 -1
  36. package/dist/cjs/query/select.d.cts +2 -2
  37. package/dist/cjs/query/types.d.cts +1 -0
  38. package/dist/cjs/transactions.cjs +17 -8
  39. package/dist/cjs/transactions.cjs.map +1 -1
  40. package/dist/cjs/types.d.cts +41 -7
  41. package/dist/esm/collection.d.ts +38 -11
  42. package/dist/esm/collection.js +113 -94
  43. package/dist/esm/collection.js.map +1 -1
  44. package/dist/esm/index.js +2 -1
  45. package/dist/esm/proxy.d.ts +5 -5
  46. package/dist/esm/proxy.js +87 -248
  47. package/dist/esm/proxy.js.map +1 -1
  48. package/dist/esm/query/compiled-query.d.ts +3 -1
  49. package/dist/esm/query/compiled-query.js +23 -14
  50. package/dist/esm/query/compiled-query.js.map +1 -1
  51. package/dist/esm/query/evaluators.d.ts +3 -2
  52. package/dist/esm/query/evaluators.js +21 -21
  53. package/dist/esm/query/evaluators.js.map +1 -1
  54. package/dist/esm/query/extractors.d.ts +3 -3
  55. package/dist/esm/query/extractors.js +20 -20
  56. package/dist/esm/query/extractors.js.map +1 -1
  57. package/dist/esm/query/group-by.d.ts +7 -7
  58. package/dist/esm/query/group-by.js +14 -17
  59. package/dist/esm/query/group-by.js.map +1 -1
  60. package/dist/esm/query/joins.d.ts +3 -3
  61. package/dist/esm/query/joins.js +42 -56
  62. package/dist/esm/query/joins.js.map +1 -1
  63. package/dist/esm/query/order-by.d.ts +2 -2
  64. package/dist/esm/query/order-by.js +39 -86
  65. package/dist/esm/query/order-by.js.map +1 -1
  66. package/dist/esm/query/pipeline-compiler.d.ts +2 -1
  67. package/dist/esm/query/pipeline-compiler.js +14 -19
  68. package/dist/esm/query/pipeline-compiler.js.map +1 -1
  69. package/dist/esm/query/query-builder.d.ts +4 -8
  70. package/dist/esm/query/query-builder.js +0 -12
  71. package/dist/esm/query/query-builder.js.map +1 -1
  72. package/dist/esm/query/schema.d.ts +1 -6
  73. package/dist/esm/query/select.d.ts +2 -2
  74. package/dist/esm/query/select.js +36 -25
  75. package/dist/esm/query/select.js.map +1 -1
  76. package/dist/esm/query/types.d.ts +1 -0
  77. package/dist/esm/transactions.js +17 -8
  78. package/dist/esm/transactions.js.map +1 -1
  79. package/dist/esm/types.d.ts +41 -7
  80. package/package.json +2 -2
  81. package/src/collection.ts +174 -121
  82. package/src/proxy.ts +141 -358
  83. package/src/query/compiled-query.ts +30 -15
  84. package/src/query/evaluators.ts +22 -21
  85. package/src/query/extractors.ts +24 -21
  86. package/src/query/group-by.ts +24 -22
  87. package/src/query/joins.ts +88 -75
  88. package/src/query/order-by.ts +56 -106
  89. package/src/query/pipeline-compiler.ts +34 -37
  90. package/src/query/query-builder.ts +9 -23
  91. package/src/query/schema.ts +1 -10
  92. package/src/query/select.ts +44 -32
  93. package/src/query/types.ts +1 -0
  94. package/src/transactions.ts +22 -13
  95. package/src/types.ts +48 -7
  96. package/dist/cjs/query/key-by.cjs +0 -43
  97. package/dist/cjs/query/key-by.cjs.map +0 -1
  98. package/dist/cjs/query/key-by.d.cts +0 -3
  99. package/dist/esm/query/key-by.d.ts +0 -3
  100. package/dist/esm/query/key-by.js +0 -43
  101. package/dist/esm/query/key-by.js.map +0 -1
  102. package/src/query/key-by.ts +0 -61
@@ -50,13 +50,11 @@ function processOrderBy(resultPipeline, query, mainTableAlias) {
50
50
  });
51
51
  }
52
52
  }
53
- const valueExtractor = (value) => {
54
- const row = value;
55
- const nestedRow = { [mainTableAlias]: row };
53
+ const valueExtractor = (namespacedRow) => {
56
54
  if (orderByItems.length > 1) {
57
55
  return orderByItems.map((item) => {
58
- const val = extractors.evaluateOperandOnNestedRow(
59
- nestedRow,
56
+ const val = extractors.evaluateOperandOnNamespacedRow(
57
+ namespacedRow,
60
58
  item.operand,
61
59
  mainTableAlias
62
60
  );
@@ -66,8 +64,8 @@ function processOrderBy(resultPipeline, query, mainTableAlias) {
66
64
  });
67
65
  } else if (orderByItems.length === 1) {
68
66
  const item = orderByItems[0];
69
- const val = extractors.evaluateOperandOnNestedRow(
70
- nestedRow,
67
+ const val = extractors.evaluateOperandOnNamespacedRow(
68
+ namespacedRow,
71
69
  item.operand,
72
70
  mainTableAlias
73
71
  );
@@ -118,97 +116,52 @@ function processOrderBy(resultPipeline, query, mainTableAlias) {
118
116
  }
119
117
  return a.toString().localeCompare(b.toString());
120
118
  };
121
- let topKComparator;
122
- if (!query.keyBy) {
123
- topKComparator = (a, b) => {
124
- const aValue = valueExtractor(a);
125
- const bValue = valueExtractor(b);
126
- return comparator(aValue, bValue);
127
- };
128
- }
129
119
  if (hasOrderIndexColumn) {
130
120
  if (orderIndexType === `numeric`) {
131
- if (query.keyBy) {
132
- resultPipeline = resultPipeline.pipe(
133
- d2ts.orderByWithIndex(valueExtractor, {
134
- limit: query.limit,
135
- offset: query.offset,
136
- comparator
137
- }),
138
- d2ts.map(([key, [value, index]]) => {
139
- const result = {
140
- ...value,
141
- [orderIndexAlias]: index
142
- };
143
- return [key, result];
144
- })
145
- );
146
- } else {
147
- resultPipeline = resultPipeline.pipe(
148
- d2ts.map((value) => [null, value]),
149
- d2ts.topKWithIndex(topKComparator, {
150
- limit: query.limit,
151
- offset: query.offset
152
- }),
153
- d2ts.map(([_, [value, index]]) => {
154
- return {
155
- ...value,
156
- [orderIndexAlias]: index
157
- };
158
- })
159
- );
160
- }
161
- } else {
162
- if (query.keyBy) {
163
- resultPipeline = resultPipeline.pipe(
164
- d2ts.orderByWithFractionalIndex(valueExtractor, {
165
- limit: query.limit,
166
- offset: query.offset,
167
- comparator
168
- }),
169
- d2ts.map(([key, [value, index]]) => {
170
- const result = {
171
- ...value,
172
- [orderIndexAlias]: index
173
- };
174
- return [key, result];
175
- })
176
- );
177
- } else {
178
- resultPipeline = resultPipeline.pipe(
179
- d2ts.map((value) => [null, value]),
180
- d2ts.topKWithFractionalIndex(topKComparator, {
181
- limit: query.limit,
182
- offset: query.offset
183
- }),
184
- d2ts.map(([_, [value, index]]) => {
185
- return {
186
- ...value,
187
- [orderIndexAlias]: index
188
- };
189
- })
190
- );
191
- }
192
- }
193
- } else {
194
- if (query.keyBy) {
195
121
  resultPipeline = resultPipeline.pipe(
196
- d2ts.orderBy(valueExtractor, {
122
+ d2ts.orderByWithIndex(valueExtractor, {
197
123
  limit: query.limit,
198
124
  offset: query.offset,
199
125
  comparator
126
+ }),
127
+ d2ts.map(([key, [value, index]]) => {
128
+ const result = {
129
+ ...value,
130
+ [mainTableAlias]: {
131
+ ...value[mainTableAlias],
132
+ [orderIndexAlias]: index
133
+ }
134
+ };
135
+ return [key, result];
200
136
  })
201
137
  );
202
138
  } else {
203
139
  resultPipeline = resultPipeline.pipe(
204
- d2ts.map((value) => [null, value]),
205
- d2ts.topK(topKComparator, {
140
+ d2ts.orderByWithFractionalIndex(valueExtractor, {
206
141
  limit: query.limit,
207
- offset: query.offset
142
+ offset: query.offset,
143
+ comparator
208
144
  }),
209
- d2ts.map(([_, value]) => value)
145
+ d2ts.map(([key, [value, index]]) => {
146
+ const result = {
147
+ ...value,
148
+ [mainTableAlias]: {
149
+ ...value[mainTableAlias],
150
+ [orderIndexAlias]: index
151
+ }
152
+ };
153
+ return [key, result];
154
+ })
210
155
  );
211
156
  }
157
+ } else {
158
+ resultPipeline = resultPipeline.pipe(
159
+ d2ts.orderBy(valueExtractor, {
160
+ limit: query.limit,
161
+ offset: query.offset,
162
+ comparator
163
+ })
164
+ );
212
165
  }
213
166
  return resultPipeline;
214
167
  }
@@ -1 +1 @@
1
- {"version":3,"file":"order-by.cjs","sources":["../../../src/query/order-by.ts"],"sourcesContent":["import {\n map,\n orderBy,\n orderByWithFractionalIndex,\n orderByWithIndex,\n topK,\n topKWithFractionalIndex,\n topKWithIndex,\n} from \"@electric-sql/d2ts\"\nimport { evaluateOperandOnNestedRow } from \"./extractors\"\nimport { isOrderIndexFunctionCall } from \"./utils\"\nimport type { ConditionOperand, Query } from \"./schema\"\nimport type { IStreamBuilder } from \"@electric-sql/d2ts\"\n\nexport function processOrderBy(\n resultPipeline: IStreamBuilder<\n Record<string, unknown> | [string | number, Record<string, unknown>]\n >,\n query: Query,\n mainTableAlias: string\n) {\n // Check if any column in the SELECT clause is an ORDER_INDEX function call\n let hasOrderIndexColumn = false\n let orderIndexType: `numeric` | `fractional` = `numeric`\n let orderIndexAlias = ``\n\n // Scan the SELECT clause for ORDER_INDEX functions\n for (const item of query.select) {\n if (typeof item === `object`) {\n for (const [alias, expr] of Object.entries(item)) {\n if (typeof expr === `object` && isOrderIndexFunctionCall(expr)) {\n hasOrderIndexColumn = true\n orderIndexAlias = alias\n orderIndexType = getOrderIndexType(expr)\n break\n }\n }\n }\n if (hasOrderIndexColumn) break\n }\n\n // Normalize orderBy to an array of objects\n const orderByItems: Array<{\n operand: ConditionOperand\n direction: `asc` | `desc`\n }> = []\n\n if (typeof query.orderBy === `string`) {\n // Handle string format: '@column'\n orderByItems.push({\n operand: query.orderBy,\n direction: `asc`,\n })\n } else if (Array.isArray(query.orderBy)) {\n // Handle array format: ['@column1', { '@column2': 'desc' }]\n for (const item of query.orderBy) {\n if (typeof item === `string`) {\n orderByItems.push({\n operand: item,\n direction: `asc`,\n })\n } else if (typeof item === `object`) {\n for (const [column, direction] of Object.entries(item)) {\n orderByItems.push({\n operand: column,\n direction: direction as `asc` | `desc`,\n })\n }\n }\n }\n } else if (typeof query.orderBy === `object`) {\n // Handle object format: { '@column': 'desc' }\n for (const [column, direction] of Object.entries(query.orderBy)) {\n orderByItems.push({\n operand: column,\n direction: direction as `asc` | `desc`,\n })\n }\n }\n\n // Create a value extractor function for the orderBy operator\n const valueExtractor = (value: unknown) => {\n const row = value as Record<string, unknown>\n\n // Create a nested row structure for evaluateOperandOnNestedRow\n const nestedRow: Record<string, unknown> = { [mainTableAlias]: row }\n\n // For multiple orderBy columns, create a composite key\n if (orderByItems.length > 1) {\n return orderByItems.map((item) => {\n const val = evaluateOperandOnNestedRow(\n nestedRow,\n item.operand,\n mainTableAlias\n )\n\n // Reverse the value for 'desc' ordering\n return item.direction === `desc` && typeof val === `number`\n ? -val\n : item.direction === `desc` && typeof val === `string`\n ? String.fromCharCode(\n ...[...val].map((c) => 0xffff - c.charCodeAt(0))\n )\n : val\n })\n } else if (orderByItems.length === 1) {\n // For a single orderBy column, use the value directly\n const item = orderByItems[0]\n const val = evaluateOperandOnNestedRow(\n nestedRow,\n item!.operand,\n mainTableAlias\n )\n\n // Reverse the value for 'desc' ordering\n return item!.direction === `desc` && typeof val === `number`\n ? -val\n : item!.direction === `desc` && typeof val === `string`\n ? String.fromCharCode(\n ...[...val].map((c) => 0xffff - c.charCodeAt(0))\n )\n : val\n }\n\n // Default case - no ordering\n return null\n }\n\n const comparator = (a: unknown, b: unknown): number => {\n // if a and b are both numbers compare them directly\n if (typeof a === `number` && typeof b === `number`) {\n return a - b\n }\n // if a and b are both strings, compare them lexicographically\n if (typeof a === `string` && typeof b === `string`) {\n return a.localeCompare(b)\n }\n // if a and b are both booleans, compare them\n if (typeof a === `boolean` && typeof b === `boolean`) {\n return a === b ? 0 : a ? 1 : -1\n }\n // if a and b are both dates, compare them\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() - b.getTime()\n }\n // if a and b are both null, return 0\n if (a === null || b === null) {\n return 0\n }\n\n // if a and b are both arrays, compare them element by element\n if (Array.isArray(a) && Array.isArray(b)) {\n for (let i = 0; i < Math.min(a.length, b.length); i++) {\n // Get the values from the array\n const aVal = a[i]\n const bVal = b[i]\n\n // Compare the values\n let result: number\n\n if (typeof aVal === `boolean` && typeof bVal === `boolean`) {\n // Special handling for booleans - false comes before true\n result = aVal === bVal ? 0 : aVal ? 1 : -1\n } else if (typeof aVal === `number` && typeof bVal === `number`) {\n // Numeric comparison\n result = aVal - bVal\n } else if (typeof aVal === `string` && typeof bVal === `string`) {\n // String comparison\n result = aVal.localeCompare(bVal)\n } else {\n // Default comparison using the general comparator\n result = comparator(aVal, bVal)\n }\n\n if (result !== 0) {\n return result\n }\n }\n // All elements are equal up to the minimum length\n return a.length - b.length\n }\n // if a and b are both null/undefined, return 0\n if (a == null && b == null) {\n return 0\n }\n // Fallback to string comparison for all other cases\n return (a as any).toString().localeCompare((b as any).toString())\n }\n\n let topKComparator: (a: unknown, b: unknown) => number\n if (!query.keyBy) {\n topKComparator = (a, b) => {\n const aValue = valueExtractor(a)\n const bValue = valueExtractor(b)\n return comparator(aValue, bValue)\n }\n }\n\n // Apply the appropriate orderBy operator based on whether an ORDER_INDEX column is requested\n if (hasOrderIndexColumn) {\n if (orderIndexType === `numeric`) {\n if (query.keyBy) {\n // Use orderByWithIndex for numeric indices\n resultPipeline = resultPipeline.pipe(\n orderByWithIndex(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n }),\n map(([key, [value, index]]) => {\n // Add the index to the result\n const result = {\n ...(value as Record<string, unknown>),\n [orderIndexAlias]: index,\n }\n return [key, result]\n })\n )\n } else {\n // Use topKWithIndex for numeric indices\n resultPipeline = resultPipeline.pipe(\n map((value) => [null, value]),\n topKWithIndex(topKComparator!, {\n limit: query.limit,\n offset: query.offset,\n }),\n map(([_, [value, index]]) => {\n // Add the index to the result\n return {\n ...(value as Record<string, unknown>),\n [orderIndexAlias]: index,\n }\n })\n )\n }\n } else {\n if (query.keyBy) {\n // Use orderByWithFractionalIndex for fractional indices\n resultPipeline = resultPipeline.pipe(\n orderByWithFractionalIndex(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n }),\n map(([key, [value, index]]) => {\n // Add the index to the result\n const result = {\n ...(value as Record<string, unknown>),\n [orderIndexAlias]: index,\n }\n return [key, result]\n })\n )\n } else {\n // Use topKWithFractionalIndex for fractional indices\n resultPipeline = resultPipeline.pipe(\n map((value) => [null, value]),\n topKWithFractionalIndex(topKComparator!, {\n limit: query.limit,\n offset: query.offset,\n }),\n map(([_, [value, index]]) => {\n // Add the index to the result\n return {\n ...(value as Record<string, unknown>),\n [orderIndexAlias]: index,\n }\n })\n )\n }\n }\n } else {\n if (query.keyBy) {\n // Use regular orderBy if no index column is requested and but a keyBy is requested\n resultPipeline = resultPipeline.pipe(\n orderBy(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n })\n )\n } else {\n // Use topK if no index column is requested and no keyBy is requested\n resultPipeline = resultPipeline.pipe(\n map((value) => [null, value]),\n topK(topKComparator!, {\n limit: query.limit,\n offset: query.offset,\n }),\n map(([_, value]) => value as Record<string, unknown>)\n )\n }\n }\n\n return resultPipeline\n}\n\n// Helper function to extract the ORDER_INDEX type from a function call\nfunction getOrderIndexType(obj: any): `numeric` | `fractional` {\n if (!isOrderIndexFunctionCall(obj)) {\n throw new Error(`Not an ORDER_INDEX function call`)\n }\n\n const arg = obj[`ORDER_INDEX`]\n if (arg === `numeric` || arg === true || arg === `default`) {\n return `numeric`\n } else if (arg === `fractional`) {\n return `fractional`\n } else {\n throw new Error(`Invalid ORDER_INDEX type: ` + arg)\n }\n}\n"],"names":["isOrderIndexFunctionCall","evaluateOperandOnNestedRow","orderByWithIndex","map","topKWithIndex","orderByWithFractionalIndex","topKWithFractionalIndex","orderBy","topK"],"mappings":"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"}
1
+ {"version":3,"file":"order-by.cjs","sources":["../../../src/query/order-by.ts"],"sourcesContent":["import {\n map,\n orderBy,\n orderByWithFractionalIndex,\n orderByWithIndex,\n} from \"@electric-sql/d2ts\"\nimport { evaluateOperandOnNamespacedRow } from \"./extractors\"\nimport { isOrderIndexFunctionCall } from \"./utils\"\nimport type { ConditionOperand, Query } from \"./schema\"\nimport type {\n KeyedNamespacedRow,\n NamespacedAndKeyedStream,\n NamespacedRow,\n} from \"../types\"\n\nexport function processOrderBy(\n resultPipeline: NamespacedAndKeyedStream,\n query: Query,\n mainTableAlias: string\n) {\n // Check if any column in the SELECT clause is an ORDER_INDEX function call\n let hasOrderIndexColumn = false\n let orderIndexType: `numeric` | `fractional` = `numeric`\n let orderIndexAlias = ``\n\n // Scan the SELECT clause for ORDER_INDEX functions\n // TODO: Select is going to be optional in future - we will automatically add an\n // attribute for the index column\n for (const item of query.select!) {\n if (typeof item === `object`) {\n for (const [alias, expr] of Object.entries(item)) {\n if (typeof expr === `object` && isOrderIndexFunctionCall(expr)) {\n hasOrderIndexColumn = true\n orderIndexAlias = alias\n orderIndexType = getOrderIndexType(expr)\n break\n }\n }\n }\n if (hasOrderIndexColumn) break\n }\n\n // Normalize orderBy to an array of objects\n const orderByItems: Array<{\n operand: ConditionOperand\n direction: `asc` | `desc`\n }> = []\n\n if (typeof query.orderBy === `string`) {\n // Handle string format: '@column'\n orderByItems.push({\n operand: query.orderBy,\n direction: `asc`,\n })\n } else if (Array.isArray(query.orderBy)) {\n // Handle array format: ['@column1', { '@column2': 'desc' }]\n for (const item of query.orderBy) {\n if (typeof item === `string`) {\n orderByItems.push({\n operand: item,\n direction: `asc`,\n })\n } else if (typeof item === `object`) {\n for (const [column, direction] of Object.entries(item)) {\n orderByItems.push({\n operand: column,\n direction: direction as `asc` | `desc`,\n })\n }\n }\n }\n } else if (typeof query.orderBy === `object`) {\n // Handle object format: { '@column': 'desc' }\n for (const [column, direction] of Object.entries(query.orderBy)) {\n orderByItems.push({\n operand: column,\n direction: direction as `asc` | `desc`,\n })\n }\n }\n\n // Create a value extractor function for the orderBy operator\n // const valueExtractor = ([key, namespacedRow]: [\n const valueExtractor = (namespacedRow: NamespacedRow) => {\n // For multiple orderBy columns, create a composite key\n if (orderByItems.length > 1) {\n return orderByItems.map((item) => {\n const val = evaluateOperandOnNamespacedRow(\n namespacedRow,\n item.operand,\n mainTableAlias\n )\n\n // Reverse the value for 'desc' ordering\n return item.direction === `desc` && typeof val === `number`\n ? -val\n : item.direction === `desc` && typeof val === `string`\n ? String.fromCharCode(\n ...[...val].map((c) => 0xffff - c.charCodeAt(0))\n )\n : val\n })\n } else if (orderByItems.length === 1) {\n // For a single orderBy column, use the value directly\n const item = orderByItems[0]\n const val = evaluateOperandOnNamespacedRow(\n namespacedRow,\n item!.operand,\n mainTableAlias\n )\n\n // Reverse the value for 'desc' ordering\n return item!.direction === `desc` && typeof val === `number`\n ? -val\n : item!.direction === `desc` && typeof val === `string`\n ? String.fromCharCode(\n ...[...val].map((c) => 0xffff - c.charCodeAt(0))\n )\n : val\n }\n\n // Default case - no ordering\n return null\n }\n\n const comparator = (a: unknown, b: unknown): number => {\n // if a and b are both numbers compare them directly\n if (typeof a === `number` && typeof b === `number`) {\n return a - b\n }\n // if a and b are both strings, compare them lexicographically\n if (typeof a === `string` && typeof b === `string`) {\n return a.localeCompare(b)\n }\n // if a and b are both booleans, compare them\n if (typeof a === `boolean` && typeof b === `boolean`) {\n return a === b ? 0 : a ? 1 : -1\n }\n // if a and b are both dates, compare them\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() - b.getTime()\n }\n // if a and b are both null, return 0\n if (a === null || b === null) {\n return 0\n }\n\n // if a and b are both arrays, compare them element by element\n if (Array.isArray(a) && Array.isArray(b)) {\n for (let i = 0; i < Math.min(a.length, b.length); i++) {\n // Get the values from the array\n const aVal = a[i]\n const bVal = b[i]\n\n // Compare the values\n let result: number\n\n if (typeof aVal === `boolean` && typeof bVal === `boolean`) {\n // Special handling for booleans - false comes before true\n result = aVal === bVal ? 0 : aVal ? 1 : -1\n } else if (typeof aVal === `number` && typeof bVal === `number`) {\n // Numeric comparison\n result = aVal - bVal\n } else if (typeof aVal === `string` && typeof bVal === `string`) {\n // String comparison\n result = aVal.localeCompare(bVal)\n } else {\n // Default comparison using the general comparator\n result = comparator(aVal, bVal)\n }\n\n if (result !== 0) {\n return result\n }\n }\n // All elements are equal up to the minimum length\n return a.length - b.length\n }\n // if a and b are both null/undefined, return 0\n if (a == null && b == null) {\n return 0\n }\n // Fallback to string comparison for all other cases\n return (a as any).toString().localeCompare((b as any).toString())\n }\n\n // Apply the appropriate orderBy operator based on whether an ORDER_INDEX column is requested\n if (hasOrderIndexColumn) {\n if (orderIndexType === `numeric`) {\n // Use orderByWithIndex for numeric indices\n resultPipeline = resultPipeline.pipe(\n orderByWithIndex(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n }),\n map(([key, [value, index]]) => {\n // Add the index to the result\n // We add this to the main table alias for now\n // TODO: re are going to need to refactor the whole order by pipeline\n const result = {\n ...(value as Record<string, unknown>),\n [mainTableAlias]: {\n ...value[mainTableAlias],\n [orderIndexAlias]: index,\n },\n }\n return [key, result] as KeyedNamespacedRow\n })\n )\n } else {\n // Use orderByWithFractionalIndex for fractional indices\n resultPipeline = resultPipeline.pipe(\n orderByWithFractionalIndex(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n }),\n map(([key, [value, index]]) => {\n // Add the index to the result\n // We add this to the main table alias for now\n // TODO: re are going to need to refactor the whole order by pipeline\n const result = {\n ...(value as Record<string, unknown>),\n [mainTableAlias]: {\n ...value[mainTableAlias],\n [orderIndexAlias]: index,\n },\n }\n return [key, result] as KeyedNamespacedRow\n })\n )\n }\n } else {\n // Use regular orderBy if no index column is requested\n resultPipeline = resultPipeline.pipe(\n orderBy(valueExtractor, {\n limit: query.limit,\n offset: query.offset,\n comparator,\n })\n )\n }\n\n return resultPipeline\n}\n\n// Helper function to extract the ORDER_INDEX type from a function call\nfunction getOrderIndexType(obj: any): `numeric` | `fractional` {\n if (!isOrderIndexFunctionCall(obj)) {\n throw new Error(`Not an ORDER_INDEX function call`)\n }\n\n const arg = obj[`ORDER_INDEX`]\n if (arg === `numeric` || arg === true || arg === `default`) {\n return `numeric`\n } else if (arg === `fractional`) {\n return `fractional`\n } else {\n throw new Error(`Invalid ORDER_INDEX type: ` + arg)\n }\n}\n"],"names":["isOrderIndexFunctionCall","evaluateOperandOnNamespacedRow","orderByWithIndex","map","orderByWithFractionalIndex","orderBy"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  import { Query } from './schema.cjs';
2
- import { IStreamBuilder } from '@electric-sql/d2ts';
3
- export declare function processOrderBy(resultPipeline: IStreamBuilder<Record<string, unknown> | [string | number, Record<string, unknown>]>, query: Query, mainTableAlias: string): IStreamBuilder<Record<string, unknown> | [string | number, Record<string, unknown>]>;
2
+ import { NamespacedAndKeyedStream } from '../types.cjs';
3
+ export declare function processOrderBy(resultPipeline: NamespacedAndKeyedStream, query: Query, mainTableAlias: string): NamespacedAndKeyedStream;
@@ -5,7 +5,6 @@ const evaluators = require("./evaluators.cjs");
5
5
  const joins = require("./joins.cjs");
6
6
  const groupBy = require("./group-by.cjs");
7
7
  const orderBy = require("./order-by.cjs");
8
- const keyBy = require("./key-by.cjs");
9
8
  const select = require("./select.cjs");
10
9
  function compileQueryPipeline(query, inputs) {
11
10
  const allInputs = { ...inputs };
@@ -14,9 +13,6 @@ function compileQueryPipeline(query, inputs) {
14
13
  if (!withQuery.as) {
15
14
  throw new Error(`WITH query must have an "as" property`);
16
15
  }
17
- if (withQuery.keyBy !== void 0) {
18
- throw new Error(`WITH query cannot have a "keyBy" property`);
19
- }
20
16
  if (allInputs[withQuery.as]) {
21
17
  throw new Error(`CTE with name "${withQuery.as}" already exists`);
22
18
  }
@@ -36,8 +32,9 @@ function compileQueryPipeline(query, inputs) {
36
32
  }
37
33
  tables[mainTableAlias] = input;
38
34
  let pipeline = input.pipe(
39
- d2ts.map((row) => {
40
- return { [mainTableAlias]: row };
35
+ d2ts.map(([key, row]) => {
36
+ const ret = [key, { [mainTableAlias]: row }];
37
+ return ret;
41
38
  })
42
39
  );
43
40
  if (query.join) {
@@ -51,9 +48,9 @@ function compileQueryPipeline(query, inputs) {
51
48
  }
52
49
  if (query.where) {
53
50
  pipeline = pipeline.pipe(
54
- d2ts.filter((nestedRow) => {
55
- const result = evaluators.evaluateConditionOnNestedRow(
56
- nestedRow,
51
+ d2ts.filter(([_key, row]) => {
52
+ const result = evaluators.evaluateConditionOnNamespacedRow(
53
+ row,
57
54
  query.where,
58
55
  mainTableAlias
59
56
  );
@@ -66,9 +63,9 @@ function compileQueryPipeline(query, inputs) {
66
63
  }
67
64
  if (query.having) {
68
65
  pipeline = pipeline.pipe(
69
- d2ts.filter((row) => {
70
- const result = evaluators.evaluateConditionOnNestedRow(
71
- { [mainTableAlias]: row, ...row },
66
+ d2ts.filter(([_key, row]) => {
67
+ const result = evaluators.evaluateConditionOnNamespacedRow(
68
+ row,
72
69
  query.having,
73
70
  mainTableAlias
74
71
  );
@@ -76,18 +73,16 @@ function compileQueryPipeline(query, inputs) {
76
73
  })
77
74
  );
78
75
  }
79
- pipeline = select.processSelect(pipeline, query, mainTableAlias, allInputs);
80
- let resultPipeline = pipeline;
81
- if (query.keyBy) {
82
- resultPipeline = keyBy.processKeyBy(resultPipeline, query);
83
- }
84
76
  if (query.orderBy) {
85
- resultPipeline = orderBy.processOrderBy(resultPipeline, query, mainTableAlias);
77
+ pipeline = orderBy.processOrderBy(pipeline, query, mainTableAlias);
86
78
  } else if (query.limit !== void 0 || query.offset !== void 0) {
87
79
  throw new Error(
88
80
  `LIMIT and OFFSET require an ORDER BY clause to ensure deterministic results`
89
81
  );
90
82
  }
83
+ const resultPipeline = query.select ? select.processSelect(pipeline, query, mainTableAlias, allInputs) : !query.join && !query.groupBy ? pipeline.pipe(
84
+ d2ts.map(([key, row]) => [key, row[mainTableAlias]])
85
+ ) : pipeline;
91
86
  return resultPipeline;
92
87
  }
93
88
  exports.compileQueryPipeline = compileQueryPipeline;
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-compiler.cjs","sources":["../../../src/query/pipeline-compiler.ts"],"sourcesContent":["import { filter, map } from \"@electric-sql/d2ts\"\nimport { evaluateConditionOnNestedRow } from \"./evaluators.js\"\nimport { processJoinClause } from \"./joins.js\"\nimport { processGroupBy } from \"./group-by.js\"\nimport { processOrderBy } from \"./order-by.js\"\nimport { processKeyBy } from \"./key-by.js\"\nimport { processSelect } from \"./select.js\"\nimport type { Condition, Query } from \"./schema.js\"\nimport type { IStreamBuilder } from \"@electric-sql/d2ts\"\n\n/**\n * Compiles a query into a D2 pipeline\n * @param query The query to compile\n * @param inputs Mapping of table names to input streams\n * @returns A stream builder representing the compiled query\n */\nexport function compileQueryPipeline<T extends IStreamBuilder<unknown>>(\n query: Query,\n inputs: Record<string, IStreamBuilder<Record<string, unknown>>>\n): T {\n // Create a copy of the inputs map to avoid modifying the original\n const allInputs = { ...inputs }\n\n // Process WITH queries if they exist\n if (query.with && query.with.length > 0) {\n // Process each WITH query in order\n for (const withQuery of query.with) {\n // Ensure the WITH query has an alias\n if (!withQuery.as) {\n throw new Error(`WITH query must have an \"as\" property`)\n }\n\n // Ensure the WITH query is not keyed\n if ((withQuery as Query).keyBy !== undefined) {\n throw new Error(`WITH query cannot have a \"keyBy\" property`)\n }\n\n // Check if this CTE name already exists in the inputs\n if (allInputs[withQuery.as]) {\n throw new Error(`CTE with name \"${withQuery.as}\" already exists`)\n }\n\n // Create a new query without the 'with' property to avoid circular references\n const withQueryWithoutWith = { ...withQuery, with: undefined }\n\n // Compile the WITH query using the current set of inputs\n // (which includes previously compiled WITH queries)\n const compiledWithQuery = compileQueryPipeline(\n withQueryWithoutWith,\n allInputs\n )\n\n // Add the compiled query to the inputs map using its alias\n allInputs[withQuery.as] = compiledWithQuery as IStreamBuilder<\n Record<string, unknown>\n >\n }\n }\n\n // Create a map of table aliases to inputs\n const tables: Record<string, IStreamBuilder<Record<string, unknown>>> = {}\n\n // The main table is the one in the FROM clause\n const mainTableAlias = query.as || query.from\n\n // Get the main input from the inputs map (now including CTEs)\n const input = allInputs[query.from]\n if (!input) {\n throw new Error(`Input for table \"${query.from}\" not found in inputs map`)\n }\n\n tables[mainTableAlias] = input\n\n // Prepare the initial pipeline with the main table wrapped in its alias\n let pipeline = input.pipe(\n map((row: unknown) => {\n // Initialize the record with a nested structure\n return { [mainTableAlias]: row } as Record<string, unknown>\n })\n )\n\n // Process JOIN clauses if they exist\n if (query.join) {\n pipeline = processJoinClause(\n pipeline,\n query,\n tables,\n mainTableAlias,\n allInputs\n )\n }\n\n // Process the WHERE clause if it exists\n if (query.where) {\n pipeline = pipeline.pipe(\n filter((nestedRow) => {\n const result = evaluateConditionOnNestedRow(\n nestedRow,\n query.where as Condition,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process the GROUP BY clause if it exists\n if (query.groupBy) {\n pipeline = processGroupBy(pipeline, query, mainTableAlias)\n }\n\n // Process the HAVING clause if it exists\n // This works similarly to WHERE but is applied after any aggregations\n if (query.having) {\n pipeline = pipeline.pipe(\n filter((row) => {\n // For HAVING, we're working with the flattened row that contains both\n // the group by keys and the aggregate results directly\n const result = evaluateConditionOnNestedRow(\n { [mainTableAlias]: row, ...row } as Record<string, unknown>,\n query.having as Condition,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process the SELECT clause - this is where we flatten the structure\n pipeline = processSelect(pipeline, query, mainTableAlias, allInputs)\n\n let resultPipeline: IStreamBuilder<\n Record<string, unknown> | [string | number, Record<string, unknown>]\n > = pipeline\n\n // Process keyBy parameter if it exists\n if (query.keyBy) {\n resultPipeline = processKeyBy(resultPipeline, query)\n }\n\n // Process orderBy parameter if it exists\n if (query.orderBy) {\n resultPipeline = processOrderBy(resultPipeline, query, mainTableAlias)\n } else if (query.limit !== undefined || query.offset !== undefined) {\n // If there's a limit or offset without orderBy, throw an error\n throw new Error(\n `LIMIT and OFFSET require an ORDER BY clause to ensure deterministic results`\n )\n }\n\n return resultPipeline as T\n}\n"],"names":["map","processJoinClause","filter","evaluateConditionOnNestedRow","processGroupBy","processSelect","processKeyBy","processOrderBy"],"mappings":";;;;;;;;;AAgBgB,SAAA,qBACd,OACA,QACG;AAEG,QAAA,YAAY,EAAE,GAAG,OAAO;AAG9B,MAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,GAAG;AAE5B,eAAA,aAAa,MAAM,MAAM;AAE9B,UAAA,CAAC,UAAU,IAAI;AACX,cAAA,IAAI,MAAM,uCAAuC;AAAA,MAAA;AAIpD,UAAA,UAAoB,UAAU,QAAW;AACtC,cAAA,IAAI,MAAM,2CAA2C;AAAA,MAAA;AAIzD,UAAA,UAAU,UAAU,EAAE,GAAG;AAC3B,cAAM,IAAI,MAAM,kBAAkB,UAAU,EAAE,kBAAkB;AAAA,MAAA;AAIlE,YAAM,uBAAuB,EAAE,GAAG,WAAW,MAAM,OAAU;AAI7D,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAGU,gBAAA,UAAU,EAAE,IAAI;AAAA,IAAA;AAAA,EAG5B;AAIF,QAAM,SAAkE,CAAC;AAGnE,QAAA,iBAAiB,MAAM,MAAM,MAAM;AAGnC,QAAA,QAAQ,UAAU,MAAM,IAAI;AAClC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,oBAAoB,MAAM,IAAI,2BAA2B;AAAA,EAAA;AAG3E,SAAO,cAAc,IAAI;AAGzB,MAAI,WAAW,MAAM;AAAA,IACnBA,KAAA,IAAI,CAAC,QAAiB;AAEpB,aAAO,EAAE,CAAC,cAAc,GAAG,IAAI;AAAA,IAChC,CAAA;AAAA,EACH;AAGA,MAAI,MAAM,MAAM;AACH,eAAAC,MAAA;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAIF,MAAI,MAAM,OAAO;AACf,eAAW,SAAS;AAAA,MAClBC,KAAA,OAAO,CAAC,cAAc;AACpB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAC,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA;AAK3D,MAAI,MAAM,QAAQ;AAChB,eAAW,SAAS;AAAA,MAClBF,KAAA,OAAO,CAAC,QAAQ;AAGd,cAAM,SAASC,WAAA;AAAA,UACb,EAAE,CAAC,cAAc,GAAG,KAAK,GAAG,IAAI;AAAA,UAChC,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,aAAWE,OAAAA,cAAc,UAAU,OAAO,gBAAgB,SAAS;AAEnE,MAAI,iBAEA;AAGJ,MAAI,MAAM,OAAO;AACE,qBAAAC,MAAAA,aAAa,gBAAgB,KAAK;AAAA,EAAA;AAIrD,MAAI,MAAM,SAAS;AACA,qBAAAC,QAAA,eAAe,gBAAgB,OAAO,cAAc;AAAA,EAAA,WAC5D,MAAM,UAAU,UAAa,MAAM,WAAW,QAAW;AAElE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAGK,SAAA;AACT;;"}
1
+ {"version":3,"file":"pipeline-compiler.cjs","sources":["../../../src/query/pipeline-compiler.ts"],"sourcesContent":["import { filter, map } from \"@electric-sql/d2ts\"\nimport { evaluateConditionOnNamespacedRow } from \"./evaluators.js\"\nimport { processJoinClause } from \"./joins.js\"\nimport { processGroupBy } from \"./group-by.js\"\nimport { processOrderBy } from \"./order-by.js\"\nimport { processSelect } from \"./select.js\"\nimport type { Query } from \"./schema.js\"\nimport type { IStreamBuilder } from \"@electric-sql/d2ts\"\nimport type {\n InputRow,\n KeyedStream,\n NamespacedAndKeyedStream,\n} from \"../types.js\"\n\n/**\n * Compiles a query into a D2 pipeline\n * @param query The query to compile\n * @param inputs Mapping of table names to input streams\n * @returns A stream builder representing the compiled query\n */\nexport function compileQueryPipeline<T extends IStreamBuilder<unknown>>(\n query: Query,\n inputs: Record<string, KeyedStream>\n): T {\n // Create a copy of the inputs map to avoid modifying the original\n const allInputs = { ...inputs }\n\n // Process WITH queries if they exist\n if (query.with && query.with.length > 0) {\n // Process each WITH query in order\n for (const withQuery of query.with) {\n // Ensure the WITH query has an alias\n if (!withQuery.as) {\n throw new Error(`WITH query must have an \"as\" property`)\n }\n\n // Check if this CTE name already exists in the inputs\n if (allInputs[withQuery.as]) {\n throw new Error(`CTE with name \"${withQuery.as}\" already exists`)\n }\n\n // Create a new query without the 'with' property to avoid circular references\n const withQueryWithoutWith = { ...withQuery, with: undefined }\n\n // Compile the WITH query using the current set of inputs\n // (which includes previously compiled WITH queries)\n const compiledWithQuery = compileQueryPipeline(\n withQueryWithoutWith,\n allInputs\n )\n\n // Add the compiled query to the inputs map using its alias\n allInputs[withQuery.as] = compiledWithQuery as KeyedStream\n }\n }\n\n // Create a map of table aliases to inputs\n const tables: Record<string, KeyedStream> = {}\n\n // The main table is the one in the FROM clause\n const mainTableAlias = query.as || query.from\n\n // Get the main input from the inputs map (now including CTEs)\n const input = allInputs[query.from]\n if (!input) {\n throw new Error(`Input for table \"${query.from}\" not found in inputs map`)\n }\n\n tables[mainTableAlias] = input\n\n // Prepare the initial pipeline with the main table wrapped in its alias\n let pipeline: NamespacedAndKeyedStream = input.pipe(\n map(([key, row]) => {\n // Initialize the record with a nested structure\n const ret = [key, { [mainTableAlias]: row }] as [\n string,\n Record<string, typeof row>,\n ]\n return ret\n })\n )\n\n // Process JOIN clauses if they exist\n if (query.join) {\n pipeline = processJoinClause(\n pipeline,\n query,\n tables,\n mainTableAlias,\n allInputs\n )\n }\n\n // Process the WHERE clause if it exists\n if (query.where) {\n pipeline = pipeline.pipe(\n filter(([_key, row]) => {\n const result = evaluateConditionOnNamespacedRow(\n row,\n query.where!,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process the GROUP BY clause if it exists\n if (query.groupBy) {\n pipeline = processGroupBy(pipeline, query, mainTableAlias)\n }\n\n // Process the HAVING clause if it exists\n // This works similarly to WHERE but is applied after any aggregations\n if (query.having) {\n pipeline = pipeline.pipe(\n filter(([_key, row]) => {\n // For HAVING, we're working with the flattened row that contains both\n // the group by keys and the aggregate results directly\n const result = evaluateConditionOnNamespacedRow(\n row,\n query.having!,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process orderBy parameter if it exists\n if (query.orderBy) {\n pipeline = processOrderBy(pipeline, query, mainTableAlias)\n } else if (query.limit !== undefined || query.offset !== undefined) {\n // If there's a limit or offset without orderBy, throw an error\n throw new Error(\n `LIMIT and OFFSET require an ORDER BY clause to ensure deterministic results`\n )\n }\n\n // Process the SELECT clause - this is where we flatten the structure\n const resultPipeline: KeyedStream | NamespacedAndKeyedStream = query.select\n ? processSelect(pipeline, query, mainTableAlias, allInputs)\n : !query.join && !query.groupBy\n ? pipeline.pipe(\n map(([key, row]) => [key, row[mainTableAlias]] as InputRow)\n )\n : pipeline\n return resultPipeline as T\n}\n"],"names":["map","processJoinClause","filter","evaluateConditionOnNamespacedRow","processGroupBy","processOrderBy","processSelect"],"mappings":";;;;;;;;AAoBgB,SAAA,qBACd,OACA,QACG;AAEG,QAAA,YAAY,EAAE,GAAG,OAAO;AAG9B,MAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,GAAG;AAE5B,eAAA,aAAa,MAAM,MAAM;AAE9B,UAAA,CAAC,UAAU,IAAI;AACX,cAAA,IAAI,MAAM,uCAAuC;AAAA,MAAA;AAIrD,UAAA,UAAU,UAAU,EAAE,GAAG;AAC3B,cAAM,IAAI,MAAM,kBAAkB,UAAU,EAAE,kBAAkB;AAAA,MAAA;AAIlE,YAAM,uBAAuB,EAAE,GAAG,WAAW,MAAM,OAAU;AAI7D,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAGU,gBAAA,UAAU,EAAE,IAAI;AAAA,IAAA;AAAA,EAC5B;AAIF,QAAM,SAAsC,CAAC;AAGvC,QAAA,iBAAiB,MAAM,MAAM,MAAM;AAGnC,QAAA,QAAQ,UAAU,MAAM,IAAI;AAClC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,oBAAoB,MAAM,IAAI,2BAA2B;AAAA,EAAA;AAG3E,SAAO,cAAc,IAAI;AAGzB,MAAI,WAAqC,MAAM;AAAA,IAC7CA,KAAAA,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM;AAEZ,YAAA,MAAM,CAAC,KAAK,EAAE,CAAC,cAAc,GAAG,KAAK;AAIpC,aAAA;AAAA,IACR,CAAA;AAAA,EACH;AAGA,MAAI,MAAM,MAAM;AACH,eAAAC,MAAA;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAIF,MAAI,MAAM,OAAO;AACf,eAAW,SAAS;AAAA,MAClBC,KAAAA,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM;AACtB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAC,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA;AAK3D,MAAI,MAAM,QAAQ;AAChB,eAAW,SAAS;AAAA,MAClBF,KAAAA,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM;AAGtB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAE,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA,WAChD,MAAM,UAAU,UAAa,MAAM,WAAW,QAAW;AAElE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAIF,QAAM,iBAAyD,MAAM,SACjEC,OAAAA,cAAc,UAAU,OAAO,gBAAgB,SAAS,IACxD,CAAC,MAAM,QAAQ,CAAC,MAAM,UACpB,SAAS;AAAA,IACPN,SAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,cAAc,CAAC,CAAa;AAAA,EAAA,IAE5D;AACC,SAAA;AACT;;"}
@@ -1,9 +1,10 @@
1
1
  import { Query } from './schema.js';
2
2
  import { IStreamBuilder } from '@electric-sql/d2ts';
3
+ import { KeyedStream } from '../types.js';
3
4
  /**
4
5
  * Compiles a query into a D2 pipeline
5
6
  * @param query The query to compile
6
7
  * @param inputs Mapping of table names to input streams
7
8
  * @returns A stream builder representing the compiled query
8
9
  */
9
- export declare function compileQueryPipeline<T extends IStreamBuilder<unknown>>(query: Query, inputs: Record<string, IStreamBuilder<Record<string, unknown>>>): T;
10
+ export declare function compileQueryPipeline<T extends IStreamBuilder<unknown>>(query: Query, inputs: Record<string, KeyedStream>): T;
@@ -251,18 +251,6 @@ class BaseQueryBuilder {
251
251
  newBuilder.query.offset = offset;
252
252
  return newBuilder;
253
253
  }
254
- /**
255
- * Specify which column(s) to use as keys in the output keyed stream.
256
- *
257
- * @param keyBy The column(s) to use as keys
258
- * @returns A new QueryBuilder with the keyBy clause set
259
- */
260
- keyBy(keyBy) {
261
- const newBuilder = new BaseQueryBuilder();
262
- Object.assign(newBuilder.query, this.query);
263
- newBuilder.query.keyBy = keyBy;
264
- return newBuilder;
265
- }
266
254
  /**
267
255
  * Add a groupBy clause to group the results by one or more columns.
268
256
  *
@@ -1 +1 @@
1
- {"version":3,"file":"query-builder.cjs","sources":["../../../src/query/query-builder.ts"],"sourcesContent":["import type { Collection } from \"../collection\"\nimport type {\n Comparator,\n Condition,\n From,\n JoinClause,\n Limit,\n LiteralValue,\n Offset,\n OrderBy,\n Query,\n Select,\n WithQuery,\n} from \"./schema.js\"\nimport type {\n Context,\n Flatten,\n InferResultTypeFromSelectTuple,\n Input,\n InputReference,\n PropertyReference,\n PropertyReferenceString,\n RemoveIndexSignature,\n Schema,\n} from \"./types.js\"\n\ntype CollectionRef = { [K: string]: Collection<any> }\n\nexport class BaseQueryBuilder<TContext extends Context<Schema>> {\n private readonly query: Partial<Query<TContext>> = {}\n\n /**\n * Create a new QueryBuilder instance.\n */\n constructor(query: Partial<Query<TContext>> = {}) {\n this.query = query\n }\n\n from<TCollectionRef extends CollectionRef>(\n collectionRef: TCollectionRef\n ): QueryBuilder<{\n baseSchema: Flatten<\n TContext[`baseSchema`] & {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n >\n schema: Flatten<{\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }>\n default: keyof TCollectionRef & string\n }>\n\n from<\n T extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n >(\n collection: T\n ): QueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {\n [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]>\n }\n default: T\n }>\n\n from<\n T extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n TAs extends string,\n >(\n collection: T,\n as: TAs\n ): QueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {\n [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][T]>\n }\n default: TAs\n }>\n\n /**\n * Specify the collection to query from.\n * This is the first method that must be called in the chain.\n *\n * @param collection The collection name to query from\n * @param as Optional alias for the collection\n * @returns A new QueryBuilder with the from clause set\n */\n from<\n T extends\n | InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>\n | CollectionRef,\n TAs extends string | undefined,\n >(collection: T, as?: TAs) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (typeof collection === `object` && collection !== null) {\n return this.fromCollectionRef(collection)\n } else if (typeof collection === `string`) {\n return this.fromInputReference(\n collection as InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n as\n )\n } else {\n throw new Error(`Invalid collection type`)\n }\n }\n\n private fromCollectionRef<TCollectionRef extends CollectionRef>(\n collectionRef: TCollectionRef\n ) {\n const keys = Object.keys(collectionRef)\n if (keys.length !== 1) {\n throw new Error(`Expected exactly one key`)\n }\n\n const key = keys[0]!\n const collection = collectionRef[key]!\n\n const newBuilder = new BaseQueryBuilder()\n Object.assign(newBuilder.query, this.query)\n newBuilder.query.from = key as From<TContext>\n newBuilder.query.collections ??= {}\n newBuilder.query.collections[key] = collection\n\n return newBuilder as unknown as QueryBuilder<{\n baseSchema: TContext[`baseSchema`] & {\n [K in keyof TCollectionRef &\n string]: (TCollectionRef[keyof TCollectionRef] extends Collection<\n infer T\n >\n ? T\n : never) &\n Input\n }\n schema: {\n [K in keyof TCollectionRef &\n string]: (TCollectionRef[keyof TCollectionRef] extends Collection<\n infer T\n >\n ? T\n : never) &\n Input\n }\n default: keyof TCollectionRef & string\n }>\n }\n\n private fromInputReference<\n T extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n TAs extends string | undefined,\n >(collection: T, as?: TAs) {\n const newBuilder = new BaseQueryBuilder()\n Object.assign(newBuilder.query, this.query)\n newBuilder.query.from = collection as From<TContext>\n if (as) {\n newBuilder.query.as = as\n }\n\n // Calculate the result type without deep nesting\n type ResultSchema = TAs extends undefined\n ? { [K in T]: TContext[`baseSchema`][T] }\n : { [K in string & TAs]: TContext[`baseSchema`][T] }\n\n type ResultDefault = TAs extends undefined ? T : string & TAs\n\n // Use simpler type assertion to avoid excessive depth\n return newBuilder as unknown as QueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: ResultSchema\n default: ResultDefault\n }>\n }\n\n /**\n * Specify what columns to select.\n * Overwrites any previous select clause.\n *\n * @param selects The columns to select\n * @returns A new QueryBuilder with the select clause set\n */\n select<TSelects extends Array<Select<TContext>>>(\n this: QueryBuilder<TContext>,\n ...selects: TSelects\n ) {\n // Validate function calls in the selects\n // Need to use a type assertion to bypass deep recursive type checking\n const validatedSelects = selects.map((select) => {\n // If the select is an object with aliases, validate each value\n if (\n typeof select === `object` &&\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n select !== null &&\n !Array.isArray(select)\n ) {\n const result: Record<string, any> = {}\n\n for (const [key, value] of Object.entries(select)) {\n // If it's a function call (object with a single key that is an allowed function name)\n if (\n typeof value === `object` &&\n value !== null &&\n !Array.isArray(value)\n ) {\n const keys = Object.keys(value)\n if (keys.length === 1) {\n const funcName = keys[0]!\n // List of allowed function names from AllowedFunctionName\n const allowedFunctions = [\n `SUM`,\n `COUNT`,\n `AVG`,\n `MIN`,\n `MAX`,\n `DATE`,\n `JSON_EXTRACT`,\n `JSON_EXTRACT_PATH`,\n `UPPER`,\n `LOWER`,\n `COALESCE`,\n `CONCAT`,\n `LENGTH`,\n `ORDER_INDEX`,\n ]\n\n if (!allowedFunctions.includes(funcName)) {\n console.warn(\n `Unsupported function: ${funcName}. Expected one of: ${allowedFunctions.join(`, `)}`\n )\n }\n }\n }\n\n result[key] = value\n }\n\n return result\n }\n\n return select\n })\n\n // Ensure we have an orderByIndex in the select if we have an orderBy\n // This is required if select is called after orderBy\n if (this._query.orderBy) {\n validatedSelects.push({ _orderByIndex: { ORDER_INDEX: `numeric` } })\n }\n\n const newBuilder = new BaseQueryBuilder<TContext>(\n (this as BaseQueryBuilder<TContext>).query\n )\n newBuilder.query.select = validatedSelects as Array<Select<TContext>>\n\n return newBuilder as QueryBuilder<\n Flatten<\n Omit<TContext, `result`> & {\n result: InferResultTypeFromSelectTuple<TContext, TSelects>\n }\n >\n >\n }\n\n /**\n * Add a where clause comparing two values.\n */\n where(\n left: PropertyReferenceString<TContext> | LiteralValue,\n operator: Comparator,\n right: PropertyReferenceString<TContext> | LiteralValue\n ): QueryBuilder<TContext>\n\n /**\n * Add a where clause with a complete condition object.\n */\n where(condition: Condition<TContext>): QueryBuilder<TContext>\n\n /**\n * Add a where clause to filter the results.\n * Can be called multiple times to add AND conditions.\n *\n * @param leftOrCondition The left operand or complete condition\n * @param operator Optional comparison operator\n * @param right Optional right operand\n * @returns A new QueryBuilder with the where clause added\n */\n where(\n leftOrCondition: any,\n operator?: any,\n right?: any\n ): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n // Use simplistic approach to avoid deep type errors\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n let condition: any\n\n // Determine if this is a complete condition or individual parts\n if (operator !== undefined && right !== undefined) {\n // Create a condition from parts\n condition = [leftOrCondition, operator, right]\n } else {\n // Use the provided condition directly\n condition = leftOrCondition\n }\n\n if (!newBuilder.query.where) {\n newBuilder.query.where = condition\n } else {\n // Create a composite condition with AND\n // Use any to bypass type checking issues\n const andArray: any = [newBuilder.query.where, `and`, condition]\n newBuilder.query.where = andArray\n }\n\n return newBuilder as unknown as QueryBuilder<TContext>\n }\n\n /**\n * Add a having clause comparing two values.\n * For filtering results after they have been grouped.\n */\n having(\n left: PropertyReferenceString<TContext> | LiteralValue,\n operator: Comparator,\n right: PropertyReferenceString<TContext> | LiteralValue\n ): QueryBuilder<TContext>\n\n /**\n * Add a having clause with a complete condition object.\n * For filtering results after they have been grouped.\n */\n having(condition: Condition<TContext>): QueryBuilder<TContext>\n\n /**\n * Add a having clause to filter the grouped results.\n * Can be called multiple times to add AND conditions.\n *\n * @param leftOrCondition The left operand or complete condition\n * @param operator Optional comparison operator\n * @param right Optional right operand\n * @returns A new QueryBuilder with the having clause added\n */\n having(\n leftOrCondition: any,\n operator?: any,\n right?: any\n ): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n let condition: any\n\n // Determine if this is a complete condition or individual parts\n if (operator !== undefined && right !== undefined) {\n // Create a condition from parts\n condition = [leftOrCondition, operator, right]\n } else {\n // Use the provided condition directly\n condition = leftOrCondition\n }\n\n if (!newBuilder.query.having) {\n newBuilder.query.having = condition\n } else {\n // Create a composite condition with AND\n // Use any to bypass type checking issues\n const andArray: any = [newBuilder.query.having, `and`, condition]\n newBuilder.query.having = andArray\n }\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Add a join clause to the query using a CollectionRef.\n */\n join<TCollectionRef extends CollectionRef>(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TCollectionRef\n on: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] & {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n }>\n >\n where?: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n }>\n >\n }): QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n }\n >\n >\n\n /**\n * Add a join clause to the query without specifying an alias.\n * The collection name will be used as the default alias.\n */\n join<\n T extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n >(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: T\n on: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] & {\n [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]>\n }\n }>\n >\n where?: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: { [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]> }\n }>\n >\n }): QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]>\n }\n }\n >\n >\n\n /**\n * Add a join clause to the query with a specified alias.\n */\n join<\n TFrom extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n TAs extends string,\n >(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TFrom\n as: TAs\n on: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] & {\n [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][TFrom]>\n }\n }>\n >\n where?: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: {\n [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][TFrom]>\n }\n }>\n >\n }): QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][TFrom]>\n }\n }\n >\n >\n\n join<\n TFrom extends\n | InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>\n | CollectionRef,\n TAs extends string | undefined = undefined,\n >(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TFrom\n as?: TAs\n on: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] &\n (TFrom extends CollectionRef\n ? {\n [K in keyof TFrom & string]: RemoveIndexSignature<\n (TFrom[keyof TFrom] extends Collection<infer T> ? T : never) &\n Input\n >\n }\n : TFrom extends InputReference<infer TRef>\n ? {\n [K in keyof TRef & string]: RemoveIndexSignature<\n TRef[keyof TRef]\n >\n }\n : never)\n }>\n >\n where?: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] &\n (TFrom extends CollectionRef\n ? {\n [K in keyof TFrom & string]: RemoveIndexSignature<\n (TFrom[keyof TFrom] extends Collection<infer T> ? T : never) &\n Input\n >\n }\n : TFrom extends InputReference<infer TRef>\n ? {\n [K in keyof TRef & string]: RemoveIndexSignature<\n TRef[keyof TRef]\n >\n }\n : never)\n }>\n >\n }): QueryBuilder<any> {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (typeof joinClause.from === `object` && joinClause.from !== null) {\n return this.joinCollectionRef(\n joinClause as {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: CollectionRef\n on: Condition<any>\n where?: Condition<any>\n }\n )\n } else {\n return this.joinInputReference(\n joinClause as {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>\n as?: TAs\n on: Condition<any>\n where?: Condition<any>\n }\n )\n }\n }\n\n private joinCollectionRef<TCollectionRef extends CollectionRef>(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TCollectionRef\n on: Condition<any>\n where?: Condition<any>\n }): QueryBuilder<any> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Get the collection key\n const keys = Object.keys(joinClause.from)\n if (keys.length !== 1) {\n throw new Error(`Expected exactly one key in CollectionRef`)\n }\n const key = keys[0]!\n const collection = joinClause.from[key]\n if (!collection) {\n throw new Error(`Collection not found for key: ${key}`)\n }\n\n // Create a copy of the join clause for the query\n const joinClauseCopy = {\n type: joinClause.type,\n from: key,\n on: joinClause.on,\n where: joinClause.where,\n } as JoinClause<TContext>\n\n // Add the join clause to the query\n if (!newBuilder.query.join) {\n newBuilder.query.join = [joinClauseCopy]\n } else {\n newBuilder.query.join = [...newBuilder.query.join, joinClauseCopy]\n }\n\n // Add the collection to the collections map\n newBuilder.query.collections ??= {}\n newBuilder.query.collections[key] = collection\n\n // Return the new builder with updated schema type\n return newBuilder as QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n }\n >\n >\n }\n\n private joinInputReference<\n TFrom extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n TAs extends string | undefined = undefined,\n >(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TFrom\n as?: TAs\n on: Condition<any>\n where?: Condition<any>\n }): QueryBuilder<any> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Create a copy of the join clause for the query\n const joinClauseCopy = { ...joinClause } as JoinClause<TContext>\n\n // Add the join clause to the query\n if (!newBuilder.query.join) {\n newBuilder.query.join = [joinClauseCopy]\n } else {\n newBuilder.query.join = [...newBuilder.query.join, joinClauseCopy]\n }\n\n // Determine the alias or use the collection name as default\n const _effectiveAlias = joinClause.as ?? joinClause.from\n\n // Return the new builder with updated schema type\n return newBuilder as QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in typeof _effectiveAlias]: TContext[`baseSchema`][TFrom]\n }\n }\n >\n >\n }\n\n /**\n * Add an orderBy clause to sort the results.\n * Overwrites any previous orderBy clause.\n *\n * @param orderBy The order specification\n * @returns A new QueryBuilder with the orderBy clause set\n */\n orderBy(orderBy: OrderBy<TContext>): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the orderBy clause\n newBuilder.query.orderBy = orderBy\n\n // Ensure we have an orderByIndex in the select if we have an orderBy\n // This is required if select is called before orderBy\n newBuilder.query.select = [\n ...(newBuilder.query.select ?? []),\n { _orderByIndex: { ORDER_INDEX: `numeric` } },\n ]\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Set a limit on the number of results returned.\n *\n * @param limit Maximum number of results to return\n * @returns A new QueryBuilder with the limit set\n */\n limit(limit: Limit<TContext>): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the limit\n newBuilder.query.limit = limit\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Set an offset to skip a number of results.\n *\n * @param offset Number of results to skip\n * @returns A new QueryBuilder with the offset set\n */\n offset(offset: Offset<TContext>): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the offset\n newBuilder.query.offset = offset\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Specify which column(s) to use as keys in the output keyed stream.\n *\n * @param keyBy The column(s) to use as keys\n * @returns A new QueryBuilder with the keyBy clause set\n */\n keyBy(\n keyBy: PropertyReference<TContext> | Array<PropertyReference<TContext>>\n ): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the keyBy clause\n newBuilder.query.keyBy = keyBy\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Add a groupBy clause to group the results by one or more columns.\n *\n * @param groupBy The column(s) to group by\n * @returns A new QueryBuilder with the groupBy clause set\n */\n groupBy(\n groupBy: PropertyReference<TContext> | Array<PropertyReference<TContext>>\n ): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the groupBy clause\n newBuilder.query.groupBy = groupBy\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Define a Common Table Expression (CTE) that can be referenced in the main query.\n * This allows referencing the CTE by name in subsequent from/join clauses.\n *\n * @param name The name of the CTE\n * @param queryBuilderCallback A function that builds the CTE query\n * @returns A new QueryBuilder with the CTE added\n */\n with<TName extends string, TResult = Record<string, unknown>>(\n name: TName,\n queryBuilderCallback: (\n builder: InitialQueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {}\n }>\n ) => QueryBuilder<any>\n ): InitialQueryBuilder<{\n baseSchema: TContext[`baseSchema`] & { [K in TName]: TResult }\n schema: TContext[`schema`]\n }> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Create a new builder for the CTE\n const cteBuilder = new BaseQueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {}\n }>()\n\n // Get the CTE query from the callback\n const cteQueryBuilder = queryBuilderCallback(\n cteBuilder as InitialQueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {}\n }>\n )\n\n // Get the query from the builder\n const cteQuery = cteQueryBuilder._query\n\n // Add an 'as' property to the CTE\n const withQuery: WithQuery<any> = {\n ...cteQuery,\n as: name,\n }\n\n // Add the CTE to the with array\n if (!newBuilder.query.with) {\n newBuilder.query.with = [withQuery]\n } else {\n newBuilder.query.with = [...newBuilder.query.with, withQuery]\n }\n\n // Use a type cast that simplifies the type structure to avoid recursion\n return newBuilder as unknown as InitialQueryBuilder<{\n baseSchema: TContext[`baseSchema`] & { [K in TName]: TResult }\n schema: TContext[`schema`]\n }>\n }\n\n get _query(): Query<TContext> {\n return this.query as Query<TContext>\n }\n}\n\nexport type InitialQueryBuilder<TContext extends Context<Schema>> = Pick<\n BaseQueryBuilder<TContext>,\n `from` | `with`\n>\n\nexport type QueryBuilder<TContext extends Context<Schema>> = Omit<\n BaseQueryBuilder<TContext>,\n `from`\n>\n\n/**\n * Create a new query builder with the given schema\n */\nexport function queryBuilder<TBaseSchema extends Schema = {}>() {\n return new BaseQueryBuilder<{\n baseSchema: TBaseSchema\n schema: {}\n }>() as InitialQueryBuilder<{\n baseSchema: TBaseSchema\n schema: {}\n }>\n}\n\nexport type ResultsFromContext<TContext extends Context<Schema>> = Flatten<\n TContext[`result`] extends object\n ? TContext[`result`]\n : TContext[`result`] extends undefined\n ? TContext[`schema`]\n : object\n>\n\nexport type ResultFromQueryBuilder<TQueryBuilder> = Flatten<\n TQueryBuilder extends QueryBuilder<infer C>\n ? C extends { result: infer R }\n ? R\n : never\n : never\n>\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query-builder.cjs","sources":["../../../src/query/query-builder.ts"],"sourcesContent":["import type { Collection } from \"../collection\"\nimport type {\n Comparator,\n Condition,\n From,\n JoinClause,\n Limit,\n LiteralValue,\n Offset,\n OrderBy,\n Query,\n Select,\n WithQuery,\n} from \"./schema.js\"\nimport type {\n Context,\n Flatten,\n InferResultTypeFromSelectTuple,\n Input,\n InputReference,\n PropertyReference,\n PropertyReferenceString,\n RemoveIndexSignature,\n Schema,\n} from \"./types.js\"\n\ntype CollectionRef = { [K: string]: Collection<any> }\n\nexport class BaseQueryBuilder<TContext extends Context<Schema>> {\n private readonly query: Partial<Query<TContext>> = {}\n\n /**\n * Create a new QueryBuilder instance.\n */\n constructor(query: Partial<Query<TContext>> = {}) {\n this.query = query\n }\n\n from<TCollectionRef extends CollectionRef>(\n collectionRef: TCollectionRef\n ): QueryBuilder<{\n baseSchema: Flatten<\n TContext[`baseSchema`] & {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n >\n schema: Flatten<{\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }>\n default: keyof TCollectionRef & string\n }>\n\n from<\n T extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n >(\n collection: T\n ): QueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {\n [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]>\n }\n default: T\n }>\n\n from<\n T extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n TAs extends string,\n >(\n collection: T,\n as: TAs\n ): QueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {\n [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][T]>\n }\n default: TAs\n }>\n\n /**\n * Specify the collection to query from.\n * This is the first method that must be called in the chain.\n *\n * @param collection The collection name to query from\n * @param as Optional alias for the collection\n * @returns A new QueryBuilder with the from clause set\n */\n from<\n T extends\n | InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>\n | CollectionRef,\n TAs extends string | undefined,\n >(collection: T, as?: TAs) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (typeof collection === `object` && collection !== null) {\n return this.fromCollectionRef(collection)\n } else if (typeof collection === `string`) {\n return this.fromInputReference(\n collection as InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n as\n )\n } else {\n throw new Error(`Invalid collection type`)\n }\n }\n\n private fromCollectionRef<TCollectionRef extends CollectionRef>(\n collectionRef: TCollectionRef\n ) {\n const keys = Object.keys(collectionRef)\n if (keys.length !== 1) {\n throw new Error(`Expected exactly one key`)\n }\n\n const key = keys[0]!\n const collection = collectionRef[key]!\n\n const newBuilder = new BaseQueryBuilder()\n Object.assign(newBuilder.query, this.query)\n newBuilder.query.from = key as From<TContext>\n newBuilder.query.collections ??= {}\n newBuilder.query.collections[key] = collection\n\n return newBuilder as unknown as QueryBuilder<{\n baseSchema: TContext[`baseSchema`] & {\n [K in keyof TCollectionRef &\n string]: (TCollectionRef[keyof TCollectionRef] extends Collection<\n infer T\n >\n ? T\n : never) &\n Input\n }\n schema: {\n [K in keyof TCollectionRef &\n string]: (TCollectionRef[keyof TCollectionRef] extends Collection<\n infer T\n >\n ? T\n : never) &\n Input\n }\n default: keyof TCollectionRef & string\n }>\n }\n\n private fromInputReference<\n T extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n TAs extends string | undefined,\n >(collection: T, as?: TAs) {\n const newBuilder = new BaseQueryBuilder()\n Object.assign(newBuilder.query, this.query)\n newBuilder.query.from = collection as From<TContext>\n if (as) {\n newBuilder.query.as = as\n }\n\n // Calculate the result type without deep nesting\n type ResultSchema = TAs extends undefined\n ? { [K in T]: TContext[`baseSchema`][T] }\n : { [K in string & TAs]: TContext[`baseSchema`][T] }\n\n type ResultDefault = TAs extends undefined ? T : string & TAs\n\n // Use simpler type assertion to avoid excessive depth\n return newBuilder as unknown as QueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: ResultSchema\n default: ResultDefault\n }>\n }\n\n /**\n * Specify what columns to select.\n * Overwrites any previous select clause.\n *\n * @param selects The columns to select\n * @returns A new QueryBuilder with the select clause set\n */\n select<TSelects extends Array<Select<TContext>>>(\n this: QueryBuilder<TContext>,\n ...selects: TSelects\n ) {\n // Validate function calls in the selects\n // Need to use a type assertion to bypass deep recursive type checking\n const validatedSelects = selects.map((select) => {\n // If the select is an object with aliases, validate each value\n if (\n typeof select === `object` &&\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n select !== null &&\n !Array.isArray(select)\n ) {\n const result: Record<string, any> = {}\n\n for (const [key, value] of Object.entries(select)) {\n // If it's a function call (object with a single key that is an allowed function name)\n if (\n typeof value === `object` &&\n value !== null &&\n !Array.isArray(value)\n ) {\n const keys = Object.keys(value)\n if (keys.length === 1) {\n const funcName = keys[0]!\n // List of allowed function names from AllowedFunctionName\n const allowedFunctions = [\n `SUM`,\n `COUNT`,\n `AVG`,\n `MIN`,\n `MAX`,\n `DATE`,\n `JSON_EXTRACT`,\n `JSON_EXTRACT_PATH`,\n `UPPER`,\n `LOWER`,\n `COALESCE`,\n `CONCAT`,\n `LENGTH`,\n `ORDER_INDEX`,\n ]\n\n if (!allowedFunctions.includes(funcName)) {\n console.warn(\n `Unsupported function: ${funcName}. Expected one of: ${allowedFunctions.join(`, `)}`\n )\n }\n }\n }\n\n result[key] = value\n }\n\n return result\n }\n\n return select\n })\n\n // Ensure we have an orderByIndex in the select if we have an orderBy\n // This is required if select is called after orderBy\n if (this._query.orderBy) {\n validatedSelects.push({ _orderByIndex: { ORDER_INDEX: `numeric` } })\n }\n\n const newBuilder = new BaseQueryBuilder<TContext>(\n (this as BaseQueryBuilder<TContext>).query\n )\n newBuilder.query.select = validatedSelects as Array<Select<TContext>>\n\n return newBuilder as QueryBuilder<\n Flatten<\n Omit<TContext, `result`> & {\n result: InferResultTypeFromSelectTuple<TContext, TSelects>\n }\n >\n >\n }\n\n /**\n * Add a where clause comparing two values.\n */\n where(\n left: PropertyReferenceString<TContext> | LiteralValue,\n operator: Comparator,\n right: PropertyReferenceString<TContext> | LiteralValue\n ): QueryBuilder<TContext>\n\n /**\n * Add a where clause with a complete condition object.\n */\n where(condition: Condition<TContext>): QueryBuilder<TContext>\n\n /**\n * Add a where clause to filter the results.\n * Can be called multiple times to add AND conditions.\n *\n * @param leftOrCondition The left operand or complete condition\n * @param operator Optional comparison operator\n * @param right Optional right operand\n * @returns A new QueryBuilder with the where clause added\n */\n where(\n leftOrCondition: any,\n operator?: any,\n right?: any\n ): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n // Use simplistic approach to avoid deep type errors\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n let condition: any\n\n // Determine if this is a complete condition or individual parts\n if (operator !== undefined && right !== undefined) {\n // Create a condition from parts\n condition = [leftOrCondition, operator, right]\n } else {\n // Use the provided condition directly\n condition = leftOrCondition\n }\n\n if (!newBuilder.query.where) {\n newBuilder.query.where = condition\n } else {\n // Create a composite condition with AND\n // Use any to bypass type checking issues\n const andArray: any = [newBuilder.query.where, `and`, condition]\n newBuilder.query.where = andArray\n }\n\n return newBuilder as unknown as QueryBuilder<TContext>\n }\n\n /**\n * Add a having clause comparing two values.\n * For filtering results after they have been grouped.\n */\n having(\n left: PropertyReferenceString<TContext> | LiteralValue,\n operator: Comparator,\n right: PropertyReferenceString<TContext> | LiteralValue\n ): QueryBuilder<TContext>\n\n /**\n * Add a having clause with a complete condition object.\n * For filtering results after they have been grouped.\n */\n having(condition: Condition<TContext>): QueryBuilder<TContext>\n\n /**\n * Add a having clause to filter the grouped results.\n * Can be called multiple times to add AND conditions.\n *\n * @param leftOrCondition The left operand or complete condition\n * @param operator Optional comparison operator\n * @param right Optional right operand\n * @returns A new QueryBuilder with the having clause added\n */\n having(\n leftOrCondition: any,\n operator?: any,\n right?: any\n ): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n let condition: any\n\n // Determine if this is a complete condition or individual parts\n if (operator !== undefined && right !== undefined) {\n // Create a condition from parts\n condition = [leftOrCondition, operator, right]\n } else {\n // Use the provided condition directly\n condition = leftOrCondition\n }\n\n if (!newBuilder.query.having) {\n newBuilder.query.having = condition\n } else {\n // Create a composite condition with AND\n // Use any to bypass type checking issues\n const andArray: any = [newBuilder.query.having, `and`, condition]\n newBuilder.query.having = andArray\n }\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Add a join clause to the query using a CollectionRef.\n */\n join<TCollectionRef extends CollectionRef>(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TCollectionRef\n on: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] & {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n }>\n >\n where?: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n }>\n >\n }): QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n hasJoin: true\n }\n >\n >\n\n /**\n * Add a join clause to the query without specifying an alias.\n * The collection name will be used as the default alias.\n */\n join<\n T extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n >(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: T\n on: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] & {\n [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]>\n }\n }>\n >\n where?: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: { [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]> }\n }>\n >\n }): QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]>\n }\n hasJoin: true\n }\n >\n >\n\n /**\n * Add a join clause to the query with a specified alias.\n */\n join<\n TFrom extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n TAs extends string,\n >(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TFrom\n as: TAs\n on: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] & {\n [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][TFrom]>\n }\n }>\n >\n where?: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: {\n [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][TFrom]>\n }\n }>\n >\n }): QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][TFrom]>\n }\n hasJoin: true\n }\n >\n >\n\n join<\n TFrom extends\n | InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>\n | CollectionRef,\n TAs extends string | undefined = undefined,\n >(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TFrom\n as?: TAs\n on: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] &\n (TFrom extends CollectionRef\n ? {\n [K in keyof TFrom & string]: RemoveIndexSignature<\n (TFrom[keyof TFrom] extends Collection<infer T> ? T : never) &\n Input\n >\n }\n : TFrom extends InputReference<infer TRef>\n ? {\n [K in keyof TRef & string]: RemoveIndexSignature<\n TRef[keyof TRef]\n >\n }\n : never)\n }>\n >\n where?: Condition<\n Flatten<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`schema`] &\n (TFrom extends CollectionRef\n ? {\n [K in keyof TFrom & string]: RemoveIndexSignature<\n (TFrom[keyof TFrom] extends Collection<infer T> ? T : never) &\n Input\n >\n }\n : TFrom extends InputReference<infer TRef>\n ? {\n [K in keyof TRef & string]: RemoveIndexSignature<\n TRef[keyof TRef]\n >\n }\n : never)\n }>\n >\n }): QueryBuilder<any> {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (typeof joinClause.from === `object` && joinClause.from !== null) {\n return this.joinCollectionRef(\n joinClause as {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: CollectionRef\n on: Condition<any>\n where?: Condition<any>\n }\n )\n } else {\n return this.joinInputReference(\n joinClause as {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>\n as?: TAs\n on: Condition<any>\n where?: Condition<any>\n }\n )\n }\n }\n\n private joinCollectionRef<TCollectionRef extends CollectionRef>(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TCollectionRef\n on: Condition<any>\n where?: Condition<any>\n }): QueryBuilder<any> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Get the collection key\n const keys = Object.keys(joinClause.from)\n if (keys.length !== 1) {\n throw new Error(`Expected exactly one key in CollectionRef`)\n }\n const key = keys[0]!\n const collection = joinClause.from[key]\n if (!collection) {\n throw new Error(`Collection not found for key: ${key}`)\n }\n\n // Create a copy of the join clause for the query\n const joinClauseCopy = {\n type: joinClause.type,\n from: key,\n on: joinClause.on,\n where: joinClause.where,\n } as JoinClause<TContext>\n\n // Add the join clause to the query\n if (!newBuilder.query.join) {\n newBuilder.query.join = [joinClauseCopy]\n } else {\n newBuilder.query.join = [...newBuilder.query.join, joinClauseCopy]\n }\n\n // Add the collection to the collections map\n newBuilder.query.collections ??= {}\n newBuilder.query.collections[key] = collection\n\n // Return the new builder with updated schema type\n return newBuilder as QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in keyof TCollectionRef & string]: RemoveIndexSignature<\n (TCollectionRef[keyof TCollectionRef] extends Collection<infer T>\n ? T\n : never) &\n Input\n >\n }\n }\n >\n >\n }\n\n private joinInputReference<\n TFrom extends InputReference<{\n baseSchema: TContext[`baseSchema`]\n schema: TContext[`baseSchema`]\n }>,\n TAs extends string | undefined = undefined,\n >(joinClause: {\n type: `inner` | `left` | `right` | `full` | `cross`\n from: TFrom\n as?: TAs\n on: Condition<any>\n where?: Condition<any>\n }): QueryBuilder<any> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Create a copy of the join clause for the query\n const joinClauseCopy = { ...joinClause } as JoinClause<TContext>\n\n // Add the join clause to the query\n if (!newBuilder.query.join) {\n newBuilder.query.join = [joinClauseCopy]\n } else {\n newBuilder.query.join = [...newBuilder.query.join, joinClauseCopy]\n }\n\n // Determine the alias or use the collection name as default\n const _effectiveAlias = joinClause.as ?? joinClause.from\n\n // Return the new builder with updated schema type\n return newBuilder as QueryBuilder<\n Flatten<\n Omit<TContext, `schema`> & {\n schema: TContext[`schema`] & {\n [K in typeof _effectiveAlias]: TContext[`baseSchema`][TFrom]\n }\n }\n >\n >\n }\n\n /**\n * Add an orderBy clause to sort the results.\n * Overwrites any previous orderBy clause.\n *\n * @param orderBy The order specification\n * @returns A new QueryBuilder with the orderBy clause set\n */\n orderBy(orderBy: OrderBy<TContext>): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the orderBy clause\n newBuilder.query.orderBy = orderBy\n\n // Ensure we have an orderByIndex in the select if we have an orderBy\n // This is required if select is called before orderBy\n newBuilder.query.select = [\n ...(newBuilder.query.select ?? []),\n { _orderByIndex: { ORDER_INDEX: `numeric` } },\n ]\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Set a limit on the number of results returned.\n *\n * @param limit Maximum number of results to return\n * @returns A new QueryBuilder with the limit set\n */\n limit(limit: Limit<TContext>): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the limit\n newBuilder.query.limit = limit\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Set an offset to skip a number of results.\n *\n * @param offset Number of results to skip\n * @returns A new QueryBuilder with the offset set\n */\n offset(offset: Offset<TContext>): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the offset\n newBuilder.query.offset = offset\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Add a groupBy clause to group the results by one or more columns.\n *\n * @param groupBy The column(s) to group by\n * @returns A new QueryBuilder with the groupBy clause set\n */\n groupBy(\n groupBy: PropertyReference<TContext> | Array<PropertyReference<TContext>>\n ): QueryBuilder<TContext> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Set the groupBy clause\n newBuilder.query.groupBy = groupBy\n\n return newBuilder as QueryBuilder<TContext>\n }\n\n /**\n * Define a Common Table Expression (CTE) that can be referenced in the main query.\n * This allows referencing the CTE by name in subsequent from/join clauses.\n *\n * @param name The name of the CTE\n * @param queryBuilderCallback A function that builds the CTE query\n * @returns A new QueryBuilder with the CTE added\n */\n with<TName extends string, TResult = Record<string, unknown>>(\n name: TName,\n queryBuilderCallback: (\n builder: InitialQueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {}\n }>\n ) => QueryBuilder<any>\n ): InitialQueryBuilder<{\n baseSchema: TContext[`baseSchema`] & { [K in TName]: TResult }\n schema: TContext[`schema`]\n }> {\n // Create a new builder with a copy of the current query\n const newBuilder = new BaseQueryBuilder<TContext>()\n Object.assign(newBuilder.query, this.query)\n\n // Create a new builder for the CTE\n const cteBuilder = new BaseQueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {}\n }>()\n\n // Get the CTE query from the callback\n const cteQueryBuilder = queryBuilderCallback(\n cteBuilder as InitialQueryBuilder<{\n baseSchema: TContext[`baseSchema`]\n schema: {}\n }>\n )\n\n // Get the query from the builder\n const cteQuery = cteQueryBuilder._query\n\n // Add an 'as' property to the CTE\n const withQuery: WithQuery<any> = {\n ...cteQuery,\n as: name,\n }\n\n // Add the CTE to the with array\n if (!newBuilder.query.with) {\n newBuilder.query.with = [withQuery]\n } else {\n newBuilder.query.with = [...newBuilder.query.with, withQuery]\n }\n\n // Use a type cast that simplifies the type structure to avoid recursion\n return newBuilder as unknown as InitialQueryBuilder<{\n baseSchema: TContext[`baseSchema`] & { [K in TName]: TResult }\n schema: TContext[`schema`]\n }>\n }\n\n get _query(): Query<TContext> {\n return this.query as Query<TContext>\n }\n}\n\nexport type InitialQueryBuilder<TContext extends Context<Schema>> = Pick<\n BaseQueryBuilder<TContext>,\n `from` | `with`\n>\n\nexport type QueryBuilder<TContext extends Context<Schema>> = Omit<\n BaseQueryBuilder<TContext>,\n `from`\n>\n\n/**\n * Create a new query builder with the given schema\n */\nexport function queryBuilder<TBaseSchema extends Schema = {}>() {\n return new BaseQueryBuilder<{\n baseSchema: TBaseSchema\n schema: {}\n }>() as InitialQueryBuilder<{\n baseSchema: TBaseSchema\n schema: {}\n }>\n}\n\nexport type ResultsFromContext<TContext extends Context<Schema>> = Flatten<\n TContext[`result`] extends object\n ? TContext[`result`] // If there is a select we will have a result type\n : TContext[`hasJoin`] extends true\n ? TContext[`schema`] // If there is a join, the query returns the namespaced schema\n : TContext[`default`] extends keyof TContext[`schema`]\n ? TContext[`schema`][TContext[`default`]] // If there is no join we return the flat default schema\n : never // Should never happen\n>\n\nexport type ResultFromQueryBuilder<TQueryBuilder> = Flatten<\n TQueryBuilder extends QueryBuilder<infer C>\n ? C extends { result: infer R }\n ? R\n : never\n : never\n>\n"],"names":[],"mappings":"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"}
@@ -91,6 +91,7 @@ export declare class BaseQueryBuilder<TContext extends Context<Schema>> {
91
91
  schema: TContext[`schema`] & {
92
92
  [K in keyof TCollectionRef & string]: RemoveIndexSignature<(TCollectionRef[keyof TCollectionRef] extends Collection<infer T> ? T : never) & Input>;
93
93
  };
94
+ hasJoin: true;
94
95
  }>>;
95
96
  /**
96
97
  * Add a join clause to the query without specifying an alias.
@@ -118,6 +119,7 @@ export declare class BaseQueryBuilder<TContext extends Context<Schema>> {
118
119
  schema: TContext[`schema`] & {
119
120
  [K in T]: RemoveIndexSignature<TContext[`baseSchema`][T]>;
120
121
  };
122
+ hasJoin: true;
121
123
  }>>;
122
124
  /**
123
125
  * Add a join clause to the query with a specified alias.
@@ -145,6 +147,7 @@ export declare class BaseQueryBuilder<TContext extends Context<Schema>> {
145
147
  schema: TContext[`schema`] & {
146
148
  [K in TAs]: RemoveIndexSignature<TContext[`baseSchema`][TFrom]>;
147
149
  };
150
+ hasJoin: true;
148
151
  }>>;
149
152
  private joinCollectionRef;
150
153
  private joinInputReference;
@@ -170,13 +173,6 @@ export declare class BaseQueryBuilder<TContext extends Context<Schema>> {
170
173
  * @returns A new QueryBuilder with the offset set
171
174
  */
172
175
  offset(offset: Offset<TContext>): QueryBuilder<TContext>;
173
- /**
174
- * Specify which column(s) to use as keys in the output keyed stream.
175
- *
176
- * @param keyBy The column(s) to use as keys
177
- * @returns A new QueryBuilder with the keyBy clause set
178
- */
179
- keyBy(keyBy: PropertyReference<TContext> | Array<PropertyReference<TContext>>): QueryBuilder<TContext>;
180
176
  /**
181
177
  * Add a groupBy clause to group the results by one or more columns.
182
178
  *
@@ -212,7 +208,7 @@ export declare function queryBuilder<TBaseSchema extends Schema = {}>(): Initial
212
208
  baseSchema: TBaseSchema;
213
209
  schema: {};
214
210
  }>;
215
- export type ResultsFromContext<TContext extends Context<Schema>> = Flatten<TContext[`result`] extends object ? TContext[`result`] : TContext[`result`] extends undefined ? TContext[`schema`] : object>;
211
+ export type ResultsFromContext<TContext extends Context<Schema>> = Flatten<TContext[`result`] extends object ? TContext[`result`] : TContext[`hasJoin`] extends true ? TContext[`schema`] : TContext[`default`] extends keyof TContext[`schema`] ? TContext[`schema`][TContext[`default`]] : never>;
216
212
  export type ResultFromQueryBuilder<TQueryBuilder> = Flatten<TQueryBuilder extends QueryBuilder<infer C> ? C extends {
217
213
  result: infer R;
218
214
  } ? R : never : never>;
@@ -51,7 +51,6 @@ export interface JoinClause<TContext extends Context = Context> {
51
51
  from: string;
52
52
  as?: string;
53
53
  on: Condition<TContext>;
54
- where?: Condition<TContext>;
55
54
  }
56
55
  export type OrderBy<TContext extends Context = Context> = PropertyReferenceString<TContext> | {
57
56
  [column in PropertyReferenceString<TContext>]?: `asc` | `desc`;
@@ -72,7 +71,7 @@ export type Having<TContext extends Context = Context> = Condition<TContext>;
72
71
  export type Limit<TContext extends Context = Context> = number;
73
72
  export type Offset<TContext extends Context = Context> = number;
74
73
  export interface BaseQuery<TContext extends Context = Context> {
75
- select: Array<Select<TContext>>;
74
+ select?: Array<Select<TContext>>;
76
75
  as?: As<TContext>;
77
76
  from: From<TContext>;
78
77
  join?: Array<JoinClause<TContext>>;
@@ -84,7 +83,6 @@ export interface BaseQuery<TContext extends Context = Context> {
84
83
  offset?: Offset<TContext>;
85
84
  }
86
85
  export interface Query<TContext extends Context = Context> extends BaseQuery<TContext> {
87
- keyBy?: PropertyReference<TContext> | Array<PropertyReference<TContext>>;
88
86
  with?: Array<WithQuery<TContext>>;
89
87
  collections?: {
90
88
  [K: string]: Collection<any>;
@@ -93,6 +91,3 @@ export interface Query<TContext extends Context = Context> extends BaseQuery<TCo
93
91
  export interface WithQuery<TContext extends Context = Context> extends BaseQuery<TContext> {
94
92
  as: string;
95
93
  }
96
- export interface KeyedQuery<TContext extends Context = Context> extends Query<TContext> {
97
- keyBy: PropertyReference<TContext> | Array<PropertyReference<TContext>>;
98
- }