@prisma-next/sql-contract-psl 0.3.0-dev.71 → 0.4.0-dev.1
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.
- package/README.md +18 -17
- package/dist/default-function-registry-DUMRIhJH.d.mts +71 -0
- package/dist/default-function-registry-DUMRIhJH.d.mts.map +1 -0
- package/dist/index.d.mts +18 -42
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/interpreter-iFCRN9nb.mjs +2343 -0
- package/dist/interpreter-iFCRN9nb.mjs.map +1 -0
- package/dist/provider.d.mts +14 -12
- package/dist/provider.d.mts.map +1 -1
- package/dist/provider.mjs +20 -13
- package/dist/provider.mjs.map +1 -1
- package/package.json +9 -6
- package/src/default-function-registry.ts +52 -300
- package/src/exports/index.ts +10 -2
- package/src/interpreter.ts +1074 -1326
- package/src/provider.ts +44 -25
- package/src/psl-attribute-parsing.ts +303 -0
- package/src/psl-authoring-arguments.ts +454 -0
- package/src/psl-column-resolution.ts +600 -0
- package/src/psl-field-resolution.ts +335 -0
- package/src/psl-relation-resolution.ts +371 -0
- package/dist/interpreter-IXr5c7s7.mjs +0 -1376
- package/dist/interpreter-IXr5c7s7.mjs.map +0 -1
|
@@ -18,13 +18,14 @@ export interface DefaultFunctionLoweringContext {
|
|
|
18
18
|
readonly sourceId: string;
|
|
19
19
|
readonly modelName: string;
|
|
20
20
|
readonly fieldName: string;
|
|
21
|
+
readonly columnCodecId?: string;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
type LoweredDefaultValue =
|
|
24
|
+
export type LoweredDefaultValue =
|
|
24
25
|
| { readonly kind: 'storage'; readonly defaultValue: ColumnDefault }
|
|
25
26
|
| { readonly kind: 'execution'; readonly generated: ExecutionMutationDefaultValue };
|
|
26
27
|
|
|
27
|
-
type LoweredDefaultResult =
|
|
28
|
+
export type LoweredDefaultResult =
|
|
28
29
|
| { readonly ok: true; readonly value: LoweredDefaultValue }
|
|
29
30
|
| { readonly ok: false; readonly diagnostic: ContractSourceDiagnostic };
|
|
30
31
|
|
|
@@ -33,7 +34,42 @@ export type DefaultFunctionLoweringHandler = (input: {
|
|
|
33
34
|
readonly context: DefaultFunctionLoweringContext;
|
|
34
35
|
}) => LoweredDefaultResult;
|
|
35
36
|
|
|
36
|
-
export
|
|
37
|
+
export interface DefaultFunctionRegistryEntry {
|
|
38
|
+
readonly lower: DefaultFunctionLoweringHandler;
|
|
39
|
+
readonly usageSignatures?: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type DefaultFunctionRegistry = ReadonlyMap<string, DefaultFunctionRegistryEntry>;
|
|
43
|
+
|
|
44
|
+
export interface MutationDefaultGeneratorDescriptor {
|
|
45
|
+
readonly id: string;
|
|
46
|
+
readonly applicableCodecIds: readonly string[];
|
|
47
|
+
readonly resolveGeneratedColumnDescriptor?: (input: {
|
|
48
|
+
readonly generated: ExecutionMutationDefaultValue;
|
|
49
|
+
}) =>
|
|
50
|
+
| {
|
|
51
|
+
readonly codecId: string;
|
|
52
|
+
readonly nativeType: string;
|
|
53
|
+
readonly typeRef?: string;
|
|
54
|
+
readonly typeParams?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
| undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ControlMutationDefaultEntry {
|
|
60
|
+
readonly lower: (input: {
|
|
61
|
+
readonly call: ParsedDefaultFunctionCall;
|
|
62
|
+
readonly context: DefaultFunctionLoweringContext;
|
|
63
|
+
}) => LoweredDefaultResult;
|
|
64
|
+
readonly usageSignatures?: readonly string[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type ControlMutationDefaultRegistry = ReadonlyMap<string, ControlMutationDefaultEntry>;
|
|
68
|
+
|
|
69
|
+
export interface ControlMutationDefaults {
|
|
70
|
+
readonly defaultFunctionRegistry: ControlMutationDefaultRegistry;
|
|
71
|
+
readonly generatorDescriptors: readonly MutationDefaultGeneratorDescriptor[];
|
|
72
|
+
}
|
|
37
73
|
|
|
38
74
|
function resolveSpanPositionFromBase(
|
|
39
75
|
base: PslSpan,
|
|
@@ -191,318 +227,34 @@ export function parseDefaultFunctionCall(
|
|
|
191
227
|
};
|
|
192
228
|
}
|
|
193
229
|
|
|
194
|
-
function
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
code: 'PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT',
|
|
203
|
-
message: input.message,
|
|
204
|
-
sourceId: input.context.sourceId,
|
|
205
|
-
span: input.span,
|
|
206
|
-
},
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function executionGenerator(
|
|
211
|
-
id: ExecutionMutationDefaultValue['id'],
|
|
212
|
-
params?: Record<string, unknown>,
|
|
213
|
-
): LoweredDefaultResult {
|
|
214
|
-
return {
|
|
215
|
-
ok: true,
|
|
216
|
-
value: {
|
|
217
|
-
kind: 'execution',
|
|
218
|
-
generated: {
|
|
219
|
-
kind: 'generator',
|
|
220
|
-
id,
|
|
221
|
-
...(params ? { params } : {}),
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function expectNoArgs(input: {
|
|
228
|
-
readonly call: ParsedDefaultFunctionCall;
|
|
229
|
-
readonly context: DefaultFunctionLoweringContext;
|
|
230
|
-
readonly usage: string;
|
|
231
|
-
}): LoweredDefaultResult | undefined {
|
|
232
|
-
if (input.call.args.length === 0) {
|
|
233
|
-
return undefined;
|
|
234
|
-
}
|
|
235
|
-
return invalidArgumentDiagnostic({
|
|
236
|
-
context: input.context,
|
|
237
|
-
span: input.call.span,
|
|
238
|
-
message: `Default function "${input.call.name}" does not accept arguments. Use ${input.usage}.`,
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function parseIntegerArgument(raw: string): number | undefined {
|
|
243
|
-
const trimmed = raw.trim();
|
|
244
|
-
if (!/^-?\d+$/.test(trimmed)) {
|
|
245
|
-
return undefined;
|
|
246
|
-
}
|
|
247
|
-
const value = Number(trimmed);
|
|
248
|
-
if (!Number.isInteger(value)) {
|
|
249
|
-
return undefined;
|
|
250
|
-
}
|
|
251
|
-
return value;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function parseStringLiteral(raw: string): string | undefined {
|
|
255
|
-
const match = raw.trim().match(/^(['"])(.*)\1$/s);
|
|
256
|
-
if (!match) {
|
|
257
|
-
return undefined;
|
|
258
|
-
}
|
|
259
|
-
return match[2] ?? '';
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function lowerAutoincrement(input: {
|
|
263
|
-
readonly call: ParsedDefaultFunctionCall;
|
|
264
|
-
readonly context: DefaultFunctionLoweringContext;
|
|
265
|
-
}): LoweredDefaultResult {
|
|
266
|
-
const maybeNoArgs = expectNoArgs({
|
|
267
|
-
call: input.call,
|
|
268
|
-
context: input.context,
|
|
269
|
-
usage: '`autoincrement()`',
|
|
270
|
-
});
|
|
271
|
-
if (maybeNoArgs) {
|
|
272
|
-
return maybeNoArgs;
|
|
273
|
-
}
|
|
274
|
-
return {
|
|
275
|
-
ok: true,
|
|
276
|
-
value: {
|
|
277
|
-
kind: 'storage',
|
|
278
|
-
defaultValue: {
|
|
279
|
-
kind: 'function',
|
|
280
|
-
expression: 'autoincrement()',
|
|
281
|
-
},
|
|
282
|
-
},
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function lowerNow(input: {
|
|
287
|
-
readonly call: ParsedDefaultFunctionCall;
|
|
288
|
-
readonly context: DefaultFunctionLoweringContext;
|
|
289
|
-
}): LoweredDefaultResult {
|
|
290
|
-
const maybeNoArgs = expectNoArgs({
|
|
291
|
-
call: input.call,
|
|
292
|
-
context: input.context,
|
|
293
|
-
usage: '`now()`',
|
|
294
|
-
});
|
|
295
|
-
if (maybeNoArgs) {
|
|
296
|
-
return maybeNoArgs;
|
|
297
|
-
}
|
|
298
|
-
return {
|
|
299
|
-
ok: true,
|
|
300
|
-
value: {
|
|
301
|
-
kind: 'storage',
|
|
302
|
-
defaultValue: {
|
|
303
|
-
kind: 'function',
|
|
304
|
-
expression: 'now()',
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
function lowerUuid(input: {
|
|
311
|
-
readonly call: ParsedDefaultFunctionCall;
|
|
312
|
-
readonly context: DefaultFunctionLoweringContext;
|
|
313
|
-
}): LoweredDefaultResult {
|
|
314
|
-
if (input.call.args.length === 0) {
|
|
315
|
-
return executionGenerator('uuidv4');
|
|
316
|
-
}
|
|
317
|
-
if (input.call.args.length !== 1) {
|
|
318
|
-
return invalidArgumentDiagnostic({
|
|
319
|
-
context: input.context,
|
|
320
|
-
span: input.call.span,
|
|
321
|
-
message:
|
|
322
|
-
'Default function "uuid" accepts at most one version argument: `uuid()`, `uuid(4)`, or `uuid(7)`.',
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
const version = parseIntegerArgument(input.call.args[0]?.raw ?? '');
|
|
326
|
-
if (version === 4) {
|
|
327
|
-
return executionGenerator('uuidv4');
|
|
328
|
-
}
|
|
329
|
-
if (version === 7) {
|
|
330
|
-
return executionGenerator('uuidv7');
|
|
331
|
-
}
|
|
332
|
-
return invalidArgumentDiagnostic({
|
|
333
|
-
context: input.context,
|
|
334
|
-
span: input.call.args[0]?.span ?? input.call.span,
|
|
335
|
-
message:
|
|
336
|
-
'Default function "uuid" supports only `uuid()`, `uuid(4)`, or `uuid(7)` in SQL PSL provider v1.',
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
function lowerCuid(input: {
|
|
341
|
-
readonly call: ParsedDefaultFunctionCall;
|
|
342
|
-
readonly context: DefaultFunctionLoweringContext;
|
|
343
|
-
}): LoweredDefaultResult {
|
|
344
|
-
if (input.call.args.length === 0) {
|
|
345
|
-
return {
|
|
346
|
-
ok: false,
|
|
347
|
-
diagnostic: {
|
|
348
|
-
code: 'PSL_UNKNOWN_DEFAULT_FUNCTION',
|
|
349
|
-
message:
|
|
350
|
-
'Default function "cuid()" is not supported in SQL PSL provider v1. Use `cuid(2)` instead.',
|
|
351
|
-
sourceId: input.context.sourceId,
|
|
352
|
-
span: input.call.span,
|
|
353
|
-
},
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
if (input.call.args.length !== 1) {
|
|
357
|
-
return invalidArgumentDiagnostic({
|
|
358
|
-
context: input.context,
|
|
359
|
-
span: input.call.span,
|
|
360
|
-
message: 'Default function "cuid" accepts exactly one version argument: `cuid(2)`.',
|
|
230
|
+
function formatSupportedFunctionList(registry: ControlMutationDefaultRegistry): string {
|
|
231
|
+
const signatures = Array.from(registry.entries())
|
|
232
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
233
|
+
.flatMap(([functionName, entry]) => {
|
|
234
|
+
const usageSignatures = entry.usageSignatures?.filter((signature) => signature.length > 0);
|
|
235
|
+
return usageSignatures && usageSignatures.length > 0
|
|
236
|
+
? usageSignatures
|
|
237
|
+
: [`${functionName}()`];
|
|
361
238
|
});
|
|
362
|
-
}
|
|
363
|
-
const version = parseIntegerArgument(input.call.args[0]?.raw ?? '');
|
|
364
|
-
if (version === 2) {
|
|
365
|
-
return executionGenerator('cuid2');
|
|
366
|
-
}
|
|
367
|
-
return invalidArgumentDiagnostic({
|
|
368
|
-
context: input.context,
|
|
369
|
-
span: input.call.args[0]?.span ?? input.call.span,
|
|
370
|
-
message: 'Default function "cuid" supports only `cuid(2)` in SQL PSL provider v1.',
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function lowerUlid(input: {
|
|
375
|
-
readonly call: ParsedDefaultFunctionCall;
|
|
376
|
-
readonly context: DefaultFunctionLoweringContext;
|
|
377
|
-
}): LoweredDefaultResult {
|
|
378
|
-
const maybeNoArgs = expectNoArgs({
|
|
379
|
-
call: input.call,
|
|
380
|
-
context: input.context,
|
|
381
|
-
usage: '`ulid()`',
|
|
382
|
-
});
|
|
383
|
-
if (maybeNoArgs) {
|
|
384
|
-
return maybeNoArgs;
|
|
385
|
-
}
|
|
386
|
-
return executionGenerator('ulid');
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
function lowerNanoid(input: {
|
|
390
|
-
readonly call: ParsedDefaultFunctionCall;
|
|
391
|
-
readonly context: DefaultFunctionLoweringContext;
|
|
392
|
-
}): LoweredDefaultResult {
|
|
393
|
-
if (input.call.args.length === 0) {
|
|
394
|
-
return executionGenerator('nanoid');
|
|
395
|
-
}
|
|
396
|
-
if (input.call.args.length !== 1) {
|
|
397
|
-
return invalidArgumentDiagnostic({
|
|
398
|
-
context: input.context,
|
|
399
|
-
span: input.call.span,
|
|
400
|
-
message:
|
|
401
|
-
'Default function "nanoid" accepts at most one size argument: `nanoid()` or `nanoid(<2-255>)`.',
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
const size = parseIntegerArgument(input.call.args[0]?.raw ?? '');
|
|
405
|
-
if (size !== undefined && size >= 2 && size <= 255) {
|
|
406
|
-
return executionGenerator('nanoid', { size });
|
|
407
|
-
}
|
|
408
|
-
return invalidArgumentDiagnostic({
|
|
409
|
-
context: input.context,
|
|
410
|
-
span: input.call.args[0]?.span ?? input.call.span,
|
|
411
|
-
message: 'Default function "nanoid" size argument must be an integer between 2 and 255.',
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
function lowerDbgenerated(input: {
|
|
416
|
-
readonly call: ParsedDefaultFunctionCall;
|
|
417
|
-
readonly context: DefaultFunctionLoweringContext;
|
|
418
|
-
}): LoweredDefaultResult {
|
|
419
|
-
if (input.call.args.length !== 1) {
|
|
420
|
-
return invalidArgumentDiagnostic({
|
|
421
|
-
context: input.context,
|
|
422
|
-
span: input.call.span,
|
|
423
|
-
message:
|
|
424
|
-
'Default function "dbgenerated" requires exactly one string argument: `dbgenerated("...")`.',
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
const rawExpression = parseStringLiteral(input.call.args[0]?.raw ?? '');
|
|
428
|
-
if (rawExpression === undefined) {
|
|
429
|
-
return invalidArgumentDiagnostic({
|
|
430
|
-
context: input.context,
|
|
431
|
-
span: input.call.args[0]?.span ?? input.call.span,
|
|
432
|
-
message: 'Default function "dbgenerated" argument must be a string literal.',
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
if (rawExpression.trim().length === 0) {
|
|
436
|
-
return invalidArgumentDiagnostic({
|
|
437
|
-
context: input.context,
|
|
438
|
-
span: input.call.args[0]?.span ?? input.call.span,
|
|
439
|
-
message: 'Default function "dbgenerated" argument cannot be empty.',
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
return {
|
|
443
|
-
ok: true,
|
|
444
|
-
value: {
|
|
445
|
-
kind: 'storage',
|
|
446
|
-
defaultValue: {
|
|
447
|
-
kind: 'function',
|
|
448
|
-
expression: rawExpression,
|
|
449
|
-
},
|
|
450
|
-
},
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
const supportedFunctionUsageByName: Readonly<Record<string, readonly string[]>> = {
|
|
455
|
-
autoincrement: ['autoincrement()'],
|
|
456
|
-
now: ['now()'],
|
|
457
|
-
uuid: ['uuid()', 'uuid(4)', 'uuid(7)'],
|
|
458
|
-
cuid: ['cuid(2)'],
|
|
459
|
-
ulid: ['ulid()'],
|
|
460
|
-
nanoid: ['nanoid()', 'nanoid(n)'],
|
|
461
|
-
dbgenerated: ['dbgenerated("...")'],
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
const unknownFunctionSuggestionsByName: Readonly<Record<string, string>> = {
|
|
465
|
-
cuid2: 'Use `cuid(2)`.',
|
|
466
|
-
uuidv4: 'Use `uuid()` or `uuid(4)`.',
|
|
467
|
-
uuidv7: 'Use `uuid(7)`.',
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
function formatSupportedFunctionList(registry: DefaultFunctionRegistry): string {
|
|
471
|
-
const signatures = Array.from(registry.keys())
|
|
472
|
-
.sort()
|
|
473
|
-
.flatMap((functionName) => supportedFunctionUsageByName[functionName] ?? [`${functionName}()`]);
|
|
474
239
|
return signatures.length > 0 ? signatures.join(', ') : 'none';
|
|
475
240
|
}
|
|
476
241
|
|
|
477
|
-
export function createBuiltinDefaultFunctionRegistry(): DefaultFunctionRegistry {
|
|
478
|
-
return new Map<string, DefaultFunctionLoweringHandler>([
|
|
479
|
-
['autoincrement', lowerAutoincrement],
|
|
480
|
-
['now', lowerNow],
|
|
481
|
-
['uuid', lowerUuid],
|
|
482
|
-
['cuid', lowerCuid],
|
|
483
|
-
['ulid', lowerUlid],
|
|
484
|
-
['nanoid', lowerNanoid],
|
|
485
|
-
['dbgenerated', lowerDbgenerated],
|
|
486
|
-
]);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
242
|
export function lowerDefaultFunctionWithRegistry(input: {
|
|
490
243
|
readonly call: ParsedDefaultFunctionCall;
|
|
491
|
-
readonly registry:
|
|
244
|
+
readonly registry: ControlMutationDefaultRegistry;
|
|
492
245
|
readonly context: DefaultFunctionLoweringContext;
|
|
493
246
|
}): LoweredDefaultResult {
|
|
494
|
-
const
|
|
495
|
-
if (
|
|
496
|
-
return
|
|
247
|
+
const entry = input.registry.get(input.call.name);
|
|
248
|
+
if (entry) {
|
|
249
|
+
return entry.lower({ call: input.call, context: input.context });
|
|
497
250
|
}
|
|
498
251
|
const supportedFunctionList = formatSupportedFunctionList(input.registry);
|
|
499
|
-
const suggestion = unknownFunctionSuggestionsByName[input.call.name];
|
|
500
252
|
|
|
501
253
|
return {
|
|
502
254
|
ok: false,
|
|
503
255
|
diagnostic: {
|
|
504
256
|
code: 'PSL_UNKNOWN_DEFAULT_FUNCTION',
|
|
505
|
-
message: `Default function "${input.call.name}" is not supported in SQL PSL provider v1. Supported functions: ${supportedFunctionList}
|
|
257
|
+
message: `Default function "${input.call.name}" is not supported in SQL PSL provider v1. Supported functions: ${supportedFunctionList}.`,
|
|
506
258
|
sourceId: input.context.sourceId,
|
|
507
259
|
span: input.call.span,
|
|
508
260
|
},
|
package/src/exports/index.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
ControlMutationDefaults,
|
|
3
|
+
DefaultFunctionLoweringContext,
|
|
4
|
+
DefaultFunctionLoweringHandler,
|
|
5
|
+
DefaultFunctionRegistry,
|
|
6
|
+
DefaultFunctionRegistryEntry,
|
|
7
|
+
MutationDefaultGeneratorDescriptor,
|
|
8
|
+
} from '../default-function-registry';
|
|
1
9
|
export {
|
|
2
|
-
type
|
|
3
|
-
|
|
10
|
+
type InterpretPslDocumentToSqlContractInput,
|
|
11
|
+
interpretPslDocumentToSqlContract,
|
|
4
12
|
} from '../interpreter';
|