@prisma-next/sql-relational-core 0.3.0-dev.14 → 0.3.0-dev.146

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 (163) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +19 -5
  3. package/dist/codec-types-DcEITed4.d.mts +144 -0
  4. package/dist/codec-types-DcEITed4.d.mts.map +1 -0
  5. package/dist/errors-Cs52upp3.d.mts +8 -0
  6. package/dist/errors-Cs52upp3.d.mts.map +1 -0
  7. package/dist/errors-D3xmG4h-.mjs +35 -0
  8. package/dist/errors-D3xmG4h-.mjs.map +1 -0
  9. package/dist/exports/ast.d.mts +158 -0
  10. package/dist/exports/ast.d.mts.map +1 -0
  11. package/dist/exports/ast.mjs +1358 -0
  12. package/dist/exports/ast.mjs.map +1 -0
  13. package/dist/exports/errors.d.mts +5 -0
  14. package/dist/exports/errors.mjs +3 -0
  15. package/dist/exports/plan.d.mts +2 -0
  16. package/dist/exports/plan.mjs +17 -0
  17. package/dist/exports/plan.mjs.map +1 -0
  18. package/dist/exports/query-lane-context.d.mts +3 -0
  19. package/dist/exports/query-lane-context.mjs +1 -0
  20. package/dist/exports/types.d.mts +4 -0
  21. package/dist/exports/types.mjs +1 -0
  22. package/dist/index.d.mts +11 -0
  23. package/dist/index.mjs +7 -0
  24. package/dist/plan-5qUWdlJM.d.mts +28 -0
  25. package/dist/plan-5qUWdlJM.d.mts.map +1 -0
  26. package/dist/query-lane-context-UlR8vOkd.d.mts +89 -0
  27. package/dist/query-lane-context-UlR8vOkd.d.mts.map +1 -0
  28. package/dist/types-CLCtwVWx.d.mts +485 -0
  29. package/dist/types-CLCtwVWx.d.mts.map +1 -0
  30. package/dist/types-V1qiC5DO.d.mts +200 -0
  31. package/dist/types-V1qiC5DO.d.mts.map +1 -0
  32. package/package.json +32 -54
  33. package/src/ast/adapter-types.ts +11 -0
  34. package/src/ast/codec-types.ts +101 -53
  35. package/src/ast/driver-types.ts +20 -3
  36. package/src/ast/sql-codecs.ts +142 -0
  37. package/src/ast/types.ts +1681 -77
  38. package/src/errors.ts +47 -1
  39. package/src/exports/ast.ts +1 -8
  40. package/src/index.ts +0 -3
  41. package/src/plan.ts +4 -4
  42. package/src/query-lane-context.ts +81 -6
  43. package/src/types.ts +102 -354
  44. package/dist/ast/adapter-types.d.ts +0 -28
  45. package/dist/ast/adapter-types.d.ts.map +0 -1
  46. package/dist/ast/codec-types.d.ts +0 -141
  47. package/dist/ast/codec-types.d.ts.map +0 -1
  48. package/dist/ast/common.d.ts +0 -7
  49. package/dist/ast/common.d.ts.map +0 -1
  50. package/dist/ast/delete.d.ts +0 -8
  51. package/dist/ast/delete.d.ts.map +0 -1
  52. package/dist/ast/driver-types.d.ts +0 -20
  53. package/dist/ast/driver-types.d.ts.map +0 -1
  54. package/dist/ast/insert.d.ts +0 -8
  55. package/dist/ast/insert.d.ts.map +0 -1
  56. package/dist/ast/join.d.ts +0 -6
  57. package/dist/ast/join.d.ts.map +0 -1
  58. package/dist/ast/order.d.ts +0 -6
  59. package/dist/ast/order.d.ts.map +0 -1
  60. package/dist/ast/predicate.d.ts +0 -4
  61. package/dist/ast/predicate.d.ts.map +0 -1
  62. package/dist/ast/select.d.ts +0 -18
  63. package/dist/ast/select.d.ts.map +0 -1
  64. package/dist/ast/types.d.ts +0 -118
  65. package/dist/ast/types.d.ts.map +0 -1
  66. package/dist/ast/update.d.ts +0 -9
  67. package/dist/ast/update.d.ts.map +0 -1
  68. package/dist/ast/util.d.ts +0 -2
  69. package/dist/ast/util.d.ts.map +0 -1
  70. package/dist/chunk-2F7DSEOU.js +0 -8
  71. package/dist/chunk-2F7DSEOU.js.map +0 -1
  72. package/dist/chunk-36WJWNHT.js +0 -1
  73. package/dist/chunk-36WJWNHT.js.map +0 -1
  74. package/dist/chunk-5N34PNVZ.js +0 -62
  75. package/dist/chunk-5N34PNVZ.js.map +0 -1
  76. package/dist/chunk-7I3EMQID.js +0 -16
  77. package/dist/chunk-7I3EMQID.js.map +0 -1
  78. package/dist/chunk-D4JLPIWO.js +0 -13
  79. package/dist/chunk-D4JLPIWO.js.map +0 -1
  80. package/dist/chunk-G52ENULI.js +0 -1
  81. package/dist/chunk-G52ENULI.js.map +0 -1
  82. package/dist/chunk-J6O2HVBM.js +0 -320
  83. package/dist/chunk-J6O2HVBM.js.map +0 -1
  84. package/dist/chunk-KYSP7L5C.js +0 -16
  85. package/dist/chunk-KYSP7L5C.js.map +0 -1
  86. package/dist/chunk-M23L3JHG.js +0 -159
  87. package/dist/chunk-M23L3JHG.js.map +0 -1
  88. package/dist/chunk-U7AXAUJA.js +0 -1
  89. package/dist/chunk-U7AXAUJA.js.map +0 -1
  90. package/dist/chunk-U7IAFPVU.js +0 -152
  91. package/dist/chunk-U7IAFPVU.js.map +0 -1
  92. package/dist/errors.d.ts +0 -2
  93. package/dist/errors.d.ts.map +0 -1
  94. package/dist/exports/ast.d.ts +0 -14
  95. package/dist/exports/ast.d.ts.map +0 -1
  96. package/dist/exports/ast.js +0 -46
  97. package/dist/exports/ast.js.map +0 -1
  98. package/dist/exports/errors.d.ts +0 -2
  99. package/dist/exports/errors.d.ts.map +0 -1
  100. package/dist/exports/errors.js +0 -9
  101. package/dist/exports/errors.js.map +0 -1
  102. package/dist/exports/guards.d.ts +0 -2
  103. package/dist/exports/guards.d.ts.map +0 -1
  104. package/dist/exports/guards.js +0 -21
  105. package/dist/exports/guards.js.map +0 -1
  106. package/dist/exports/operations-registry.d.ts +0 -2
  107. package/dist/exports/operations-registry.d.ts.map +0 -1
  108. package/dist/exports/operations-registry.js +0 -9
  109. package/dist/exports/operations-registry.js.map +0 -1
  110. package/dist/exports/param.d.ts +0 -3
  111. package/dist/exports/param.d.ts.map +0 -1
  112. package/dist/exports/param.js +0 -7
  113. package/dist/exports/param.js.map +0 -1
  114. package/dist/exports/plan.d.ts +0 -2
  115. package/dist/exports/plan.d.ts.map +0 -1
  116. package/dist/exports/plan.js +0 -7
  117. package/dist/exports/plan.js.map +0 -1
  118. package/dist/exports/query-lane-context.d.ts +0 -2
  119. package/dist/exports/query-lane-context.d.ts.map +0 -1
  120. package/dist/exports/query-lane-context.js +0 -2
  121. package/dist/exports/query-lane-context.js.map +0 -1
  122. package/dist/exports/schema.d.ts +0 -3
  123. package/dist/exports/schema.d.ts.map +0 -1
  124. package/dist/exports/schema.js +0 -14
  125. package/dist/exports/schema.js.map +0 -1
  126. package/dist/exports/types.d.ts +0 -2
  127. package/dist/exports/types.d.ts.map +0 -1
  128. package/dist/exports/types.js +0 -10
  129. package/dist/exports/types.js.map +0 -1
  130. package/dist/index.d.ts +0 -9
  131. package/dist/index.d.ts.map +0 -1
  132. package/dist/index.js +0 -81
  133. package/dist/index.js.map +0 -1
  134. package/dist/operations-registry.d.ts +0 -5
  135. package/dist/operations-registry.d.ts.map +0 -1
  136. package/dist/param.d.ts +0 -4
  137. package/dist/param.d.ts.map +0 -1
  138. package/dist/plan.d.ts +0 -23
  139. package/dist/plan.d.ts.map +0 -1
  140. package/dist/query-lane-context.d.ts +0 -16
  141. package/dist/query-lane-context.d.ts.map +0 -1
  142. package/dist/schema.d.ts +0 -63
  143. package/dist/schema.d.ts.map +0 -1
  144. package/dist/types.d.ts +0 -332
  145. package/dist/types.d.ts.map +0 -1
  146. package/dist/utils/guards.d.ts +0 -55
  147. package/dist/utils/guards.d.ts.map +0 -1
  148. package/src/ast/common.ts +0 -36
  149. package/src/ast/delete.ts +0 -17
  150. package/src/ast/insert.ts +0 -17
  151. package/src/ast/join.ts +0 -54
  152. package/src/ast/order.ts +0 -11
  153. package/src/ast/predicate.ts +0 -30
  154. package/src/ast/select.ts +0 -39
  155. package/src/ast/update.ts +0 -19
  156. package/src/exports/guards.ts +0 -10
  157. package/src/exports/operations-registry.ts +0 -1
  158. package/src/exports/param.ts +0 -2
  159. package/src/exports/schema.ts +0 -6
  160. package/src/operations-registry.ts +0 -237
  161. package/src/param.ts +0 -15
  162. package/src/schema.ts +0 -373
  163. package/src/utils/guards.ts +0 -123
package/src/schema.ts DELETED
@@ -1,373 +0,0 @@
1
- import type { OperationRegistry } from '@prisma-next/operations';
2
- import { planInvalid } from '@prisma-next/plan';
3
- import type {
4
- ExtractCodecTypes,
5
- ExtractOperationTypes,
6
- SqlContract,
7
- SqlStorage,
8
- StorageColumn,
9
- } from '@prisma-next/sql-contract/types';
10
- import type { BinaryOp, TableRef } from './ast/types';
11
- import { attachOperationsToColumnBuilder } from './operations-registry';
12
- import type { QueryLaneContext } from './query-lane-context';
13
- import type {
14
- AnyColumnBuilderBase,
15
- BinaryBuilder,
16
- CodecTypes as CodecTypesType,
17
- ColumnBuilder,
18
- ComputeColumnJsType,
19
- OperationTypeSignature,
20
- OperationTypes,
21
- OrderBuilder,
22
- ParamPlaceholder,
23
- } from './types';
24
- import { isColumnBuilder } from './types';
25
-
26
- type TableColumns<Table extends { columns: Record<string, StorageColumn> }> = Table['columns'];
27
-
28
- type ColumnBuilders<
29
- Contract extends SqlContract<SqlStorage>,
30
- TableName extends string,
31
- Columns extends Record<string, StorageColumn>,
32
- CodecTypes extends CodecTypesType,
33
- Operations extends OperationTypes,
34
- > = {
35
- readonly [K in keyof Columns]: ColumnBuilder<
36
- K & string,
37
- Columns[K],
38
- ComputeColumnJsType<Contract, TableName, K & string, Columns[K], CodecTypes>,
39
- Operations
40
- >;
41
- };
42
-
43
- export class ColumnBuilderImpl<
44
- ColumnName extends string,
45
- ColumnMeta extends StorageColumn,
46
- JsType = unknown,
47
- > {
48
- readonly kind = 'column' as const;
49
-
50
- constructor(
51
- readonly table: string,
52
- readonly column: ColumnName,
53
- private readonly storageColumn: ColumnMeta,
54
- ) {}
55
-
56
- get columnMeta(): ColumnMeta {
57
- return this.storageColumn;
58
- }
59
-
60
- // Type-level helper property (not used at runtime)
61
- get __jsType(): JsType {
62
- return undefined as unknown as JsType;
63
- }
64
-
65
- private createBinaryBuilder(
66
- op: BinaryOp,
67
- value: ParamPlaceholder | AnyColumnBuilderBase,
68
- ): BinaryBuilder<ColumnName, ColumnMeta, JsType> {
69
- if (value == null) {
70
- throw planInvalid('Parameter placeholder or column builder required for column comparison');
71
- }
72
- if (value.kind === 'param-placeholder' || isColumnBuilder(value)) {
73
- return Object.freeze({
74
- kind: 'binary' as const,
75
- op,
76
- left: this as unknown as ColumnBuilder<ColumnName, ColumnMeta, JsType>,
77
- right: value,
78
- }) as BinaryBuilder<ColumnName, ColumnMeta, JsType>;
79
- }
80
- throw planInvalid('Parameter placeholder or column builder required for column comparison');
81
- }
82
-
83
- eq(
84
- value: ParamPlaceholder | AnyColumnBuilderBase,
85
- ): BinaryBuilder<ColumnName, ColumnMeta, JsType> {
86
- return this.createBinaryBuilder('eq', value);
87
- }
88
-
89
- neq(
90
- value: ParamPlaceholder | AnyColumnBuilderBase,
91
- ): BinaryBuilder<ColumnName, ColumnMeta, JsType> {
92
- return this.createBinaryBuilder('neq', value);
93
- }
94
-
95
- gt(
96
- value: ParamPlaceholder | AnyColumnBuilderBase,
97
- ): BinaryBuilder<ColumnName, ColumnMeta, JsType> {
98
- return this.createBinaryBuilder('gt', value);
99
- }
100
-
101
- lt(
102
- value: ParamPlaceholder | AnyColumnBuilderBase,
103
- ): BinaryBuilder<ColumnName, ColumnMeta, JsType> {
104
- return this.createBinaryBuilder('lt', value);
105
- }
106
-
107
- gte(
108
- value: ParamPlaceholder | AnyColumnBuilderBase,
109
- ): BinaryBuilder<ColumnName, ColumnMeta, JsType> {
110
- return this.createBinaryBuilder('gte', value);
111
- }
112
-
113
- lte(
114
- value: ParamPlaceholder | AnyColumnBuilderBase,
115
- ): BinaryBuilder<ColumnName, ColumnMeta, JsType> {
116
- return this.createBinaryBuilder('lte', value);
117
- }
118
-
119
- asc(): OrderBuilder<ColumnName, ColumnMeta, JsType> {
120
- return Object.freeze({
121
- kind: 'order' as const,
122
- expr: this as unknown as ColumnBuilder<ColumnName, ColumnMeta, JsType>,
123
- dir: 'asc' as const,
124
- }) as OrderBuilder<ColumnName, ColumnMeta, JsType>;
125
- }
126
-
127
- desc(): OrderBuilder<ColumnName, ColumnMeta, JsType> {
128
- return Object.freeze({
129
- kind: 'order' as const,
130
- expr: this as unknown as ColumnBuilder<ColumnName, ColumnMeta, JsType>,
131
- dir: 'desc' as const,
132
- }) as OrderBuilder<ColumnName, ColumnMeta, JsType>;
133
- }
134
- }
135
-
136
- export class TableBuilderImpl<
137
- Contract extends SqlContract<SqlStorage>,
138
- TableName extends string,
139
- Columns extends Record<string, StorageColumn>,
140
- CodecTypes extends CodecTypesType,
141
- Operations extends OperationTypes,
142
- > implements TableRef
143
- {
144
- readonly kind = 'table' as const;
145
- readonly columns: ColumnBuilders<Contract, TableName, Columns, CodecTypes, Operations>;
146
- private readonly _name: TableName;
147
-
148
- constructor(
149
- name: TableName,
150
- columns: ColumnBuilders<Contract, TableName, Columns, CodecTypes, Operations>,
151
- ) {
152
- this._name = name;
153
- this.columns = columns;
154
- }
155
-
156
- get name(): string {
157
- return this._name;
158
- }
159
- }
160
-
161
- function buildColumns<
162
- Contract extends SqlContract<SqlStorage>,
163
- TableName extends keyof Contract['storage']['tables'] & string,
164
- CodecTypes extends CodecTypesType,
165
- Operations extends OperationTypes,
166
- >(
167
- tableName: TableName,
168
- storage: SqlStorage,
169
- _contract: Contract,
170
- operationRegistry?: OperationRegistry,
171
- contractCapabilities?: Record<string, Record<string, boolean>>,
172
- ): ColumnBuilders<
173
- Contract,
174
- TableName,
175
- Contract['storage']['tables'][TableName]['columns'],
176
- CodecTypes,
177
- Operations
178
- > {
179
- const table = storage.tables[tableName];
180
-
181
- if (!table) {
182
- throw planInvalid(`Unknown table ${tableName}`);
183
- }
184
-
185
- type Columns = Contract['storage']['tables'][TableName]['columns'];
186
- const tableColumns = table.columns as Columns;
187
-
188
- const result = {} as {
189
- [K in keyof Columns]: ColumnBuilder<
190
- K & string,
191
- Columns[K],
192
- ComputeColumnJsType<Contract, TableName, K & string, Columns[K], CodecTypes>,
193
- Operations
194
- >;
195
- };
196
-
197
- const assignColumn = <ColumnKey extends keyof Columns & string>(
198
- columnName: ColumnKey,
199
- columnDef: Columns[ColumnKey],
200
- ) => {
201
- type JsType = ComputeColumnJsType<
202
- Contract,
203
- TableName,
204
- ColumnKey,
205
- Columns[ColumnKey],
206
- CodecTypes
207
- >;
208
-
209
- const columnBuilder = new ColumnBuilderImpl<ColumnKey, Columns[ColumnKey], JsType>(
210
- tableName,
211
- columnName,
212
- columnDef,
213
- );
214
-
215
- const builderWithOps = attachOperationsToColumnBuilder<
216
- ColumnKey,
217
- Columns[ColumnKey],
218
- JsType,
219
- Operations
220
- >(
221
- columnBuilder as unknown as ColumnBuilder<
222
- ColumnKey,
223
- Columns[ColumnKey],
224
- JsType,
225
- Record<string, never>
226
- >,
227
- columnDef,
228
- operationRegistry,
229
- contractCapabilities,
230
- );
231
-
232
- (result as Record<string, unknown>)[columnName] = builderWithOps;
233
- };
234
-
235
- for (const columnName of Object.keys(tableColumns) as Array<keyof Columns & string>) {
236
- const columnDef = tableColumns[columnName];
237
- if (!columnDef) continue;
238
- assignColumn(columnName, columnDef);
239
- }
240
-
241
- return result as ColumnBuilders<Contract, TableName, Columns, CodecTypes, Operations>;
242
- }
243
-
244
- /**
245
- * Creates a Proxy that enables accessing table columns directly on the table object,
246
- * in addition to the standard `table.columns.columnName` syntax.
247
- *
248
- * This allows both access patterns:
249
- * - `tables.user.columns.id` (standard access)
250
- * - `tables.user.id` (convenience access via proxy)
251
- *
252
- * The proxy intercepts property access and routes column name lookups to
253
- * `table.columns[prop]`, while preserving direct access to table properties
254
- * like `name`, `kind`, and `columns`.
255
- */
256
- function createTableProxy<
257
- Contract extends SqlContract<SqlStorage>,
258
- TableName extends string,
259
- Columns extends Record<string, StorageColumn>,
260
- CodecTypes extends CodecTypesType,
261
- Operations extends OperationTypes,
262
- >(
263
- table: TableBuilderImpl<Contract, TableName, Columns, CodecTypes, Operations>,
264
- ): TableBuilderImpl<Contract, TableName, Columns, CodecTypes, Operations> {
265
- return new Proxy(table, {
266
- get(target, prop) {
267
- if (prop === 'name' || prop === 'kind' || prop === 'columns') {
268
- return Reflect.get(target, prop);
269
- }
270
- if (typeof prop === 'string' && prop in target.columns) {
271
- return target.columns[prop as keyof typeof target.columns];
272
- }
273
- return undefined;
274
- },
275
- });
276
- }
277
-
278
- type ExtractSchemaTables<
279
- Contract extends SqlContract<SqlStorage>,
280
- CodecTypes extends CodecTypesType,
281
- Operations extends OperationTypes,
282
- > = {
283
- readonly [TableName in keyof Contract['storage']['tables']]: TableBuilderImpl<
284
- Contract,
285
- TableName & string,
286
- TableColumns<Contract['storage']['tables'][TableName]>,
287
- CodecTypes,
288
- Operations
289
- > &
290
- TableRef;
291
- };
292
-
293
- export type SchemaHandle<
294
- Contract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
295
- CodecTypes extends CodecTypesType = CodecTypesType,
296
- Operations extends OperationTypes = Record<string, never>,
297
- > = {
298
- readonly tables: ExtractSchemaTables<Contract, CodecTypes, Operations>;
299
- };
300
-
301
- type SchemaReturnType<Contract extends SqlContract<SqlStorage>> = SchemaHandle<
302
- Contract,
303
- ExtractCodecTypes<Contract>,
304
- ToOperationTypes<ExtractOperationTypes<Contract>>
305
- >;
306
-
307
- type NormalizeOperationTypes<T> = {
308
- [TypeId in keyof T]: {
309
- [Method in keyof T[TypeId]]: T[TypeId][Method] extends OperationTypeSignature
310
- ? T[TypeId][Method]
311
- : OperationTypeSignature;
312
- };
313
- };
314
-
315
- type ToOperationTypes<T> = T extends OperationTypes ? T : NormalizeOperationTypes<T>;
316
-
317
- /**
318
- * Creates a schema handle for building SQL queries.
319
- *
320
- * @param context - Query lane context containing contract, codec and operation registries
321
- * @returns A schema handle with typed table builders
322
- *
323
- * @example
324
- * ```typescript
325
- * const schemaHandle = schema<Contract>(context);
326
- * const userTable = schemaHandle.tables.user;
327
- * ```
328
- */
329
- export function schema<Contract extends SqlContract<SqlStorage>>(
330
- context: QueryLaneContext<Contract>,
331
- ): SchemaReturnType<Contract> {
332
- const contract = context.contract;
333
- const storage = contract.storage;
334
- type CodecTypes = ExtractCodecTypes<Contract>;
335
- type Operations = ToOperationTypes<ExtractOperationTypes<Contract>>;
336
- const tables = {} as ExtractSchemaTables<Contract, CodecTypes, Operations>;
337
- const contractCapabilities = contract.capabilities;
338
-
339
- const operationRegistry = context.operations;
340
-
341
- for (const tableName of Object.keys(storage.tables) as Array<
342
- keyof Contract['storage']['tables'] & string
343
- >) {
344
- const columns = buildColumns<Contract, typeof tableName, CodecTypes, Operations>(
345
- tableName,
346
- storage,
347
- contract,
348
- operationRegistry,
349
- contractCapabilities,
350
- );
351
- const table = new TableBuilderImpl<
352
- Contract,
353
- typeof tableName & string,
354
- Contract['storage']['tables'][typeof tableName]['columns'],
355
- CodecTypes,
356
- Operations
357
- >(tableName, columns);
358
- const proxiedTable = createTableProxy<
359
- Contract,
360
- typeof tableName & string,
361
- Contract['storage']['tables'][typeof tableName]['columns'],
362
- CodecTypes,
363
- Operations
364
- >(table);
365
- (tables as Record<string, unknown>)[tableName] = Object.freeze(
366
- proxiedTable,
367
- ) as ExtractSchemaTables<Contract, CodecTypes, Operations>[typeof tableName];
368
- }
369
-
370
- return Object.freeze({ tables }) as SchemaReturnType<Contract>;
371
- }
372
-
373
- export type { ColumnBuilderImpl as Column, TableBuilderImpl as Table };
@@ -1,123 +0,0 @@
1
- import type { StorageColumn } from '@prisma-next/sql-contract/types';
2
- import type { ColumnRef, LiteralExpr, OperationExpr, ParamRef } from '../ast/types';
3
- import type { AnyColumnBuilder, ParamPlaceholder } from '../types';
4
-
5
- /**
6
- * Helper to extract columnMeta from a ColumnBuilder.
7
- * Returns StorageColumn if present, undefined otherwise.
8
- * AnyColumnBuilder is a union that includes types with columnMeta property,
9
- * so we can safely access it after checking for existence.
10
- */
11
- export function getColumnMeta(expr: AnyColumnBuilder): StorageColumn | undefined {
12
- // AnyColumnBuilder includes AnyColumnBuilderBase which has columnMeta: StorageColumn
13
- // and ColumnBuilder which has columnMeta: ColumnMeta extends StorageColumn
14
- // TypeScript should narrow the type after the 'in' check
15
- if ('columnMeta' in expr) {
16
- return expr.columnMeta;
17
- }
18
- return undefined;
19
- }
20
-
21
- /**
22
- * Type predicate to check if a value is a ParamPlaceholder.
23
- */
24
- export function isParamPlaceholder(value: unknown): value is ParamPlaceholder {
25
- return (
26
- typeof value === 'object' &&
27
- value !== null &&
28
- 'kind' in value &&
29
- (value as { kind: unknown }).kind === 'param-placeholder' &&
30
- 'name' in value &&
31
- typeof (value as { name: unknown }).name === 'string'
32
- );
33
- }
34
-
35
- /**
36
- * Recursively extracts the base ColumnRef from an OperationExpr.
37
- * If the expression is already a ColumnRef, it is returned directly.
38
- */
39
- export function extractBaseColumnRef(expr: ColumnRef | OperationExpr): ColumnRef {
40
- if (expr.kind === 'col') {
41
- return expr;
42
- }
43
- return extractBaseColumnRef(expr.self);
44
- }
45
-
46
- /**
47
- * Recursively collects all ColumnRef nodes from an expression tree.
48
- * Handles nested OperationExpr structures by traversing both self and args.
49
- */
50
- export function collectColumnRefs(
51
- expr: ColumnRef | ParamRef | LiteralExpr | OperationExpr,
52
- ): ColumnRef[] {
53
- if (expr.kind === 'col') {
54
- return [expr];
55
- }
56
- if (expr.kind === 'operation') {
57
- const refs: ColumnRef[] = collectColumnRefs(expr.self);
58
- for (const arg of expr.args) {
59
- refs.push(...collectColumnRefs(arg));
60
- }
61
- return refs;
62
- }
63
- return [];
64
- }
65
-
66
- /**
67
- * Type predicate to check if an expression is an OperationExpr.
68
- */
69
- export function isOperationExpr(expr: AnyColumnBuilder | OperationExpr): expr is OperationExpr {
70
- return typeof expr === 'object' && expr !== null && 'kind' in expr && expr.kind === 'operation';
71
- }
72
-
73
- /**
74
- * Helper to extract table and column from a ColumnBuilder or OperationExpr.
75
- * For OperationExpr, recursively unwraps to find the base ColumnRef.
76
- */
77
- export function getColumnInfo(expr: AnyColumnBuilder | OperationExpr): {
78
- table: string;
79
- column: string;
80
- } {
81
- if (isOperationExpr(expr)) {
82
- const baseCol = extractBaseColumnRef(expr);
83
- return { table: baseCol.table, column: baseCol.column };
84
- }
85
- // expr is ColumnBuilder - TypeScript can't narrow properly
86
- const colBuilder = expr as unknown as { table: string; column: string };
87
- return { table: colBuilder.table, column: colBuilder.column };
88
- }
89
-
90
- /**
91
- * Type predicate to check if a value is a ColumnBuilder.
92
- */
93
- export function isColumnBuilder(value: unknown): value is AnyColumnBuilder {
94
- return (
95
- typeof value === 'object' &&
96
- value !== null &&
97
- 'kind' in value &&
98
- (value as { kind: unknown }).kind === 'column'
99
- );
100
- }
101
-
102
- /**
103
- * Extracts and returns an OperationExpr from a builder.
104
- * Returns the OperationExpr if the builder is an OperationExpr or has an _operationExpr property,
105
- * otherwise returns undefined.
106
- *
107
- * @design-note: This function accesses the hidden `_operationExpr` property, which is a code smell.
108
- * The issue is that `executeOperation()` in relational-core returns a ColumnBuilder-shaped object
109
- * with a hidden `_operationExpr` property, creating coupling between lanes and relational-core
110
- * implementation details. A cleaner design would be to have operation results be a separate
111
- * type (e.g., `OperationResultBuilder`) that properly represents expression nodes rather than
112
- * pretending to be a ColumnBuilder. This would require refactoring the operation execution
113
- * system in relational-core to return proper expression types.
114
- */
115
- export function getOperationExpr(
116
- builder: AnyColumnBuilder | OperationExpr,
117
- ): OperationExpr | undefined {
118
- if (isOperationExpr(builder)) {
119
- return builder;
120
- }
121
- const builderWithExpr = builder as unknown as { _operationExpr?: OperationExpr };
122
- return builderWithExpr._operationExpr;
123
- }