@prisma-next/framework-components 0.5.0-dev.5 → 0.5.0-dev.50
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 +61 -0
- package/dist/authoring.d.mts +1 -1
- package/dist/authoring.mjs +1 -1
- package/dist/authoring.mjs.map +1 -1
- package/dist/codec-types-CB0jWeHU.d.mts +207 -0
- package/dist/codec-types-CB0jWeHU.d.mts.map +1 -0
- package/dist/codec.d.mts +2 -2
- package/dist/codec.mjs +38 -2
- package/dist/codec.mjs.map +1 -1
- package/dist/components.d.mts +1 -1
- package/dist/components.mjs +1 -1
- package/dist/control.d.mts +109 -70
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +11 -5
- package/dist/control.mjs.map +1 -1
- package/dist/emission-types-D6t3_a0x.d.mts +39 -0
- package/dist/emission-types-D6t3_a0x.d.mts.map +1 -0
- package/dist/emission.d.mts +2 -2
- package/dist/execution.d.mts +5 -5
- package/dist/execution.d.mts.map +1 -1
- package/dist/execution.mjs +3 -3
- package/dist/execution.mjs.map +1 -1
- package/dist/{framework-authoring-D1-JZ37B.d.mts → framework-authoring-BdrFDx4x.d.mts} +2 -2
- package/dist/framework-authoring-BdrFDx4x.d.mts.map +1 -0
- package/dist/{framework-components-EJXe-pum.d.mts → framework-components-AHI6V96G.d.mts} +6 -6
- package/dist/framework-components-AHI6V96G.d.mts.map +1 -0
- package/dist/{framework-components-C8ZhSwXe.mjs → framework-components-BsWST1Rn.mjs} +2 -2
- package/dist/framework-components-BsWST1Rn.mjs.map +1 -0
- package/dist/psl-ast-9X5rwo98.d.mts +159 -0
- package/dist/psl-ast-9X5rwo98.d.mts.map +1 -0
- package/dist/psl-ast.d.mts +2 -0
- package/dist/psl-ast.mjs +1 -0
- package/dist/runtime.d.mts +346 -19
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +256 -4
- package/dist/runtime.mjs.map +1 -1
- package/dist/{types-import-spec-C4sc7wbb.d.mts → types-import-spec-D-O6GotH.d.mts} +2 -2
- package/dist/types-import-spec-D-O6GotH.d.mts.map +1 -0
- package/package.json +6 -4
- package/src/control/control-capabilities.ts +71 -0
- package/src/{control-descriptors.ts → control/control-descriptors.ts} +7 -7
- package/src/{control-instances.ts → control/control-instances.ts} +6 -6
- package/src/{control-migration-types.ts → control/control-migration-types.ts} +57 -60
- package/src/control/control-operation-preview.ts +23 -0
- package/src/{control-stack.ts → control/control-stack.ts} +13 -13
- package/src/control/emission-types.ts +49 -0
- package/src/control/psl-ast.ts +193 -0
- package/src/{execution-descriptors.ts → execution/execution-descriptors.ts} +7 -7
- package/src/{execution-instances.ts → execution/execution-instances.ts} +1 -1
- package/src/{execution-requirements.ts → execution/execution-requirements.ts} +1 -1
- package/src/execution/query-plan.ts +53 -0
- package/src/execution/race-against-abort.ts +85 -0
- package/src/execution/run-with-middleware.ts +132 -0
- package/src/execution/runtime-core.ts +133 -0
- package/src/execution/runtime-error.ts +83 -0
- package/src/execution/runtime-middleware.ts +182 -0
- package/src/exports/authoring.ts +2 -2
- package/src/exports/codec.ts +14 -2
- package/src/exports/components.ts +2 -2
- package/src/exports/control.ts +26 -13
- package/src/exports/emission.ts +2 -2
- package/src/exports/execution.ts +5 -5
- package/src/exports/psl-ast.ts +1 -0
- package/src/exports/runtime.ts +17 -5
- package/src/shared/codec-types.ts +261 -0
- package/dist/codec-types-B58nCJiu.d.mts +0 -40
- package/dist/codec-types-B58nCJiu.d.mts.map +0 -1
- package/dist/emission-types-BPAALJbF.d.mts +0 -24
- package/dist/emission-types-BPAALJbF.d.mts.map +0 -1
- package/dist/framework-authoring-D1-JZ37B.d.mts.map +0 -1
- package/dist/framework-components-C8ZhSwXe.mjs.map +0 -1
- package/dist/framework-components-EJXe-pum.d.mts.map +0 -1
- package/dist/types-import-spec-C4sc7wbb.d.mts.map +0 -1
- package/src/codec-types.ts +0 -46
- package/src/control-capabilities.ts +0 -34
- package/src/emission-types.ts +0 -28
- package/src/runtime-error.ts +0 -39
- package/src/runtime-middleware.ts +0 -83
- /package/src/{control-result-types.ts → control/control-result-types.ts} +0 -0
- /package/src/{control-schema-view.ts → control/control-schema-view.ts} +0 -0
- /package/src/{async-iterable-result.ts → execution/async-iterable-result.ts} +0 -0
- /package/src/{execution-stack.ts → execution/execution-stack.ts} +0 -0
- /package/src/{framework-authoring.ts → shared/framework-authoring.ts} +0 -0
- /package/src/{framework-components.ts → shared/framework-components.ts} +0 -0
- /package/src/{mutation-default-types.ts → shared/mutation-default-types.ts} +0 -0
- /package/src/{types-import-spec.ts → shared/types-import-spec.ts} +0 -0
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
import type { Contract } from '@prisma-next/contract/types';
|
|
13
13
|
import type { Result } from '@prisma-next/utils/result';
|
|
14
|
+
import type { TargetBoundComponentDescriptor } from '../shared/framework-components';
|
|
14
15
|
import type { ControlDriverInstance, ControlFamilyInstance } from './control-instances';
|
|
15
|
-
import type { TargetBoundComponentDescriptor } from './framework-components';
|
|
16
16
|
|
|
17
17
|
// ============================================================================
|
|
18
18
|
// Operation Classes and Policy
|
|
@@ -28,61 +28,23 @@ import type { TargetBoundComponentDescriptor } from './framework-components';
|
|
|
28
28
|
export type MigrationOperationClass = 'additive' | 'widening' | 'destructive' | 'data';
|
|
29
29
|
|
|
30
30
|
// ============================================================================
|
|
31
|
-
//
|
|
31
|
+
// Serialized Query Plan
|
|
32
32
|
// ============================================================================
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* A lowered query statement as stored in ops.json.
|
|
36
36
|
* Contains the SQL string and parameter values — ready for execution.
|
|
37
37
|
* Lowering from query builder AST to SQL happens at verify time.
|
|
38
|
+
*
|
|
39
|
+
* The Postgres `dataTransform` factory uses this shape internally to
|
|
40
|
+
* carry the user's lowered `check`/`run` plans before wrapping them
|
|
41
|
+
* into precheck/execute/postcheck steps on the unified migration op.
|
|
38
42
|
*/
|
|
39
43
|
export interface SerializedQueryPlan {
|
|
40
44
|
readonly sql: string;
|
|
41
45
|
readonly params: readonly unknown[];
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
/**
|
|
45
|
-
* A data transform operation within a migration edge.
|
|
46
|
-
*
|
|
47
|
-
* Data transforms are authored in TypeScript using the query builder,
|
|
48
|
-
* serialized to JSON ASTs at verification time, and rendered to SQL
|
|
49
|
-
* by the target adapter at apply time.
|
|
50
|
-
*
|
|
51
|
-
* The `name` serves as the invariant identity — it's recorded in the
|
|
52
|
-
* ledger and used for invariant-aware routing via environment refs.
|
|
53
|
-
*
|
|
54
|
-
* In draft state (before verification), `check` and `run` are null.
|
|
55
|
-
* After verification, they contain the serialized query ASTs.
|
|
56
|
-
*/
|
|
57
|
-
export interface DataTransformOperation extends MigrationPlanOperation {
|
|
58
|
-
readonly operationClass: 'data';
|
|
59
|
-
/**
|
|
60
|
-
* The invariant name for this data transform.
|
|
61
|
-
* Recorded in the ledger on successful edge completion.
|
|
62
|
-
* Used by environment refs to declare required invariants.
|
|
63
|
-
*/
|
|
64
|
-
readonly name: string;
|
|
65
|
-
/**
|
|
66
|
-
* Path to the TypeScript source file that produced this operation.
|
|
67
|
-
* Not part of edgeId computation — for traceability only.
|
|
68
|
-
*/
|
|
69
|
-
readonly source: string;
|
|
70
|
-
/**
|
|
71
|
-
* Serialized check query plan, or a boolean literal.
|
|
72
|
-
* - SerializedQueryPlan: describes violations; empty result = already applied.
|
|
73
|
-
* - false: always run (no check).
|
|
74
|
-
* - true: always skip.
|
|
75
|
-
* - null: not yet serialized (draft state).
|
|
76
|
-
*/
|
|
77
|
-
readonly check: SerializedQueryPlan | boolean | null;
|
|
78
|
-
/**
|
|
79
|
-
* Serialized run query plans.
|
|
80
|
-
* - Array of serialized query plans to execute sequentially.
|
|
81
|
-
* - null: not yet serialized (draft state).
|
|
82
|
-
*/
|
|
83
|
-
readonly run: readonly SerializedQueryPlan[] | null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
48
|
/**
|
|
87
49
|
* Policy defining which operation classes are allowed during a migration.
|
|
88
50
|
*/
|
|
@@ -105,6 +67,17 @@ export interface MigrationPlanOperation {
|
|
|
105
67
|
readonly label: string;
|
|
106
68
|
/** The class of operation (additive, widening, destructive). */
|
|
107
69
|
readonly operationClass: MigrationOperationClass;
|
|
70
|
+
/**
|
|
71
|
+
* Optional opt-in routing identity for data-transform operations.
|
|
72
|
+
* Presence opts the transform into invariant-aware routing; absence
|
|
73
|
+
* means it is path-dependent and not referenceable from refs.
|
|
74
|
+
*
|
|
75
|
+
* Lives on the base op so the manifest emitter and
|
|
76
|
+
* `deriveProvidedInvariants` can read it without depending on a
|
|
77
|
+
* target-specific shape. Schema-DDL ops (additive / widening /
|
|
78
|
+
* destructive) leave it undefined.
|
|
79
|
+
*/
|
|
80
|
+
readonly invariantId?: string;
|
|
108
81
|
}
|
|
109
82
|
|
|
110
83
|
// ============================================================================
|
|
@@ -151,6 +124,17 @@ export interface MigrationPlan {
|
|
|
151
124
|
};
|
|
152
125
|
/** Ordered list of operations to execute. */
|
|
153
126
|
readonly operations: readonly MigrationPlanOperation[];
|
|
127
|
+
/**
|
|
128
|
+
* Sorted, deduplicated invariant ids declared by this plan's data-transform
|
|
129
|
+
* ops. Authored migrations carry the canonical value from
|
|
130
|
+
* `migration.json.providedInvariants`; planner-built plans (`db init`,
|
|
131
|
+
* `db update`) omit it (the runner treats it as `[]`). Runners read this
|
|
132
|
+
* field for marker writes and self-edge no-op detection rather than
|
|
133
|
+
* re-deriving from `operations`, since the manifest is the canonical
|
|
134
|
+
* source for the invariant set across all runners (postgres, sqlite,
|
|
135
|
+
* mongo).
|
|
136
|
+
*/
|
|
137
|
+
readonly providedInvariants?: readonly string[];
|
|
154
138
|
}
|
|
155
139
|
|
|
156
140
|
/**
|
|
@@ -289,21 +273,23 @@ export interface MigrationPlanner<
|
|
|
289
273
|
readonly contract: unknown;
|
|
290
274
|
readonly schema: unknown;
|
|
291
275
|
readonly policy: MigrationOperationPolicy;
|
|
292
|
-
/**
|
|
293
|
-
* Storage hash of the "from" contract (the state the planner assumes the
|
|
294
|
-
* database starts at). Planners use this to populate `describe()` on the
|
|
295
|
-
* produced plan so the rendered `migration.ts` has correct `from`/`to`
|
|
296
|
-
* metadata.
|
|
297
|
-
*/
|
|
298
|
-
readonly fromHash: string;
|
|
299
276
|
/**
|
|
300
277
|
* The "from" contract (the state the planner assumes the database starts
|
|
301
|
-
* at)
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
278
|
+
* at), or `null` for a baseline plan with no prior state.
|
|
279
|
+
*
|
|
280
|
+
* Planners derive any "from" identity they need to stamp onto the
|
|
281
|
+
* produced plan's `describe()` from `fromContract?.storage.storageHash
|
|
282
|
+
* ?? null`. They also pass this to data-safety strategies so they can
|
|
283
|
+
* compare `from` and `to` column shapes (e.g. to detect unsafe type
|
|
284
|
+
* changes).
|
|
285
|
+
*
|
|
286
|
+
* Required at every call site to make the structural fact "I have a
|
|
287
|
+
* prior contract / I don't" visible in the type. Reconciliation
|
|
288
|
+
* commands (`db init`, `db update`) introspect a live schema and pass
|
|
289
|
+
* `null`; authoring commands (`migration plan`) pass the previous
|
|
290
|
+
* bundle's `metadata.toContract`.
|
|
305
291
|
*/
|
|
306
|
-
readonly fromContract
|
|
292
|
+
readonly fromContract: Contract | null;
|
|
307
293
|
/**
|
|
308
294
|
* Active framework components participating in this composition.
|
|
309
295
|
* Families/targets can interpret this list to derive family-specific metadata.
|
|
@@ -335,6 +321,16 @@ export interface MigrationRunner<
|
|
|
335
321
|
TFamilyId extends string = string,
|
|
336
322
|
TTargetId extends string = string,
|
|
337
323
|
> {
|
|
324
|
+
/**
|
|
325
|
+
* Execute a migration plan against the configured driver.
|
|
326
|
+
*
|
|
327
|
+
* The `plan` parameter is trusted input. Callers are responsible for
|
|
328
|
+
* upstream verification of the originating migration package — typically
|
|
329
|
+
* by obtaining the package via `readMigrationPackage` from
|
|
330
|
+
* `@prisma-next/migration-tools/io`, which performs hash-integrity checks
|
|
331
|
+
* at the load boundary. Runners do not re-verify the plan and assume the
|
|
332
|
+
* `(metadata, ops)` pair on disk has not been tampered with since emit.
|
|
333
|
+
*/
|
|
338
334
|
execute(options: {
|
|
339
335
|
readonly plan: MigrationPlan;
|
|
340
336
|
readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
|
|
@@ -414,11 +410,12 @@ export interface MigrationScaffoldContext {
|
|
|
414
410
|
/** Absolute path to the contract.json file, if one exists. Used by targets that emit typed-contract imports. */
|
|
415
411
|
readonly contractJsonPath?: string;
|
|
416
412
|
/**
|
|
417
|
-
* Storage hash of the "from" contract
|
|
418
|
-
* `describe()` on the
|
|
419
|
-
* is correctly
|
|
413
|
+
* Storage hash of the "from" contract, or `null` for a baseline scaffold
|
|
414
|
+
* with no prior state. Targets use this to populate `describe()` on the
|
|
415
|
+
* rendered empty migration so that identity metadata is correctly
|
|
416
|
+
* populated.
|
|
420
417
|
*/
|
|
421
|
-
readonly fromHash: string;
|
|
418
|
+
readonly fromHash: string | null;
|
|
422
419
|
/**
|
|
423
420
|
* Storage hash of the "to" contract. Same purpose as `fromHash` — threaded
|
|
424
421
|
* through so the rendered class's `describe()` declares the correct
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Family-agnostic textual preview of a migration plan, used by the CLI to
|
|
3
|
+
* render a "DDL preview" section for `db init` / `db update` / `migration plan`
|
|
4
|
+
* / `migration show`. Each statement carries a free-form `language` tag so
|
|
5
|
+
* formatters can suffix `;` for SQL but render Mongo shell lines verbatim.
|
|
6
|
+
*
|
|
7
|
+
* Producers are family-specific: SQL emits `language: 'sql'` (existing DDL
|
|
8
|
+
* extraction); Mongo emits `language: 'mongodb-shell'` via the
|
|
9
|
+
* `MongoDdlCommandFormatter` visitor.
|
|
10
|
+
*
|
|
11
|
+
* The capability `OperationPreviewCapable` (declared in
|
|
12
|
+
* `./control-capabilities`) is how a family announces it can produce these.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export interface OperationPreviewStatement {
|
|
16
|
+
readonly text: string;
|
|
17
|
+
/** Dialect identifier, e.g. `'sql'`, `'mongodb-shell'`. Free-form by design (OQ-3). */
|
|
18
|
+
readonly language: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface OperationPreview {
|
|
22
|
+
readonly statements: readonly OperationPreviewStatement[];
|
|
23
|
+
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import type { CodecLookup } from '
|
|
2
|
-
import type {
|
|
3
|
-
ControlAdapterDescriptor,
|
|
4
|
-
ControlDriverDescriptor,
|
|
5
|
-
ControlExtensionDescriptor,
|
|
6
|
-
ControlFamilyDescriptor,
|
|
7
|
-
ControlTargetDescriptor,
|
|
8
|
-
} from './control-descriptors';
|
|
1
|
+
import type { CodecLookup } from '../shared/codec-types';
|
|
9
2
|
import type {
|
|
10
3
|
AuthoringContributions,
|
|
11
4
|
AuthoringFieldNamespace,
|
|
12
5
|
AuthoringFieldPresetDescriptor,
|
|
13
6
|
AuthoringTypeConstructorDescriptor,
|
|
14
7
|
AuthoringTypeNamespace,
|
|
15
|
-
} from '
|
|
16
|
-
import type { ComponentMetadata } from '
|
|
8
|
+
} from '../shared/framework-authoring';
|
|
9
|
+
import type { ComponentMetadata } from '../shared/framework-components';
|
|
17
10
|
import type {
|
|
18
11
|
ControlMutationDefaultEntry,
|
|
19
12
|
ControlMutationDefaults,
|
|
20
13
|
MutationDefaultGeneratorDescriptor,
|
|
21
|
-
} from '
|
|
22
|
-
import type { TypesImportSpec } from '
|
|
14
|
+
} from '../shared/mutation-default-types';
|
|
15
|
+
import type { TypesImportSpec } from '../shared/types-import-spec';
|
|
16
|
+
import type {
|
|
17
|
+
ControlAdapterDescriptor,
|
|
18
|
+
ControlDriverDescriptor,
|
|
19
|
+
ControlExtensionDescriptor,
|
|
20
|
+
ControlFamilyDescriptor,
|
|
21
|
+
ControlTargetDescriptor,
|
|
22
|
+
} from './control-descriptors';
|
|
23
23
|
|
|
24
24
|
export interface AssembledAuthoringContributions {
|
|
25
25
|
readonly field: AuthoringFieldNamespace;
|
|
@@ -328,7 +328,7 @@ export function assembleControlMutationDefaults(
|
|
|
328
328
|
export function extractCodecLookup(
|
|
329
329
|
descriptors: ReadonlyArray<Pick<ComponentMetadata & { id?: string }, 'types' | 'id'>>,
|
|
330
330
|
): CodecLookup {
|
|
331
|
-
const byId = new Map<string, import('
|
|
331
|
+
const byId = new Map<string, import('../shared/codec-types').Codec>();
|
|
332
332
|
const owners = new Map<string, string>();
|
|
333
333
|
for (const descriptor of descriptors) {
|
|
334
334
|
const codecInstances = descriptor.types?.codecTypes?.codecInstances;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Contract, ContractModel } from '@prisma-next/contract/types';
|
|
2
|
+
import type { TypesImportSpec } from '../shared/types-import-spec';
|
|
3
|
+
|
|
4
|
+
export interface GenerateContractTypesOptions {
|
|
5
|
+
readonly queryOperationTypeImports?: ReadonlyArray<TypesImportSpec>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ValidationContext {
|
|
9
|
+
readonly codecTypeImports?: ReadonlyArray<TypesImportSpec>;
|
|
10
|
+
readonly operationTypeImports?: ReadonlyArray<TypesImportSpec>;
|
|
11
|
+
readonly extensionIds?: ReadonlyArray<string>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface EmissionSpi {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
|
|
17
|
+
generateStorageType(contract: Contract, storageHashTypeName: string): string;
|
|
18
|
+
|
|
19
|
+
generateModelStorageType(modelName: string, model: ContractModel): string;
|
|
20
|
+
|
|
21
|
+
getFamilyImports(): string[];
|
|
22
|
+
|
|
23
|
+
getFamilyTypeAliases(options?: GenerateContractTypesOptions): string;
|
|
24
|
+
|
|
25
|
+
getTypeMapsExpression(): string;
|
|
26
|
+
|
|
27
|
+
getContractWrapper(contractBaseName: string, typeMapsName: string): string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Per-family resolver for typeParams that don't live inline on the
|
|
31
|
+
* framework-domain `ContractField`. Some families (notably SQL) let columns
|
|
32
|
+
* reference a named entry in `storage.types` via `typeRef`; the typeParams
|
|
33
|
+
* live on that named entry rather than on the domain field. The framework
|
|
34
|
+
* emit path consults this hook so the codec's `renderOutputType` can run
|
|
35
|
+
* for typeRef-shaped columns.
|
|
36
|
+
*
|
|
37
|
+
* Inline `field.type.typeParams` always takes precedence; the hook is only
|
|
38
|
+
* consulted when the domain field has no typeParams. Families without
|
|
39
|
+
* named storage types (e.g. mongo) don't implement this hook.
|
|
40
|
+
*
|
|
41
|
+
* Returns `undefined` when the field has no resolvable typeParams.
|
|
42
|
+
*/
|
|
43
|
+
resolveFieldTypeParams?(
|
|
44
|
+
modelName: string,
|
|
45
|
+
fieldName: string,
|
|
46
|
+
model: ContractModel,
|
|
47
|
+
contract: Contract,
|
|
48
|
+
): Record<string, unknown> | undefined;
|
|
49
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
export interface PslPosition {
|
|
2
|
+
readonly offset: number;
|
|
3
|
+
readonly line: number;
|
|
4
|
+
readonly column: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface PslSpan {
|
|
8
|
+
readonly start: PslPosition;
|
|
9
|
+
readonly end: PslPosition;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type PslDiagnosticCode =
|
|
13
|
+
| 'PSL_UNTERMINATED_BLOCK'
|
|
14
|
+
| 'PSL_UNSUPPORTED_TOP_LEVEL_BLOCK'
|
|
15
|
+
| 'PSL_INVALID_ATTRIBUTE_SYNTAX'
|
|
16
|
+
| 'PSL_INVALID_MODEL_MEMBER'
|
|
17
|
+
| 'PSL_UNSUPPORTED_MODEL_ATTRIBUTE'
|
|
18
|
+
| 'PSL_UNSUPPORTED_FIELD_ATTRIBUTE'
|
|
19
|
+
| 'PSL_INVALID_RELATION_ATTRIBUTE'
|
|
20
|
+
| 'PSL_INVALID_REFERENTIAL_ACTION'
|
|
21
|
+
| 'PSL_INVALID_DEFAULT_VALUE'
|
|
22
|
+
| 'PSL_INVALID_ENUM_MEMBER'
|
|
23
|
+
| 'PSL_INVALID_TYPES_MEMBER';
|
|
24
|
+
|
|
25
|
+
export interface PslDiagnostic {
|
|
26
|
+
readonly code: PslDiagnosticCode;
|
|
27
|
+
readonly message: string;
|
|
28
|
+
readonly sourceId: string;
|
|
29
|
+
readonly span: PslSpan;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PslDefaultFunctionValue {
|
|
33
|
+
readonly kind: 'function';
|
|
34
|
+
readonly name: 'autoincrement' | 'now';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface PslDefaultLiteralValue {
|
|
38
|
+
readonly kind: 'literal';
|
|
39
|
+
readonly value: string | number | boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type PslDefaultValue = PslDefaultFunctionValue | PslDefaultLiteralValue;
|
|
43
|
+
|
|
44
|
+
export type PslAttributeTarget = 'field' | 'model' | 'enum' | 'namedType';
|
|
45
|
+
|
|
46
|
+
export interface PslAttributePositionalArgument {
|
|
47
|
+
readonly kind: 'positional';
|
|
48
|
+
readonly value: string;
|
|
49
|
+
readonly span: PslSpan;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface PslAttributeNamedArgument {
|
|
53
|
+
readonly kind: 'named';
|
|
54
|
+
readonly name: string;
|
|
55
|
+
readonly value: string;
|
|
56
|
+
readonly span: PslSpan;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type PslAttributeArgument = PslAttributePositionalArgument | PslAttributeNamedArgument;
|
|
60
|
+
|
|
61
|
+
export interface PslTypeConstructorCall {
|
|
62
|
+
readonly kind: 'typeConstructor';
|
|
63
|
+
readonly path: readonly string[];
|
|
64
|
+
readonly args: readonly PslAttributeArgument[];
|
|
65
|
+
readonly span: PslSpan;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface PslAttribute {
|
|
69
|
+
readonly kind: 'attribute';
|
|
70
|
+
readonly target: PslAttributeTarget;
|
|
71
|
+
readonly name: string;
|
|
72
|
+
readonly args: readonly PslAttributeArgument[];
|
|
73
|
+
readonly span: PslSpan;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type PslReferentialAction = string;
|
|
77
|
+
|
|
78
|
+
export type PslFieldAttribute = PslAttribute;
|
|
79
|
+
|
|
80
|
+
export interface PslField {
|
|
81
|
+
readonly kind: 'field';
|
|
82
|
+
readonly name: string;
|
|
83
|
+
readonly typeName: string;
|
|
84
|
+
readonly typeConstructor?: PslTypeConstructorCall;
|
|
85
|
+
readonly optional: boolean;
|
|
86
|
+
readonly list: boolean;
|
|
87
|
+
readonly typeRef?: string;
|
|
88
|
+
readonly attributes: readonly PslFieldAttribute[];
|
|
89
|
+
readonly span: PslSpan;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface PslUniqueConstraint {
|
|
93
|
+
readonly kind: 'unique';
|
|
94
|
+
readonly fields: readonly string[];
|
|
95
|
+
readonly span: PslSpan;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface PslIndexConstraint {
|
|
99
|
+
readonly kind: 'index';
|
|
100
|
+
readonly fields: readonly string[];
|
|
101
|
+
readonly span: PslSpan;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type PslModelAttribute = PslAttribute;
|
|
105
|
+
|
|
106
|
+
export interface PslModel {
|
|
107
|
+
readonly kind: 'model';
|
|
108
|
+
readonly name: string;
|
|
109
|
+
readonly fields: readonly PslField[];
|
|
110
|
+
readonly attributes: readonly PslModelAttribute[];
|
|
111
|
+
readonly span: PslSpan;
|
|
112
|
+
/**
|
|
113
|
+
* Optional leading comment line emitted above the `model` keyword by the
|
|
114
|
+
* printer. Producers (e.g. `sqlSchemaIrToPslAst`) attach introspection
|
|
115
|
+
* advisories such as "// WARNING: This table has no primary key in the
|
|
116
|
+
* database" here. The parser leaves this field unset; round-tripping a
|
|
117
|
+
* parsed schema does not re-attach comments.
|
|
118
|
+
*/
|
|
119
|
+
readonly comment?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface PslEnumValue {
|
|
123
|
+
readonly kind: 'enumValue';
|
|
124
|
+
readonly name: string;
|
|
125
|
+
/**
|
|
126
|
+
* Optional storage label for the enum member, captured from a trailing
|
|
127
|
+
* `@map("...")` attribute on the member line. The parser populates this
|
|
128
|
+
* when the source PSL carries an explicit `@map`. Producers (e.g.
|
|
129
|
+
* `sqlSchemaIrToPslAst`) leave it unset; the printer emits `@map(...)`
|
|
130
|
+
* automatically when normalisation would change the printed member name
|
|
131
|
+
* (so an enum value `'in-progress'` becomes `inProgress @map("in-progress")`
|
|
132
|
+
* in PSL, preserving the round-trip).
|
|
133
|
+
*/
|
|
134
|
+
readonly mapName?: string;
|
|
135
|
+
readonly span: PslSpan;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface PslEnum {
|
|
139
|
+
readonly kind: 'enum';
|
|
140
|
+
readonly name: string;
|
|
141
|
+
readonly values: readonly PslEnumValue[];
|
|
142
|
+
readonly attributes: readonly PslAttribute[];
|
|
143
|
+
readonly span: PslSpan;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface PslCompositeType {
|
|
147
|
+
readonly kind: 'compositeType';
|
|
148
|
+
readonly name: string;
|
|
149
|
+
readonly fields: readonly PslField[];
|
|
150
|
+
readonly attributes: readonly PslAttribute[];
|
|
151
|
+
readonly span: PslSpan;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface PslNamedTypeDeclaration {
|
|
155
|
+
readonly kind: 'namedType';
|
|
156
|
+
readonly name: string;
|
|
157
|
+
/**
|
|
158
|
+
* Parser invariant: exactly one of `baseType` and `typeConstructor` is set.
|
|
159
|
+
* Expressing this as a discriminated union trips TypeScript narrowing when
|
|
160
|
+
* the declaration flows through helpers that accept the full union.
|
|
161
|
+
*/
|
|
162
|
+
readonly baseType?: string;
|
|
163
|
+
readonly typeConstructor?: PslTypeConstructorCall;
|
|
164
|
+
readonly attributes: readonly PslAttribute[];
|
|
165
|
+
readonly span: PslSpan;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface PslTypesBlock {
|
|
169
|
+
readonly kind: 'types';
|
|
170
|
+
readonly declarations: readonly PslNamedTypeDeclaration[];
|
|
171
|
+
readonly span: PslSpan;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface PslDocumentAst {
|
|
175
|
+
readonly kind: 'document';
|
|
176
|
+
readonly sourceId: string;
|
|
177
|
+
readonly models: readonly PslModel[];
|
|
178
|
+
readonly enums: readonly PslEnum[];
|
|
179
|
+
readonly compositeTypes: readonly PslCompositeType[];
|
|
180
|
+
readonly types?: PslTypesBlock;
|
|
181
|
+
readonly span: PslSpan;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface ParsePslDocumentInput {
|
|
185
|
+
readonly schema: string;
|
|
186
|
+
readonly sourceId: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface ParsePslDocumentResult {
|
|
190
|
+
readonly ast: PslDocumentAst;
|
|
191
|
+
readonly diagnostics: readonly PslDiagnostic[];
|
|
192
|
+
readonly ok: boolean;
|
|
193
|
+
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AdapterDescriptor,
|
|
3
|
+
DriverDescriptor,
|
|
4
|
+
ExtensionDescriptor,
|
|
5
|
+
FamilyDescriptor,
|
|
6
|
+
TargetDescriptor,
|
|
7
|
+
} from '../shared/framework-components';
|
|
1
8
|
import type {
|
|
2
9
|
RuntimeAdapterInstance,
|
|
3
10
|
RuntimeDriverInstance,
|
|
@@ -6,13 +13,6 @@ import type {
|
|
|
6
13
|
RuntimeTargetInstance,
|
|
7
14
|
} from './execution-instances';
|
|
8
15
|
import type { ExecutionStack } from './execution-stack';
|
|
9
|
-
import type {
|
|
10
|
-
AdapterDescriptor,
|
|
11
|
-
DriverDescriptor,
|
|
12
|
-
ExtensionDescriptor,
|
|
13
|
-
FamilyDescriptor,
|
|
14
|
-
TargetDescriptor,
|
|
15
|
-
} from './framework-components';
|
|
16
16
|
|
|
17
17
|
export interface RuntimeFamilyDescriptor<
|
|
18
18
|
TFamilyId extends string,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { checkContractComponentRequirements } from '../shared/framework-components';
|
|
1
2
|
import type {
|
|
2
3
|
RuntimeAdapterDescriptor,
|
|
3
4
|
RuntimeExtensionDescriptor,
|
|
4
5
|
RuntimeFamilyDescriptor,
|
|
5
6
|
RuntimeTargetDescriptor,
|
|
6
7
|
} from './execution-descriptors';
|
|
7
|
-
import { checkContractComponentRequirements } from './framework-components';
|
|
8
8
|
|
|
9
9
|
export function assertRuntimeContractRequirementsSatisfied<
|
|
10
10
|
TFamilyId extends string,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { PlanMeta } from '@prisma-next/contract/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Family-agnostic plan marker.
|
|
5
|
+
*
|
|
6
|
+
* Carries only `meta` (the family-agnostic plan metadata) and the optional
|
|
7
|
+
* phantom `_row` parameter that lets type-level utilities recover the row
|
|
8
|
+
* type from a plan value. SQL and Mongo extend this marker with their own
|
|
9
|
+
* concrete shapes (`SqlQueryPlan`, `MongoQueryPlan`).
|
|
10
|
+
*
|
|
11
|
+
* `QueryPlan` is the *pre-lowering* marker — i.e. the surface a builder
|
|
12
|
+
* produces before family-specific lowering turns it into an executable
|
|
13
|
+
* plan (`ExecutionPlan`).
|
|
14
|
+
*/
|
|
15
|
+
export interface QueryPlan<Row = unknown> {
|
|
16
|
+
readonly meta: PlanMeta;
|
|
17
|
+
/**
|
|
18
|
+
* Phantom property to carry the Row generic for type-level utilities.
|
|
19
|
+
* Not set at runtime; used only for `ResultType` extraction.
|
|
20
|
+
*/
|
|
21
|
+
readonly _row?: Row;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Family-agnostic execution-plan marker.
|
|
26
|
+
*
|
|
27
|
+
* Extends `QueryPlan` with no additional structural fields — the marker
|
|
28
|
+
* exists to nominally distinguish executable plans from pre-lowering plans
|
|
29
|
+
* in the type system. Family-specific execution plans (`SqlExecutionPlan`,
|
|
30
|
+
* `MongoExecutionPlan`) extend this marker with their concrete shapes
|
|
31
|
+
* (e.g. `sql + params` for SQL, `wireCommand` for Mongo).
|
|
32
|
+
*/
|
|
33
|
+
export interface ExecutionPlan<Row = unknown> extends QueryPlan<Row> {}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Extracts the `Row` type from a plan via the phantom `_row` property.
|
|
37
|
+
*
|
|
38
|
+
* Works with any plan that extends `QueryPlan<Row>` — including
|
|
39
|
+
* `ExecutionPlan<Row>`, `SqlQueryPlan<Row>`, `SqlExecutionPlan<Row>`,
|
|
40
|
+
* `MongoQueryPlan<Row>`, and `MongoExecutionPlan<Row>`.
|
|
41
|
+
*
|
|
42
|
+
* The `_row` property must be present in the plan's static type for the
|
|
43
|
+
* conditional to bind `R`; objects whose type lacks `_row` resolve to
|
|
44
|
+
* `never`. Without the `keyof` guard, `extends { _row?: infer R }` would
|
|
45
|
+
* silently match any object and infer `unknown`.
|
|
46
|
+
*
|
|
47
|
+
* Example: `type Row = ResultType<typeof plan>`.
|
|
48
|
+
*/
|
|
49
|
+
export type ResultType<P> = '_row' extends keyof P
|
|
50
|
+
? P extends { readonly _row?: infer R }
|
|
51
|
+
? R
|
|
52
|
+
: never
|
|
53
|
+
: never;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { CodecCallContext } from '../shared/codec-types';
|
|
2
|
+
import type { RuntimeAbortedPhase } from './runtime-error';
|
|
3
|
+
import { runtimeAborted } from './runtime-error';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Throw a phase-tagged `RUNTIME.ABORTED` envelope if the supplied
|
|
7
|
+
* codec-call context is already aborted at the precheck site. Centralises
|
|
8
|
+
* the `if (ctx.signal?.aborted) throw runtimeAborted(...)` pattern that
|
|
9
|
+
* every codec dispatch site repeats.
|
|
10
|
+
*/
|
|
11
|
+
export function checkAborted(ctx: CodecCallContext, phase: RuntimeAbortedPhase): void {
|
|
12
|
+
if (ctx.signal?.aborted) {
|
|
13
|
+
throw runtimeAborted(phase, ctx.signal.reason);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Race a per-cell `Promise.all` (or any other in-flight work promise) against
|
|
19
|
+
* the supplied abort signal so the runtime returns `RUNTIME.ABORTED` promptly
|
|
20
|
+
* even when codec bodies ignore the signal. In-flight bodies that ignore the
|
|
21
|
+
* signal are abandoned and run to completion in the background — the
|
|
22
|
+
* cooperative-cancellation contract documented in ADR 204.
|
|
23
|
+
*
|
|
24
|
+
* Call sites still SHOULD pre-check `signal.aborted` and short-circuit with
|
|
25
|
+
* a phase-tagged `RUNTIME.ABORTED` envelope before invoking this helper —
|
|
26
|
+
* that path is the canonical "aborted at entry" surface and avoids
|
|
27
|
+
* scheduling the work promise. As a defensive belt-and-braces, this helper
|
|
28
|
+
* also handles the already-aborted case internally: `AbortSignal` does not
|
|
29
|
+
* replay past abort events to listeners registered after the abort, so we
|
|
30
|
+
* inspect `signal.aborted` synchronously and reject with the sentinel
|
|
31
|
+
* before installing the listener. The rejection is still attributed to the
|
|
32
|
+
* abort path via the sentinel-identity check.
|
|
33
|
+
*
|
|
34
|
+
* Distinguishing the rejection source is load-bearing for AC-ERR4
|
|
35
|
+
* (`RUNTIME.ENCODE_FAILED` / `RUNTIME.DECODE_FAILED` pass through unchanged).
|
|
36
|
+
* The semantically equivalent `abortable(signal)` helper in
|
|
37
|
+
* `@prisma-next/utils` rejects with `signal.reason ?? new DOMException(...)`,
|
|
38
|
+
* which is not stably distinguishable from a codec-thrown error by identity
|
|
39
|
+
* alone (a fresh fallback DOMException is allocated per call). We instead
|
|
40
|
+
* track abort attribution with a unique sentinel: only the `onAbort` listener
|
|
41
|
+
* installed here ever rejects with the sentinel, so an `error === sentinel`
|
|
42
|
+
* identity check after the race is unambiguous.
|
|
43
|
+
*
|
|
44
|
+
* Lives in `framework-components` (rather than the SQL family, where it
|
|
45
|
+
* originated in m2) so every family runtime that needs cooperative
|
|
46
|
+
* cancellation around a codec-dispatch `Promise.all` (SQL encode + decode
|
|
47
|
+
* today, Mongo encode in m3) shares the same attribution logic.
|
|
48
|
+
*/
|
|
49
|
+
export async function raceAgainstAbort<T>(
|
|
50
|
+
work: Promise<T>,
|
|
51
|
+
signal: AbortSignal | undefined,
|
|
52
|
+
phase: RuntimeAbortedPhase,
|
|
53
|
+
): Promise<T> {
|
|
54
|
+
if (signal === undefined) {
|
|
55
|
+
return await work;
|
|
56
|
+
}
|
|
57
|
+
const sentinel: { reason: unknown } = { reason: undefined };
|
|
58
|
+
let onAbort: (() => void) | undefined;
|
|
59
|
+
|
|
60
|
+
const abortPromise = new Promise<never>((_, reject) => {
|
|
61
|
+
if (signal.aborted) {
|
|
62
|
+
sentinel.reason = signal.reason;
|
|
63
|
+
reject(sentinel);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
onAbort = () => {
|
|
67
|
+
sentinel.reason = signal.reason;
|
|
68
|
+
reject(sentinel);
|
|
69
|
+
};
|
|
70
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
return await Promise.race([work, abortPromise]);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (error === sentinel) {
|
|
77
|
+
throw runtimeAborted(phase, sentinel.reason);
|
|
78
|
+
}
|
|
79
|
+
throw error;
|
|
80
|
+
} finally {
|
|
81
|
+
if (onAbort) {
|
|
82
|
+
signal.removeEventListener('abort', onAbort);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|