@prisma-next/sql-builder 0.12.0-dev.7 → 0.12.0-dev.70

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.
@@ -12,7 +12,7 @@ import {
12
12
  InsertAst,
13
13
  ParamRef,
14
14
  ProjectionItem,
15
- TableSource,
15
+ type TableSource,
16
16
  UpdateAst,
17
17
  } from '@prisma-next/sql-relational-core/ast';
18
18
  import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
@@ -153,6 +153,7 @@ export class InsertQueryImpl<
153
153
  extends BuilderBase<QC['capabilities']>
154
154
  implements InsertQuery<QC, AvailableScope, RowType>
155
155
  {
156
+ readonly #tableSource: TableSource;
156
157
  readonly #tableName: string;
157
158
  readonly #table: StorageTable;
158
159
  readonly #scope: Scope;
@@ -162,7 +163,7 @@ export class InsertQueryImpl<
162
163
  readonly #annotations: ReadonlyMap<string, AnnotationValue<unknown, OperationKind>>;
163
164
 
164
165
  constructor(
165
- tableName: string,
166
+ tableSource: TableSource,
166
167
  table: StorageTable,
167
168
  scope: Scope,
168
169
  rows: ReadonlyArray<Record<string, unknown>>,
@@ -172,7 +173,8 @@ export class InsertQueryImpl<
172
173
  annotations: ReadonlyMap<string, AnnotationValue<unknown, OperationKind>> = new Map(),
173
174
  ) {
174
175
  super(ctx);
175
- this.#tableName = tableName;
176
+ this.#tableSource = tableSource;
177
+ this.#tableName = tableSource.name;
176
178
  this.#table = table;
177
179
  this.#scope = scope;
178
180
  this.#rows = rows;
@@ -192,7 +194,7 @@ export class InsertQueryImpl<
192
194
  newRowFields[col] = field;
193
195
  }
194
196
  return new InsertQueryImpl(
195
- this.#tableName,
197
+ this.#tableSource,
196
198
  this.#table,
197
199
  this.#scope,
198
200
  this.#rows,
@@ -215,7 +217,7 @@ export class InsertQueryImpl<
215
217
  ...annotations: As & ValidAnnotations<'write', As>
216
218
  ): InsertQuery<QC, AvailableScope, RowType> {
217
219
  return new InsertQueryImpl(
218
- this.#tableName,
220
+ this.#tableSource,
219
221
  this.#table,
220
222
  this.#scope,
221
223
  this.#rows,
@@ -238,7 +240,7 @@ export class InsertQueryImpl<
238
240
  buildParamValues(rowValues, this.#table, this.#tableName, 'create', this.ctx),
239
241
  );
240
242
 
241
- let ast = InsertAst.into(TableSource.named(this.#tableName)).withRows(paramRows);
243
+ let ast = InsertAst.into(this.#tableSource).withRows(paramRows);
242
244
 
243
245
  if (this.#returningColumns.length > 0) {
244
246
  ast = ast.withReturning(
@@ -262,6 +264,7 @@ export class UpdateQueryImpl<
262
264
  extends BuilderBase<QC['capabilities']>
263
265
  implements UpdateQuery<QC, AvailableScope, RowType>
264
266
  {
267
+ readonly #tableSource: TableSource;
265
268
  readonly #tableName: string;
266
269
  readonly #scope: Scope;
267
270
  readonly #setExpressions: Record<string, AstExpression>;
@@ -271,7 +274,7 @@ export class UpdateQueryImpl<
271
274
  readonly #annotations: ReadonlyMap<string, AnnotationValue<unknown, OperationKind>>;
272
275
 
273
276
  constructor(
274
- tableName: string,
277
+ tableSource: TableSource,
275
278
  scope: Scope,
276
279
  setExpressions: Record<string, AstExpression>,
277
280
  ctx: BuilderContext,
@@ -281,7 +284,8 @@ export class UpdateQueryImpl<
281
284
  annotations: ReadonlyMap<string, AnnotationValue<unknown, OperationKind>> = new Map(),
282
285
  ) {
283
286
  super(ctx);
284
- this.#tableName = tableName;
287
+ this.#tableSource = tableSource;
288
+ this.#tableName = tableSource.name;
285
289
  this.#scope = scope;
286
290
  this.#setExpressions = setExpressions;
287
291
  this.#whereExprs = whereExprs;
@@ -295,7 +299,7 @@ export class UpdateQueryImpl<
295
299
  const fns = createFunctions(this.ctx.queryOperationTypes, this.ctx.rawCodecInferer);
296
300
  const result = (expr as ExpressionBuilder<Scope, QueryContext>)(fieldProxy, fns as never);
297
301
  return new UpdateQueryImpl(
298
- this.#tableName,
302
+ this.#tableSource,
299
303
  this.#scope,
300
304
  this.#setExpressions,
301
305
  this.ctx,
@@ -317,7 +321,7 @@ export class UpdateQueryImpl<
317
321
  newRowFields[col] = field;
318
322
  }
319
323
  return new UpdateQueryImpl(
320
- this.#tableName,
324
+ this.#tableSource,
321
325
  this.#scope,
322
326
  this.#setExpressions,
323
327
  this.ctx,
@@ -338,7 +342,7 @@ export class UpdateQueryImpl<
338
342
  ...annotations: As & ValidAnnotations<'write', As>
339
343
  ): UpdateQuery<QC, AvailableScope, RowType> {
340
344
  return new UpdateQueryImpl(
341
- this.#tableName,
345
+ this.#tableSource,
342
346
  this.#scope,
343
347
  this.#setExpressions,
344
348
  this.ctx,
@@ -353,7 +357,7 @@ export class UpdateQueryImpl<
353
357
  }
354
358
 
355
359
  build(): SqlQueryPlan<ResolveRow<RowType, QC['codecTypes'], QC['resolvedColumnOutputTypes']>> {
356
- let ast = UpdateAst.table(TableSource.named(this.#tableName))
360
+ let ast = UpdateAst.table(this.#tableSource)
357
361
  .withSet(this.#setExpressions)
358
362
  .withWhere(combineWhereExprs(this.#whereExprs));
359
363
 
@@ -379,6 +383,7 @@ export class DeleteQueryImpl<
379
383
  extends BuilderBase<QC['capabilities']>
380
384
  implements DeleteQuery<QC, AvailableScope, RowType>
381
385
  {
386
+ readonly #tableSource: TableSource;
382
387
  readonly #tableName: string;
383
388
  readonly #scope: Scope;
384
389
  readonly #whereCallbacks: readonly WhereCallback[];
@@ -387,7 +392,7 @@ export class DeleteQueryImpl<
387
392
  readonly #annotations: ReadonlyMap<string, AnnotationValue<unknown, OperationKind>>;
388
393
 
389
394
  constructor(
390
- tableName: string,
395
+ tableSource: TableSource,
391
396
  scope: Scope,
392
397
  ctx: BuilderContext,
393
398
  whereCallbacks: readonly WhereCallback[] = [],
@@ -396,7 +401,8 @@ export class DeleteQueryImpl<
396
401
  annotations: ReadonlyMap<string, AnnotationValue<unknown, OperationKind>> = new Map(),
397
402
  ) {
398
403
  super(ctx);
399
- this.#tableName = tableName;
404
+ this.#tableSource = tableSource;
405
+ this.#tableName = tableSource.name;
400
406
  this.#scope = scope;
401
407
  this.#whereCallbacks = whereCallbacks;
402
408
  this.#returningColumns = returningColumns;
@@ -406,7 +412,7 @@ export class DeleteQueryImpl<
406
412
 
407
413
  where(expr: ExpressionBuilder<AvailableScope, QC>): DeleteQuery<QC, AvailableScope, RowType> {
408
414
  return new DeleteQueryImpl(
409
- this.#tableName,
415
+ this.#tableSource,
410
416
  this.#scope,
411
417
  this.ctx,
412
418
  [...this.#whereCallbacks, expr as unknown as WhereCallback],
@@ -427,7 +433,7 @@ export class DeleteQueryImpl<
427
433
  newRowFields[col] = field;
428
434
  }
429
435
  return new DeleteQueryImpl(
430
- this.#tableName,
436
+ this.#tableSource,
431
437
  this.#scope,
432
438
  this.ctx,
433
439
  this.#whereCallbacks,
@@ -446,7 +452,7 @@ export class DeleteQueryImpl<
446
452
  ...annotations: As & ValidAnnotations<'write', As>
447
453
  ): DeleteQuery<QC, AvailableScope, RowType> {
448
454
  return new DeleteQueryImpl(
449
- this.#tableName,
455
+ this.#tableSource,
450
456
  this.#scope,
451
457
  this.ctx,
452
458
  this.#whereCallbacks,
@@ -466,7 +472,7 @@ export class DeleteQueryImpl<
466
472
  ),
467
473
  );
468
474
 
469
- let ast = DeleteAst.from(TableSource.named(this.#tableName)).withWhere(whereExpr);
475
+ let ast = DeleteAst.from(this.#tableSource).withWhere(whereExpr);
470
476
 
471
477
  if (this.#returningColumns.length > 0) {
472
478
  ast = ast.withReturning(
@@ -0,0 +1,18 @@
1
+ import { resolveStorageTable } from '@prisma-next/sql-contract/resolve-storage-table';
2
+ import type { SqlStorage, StorageTable } from '@prisma-next/sql-contract/types';
3
+
4
+ export interface ResolvedTable {
5
+ readonly namespaceId: string;
6
+ readonly table: StorageTable;
7
+ }
8
+
9
+ export function resolveTableForFlatName(
10
+ storage: SqlStorage,
11
+ tableName: string,
12
+ ): ResolvedTable | undefined {
13
+ const resolved = resolveStorageTable(storage, tableName);
14
+ if (resolved === undefined) {
15
+ return undefined;
16
+ }
17
+ return resolved;
18
+ }
@@ -1,9 +1,10 @@
1
1
  import type { Contract } from '@prisma-next/contract/types';
2
- import type { SqlStorage, StorageTable } from '@prisma-next/sql-contract/types';
2
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
3
3
  import type { RawCodecInferer } from '@prisma-next/sql-relational-core/expression';
4
4
  import type { ExecutionContext } from '@prisma-next/sql-relational-core/query-lane-context';
5
5
  import type { Db, TableProxyContract } from '../types/db';
6
6
  import type { BuilderContext } from './builder-base';
7
+ import { resolveTableForFlatName } from './resolve-table';
7
8
  import { TableProxyImpl } from './table-proxy-impl';
8
9
 
9
10
  export interface SqlOptions<C extends Contract<SqlStorage> & TableProxyContract> {
@@ -11,21 +12,6 @@ export interface SqlOptions<C extends Contract<SqlStorage> & TableProxyContract>
11
12
  readonly rawCodecInferer: RawCodecInferer;
12
13
  }
13
14
 
14
- // Find a table by name across every declared namespace. Mirrors the
15
- // flat-DSL contract (db.<tableName>): the first namespace that declares
16
- // `name` wins. Name collisions across namespaces are a type-level error
17
- // at the DSL call site; landing the namespace-aware DSL is tracked
18
- // separately.
19
- function findTableAcrossNamespaces(storage: SqlStorage, name: string): StorageTable | undefined {
20
- for (const ns of Object.values(storage.namespaces)) {
21
- const tables = (ns as { tables?: Readonly<Record<string, StorageTable>> }).tables ?? {};
22
- if (Object.hasOwn(tables, name)) {
23
- return tables[name];
24
- }
25
- }
26
- return undefined;
27
- }
28
-
29
15
  export function sql<C extends Contract<SqlStorage> & TableProxyContract>(
30
16
  options: SqlOptions<C>,
31
17
  ): Db<C> {
@@ -42,9 +28,9 @@ export function sql<C extends Contract<SqlStorage> & TableProxyContract>(
42
28
 
43
29
  return new Proxy({} as Db<C>, {
44
30
  get(_target, prop: string) {
45
- const table = findTableAcrossNamespaces(context.contract.storage, prop);
46
- if (table) {
47
- return new TableProxyImpl(prop, table, prop, ctx);
31
+ const resolved = resolveTableForFlatName(context.contract.storage, prop);
32
+ if (resolved) {
33
+ return new TableProxyImpl(prop, resolved.table, prop, ctx, resolved.namespaceId);
48
34
  }
49
35
  return undefined;
50
36
  },
@@ -1,5 +1,5 @@
1
1
  import type { StorageTable } from '@prisma-next/sql-contract/types';
2
- import { type AnyFromSource, TableSource } from '@prisma-next/sql-relational-core/ast';
2
+ import type { AnyFromSource, TableSource } from '@prisma-next/sql-relational-core/ast';
3
3
  import type {
4
4
  AggregateFunctions,
5
5
  Expression,
@@ -43,6 +43,7 @@ import {
43
43
  type UpdateSetCallback,
44
44
  } from './mutation-impl';
45
45
  import { SelectQueryImpl } from './query-impl';
46
+ import { tableSourceForProxy } from './table-source-for-proxy';
46
47
 
47
48
  export class TableProxyImpl<
48
49
  C extends TableProxyContract,
@@ -61,15 +62,23 @@ export class TableProxyImpl<
61
62
 
62
63
  readonly #tableName: string;
63
64
  readonly #table: StorageTable;
65
+ readonly #namespaceId: string;
64
66
  readonly #fromSource: TableSource;
65
67
  readonly #scope: Scope;
66
68
 
67
- constructor(tableName: string, table: StorageTable, alias: string, ctx: BuilderContext) {
69
+ constructor(
70
+ tableName: string,
71
+ table: StorageTable,
72
+ alias: string,
73
+ ctx: BuilderContext,
74
+ namespaceId: string,
75
+ ) {
68
76
  super(ctx);
69
77
  this.#tableName = tableName;
70
78
  this.#table = table;
79
+ this.#namespaceId = namespaceId;
71
80
  this.#scope = tableToScope(alias, table, { storage: ctx.storage, tableName });
72
- this.#fromSource = TableSource.named(tableName, alias !== tableName ? alias : undefined);
81
+ this.#fromSource = tableSourceForProxy(tableName, alias, namespaceId);
73
82
  }
74
83
 
75
84
  lateralJoin = this._gate(
@@ -114,7 +123,7 @@ export class TableProxyImpl<
114
123
  as<NewAlias extends string>(
115
124
  newAlias: NewAlias,
116
125
  ): TableProxy<C, Name, NewAlias, RebindScope<AvailableScope, Alias, NewAlias>, QC> {
117
- return new TableProxyImpl(this.#tableName, this.#table, newAlias, this.ctx);
126
+ return new TableProxyImpl(this.#tableName, this.#table, newAlias, this.ctx, this.#namespaceId);
118
127
  }
119
128
 
120
129
  select<Columns extends (keyof AvailableScope['topLevel'] & string)[]>(
@@ -165,7 +174,7 @@ export class TableProxyImpl<
165
174
  }
166
175
 
167
176
  insert(rows: ReadonlyArray<Record<string, unknown>>): InsertQuery<QC, AvailableScope, EmptyRow> {
168
- return new InsertQueryImpl(this.#tableName, this.#table, this.#scope, rows, this.ctx);
177
+ return new InsertQueryImpl(this.#fromSource, this.#table, this.#scope, rows, this.ctx);
169
178
  }
170
179
 
171
180
  update(
@@ -190,7 +199,7 @@ export class TableProxyImpl<
190
199
  'update',
191
200
  this.ctx,
192
201
  );
193
- return new UpdateQueryImpl(this.#tableName, this.#scope, setExpressions, this.ctx);
202
+ return new UpdateQueryImpl(this.#fromSource, this.#scope, setExpressions, this.ctx);
194
203
  }
195
204
  const setExpressions = buildParamValues(
196
205
  setOrCallback,
@@ -199,11 +208,11 @@ export class TableProxyImpl<
199
208
  'update',
200
209
  this.ctx,
201
210
  );
202
- return new UpdateQueryImpl(this.#tableName, this.#scope, setExpressions, this.ctx);
211
+ return new UpdateQueryImpl(this.#fromSource, this.#scope, setExpressions, this.ctx);
203
212
  }
204
213
 
205
214
  delete(): DeleteQuery<QC, AvailableScope, EmptyRow> {
206
- return new DeleteQueryImpl(this.#tableName, this.#scope, this.ctx);
215
+ return new DeleteQueryImpl(this.#fromSource, this.#scope, this.ctx);
207
216
  }
208
217
 
209
218
  #toJoined(): JoinedTables<QC, AvailableScope> {
@@ -0,0 +1,9 @@
1
+ import { TableSource } from '@prisma-next/sql-relational-core/ast';
2
+
3
+ export function tableSourceForProxy(
4
+ tableName: string,
5
+ alias: string,
6
+ namespaceId: string,
7
+ ): TableSource {
8
+ return TableSource.named(tableName, alias !== tableName ? alias : undefined, namespaceId);
9
+ }
package/src/types/db.ts CHANGED
@@ -12,7 +12,10 @@ export type CapabilitiesBase = Record<string, Record<string, boolean>>;
12
12
  export type TableProxyContract = {
13
13
  readonly storage: {
14
14
  readonly namespaces: Readonly<
15
- Record<string, { readonly tables: Readonly<Record<string, StorageTable>> }>
15
+ Record<
16
+ string,
17
+ { readonly entries: { readonly table: Readonly<Record<string, StorageTable>> } }
18
+ >
16
19
  >;
17
20
  };
18
21
  readonly capabilities: CapabilitiesBase;
@@ -24,14 +27,14 @@ export type UnboundTables<C extends TableProxyContract> = {
24
27
  readonly [Name in TableNamesAcrossNamespaces<C>]: TableInAnyNamespace<C, Name>;
25
28
  };
26
29
 
27
- type TableNamesAcrossNamespaces<C extends TableProxyContract> = {
28
- [NSId in keyof C['storage']['namespaces']]: keyof C['storage']['namespaces'][NSId]['tables'] &
30
+ export type TableNamesAcrossNamespaces<C extends TableProxyContract> = {
31
+ [NSId in keyof C['storage']['namespaces']]: keyof C['storage']['namespaces'][NSId]['entries']['table'] &
29
32
  string;
30
33
  }[keyof C['storage']['namespaces']];
31
34
 
32
- type TableInAnyNamespace<C extends TableProxyContract, Name extends string> = {
33
- [NSId in keyof C['storage']['namespaces']]: Name extends keyof C['storage']['namespaces'][NSId]['tables']
34
- ? C['storage']['namespaces'][NSId]['tables'][Name]
35
+ export type TableInAnyNamespace<C extends TableProxyContract, Name extends string> = {
36
+ [NSId in keyof C['storage']['namespaces']]: Name extends keyof C['storage']['namespaces'][NSId]['entries']['table']
37
+ ? C['storage']['namespaces'][NSId]['entries']['table'][Name]
35
38
  : never;
36
39
  }[keyof C['storage']['namespaces']];
37
40
 
@@ -1,4 +1,4 @@
1
- import type { Contract, ContractModelsMap } from '@prisma-next/contract/types';
1
+ import type { Contract, ContractModelDefinitions } from '@prisma-next/contract/types';
2
2
  import type {
3
3
  ExtractCodecTypes,
4
4
  ExtractFieldInputTypes,
@@ -22,24 +22,24 @@ import type { WithJoin, WithSelect } from './shared';
22
22
 
23
23
  type FindModelForTable<C, TableName extends string> = C extends Contract
24
24
  ? {
25
- [M in keyof ContractModelsMap<C> & string]: ContractModelsMap<C>[M] extends {
25
+ [M in keyof ContractModelDefinitions<C> & string]: ContractModelDefinitions<C>[M] extends {
26
26
  readonly storage: { readonly table: TableName };
27
27
  }
28
28
  ? M
29
29
  : never;
30
- }[keyof ContractModelsMap<C> & string]
30
+ }[keyof ContractModelDefinitions<C> & string]
31
31
  : never;
32
32
 
33
33
  type FindFieldForColumn<C, ModelName extends string, ColumnName extends string> = C extends Contract
34
- ? ModelName extends keyof ContractModelsMap<C>
34
+ ? ModelName extends keyof ContractModelDefinitions<C>
35
35
  ? {
36
- [F in keyof ContractModelsMap<C>[ModelName]['storage']['fields'] &
37
- string]: ContractModelsMap<C>[ModelName]['storage']['fields'][F] extends {
36
+ [F in keyof ContractModelDefinitions<C>[ModelName]['storage']['fields'] &
37
+ string]: ContractModelDefinitions<C>[ModelName]['storage']['fields'][F] extends {
38
38
  readonly column: ColumnName;
39
39
  }
40
40
  ? F
41
41
  : never;
42
- }[keyof ContractModelsMap<C>[ModelName]['storage']['fields'] & string]
42
+ }[keyof ContractModelDefinitions<C>[ModelName]['storage']['fields'] & string]
43
43
  : never
44
44
  : never;
45
45