@prisma-next/family-sql 0.5.0-dev.67 → 0.5.0-dev.69

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.
@@ -28,6 +28,7 @@ import {
28
28
  } from '@prisma-next/framework-components/control';
29
29
  import type { TypesImportSpec } from '@prisma-next/framework-components/emission';
30
30
  import type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';
31
+ import { assertDescriptorSelfConsistency } from '@prisma-next/migration-tools/spaces';
31
32
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
32
33
  import { validateContract as sqlValidateContract } from '@prisma-next/sql-contract/validate';
33
34
  import {
@@ -205,6 +206,22 @@ export interface SqlControlFamilyInstance
205
206
 
206
207
  schemaVerify(options: SchemaVerifyOptions): Promise<VerifyDatabaseSchemaResult>;
207
208
 
209
+ /**
210
+ * Verify a contract against an already-introspected schema slice.
211
+ *
212
+ * Used by the aggregate verifier to invoke per-member verification
213
+ * with the live schema pre-projected to the member's claimed slice
214
+ * via `projectSchemaToSpace`. Closes F23 — without per-member
215
+ * pre-projection, single-contract verifiers see other-space tables
216
+ * as `extras`.
217
+ */
218
+ schemaVerifyAgainstSchema(options: {
219
+ readonly contract: unknown;
220
+ readonly schema: SqlSchemaIR;
221
+ readonly strict: boolean;
222
+ readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
223
+ }): VerifyDatabaseSchemaResult;
224
+
208
225
  sign(options: {
209
226
  readonly driver: ControlDriverInstance<'sql', string>;
210
227
  readonly contract: unknown;
@@ -233,7 +250,9 @@ function isSqlControlAdapter<TTargetId extends string>(
233
250
  'introspect' in value &&
234
251
  typeof (value as { introspect: unknown }).introspect === 'function' &&
235
252
  'readMarker' in value &&
236
- typeof (value as { readMarker: unknown }).readMarker === 'function'
253
+ typeof (value as { readMarker: unknown }).readMarker === 'function' &&
254
+ 'readAllMarkers' in value &&
255
+ typeof (value as { readAllMarkers: unknown }).readAllMarkers === 'function'
237
256
  );
238
257
  }
239
258
 
@@ -301,6 +320,29 @@ export function createSqlFamilyInstance<TTargetId extends string>(
301
320
  stack.extensionPacks as unknown as readonly (SqlControlExtensionDescriptor<TTargetId> &
302
321
  DescriptorWithStorageTypes)[];
303
322
 
323
+ // Descriptor self-consistency check.
324
+ // Each extension that exposes a `contractSpace` must publish a
325
+ // `headRef.hash` that matches the canonical hash recomputed from its
326
+ // `contractJson`. A stale value would silently corrupt every downstream
327
+ // boundary that trusts `headRef.hash` as the canonical identity (drift
328
+ // detection, on-disk artefact emission, runner marker writes). Failing
329
+ // fast at descriptor-load time turns "extension author shipped an
330
+ // inconsistent descriptor" into an explicit, actionable error
331
+ // (`MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH`) rather than a confusing
332
+ // mismatch surfacing several layers downstream.
333
+ for (const extension of extensions) {
334
+ if (extension.contractSpace) {
335
+ const { contractJson, headRef } = extension.contractSpace;
336
+ assertDescriptorSelfConsistency({
337
+ extensionId: extension.id,
338
+ target: contractJson.target,
339
+ targetFamily: contractJson.targetFamily,
340
+ storage: contractJson.storage,
341
+ headRefHash: headRef.hash,
342
+ });
343
+ }
344
+ }
345
+
304
346
  const { codecTypeImports, operationTypeImports, extensionIds } = stack;
305
347
 
306
348
  const typeMetadataRegistry = buildSqlTypeMetadataRegistry({
@@ -317,7 +359,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
317
359
  const controlAdapter = adapter.create(stack);
318
360
  if (!isSqlControlAdapter(controlAdapter)) {
319
361
  throw new Error(
320
- 'Adapter does not implement SqlControlAdapter (missing introspect or readMarker)',
362
+ 'Adapter does not implement SqlControlAdapter (missing introspect, readMarker, or readAllMarkers)',
321
363
  );
322
364
  }
323
365
  return controlAdapter;
@@ -480,6 +522,27 @@ export function createSqlFamilyInstance<TTargetId extends string>(
480
522
  ...ifDefined('normalizeNativeType', controlAdapter.normalizeNativeType),
481
523
  });
482
524
  },
525
+ schemaVerifyAgainstSchema(options: {
526
+ readonly contract: unknown;
527
+ readonly schema: SqlSchemaIR;
528
+ readonly strict: boolean;
529
+ readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
530
+ }): VerifyDatabaseSchemaResult {
531
+ const contract = sqlValidateContract<Contract<SqlStorage>>(
532
+ options.contract,
533
+ emptyCodecLookup,
534
+ );
535
+ const controlAdapter = getControlAdapter();
536
+ return verifySqlSchema({
537
+ contract,
538
+ schema: options.schema,
539
+ strict: options.strict,
540
+ typeMetadataRegistry,
541
+ frameworkComponents: options.frameworkComponents,
542
+ ...ifDefined('normalizeDefault', controlAdapter.normalizeDefault),
543
+ ...ifDefined('normalizeNativeType', controlAdapter.normalizeNativeType),
544
+ });
545
+ },
483
546
  async sign(options: {
484
547
  readonly driver: ControlDriverInstance<'sql', string>;
485
548
  readonly contract: unknown;
@@ -583,6 +646,11 @@ export function createSqlFamilyInstance<TTargetId extends string>(
583
646
  }): Promise<ContractMarkerRecord | null> {
584
647
  return getControlAdapter().readMarker(options.driver, options.space);
585
648
  },
649
+ async readAllMarkers(options: {
650
+ readonly driver: ControlDriverInstance<'sql', string>;
651
+ }): Promise<ReadonlyMap<string, ContractMarkerRecord>> {
652
+ return getControlAdapter().readAllMarkers(options.driver);
653
+ },
586
654
  async introspect(options: {
587
655
  readonly driver: ControlDriverInstance<'sql', string>;
588
656
  readonly contract?: unknown;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Codec lifecycle hook planner — runs `onFieldEvent` for every per-field
3
+ * delta between two contracts and concatenates the returned ops in a
4
+ * deterministic order.
5
+ *
6
+ * Wired by each target's planner (`PostgresMigrationPlanner`,
7
+ * `SqliteMigrationPlanner`) so codec-emitted ops are inlined alongside
8
+ * structural DDL in the app-space migration's `ops.json`. Pure, target-
9
+ * agnostic, and only ever invoked at the app-space emitter; extension-space
10
+ * planning never reaches this helper.
11
+ *
12
+ * Ordering rules:
13
+ *
14
+ * - Events are grouped by phase: `'added'` → `'dropped'` → `'altered'`.
15
+ * - Within each phase, entries are sorted alphabetically by
16
+ * `(tableName, fieldName)`.
17
+ * - The hook's returned ops are appended in the order the hook returned them.
18
+ *
19
+ * `'altered'` is suppressed when only `codecId` differs (codec rotation is a
20
+ * v1 non-goal).
21
+ */
22
+
23
+ import type { Contract } from '@prisma-next/contract/types';
24
+ import type { SqlStorage, StorageColumn, StorageTable } from '@prisma-next/sql-contract/types';
25
+ import type {
26
+ CodecControlHooks,
27
+ FieldEvent,
28
+ FieldEventContext,
29
+ SqlMigrationPlanOperation,
30
+ } from './types';
31
+
32
+ export interface PlanFieldEventOperationsOptions {
33
+ /**
34
+ * Prior contract the planner is diffing against. `null` for first emits
35
+ * (every field is treated as added).
36
+ */
37
+ readonly priorContract: Contract<SqlStorage> | null;
38
+ /**
39
+ * New contract the user just authored.
40
+ */
41
+ readonly newContract: Contract<SqlStorage>;
42
+ /**
43
+ * Codec-id keyed map of control hooks, as produced by
44
+ * {@link import('./assembly').extractCodecControlHooks}. Hooks carry
45
+ * `unknown` target details after extraction; the caller casts the
46
+ * helper's returned ops to its target's `SqlMigrationPlanOperation`
47
+ * specialisation at the integration boundary, mirroring how
48
+ * `storageTypePlanCallStrategy` lifts `planTypeOperations` results into
49
+ * `RawSqlCall`.
50
+ */
51
+ readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;
52
+ }
53
+
54
+ interface FieldEntry {
55
+ readonly tableName: string;
56
+ readonly fieldName: string;
57
+ readonly priorTable: StorageTable | undefined;
58
+ readonly newTable: StorageTable | undefined;
59
+ readonly priorField: StorageColumn | undefined;
60
+ readonly newField: StorageColumn | undefined;
61
+ }
62
+
63
+ export function planFieldEventOperations(
64
+ options: PlanFieldEventOperationsOptions,
65
+ ): readonly SqlMigrationPlanOperation<unknown>[] {
66
+ const priorTables = options.priorContract?.storage.tables ?? {};
67
+ const newTables = options.newContract.storage.tables;
68
+
69
+ const added: FieldEntry[] = [];
70
+ const dropped: FieldEntry[] = [];
71
+ const altered: FieldEntry[] = [];
72
+
73
+ const tableNames = unionSorted(Object.keys(priorTables), Object.keys(newTables));
74
+ for (const tableName of tableNames) {
75
+ const priorTable = priorTables[tableName];
76
+ const newTable = newTables[tableName];
77
+ const fieldNames = unionSorted(
78
+ priorTable ? Object.keys(priorTable.columns) : [],
79
+ newTable ? Object.keys(newTable.columns) : [],
80
+ );
81
+ for (const fieldName of fieldNames) {
82
+ const priorField = priorTable?.columns[fieldName];
83
+ const newField = newTable?.columns[fieldName];
84
+ const entry: FieldEntry = {
85
+ tableName,
86
+ fieldName,
87
+ priorTable,
88
+ newTable,
89
+ priorField,
90
+ newField,
91
+ };
92
+ if (priorField === undefined && newField !== undefined) {
93
+ added.push(entry);
94
+ } else if (priorField !== undefined && newField === undefined) {
95
+ dropped.push(entry);
96
+ } else if (priorField !== undefined && newField !== undefined) {
97
+ if (isAlteration(priorField, newField)) altered.push(entry);
98
+ }
99
+ }
100
+ }
101
+
102
+ const ops: SqlMigrationPlanOperation<unknown>[] = [];
103
+ appendOps('added', added, options.codecHooks, ops, (e) => e.newField?.codecId);
104
+ appendOps('dropped', dropped, options.codecHooks, ops, (e) => e.priorField?.codecId);
105
+ appendOps('altered', altered, options.codecHooks, ops, (e) => e.newField?.codecId);
106
+ return ops;
107
+ }
108
+
109
+ function appendOps(
110
+ event: FieldEvent,
111
+ entries: readonly FieldEntry[],
112
+ codecHooks: ReadonlyMap<string, CodecControlHooks>,
113
+ ops: SqlMigrationPlanOperation<unknown>[],
114
+ pickCodecId: (entry: FieldEntry) => string | undefined,
115
+ ): void {
116
+ for (const entry of entries) {
117
+ const codecId = pickCodecId(entry);
118
+ if (codecId === undefined) continue;
119
+ const hook = codecHooks.get(codecId);
120
+ if (!hook?.onFieldEvent) continue;
121
+ const ctx = buildContext(event, entry);
122
+ const emitted = hook.onFieldEvent(event, ctx);
123
+ for (const op of emitted) ops.push(op);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * The context's prior/new sides are scoped to the event:
129
+ *
130
+ * - `'added'` — only `newTable` / `newField` populated.
131
+ * - `'dropped'` — only `priorTable` / `priorField` populated.
132
+ * - `'altered'` — both sides populated.
133
+ */
134
+ function buildContext(event: FieldEvent, entry: FieldEntry): FieldEventContext {
135
+ const base = { tableName: entry.tableName, fieldName: entry.fieldName };
136
+ if (event === 'added') {
137
+ return {
138
+ ...base,
139
+ ...(entry.newTable !== undefined ? { newTable: entry.newTable } : {}),
140
+ ...(entry.newField !== undefined ? { newField: entry.newField } : {}),
141
+ };
142
+ }
143
+ if (event === 'dropped') {
144
+ return {
145
+ ...base,
146
+ ...(entry.priorTable !== undefined ? { priorTable: entry.priorTable } : {}),
147
+ ...(entry.priorField !== undefined ? { priorField: entry.priorField } : {}),
148
+ };
149
+ }
150
+ return {
151
+ ...base,
152
+ ...(entry.priorTable !== undefined ? { priorTable: entry.priorTable } : {}),
153
+ ...(entry.newTable !== undefined ? { newTable: entry.newTable } : {}),
154
+ ...(entry.priorField !== undefined ? { priorField: entry.priorField } : {}),
155
+ ...(entry.newField !== undefined ? { newField: entry.newField } : {}),
156
+ };
157
+ }
158
+
159
+ /**
160
+ * `'altered'` predicate. Returns `false` whenever `codecId` differs —
161
+ * any codec change suppresses the `altered` event entirely, including
162
+ * cases where another property also differs in the same diff. Codec
163
+ * rotation is a v1 non-goal (project spec § Non-goals); avoiding the
164
+ * mixed event keeps the migration semantics for codec changes explicit
165
+ * (out of scope) rather than smuggling them through as `altered`.
166
+ *
167
+ * For non-`codecId` diffs, returns `true` iff any other column property
168
+ * differs.
169
+ */
170
+ function isAlteration(prior: StorageColumn, current: StorageColumn): boolean {
171
+ if (prior.codecId !== current.codecId) return false;
172
+ return !sameStorageColumn(prior, current);
173
+ }
174
+
175
+ function sameStorageColumn(a: StorageColumn, b: StorageColumn): boolean {
176
+ if (a === b) return true;
177
+ if (a.nativeType !== b.nativeType) return false;
178
+ if (a.nullable !== b.nullable) return false;
179
+ if (a.typeRef !== b.typeRef) return false;
180
+ if (!sameJson(a.typeParams, b.typeParams)) return false;
181
+ if (!sameJson(a.default, b.default)) return false;
182
+ return true;
183
+ }
184
+
185
+ function sameJson(a: unknown, b: unknown): boolean {
186
+ if (a === b) return true;
187
+ if (a === undefined || b === undefined) return false;
188
+ return JSON.stringify(a) === JSON.stringify(b);
189
+ }
190
+
191
+ function unionSorted(a: readonly string[], b: readonly string[]): readonly string[] {
192
+ const set = new Set<string>();
193
+ for (const name of a) set.add(name);
194
+ for (const name of b) set.add(name);
195
+ return [...set].sort((x, y) => (x < y ? -1 : x > y ? 1 : 0));
196
+ }
@@ -18,7 +18,12 @@ import type {
18
18
  OperationContext,
19
19
  SchemaIssue,
20
20
  } from '@prisma-next/framework-components/control';
21
- import type { SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
21
+ import type {
22
+ SqlStorage,
23
+ StorageColumn,
24
+ StorageTable,
25
+ StorageTypeInstance,
26
+ } from '@prisma-next/sql-contract/types';
22
27
  import type { SqlOperationDescriptor } from '@prisma-next/sql-operations';
23
28
  import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
24
29
  import type { Result } from '@prisma-next/utils/result';
@@ -83,6 +88,41 @@ export interface ResolveIdentityValueInput {
83
88
  readonly typeParams?: Record<string, unknown>;
84
89
  }
85
90
 
91
+ /**
92
+ * Per-field lifecycle event a codec hook can react to.
93
+ *
94
+ * Fired during app-space migration emission as the SQL family diffs the
95
+ * prior contract against the new contract.
96
+ *
97
+ * - `'added'` — the field is present in the new contract but not the prior.
98
+ * - `'dropped'` — the field is present in the prior contract but not the new.
99
+ * - `'altered'` — the field is present in both and any property other than
100
+ * `codecId` differs. Codec-id changes are a v1 non-goal:
101
+ * when only `codecId` differs, no `'altered'` event fires.
102
+ */
103
+ export type FieldEvent = 'added' | 'dropped' | 'altered';
104
+
105
+ /**
106
+ * Context passed to {@link CodecControlHooks.onFieldEvent}.
107
+ *
108
+ * `tableName` and `fieldName` are always populated; `priorTable` /
109
+ * `priorField` carry the prior contract's view of the table and column
110
+ * (present for `'dropped'` and `'altered'`); `newTable` / `newField`
111
+ * carry the new contract's view (present for `'added'` and `'altered'`).
112
+ *
113
+ * The hook only ever receives app-space contract IR — extension-space
114
+ * fields are scoped out by the API: the hook is wired at the
115
+ * application emitter only.
116
+ */
117
+ export interface FieldEventContext {
118
+ readonly tableName: string;
119
+ readonly fieldName: string;
120
+ readonly priorTable?: StorageTable;
121
+ readonly newTable?: StorageTable;
122
+ readonly priorField?: StorageColumn;
123
+ readonly newField?: StorageColumn;
124
+ }
125
+
86
126
  export interface CodecControlHooks<TTargetDetails = unknown> {
87
127
  planTypeOperations?: (options: {
88
128
  readonly typeName: string;
@@ -123,6 +163,21 @@ export interface CodecControlHooks<TTargetDetails = unknown> {
123
163
  * - undefined: no opinion; planner may use built-in fallbacks
124
164
  */
125
165
  resolveIdentityValue?: (input: ResolveIdentityValueInput) => string | null | undefined;
166
+ /**
167
+ * Reacts to per-field added / dropped / altered events as the app-space
168
+ * emitter diffs the prior contract against the new contract. Returned
169
+ * ops are inlined into the app-space migration's `ops.json` alongside
170
+ * the user's structural ops.
171
+ *
172
+ * Synchronous. Each returned op must carry its own `invariantId`. Hooks
173
+ * are dispatched per `(table, field)` based on the field's `codecId`
174
+ * (the new field's codec for `'added'` / `'altered'`; the prior field's
175
+ * codec for `'dropped'`).
176
+ */
177
+ onFieldEvent?: (
178
+ event: FieldEvent,
179
+ ctx: FieldEventContext,
180
+ ) => readonly SqlMigrationPlanOperation<TTargetDetails>[];
126
181
  }
127
182
 
128
183
  export interface SqlControlExtensionDescriptor<TTargetId extends string>
@@ -320,6 +375,14 @@ export interface SqlMigrationRunnerExecuteCallbacks<TTargetDetails> {
320
375
  export interface SqlMigrationRunnerExecuteOptions<TTargetDetails> {
321
376
  readonly plan: SqlMigrationPlan<TTargetDetails>;
322
377
  readonly driver: ControlDriverInstance<'sql', string>;
378
+ /**
379
+ * Logical contract space this plan applies to. When omitted the
380
+ * runner derives the space from {@link SqlMigrationPlan.spaceId};
381
+ * when supplied, the runner asserts it matches `plan.spaceId` so a
382
+ * caller cannot accidentally write the marker row for a different
383
+ * space than the plan was produced for.
384
+ */
385
+ readonly space?: string;
323
386
  /**
324
387
  * Destination contract IR.
325
388
  * Must correspond to `plan.destination` and is used for schema verification and marker/ledger writes.
@@ -371,11 +434,64 @@ export type SqlMigrationRunnerResult = Result<
371
434
  >;
372
435
 
373
436
  export interface SqlMigrationRunner<TTargetDetails> {
437
+ /**
438
+ * Apply a single migration plan, opening and managing its own
439
+ * transaction (and any target-specific connection-level setup, e.g.
440
+ * SQLite's `PRAGMA foreign_keys` toggle). Existing single-space
441
+ * callers route through here.
442
+ */
374
443
  execute(
375
444
  options: SqlMigrationRunnerExecuteOptions<TTargetDetails>,
376
445
  ): Promise<SqlMigrationRunnerResult>;
446
+
447
+ /**
448
+ * Apply a single migration plan against an already-open connection
449
+ * **without** opening a transaction. The caller is responsible for
450
+ * wrapping the call (and any siblings) in `BEGIN` / `COMMIT` /
451
+ * `ROLLBACK`. Used by the per-space runner wiring to fan out across
452
+ * contract spaces inside one outer transaction so a mid-apply
453
+ * failure rolls back every space's writes.
454
+ *
455
+ * Idempotent control-table setup (`prisma_contract.*`) and marker
456
+ * writes use `options.space` to address the per-space marker row.
457
+ */
458
+ executeOnConnection(
459
+ options: SqlMigrationRunnerExecuteOptions<TTargetDetails>,
460
+ ): Promise<SqlMigrationRunnerResult>;
461
+
462
+ /**
463
+ * Apply per-space plans across multiple contract spaces inside a
464
+ * single outer transaction. The caller orders the input list
465
+ * (typically via the aggregate planner's `applyOrder`: extensions
466
+ * alphabetical, then app); the runner is responsible for opening
467
+ * / committing the outer
468
+ * transaction (and any target-specific connection-level setup such
469
+ * as the SQLite FK pragma toggle). A failure on any space rolls
470
+ * back every space's writes.
471
+ *
472
+ * Each space's `SqlMigrationRunnerExecuteOptions` must reference the
473
+ * same `driver` (the connection the outer transaction is open on).
474
+ * Per-space marker writes use `options.space` to address the row.
475
+ */
476
+ executeAcrossSpaces(options: {
477
+ readonly driver: ControlDriverInstance<'sql', string>;
478
+ readonly perSpaceOptions: ReadonlyArray<SqlMigrationRunnerExecuteOptions<TTargetDetails>>;
479
+ }): Promise<MultiSpaceRunnerResult>;
480
+ }
481
+
482
+ export interface MultiSpaceRunnerSuccessValue {
483
+ readonly perSpaceResults: ReadonlyArray<{
484
+ readonly space: string;
485
+ readonly value: SqlMigrationRunnerSuccessValue;
486
+ }>;
487
+ }
488
+
489
+ export interface MultiSpaceRunnerFailure extends SqlMigrationRunnerFailure {
490
+ readonly failingSpace: string;
377
491
  }
378
492
 
493
+ export type MultiSpaceRunnerResult = Result<MultiSpaceRunnerSuccessValue, MultiSpaceRunnerFailure>;
494
+
379
495
  export interface SqlControlTargetDescriptor<TTargetId extends string, TTargetDetails>
380
496
  extends MigratableTargetDescriptor<'sql', TTargetId, SqlControlFamilyInstance> {
381
497
  readonly queryOperations?: () => ReadonlyArray<SqlOperationDescriptor>;
@@ -24,6 +24,8 @@ export {
24
24
  contractToSchemaIR,
25
25
  detectDestructiveChanges,
26
26
  } from '../core/migrations/contract-to-schema-ir';
27
+ export type { PlanFieldEventOperationsOptions } from '../core/migrations/field-event-planner';
28
+ export { planFieldEventOperations } from '../core/migrations/field-event-planner';
27
29
  export {
28
30
  createMigrationPlan,
29
31
  plannerFailure,
@@ -38,6 +40,11 @@ export type {
38
40
  ComponentDatabaseDependency,
39
41
  CreateSqlMigrationPlanOptions,
40
42
  ExpandNativeTypeInput,
43
+ FieldEvent,
44
+ FieldEventContext,
45
+ MultiSpaceRunnerFailure,
46
+ MultiSpaceRunnerResult,
47
+ MultiSpaceRunnerSuccessValue,
41
48
  ResolveIdentityValueInput,
42
49
  SqlControlAdapterDescriptor,
43
50
  SqlControlExtensionDescriptor,
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-Ds4dJyTI.d.mts","names":[],"sources":["../src/core/control-instance.ts","../src/core/migrations/types.ts"],"mappings":"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"}