@prisma-next/sql-lane 0.3.0-dev.10 → 0.3.0-dev.113

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 (66) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +18 -1
  3. package/dist/builder-DpxuiFO4.d.mts +118 -0
  4. package/dist/builder-DpxuiFO4.d.mts.map +1 -0
  5. package/dist/builder-MYJh5-Gn.mjs +1153 -0
  6. package/dist/builder-MYJh5-Gn.mjs.map +1 -0
  7. package/dist/exports/sql.d.mts +3 -0
  8. package/dist/exports/sql.mjs +3 -0
  9. package/dist/index.d.mts +3 -0
  10. package/dist/index.mjs +3 -0
  11. package/package.json +29 -24
  12. package/src/raw.ts +9 -2
  13. package/src/sql/builder.ts +12 -9
  14. package/src/sql/context.ts +3 -3
  15. package/src/sql/include-builder.ts +109 -70
  16. package/src/sql/join-builder.ts +21 -11
  17. package/src/sql/mutation-builder.ts +94 -107
  18. package/src/sql/plan.ts +88 -128
  19. package/src/sql/predicate-builder.ts +74 -65
  20. package/src/sql/projection.ts +17 -12
  21. package/src/sql/select-builder.ts +64 -102
  22. package/src/types/internal.ts +6 -5
  23. package/src/utils/errors.ts +2 -2
  24. package/src/utils/state.ts +5 -6
  25. package/dist/chunk-AWSKRSFP.js +0 -1569
  26. package/dist/chunk-AWSKRSFP.js.map +0 -1
  27. package/dist/exports/sql.d.ts +0 -5
  28. package/dist/exports/sql.d.ts.map +0 -1
  29. package/dist/exports/sql.js +0 -11
  30. package/dist/exports/sql.js.map +0 -1
  31. package/dist/index.d.ts +0 -5
  32. package/dist/index.d.ts.map +0 -1
  33. package/dist/index.js +0 -11
  34. package/dist/index.js.map +0 -1
  35. package/dist/raw.d.ts +0 -11
  36. package/dist/raw.d.ts.map +0 -1
  37. package/dist/sql/builder.d.ts +0 -11
  38. package/dist/sql/builder.d.ts.map +0 -1
  39. package/dist/sql/context.d.ts +0 -5
  40. package/dist/sql/context.d.ts.map +0 -1
  41. package/dist/sql/include-builder.d.ts +0 -35
  42. package/dist/sql/include-builder.d.ts.map +0 -1
  43. package/dist/sql/join-builder.d.ts +0 -4
  44. package/dist/sql/join-builder.d.ts.map +0 -1
  45. package/dist/sql/mutation-builder.d.ts +0 -64
  46. package/dist/sql/mutation-builder.d.ts.map +0 -1
  47. package/dist/sql/plan.d.ts +0 -4
  48. package/dist/sql/plan.d.ts.map +0 -1
  49. package/dist/sql/predicate-builder.d.ts +0 -11
  50. package/dist/sql/predicate-builder.d.ts.map +0 -1
  51. package/dist/sql/projection.d.ts +0 -18
  52. package/dist/sql/projection.d.ts.map +0 -1
  53. package/dist/sql/select-builder.d.ts +0 -35
  54. package/dist/sql/select-builder.d.ts.map +0 -1
  55. package/dist/types/internal.d.ts +0 -35
  56. package/dist/types/internal.d.ts.map +0 -1
  57. package/dist/types/public.d.ts +0 -18
  58. package/dist/types/public.d.ts.map +0 -1
  59. package/dist/utils/assertions.d.ts +0 -28
  60. package/dist/utils/assertions.d.ts.map +0 -1
  61. package/dist/utils/capabilities.d.ts +0 -4
  62. package/dist/utils/capabilities.d.ts.map +0 -1
  63. package/dist/utils/errors.d.ts +0 -30
  64. package/dist/utils/errors.d.ts.map +0 -1
  65. package/dist/utils/state.d.ts +0 -30
  66. package/dist/utils/state.d.ts.map +0 -1
@@ -1,27 +1,19 @@
1
- import type { ParamDescriptor } from '@prisma-next/contract/types';
2
1
  import type { SqlContract, SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
3
- import type {
4
- BinaryExpr,
5
- ColumnRef,
6
- Direction,
7
- IncludeAst,
8
- IncludeRef,
9
- JoinAst,
10
- OperationExpr,
11
- TableRef,
12
- } from '@prisma-next/sql-relational-core/ast';
13
2
  import {
14
- createColumnRef,
15
3
  createJoinOnBuilder,
16
- createOrderByItem,
17
- createSelectAst,
18
- createTableRef,
4
+ OrderByItem,
5
+ type ParamRef,
6
+ ProjectionItem,
7
+ SelectAst,
8
+ type TableRef,
9
+ TableSource,
19
10
  } from '@prisma-next/sql-relational-core/ast';
20
11
  import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
21
- import type { QueryLaneContext } from '@prisma-next/sql-relational-core/query-lane-context';
12
+ import type { ExecutionContext } from '@prisma-next/sql-relational-core/query-lane-context';
22
13
  import type {
23
14
  AnyBinaryBuilder,
24
15
  AnyOrderBuilder,
16
+ AnyUnaryBuilder,
25
17
  BinaryBuilder,
26
18
  BuildOptions,
27
19
  InferNestedProjectionRow,
@@ -30,10 +22,11 @@ import type {
30
22
  NestedProjection,
31
23
  OrderBuilder,
32
24
  SqlBuilderOptions,
25
+ UnaryBuilder,
33
26
  } from '@prisma-next/sql-relational-core/types';
34
- import { getOperationExpr } from '@prisma-next/sql-relational-core/utils/guards';
27
+ import { isExpressionBuilder } from '@prisma-next/sql-relational-core/utils/guards';
28
+ import { ifDefined } from '@prisma-next/utils/defined';
35
29
  import type { ProjectionInput } from '../types/internal';
36
- import { assertColumnBuilder } from '../utils/assertions';
37
30
  import { checkIncludeCapabilities } from '../utils/capabilities';
38
31
  import {
39
32
  errorChildProjectionEmpty,
@@ -41,14 +34,13 @@ import {
41
34
  errorIncludeAliasCollision,
42
35
  errorLimitMustBeNonNegativeInteger,
43
36
  errorMissingAlias,
44
- errorMissingColumnForAlias,
45
37
  errorSelectMustBeCalled,
46
38
  errorSelfJoinNotSupported,
47
39
  errorUnknownTable,
48
40
  } from '../utils/errors';
49
41
  import type { BuilderState, IncludeState, JoinState, ProjectionState } from '../utils/state';
50
42
  import {
51
- buildIncludeAst,
43
+ buildIncludeJoinArtifact,
52
44
  type IncludeChildBuilder,
53
45
  IncludeChildBuilderImpl,
54
46
  } from './include-builder';
@@ -57,6 +49,18 @@ import { buildMeta } from './plan';
57
49
  import { buildWhereExpr } from './predicate-builder';
58
50
  import { buildProjectionState } from './projection';
59
51
 
52
+ function deriveParamsFromAst(ast: { collectParamRefs(): ParamRef[] }) {
53
+ const collected = [...new Set(ast.collectParamRefs())];
54
+ return {
55
+ paramValues: collected.map((p) => p.value),
56
+ paramDescriptors: collected.map((p) => ({
57
+ ...ifDefined('name', p.name),
58
+ source: 'dsl' as const,
59
+ ...ifDefined('codecId', p.codecId),
60
+ })),
61
+ };
62
+ }
63
+
60
64
  export class SelectBuilderImpl<
61
65
  TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
62
66
  Row = unknown,
@@ -64,14 +68,12 @@ export class SelectBuilderImpl<
64
68
  Includes extends Record<string, unknown> = Record<string, never>,
65
69
  > {
66
70
  private readonly contract: TContract;
67
- private readonly codecTypes: CodecTypes;
68
- private readonly context: QueryLaneContext<TContract>;
71
+ private readonly context: ExecutionContext<TContract>;
69
72
  private state: BuilderState = {};
70
73
 
71
74
  constructor(options: SqlBuilderOptions<TContract>, state?: BuilderState) {
72
75
  this.context = options.context;
73
76
  this.contract = options.context.contract;
74
- this.codecTypes = options.context.contract.mappings.codecTypes as CodecTypes;
75
77
  if (state) {
76
78
  this.state = state;
77
79
  }
@@ -146,7 +148,6 @@ export class SelectBuilderImpl<
146
148
  // Build child builder
147
149
  const childBuilderImpl = new IncludeChildBuilderImpl<TContract, CodecTypes, unknown>(
148
150
  this.contract,
149
- this.codecTypes,
150
151
  childTable,
151
152
  );
152
153
  const builtChild = childBuilder(
@@ -238,7 +239,9 @@ export class SelectBuilderImpl<
238
239
  );
239
240
  }
240
241
 
241
- where(expr: AnyBinaryBuilder): SelectBuilderImpl<TContract, Row, CodecTypes, Includes> {
242
+ where(
243
+ expr: AnyBinaryBuilder | AnyUnaryBuilder,
244
+ ): SelectBuilderImpl<TContract, Row, CodecTypes, Includes> {
242
245
  return new SelectBuilderImpl<TContract, Row, CodecTypes, Includes>(
243
246
  {
244
247
  context: this.context,
@@ -304,43 +307,28 @@ export class SelectBuilderImpl<
304
307
  errorUnknownTable(table.name);
305
308
  }
306
309
 
307
- const paramDescriptors: ParamDescriptor[] = [];
308
- const paramValues: unknown[] = [];
309
- const paramCodecs: Record<string, string> = {};
310
-
311
310
  const whereResult = this.state.where
312
- ? buildWhereExpr(this.contract, this.state.where, paramsMap, paramDescriptors, paramValues)
311
+ ? buildWhereExpr(this.contract, this.state.where, paramsMap)
313
312
  : undefined;
314
313
  const whereExpr = whereResult?.expr;
315
314
 
316
- if (whereResult?.codecId && whereResult.paramName) {
317
- paramCodecs[whereResult.paramName] = whereResult.codecId;
318
- }
319
-
320
315
  const orderByClause = this.state.orderBy
321
316
  ? (() => {
322
317
  const orderBy = this.state.orderBy as OrderBuilder<string, StorageColumn, unknown>;
323
- const orderExpr = orderBy.expr;
324
- const operationExpr = getOperationExpr(orderExpr);
325
- const expr: ColumnRef | OperationExpr = operationExpr
326
- ? operationExpr
327
- : (() => {
328
- const colBuilder = orderExpr as { table: string; column: string };
329
- return createColumnRef(colBuilder.table, colBuilder.column);
330
- })();
331
- return [createOrderByItem(expr, orderBy.dir)];
318
+ return [new OrderByItem(orderBy.expr, orderBy.dir)];
332
319
  })()
333
320
  : undefined;
334
321
 
335
- const joins = this.state.joins?.map((join) => buildJoinAst(join));
336
-
337
- const includes = this.state.includes?.map((include) =>
338
- buildIncludeAst(include, this.contract, paramsMap, paramDescriptors, paramValues),
322
+ const joins = this.state.joins?.map((join) => buildJoinAst(join)) ?? [];
323
+ const includeArtifacts =
324
+ this.state.includes?.map((include) =>
325
+ buildIncludeJoinArtifact(include, this.contract, paramsMap),
326
+ ) ?? [];
327
+ const includeProjectionByAlias = new Map(
328
+ includeArtifacts.map((artifact) => [artifact.projection.alias, artifact.projection]),
339
329
  );
340
330
 
341
- // Build projection with support for includeRef and OperationExpr
342
- const projectEntries: Array<{ alias: string; expr: ColumnRef | IncludeRef | OperationExpr }> =
343
- [];
331
+ const projectEntries: ProjectionItem[] = [];
344
332
  for (let i = 0; i < projection.aliases.length; i++) {
345
333
  const alias = projection.aliases[i];
346
334
  if (!alias) {
@@ -348,57 +336,31 @@ export class SelectBuilderImpl<
348
336
  }
349
337
  const column = projection.columns[i];
350
338
 
351
- // Check if this alias matches an include alias first
352
- // Include placeholders have null columns
353
- const matchingInclude = this.state.includes?.find((inc) => inc.alias === alias);
354
- if (matchingInclude) {
355
- // This is an include reference - column can be null for placeholders
356
- projectEntries.push({
357
- alias,
358
- expr: { kind: 'includeRef', alias },
359
- });
360
- } else {
361
- // Not an include - column must not be null
362
- if (!column) {
363
- errorMissingColumnForAlias(alias, i);
364
- }
365
- // Check if this column has an operation expression
366
- const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
367
- if (operationExpr) {
368
- projectEntries.push({
369
- alias,
370
- expr: operationExpr,
371
- });
372
- } else {
373
- // This is a regular column
374
- // TypeScript can't narrow ColumnBuilder properly
375
- const col = column as { table: string; column: string };
376
- assertColumnBuilder(col, 'projection column');
377
- projectEntries.push({
378
- alias,
379
- expr: createColumnRef(col.table, col.column),
380
- });
381
- }
339
+ const includeProjection = includeProjectionByAlias.get(alias);
340
+ if (includeProjection) {
341
+ projectEntries.push(includeProjection);
342
+ } else if (column && isExpressionBuilder(column)) {
343
+ projectEntries.push(ProjectionItem.of(alias, column.expr));
344
+ } else if (column) {
345
+ projectEntries.push(ProjectionItem.of(alias, column.toExpr()));
382
346
  }
383
347
  }
384
348
 
385
- const ast = createSelectAst({
386
- from: createTableRef(table.name),
387
- joins,
388
- includes,
389
- project: projectEntries,
390
- where: whereExpr,
391
- orderBy: orderByClause,
392
- limit: this.state.limit,
393
- } as {
394
- from: TableRef;
395
- joins?: ReadonlyArray<JoinAst>;
396
- includes?: ReadonlyArray<IncludeAst>;
397
- project: ReadonlyArray<{ alias: string; expr: ColumnRef | IncludeRef | OperationExpr }>;
398
- where?: BinaryExpr;
399
- orderBy?: ReadonlyArray<{ expr: ColumnRef | OperationExpr; dir: Direction }>;
400
- limit?: number;
401
- });
349
+ let ast = SelectAst.from(TableSource.named(table.name, table.alias))
350
+ .withProjection(projectEntries)
351
+ .withWhere(whereExpr);
352
+ const allJoins = [...joins, ...includeArtifacts.map((artifact) => artifact.join)];
353
+ if (allJoins.length > 0) {
354
+ ast = ast.withJoins(allJoins);
355
+ }
356
+ if (orderByClause) {
357
+ ast = ast.withOrderBy(orderByClause);
358
+ }
359
+ if (this.state.limit !== undefined) {
360
+ ast = ast.withLimit(this.state.limit);
361
+ }
362
+
363
+ const { paramValues, paramDescriptors } = deriveParamsFromAst(ast);
402
364
 
403
365
  const planMeta = buildMeta({
404
366
  contract: this.contract,
@@ -407,19 +369,19 @@ export class SelectBuilderImpl<
407
369
  joins: this.state.joins,
408
370
  includes: this.state.includes,
409
371
  paramDescriptors,
410
- paramCodecs,
411
372
  where: this.state.where,
412
373
  orderBy: this.state.orderBy,
374
+ limit: this.state.limit,
413
375
  } as {
414
376
  contract: SqlContract<SqlStorage>;
415
377
  table: TableRef;
416
378
  projection: ProjectionState;
417
379
  joins?: ReadonlyArray<JoinState>;
418
380
  includes?: ReadonlyArray<IncludeState>;
419
- where?: BinaryBuilder;
381
+ where?: BinaryBuilder | UnaryBuilder;
420
382
  orderBy?: AnyOrderBuilder;
421
- paramDescriptors: ParamDescriptor[];
422
- paramCodecs?: Record<string, string>;
383
+ limit?: number;
384
+ paramDescriptors: typeof paramDescriptors;
423
385
  });
424
386
 
425
387
  const queryPlan: SqlQueryPlan<Row> = Object.freeze({
@@ -3,13 +3,14 @@ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
3
3
  import type { TableRef } from '@prisma-next/sql-relational-core/ast';
4
4
  import type {
5
5
  AnyBinaryBuilder,
6
- AnyColumnBuilder,
6
+ AnyExpressionSource,
7
7
  AnyOrderBuilder,
8
+ AnyUnaryBuilder,
8
9
  NestedProjection,
9
10
  } from '@prisma-next/sql-relational-core/types';
10
11
  import type { ProjectionState } from '../utils/state';
11
12
 
12
- export type ProjectionInput = Record<string, AnyColumnBuilder | boolean | NestedProjection>;
13
+ export type ProjectionInput = Record<string, AnyExpressionSource | boolean | NestedProjection>;
13
14
 
14
15
  export interface MetaBuildArgs {
15
16
  readonly contract: SqlContract<SqlStorage>;
@@ -31,11 +32,11 @@ export interface MetaBuildArgs {
31
32
  readonly right: unknown;
32
33
  };
33
34
  readonly childProjection: ProjectionState;
34
- readonly childWhere?: AnyBinaryBuilder;
35
+ readonly childWhere?: AnyBinaryBuilder | AnyUnaryBuilder;
35
36
  readonly childOrderBy?: AnyOrderBuilder;
36
37
  }>;
37
- readonly where?: AnyBinaryBuilder;
38
+ readonly where?: AnyBinaryBuilder | AnyUnaryBuilder;
38
39
  readonly orderBy?: AnyOrderBuilder;
40
+ readonly limit?: number;
39
41
  readonly paramDescriptors: ParamDescriptor[];
40
- readonly paramCodecs?: Record<string, string>;
41
42
  }
@@ -73,7 +73,7 @@ export function errorIncludeAliasCollision(alias: string, type: 'projection' | '
73
73
  }
74
74
 
75
75
  export function errorMissingColumnForAlias(alias: string, index: number): never {
76
- throw planInvalid(`Missing column for alias ${alias ?? 'unknown'} at index ${index}`);
76
+ throw planInvalid(`Missing column for alias ${alias} at index ${index}`);
77
77
  }
78
78
 
79
79
  export function errorMissingAlias(index: number): never {
@@ -98,7 +98,7 @@ export function errorMissingParameter(paramName: string): never {
98
98
 
99
99
  export function errorInvalidProjectionValue(path: string[]): never {
100
100
  throw planInvalid(
101
- `Invalid projection value at path ${path.join('.')}: expected ColumnBuilder or nested object`,
101
+ `Invalid projection value at path ${path.join('.')}: expected ExpressionSource (ColumnBuilder or ExpressionBuilder) or nested object`,
102
102
  );
103
103
  }
104
104
 
@@ -1,16 +1,15 @@
1
1
  import type { TableRef } from '@prisma-next/sql-relational-core/ast';
2
2
  import type {
3
3
  AnyBinaryBuilder,
4
- AnyColumnBuilder,
4
+ AnyExpressionSource,
5
5
  AnyOrderBuilder,
6
+ AnyUnaryBuilder,
6
7
  JoinOnPredicate,
7
8
  } from '@prisma-next/sql-relational-core/types';
8
9
 
9
10
  export interface ProjectionState {
10
11
  readonly aliases: string[];
11
- // columns can be null for include placeholders (when alias matches an include)
12
- // This maintains array alignment but avoids creating invalid ColumnBuilders
13
- readonly columns: (AnyColumnBuilder | null)[];
12
+ readonly columns: AnyExpressionSource[];
14
13
  }
15
14
 
16
15
  export interface JoinState {
@@ -24,7 +23,7 @@ export interface IncludeState {
24
23
  readonly table: TableRef;
25
24
  readonly on: JoinOnPredicate;
26
25
  readonly childProjection: ProjectionState;
27
- readonly childWhere?: AnyBinaryBuilder;
26
+ readonly childWhere?: AnyBinaryBuilder | AnyUnaryBuilder;
28
27
  readonly childOrderBy?: AnyOrderBuilder;
29
28
  readonly childLimit?: number;
30
29
  }
@@ -34,7 +33,7 @@ export interface BuilderState {
34
33
  joins?: ReadonlyArray<JoinState>;
35
34
  includes?: ReadonlyArray<IncludeState>;
36
35
  projection?: ProjectionState;
37
- where?: AnyBinaryBuilder;
36
+ where?: AnyBinaryBuilder | AnyUnaryBuilder;
38
37
  orderBy?: AnyOrderBuilder;
39
38
  limit?: number;
40
39
  }