@objectstack/driver-sql 10.0.0 → 10.2.0
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/dist/index.d.mts +187 -1
- package/dist/index.d.ts +187 -1
- package/dist/index.js +387 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +382 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,115 @@
|
|
|
1
1
|
import { AutonumberToken, SchemaMode, QueryAST, DriverOptions } from '@objectstack/spec/data';
|
|
2
2
|
import { IDataDriver } from '@objectstack/spec/contracts';
|
|
3
|
+
import { SchemaDiffEntry } from '@objectstack/spec/shared';
|
|
3
4
|
import knex, { Knex } from 'knex';
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Managed-datasource schema drift (issue #2186).
|
|
8
|
+
*
|
|
9
|
+
* The driver's `initObjects` sync is *additive-only*: it creates missing
|
|
10
|
+
* tables and adds missing columns, but never alters or drops existing ones.
|
|
11
|
+
* So a non-additive metadata change (relax `required`, change a type/length,
|
|
12
|
+
* drop or rename a field) silently diverges from an existing database — the
|
|
13
|
+
* served metadata says one thing and the physical column enforces another.
|
|
14
|
+
*
|
|
15
|
+
* This module is the single source of truth for *detecting* that divergence
|
|
16
|
+
* (metadata is authoritative on a `managed` datasource) and for *categorising*
|
|
17
|
+
* each divergence by how dangerous it is to reconcile:
|
|
18
|
+
*
|
|
19
|
+
* - `safe` — loosening that cannot lose data and cannot fail:
|
|
20
|
+
* relax NOT NULL → NULL, widen a varchar. Applied
|
|
21
|
+
* automatically by dev auto-reconcile (P2).
|
|
22
|
+
* - `needs_confirm`— a change a human should eyeball but that does not
|
|
23
|
+
* destroy data (e.g. a non-narrowing type change).
|
|
24
|
+
* - `destructive` — drops or tightenings that can lose data or fail:
|
|
25
|
+
* drop an orphaned column, narrow a varchar, add a
|
|
26
|
+
* NOT NULL constraint over possibly-null data. Only
|
|
27
|
+
* applied by `os migrate apply --allow-destructive`.
|
|
28
|
+
*
|
|
29
|
+
* The detector reuses {@link SchemaDiffEntry} (the same shape the external /
|
|
30
|
+
* federated validator emits, ADR-0015 §5.2) so CLI / Studio / audit can render
|
|
31
|
+
* managed and external drift uniformly.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
type SqlDialectName = 'sqlite' | 'postgres' | 'mysql' | 'unknown';
|
|
35
|
+
type DriftCategory = 'safe' | 'needs_confirm' | 'destructive';
|
|
36
|
+
/** A reconcilable schema operation, machine-readable for the reconciler. */
|
|
37
|
+
type DriftOp = {
|
|
38
|
+
type: 'relax_not_null';
|
|
39
|
+
table: string;
|
|
40
|
+
column: string;
|
|
41
|
+
} | {
|
|
42
|
+
type: 'tighten_not_null';
|
|
43
|
+
table: string;
|
|
44
|
+
column: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: 'widen_varchar';
|
|
47
|
+
table: string;
|
|
48
|
+
column: string;
|
|
49
|
+
to: number;
|
|
50
|
+
from?: number;
|
|
51
|
+
} | {
|
|
52
|
+
type: 'narrow_varchar';
|
|
53
|
+
table: string;
|
|
54
|
+
column: string;
|
|
55
|
+
to: number;
|
|
56
|
+
from?: number;
|
|
57
|
+
} | {
|
|
58
|
+
type: 'drop_column';
|
|
59
|
+
table: string;
|
|
60
|
+
column: string;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* A managed-schema drift finding: a {@link SchemaDiffEntry} enriched with the
|
|
64
|
+
* owning table, a reconcile {@link DriftOp}, and a {@link DriftCategory}.
|
|
65
|
+
*/
|
|
66
|
+
interface ManagedDriftEntry extends SchemaDiffEntry {
|
|
67
|
+
table: string;
|
|
68
|
+
category: DriftCategory;
|
|
69
|
+
op: DriftOp;
|
|
70
|
+
/** Human one-liner with an actionable hint. */
|
|
71
|
+
message: string;
|
|
72
|
+
}
|
|
73
|
+
/** Columns the driver creates unconditionally — never metadata fields. */
|
|
74
|
+
declare const BUILTIN_COLUMNS: Set<string>;
|
|
75
|
+
/** Minimal shape of an introspected physical column (see SqlDriver.introspectColumns). */
|
|
76
|
+
interface PhysicalColumn {
|
|
77
|
+
name: string;
|
|
78
|
+
type: string;
|
|
79
|
+
nullable: boolean;
|
|
80
|
+
maxLength?: number;
|
|
81
|
+
}
|
|
82
|
+
/** Minimal shape of a metadata field definition. */
|
|
83
|
+
interface FieldDef {
|
|
84
|
+
type?: string;
|
|
85
|
+
required?: boolean;
|
|
86
|
+
multiple?: boolean;
|
|
87
|
+
maxLength?: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Does this metadata field materialise a physical column? Mirrors
|
|
91
|
+
* `SqlDriver.createColumn` exactly: `formula` is virtual (computed, no column);
|
|
92
|
+
* everything else — including `multiple` (a JSON column) — gets one.
|
|
93
|
+
*/
|
|
94
|
+
declare function fieldHasColumn(field: FieldDef): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Diff one table's metadata fields against its physical columns and return the
|
|
97
|
+
* set of *drift* findings. Metadata is authoritative.
|
|
98
|
+
*
|
|
99
|
+
* Note: a metadata field with no physical column is NOT reported — the
|
|
100
|
+
* additive sync (`ALTER TABLE ADD COLUMN`) already covers added fields, so by
|
|
101
|
+
* the time this runs every expected column exists. We only surface the
|
|
102
|
+
* non-additive divergences the additive sync can never fix.
|
|
103
|
+
*/
|
|
104
|
+
declare function diffManagedTable(args: {
|
|
105
|
+
table: string;
|
|
106
|
+
fields: Record<string, FieldDef>;
|
|
107
|
+
columns: PhysicalColumn[];
|
|
108
|
+
dialect: SqlDialectName;
|
|
109
|
+
}): ManagedDriftEntry[];
|
|
110
|
+
/** Stable de-dup / sort key for a drift entry. */
|
|
111
|
+
declare function driftKey(d: ManagedDriftEntry): string;
|
|
112
|
+
|
|
5
113
|
/**
|
|
6
114
|
* SQL Driver for ObjectStack
|
|
7
115
|
*
|
|
@@ -44,6 +152,14 @@ interface IntrospectedSchema {
|
|
|
44
152
|
*/
|
|
45
153
|
type SqlDriverConfig = Knex.Config & {
|
|
46
154
|
schemaMode?: SchemaMode;
|
|
155
|
+
/**
|
|
156
|
+
* Dev-only schema auto-reconcile (issue #2186). When `'safe'`, `initObjects`
|
|
157
|
+
* automatically applies *non-destructive* alters (relax NOT NULL, widen
|
|
158
|
+
* varchar) so an existing database self-heals after a metadata change
|
|
159
|
+
* loosens a constraint. `'off'` (default) only warns. Never applies
|
|
160
|
+
* destructive DDL, and is force-disabled when `NODE_ENV==='production'`.
|
|
161
|
+
*/
|
|
162
|
+
autoMigrate?: 'off' | 'safe';
|
|
47
163
|
};
|
|
48
164
|
/**
|
|
49
165
|
* SQL Driver for ObjectStack.
|
|
@@ -171,6 +287,7 @@ declare class SqlDriver implements IDataDriver {
|
|
|
171
287
|
*/
|
|
172
288
|
protected logger: {
|
|
173
289
|
warn: (msg: string, meta?: any) => void;
|
|
290
|
+
info?: (msg: string, meta?: any) => void;
|
|
174
291
|
};
|
|
175
292
|
/** Whether the underlying database is a SQLite variant (sqlite3 or better-sqlite3). */
|
|
176
293
|
protected get isSqlite(): boolean;
|
|
@@ -212,6 +329,20 @@ declare class SqlDriver implements IDataDriver {
|
|
|
212
329
|
* `'managed'` so existing callers are unaffected.
|
|
213
330
|
*/
|
|
214
331
|
protected readonly schemaMode: SchemaMode;
|
|
332
|
+
/**
|
|
333
|
+
* Dev-only auto-reconcile policy (issue #2186). See {@link SqlDriverConfig.autoMigrate}.
|
|
334
|
+
*/
|
|
335
|
+
protected readonly autoMigrate: 'off' | 'safe';
|
|
336
|
+
/**
|
|
337
|
+
* Metadata field defs for every table this driver manages, captured during
|
|
338
|
+
* `initObjects` (tableName → fields). The source of truth that
|
|
339
|
+
* {@link detectManagedDrift} diffs the physical schema against.
|
|
340
|
+
*/
|
|
341
|
+
protected managedObjectFields: Map<string, Record<string, any>>;
|
|
342
|
+
/** Declared indexes per managed table (tableName → indexes[]), captured in `initObjects`. Used to recreate indexes after a SQLite table rebuild. */
|
|
343
|
+
protected managedObjectIndexes: Map<string, any[]>;
|
|
344
|
+
/** De-dup set for boot-time drift warnings (keyed by {@link driftKey}). */
|
|
345
|
+
protected driftWarned: Set<string>;
|
|
215
346
|
constructor(config: SqlDriverConfig);
|
|
216
347
|
/**
|
|
217
348
|
* DDL gate (ADR-0015 §5.1). Single choke-point asserting that
|
|
@@ -376,6 +507,61 @@ declare class SqlDriver implements IDataDriver {
|
|
|
376
507
|
name: string;
|
|
377
508
|
fields?: Record<string, any>;
|
|
378
509
|
}>): Promise<void>;
|
|
510
|
+
/** Canonical dialect name for the drift differ. */
|
|
511
|
+
protected get dialectName(): SqlDialectName;
|
|
512
|
+
/** True only when running under `NODE_ENV=production` — auto-DDL is force-disabled there. */
|
|
513
|
+
protected isProductionEnv(): boolean;
|
|
514
|
+
/** Diff one table's metadata fields against its physical columns. */
|
|
515
|
+
protected detectTableDrift(tableName: string, fields: Record<string, any>): Promise<ManagedDriftEntry[]>;
|
|
516
|
+
/**
|
|
517
|
+
* Detect every managed-schema divergence between metadata and the physical
|
|
518
|
+
* database. Metadata is the source of truth. Returns one entry per drift,
|
|
519
|
+
* sorted by table then column. Used by `os migrate` (P3) and tests.
|
|
520
|
+
*
|
|
521
|
+
* @param objects optional explicit object list; defaults to whatever
|
|
522
|
+
* `initObjects` last synced (captured in {@link managedObjectFields}).
|
|
523
|
+
*/
|
|
524
|
+
detectManagedDrift(objects?: Array<{
|
|
525
|
+
name: string;
|
|
526
|
+
fields?: Record<string, any>;
|
|
527
|
+
}>): Promise<ManagedDriftEntry[]>;
|
|
528
|
+
/**
|
|
529
|
+
* Boot-time per-table drift handling (P1 + P2): detect divergence, in dev
|
|
530
|
+
* auto-reconcile the *safe* (loosening) subset when `autoMigrate==='safe'`,
|
|
531
|
+
* then WARN once per remaining divergence with an actionable hint.
|
|
532
|
+
*/
|
|
533
|
+
protected reconcileAndWarnDrift(tableName: string, fields: Record<string, any>): Promise<void>;
|
|
534
|
+
/**
|
|
535
|
+
* Apply a set of drift entries to the physical schema. Destructive entries
|
|
536
|
+
* are skipped unless `allowDestructive` is set. Postgres/MySQL alter columns
|
|
537
|
+
* in place; SQLite (which cannot alter constraints in place) rebuilds each
|
|
538
|
+
* affected table (copy → swap) applying only the requested edits.
|
|
539
|
+
*
|
|
540
|
+
* @returns the entries actually applied and those skipped (e.g. destructive
|
|
541
|
+
* without `allowDestructive`, or unsupported on the dialect).
|
|
542
|
+
*/
|
|
543
|
+
applyMigrationEntries(entries: ManagedDriftEntry[], opts?: {
|
|
544
|
+
allowDestructive?: boolean;
|
|
545
|
+
}): Promise<{
|
|
546
|
+
applied: ManagedDriftEntry[];
|
|
547
|
+
skipped: ManagedDriftEntry[];
|
|
548
|
+
}>;
|
|
549
|
+
/** Apply a single drift op in place (Postgres / MySQL). Returns false if unsupported. */
|
|
550
|
+
protected applyDriftOpInPlace(op: DriftOp): Promise<boolean>;
|
|
551
|
+
/**
|
|
552
|
+
* Rebuild a SQLite table applying a set of column edits (relax/tighten NOT
|
|
553
|
+
* NULL, drop column), preserving all other columns and their data. Follows
|
|
554
|
+
* the official SQLite procedure: create patched table → copy → drop → rename.
|
|
555
|
+
* varchar widen/narrow are no-ops on SQLite (dynamic typing) and ignored.
|
|
556
|
+
*
|
|
557
|
+
* Unique field-level constraints and declared indexes are recreated from
|
|
558
|
+
* metadata afterwards (the source of truth). DB-level foreign keys declared
|
|
559
|
+
* by `lookup` fields are not re-added (ObjectStack enforces relationships at
|
|
560
|
+
* the application layer, not via SQLite FK constraints).
|
|
561
|
+
*/
|
|
562
|
+
protected rebuildSqliteTablePatched(table: string, ents: ManagedDriftEntry[]): Promise<void>;
|
|
563
|
+
/** Map an introspected SQLite column to a knex builder for the rebuilt table. */
|
|
564
|
+
protected buildRebuiltColumn(t: Knex.CreateTableBuilder, c: IntrospectedColumn): any;
|
|
379
565
|
/**
|
|
380
566
|
* Build a deterministic index name for a declared index so repeated
|
|
381
567
|
* `initObjects` runs converge on the same identifier (and can detect an
|
|
@@ -579,4 +765,4 @@ declare const _default: {
|
|
|
579
765
|
onEnable: (context: any) => Promise<void>;
|
|
580
766
|
};
|
|
581
767
|
|
|
582
|
-
export { type IntrospectedColumn, type IntrospectedForeignKey, type IntrospectedSchema, type IntrospectedTable, SqlDriver, type SqlDriverConfig, _default as default };
|
|
768
|
+
export { BUILTIN_COLUMNS, type DriftCategory, type FieldDef as DriftFieldDef, type DriftOp, type IntrospectedColumn, type IntrospectedForeignKey, type IntrospectedSchema, type IntrospectedTable, type ManagedDriftEntry, type PhysicalColumn, type SqlDialectName, SqlDriver, type SqlDriverConfig, _default as default, diffManagedTable, driftKey, fieldHasColumn };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,115 @@
|
|
|
1
1
|
import { AutonumberToken, SchemaMode, QueryAST, DriverOptions } from '@objectstack/spec/data';
|
|
2
2
|
import { IDataDriver } from '@objectstack/spec/contracts';
|
|
3
|
+
import { SchemaDiffEntry } from '@objectstack/spec/shared';
|
|
3
4
|
import knex, { Knex } from 'knex';
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Managed-datasource schema drift (issue #2186).
|
|
8
|
+
*
|
|
9
|
+
* The driver's `initObjects` sync is *additive-only*: it creates missing
|
|
10
|
+
* tables and adds missing columns, but never alters or drops existing ones.
|
|
11
|
+
* So a non-additive metadata change (relax `required`, change a type/length,
|
|
12
|
+
* drop or rename a field) silently diverges from an existing database — the
|
|
13
|
+
* served metadata says one thing and the physical column enforces another.
|
|
14
|
+
*
|
|
15
|
+
* This module is the single source of truth for *detecting* that divergence
|
|
16
|
+
* (metadata is authoritative on a `managed` datasource) and for *categorising*
|
|
17
|
+
* each divergence by how dangerous it is to reconcile:
|
|
18
|
+
*
|
|
19
|
+
* - `safe` — loosening that cannot lose data and cannot fail:
|
|
20
|
+
* relax NOT NULL → NULL, widen a varchar. Applied
|
|
21
|
+
* automatically by dev auto-reconcile (P2).
|
|
22
|
+
* - `needs_confirm`— a change a human should eyeball but that does not
|
|
23
|
+
* destroy data (e.g. a non-narrowing type change).
|
|
24
|
+
* - `destructive` — drops or tightenings that can lose data or fail:
|
|
25
|
+
* drop an orphaned column, narrow a varchar, add a
|
|
26
|
+
* NOT NULL constraint over possibly-null data. Only
|
|
27
|
+
* applied by `os migrate apply --allow-destructive`.
|
|
28
|
+
*
|
|
29
|
+
* The detector reuses {@link SchemaDiffEntry} (the same shape the external /
|
|
30
|
+
* federated validator emits, ADR-0015 §5.2) so CLI / Studio / audit can render
|
|
31
|
+
* managed and external drift uniformly.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
type SqlDialectName = 'sqlite' | 'postgres' | 'mysql' | 'unknown';
|
|
35
|
+
type DriftCategory = 'safe' | 'needs_confirm' | 'destructive';
|
|
36
|
+
/** A reconcilable schema operation, machine-readable for the reconciler. */
|
|
37
|
+
type DriftOp = {
|
|
38
|
+
type: 'relax_not_null';
|
|
39
|
+
table: string;
|
|
40
|
+
column: string;
|
|
41
|
+
} | {
|
|
42
|
+
type: 'tighten_not_null';
|
|
43
|
+
table: string;
|
|
44
|
+
column: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: 'widen_varchar';
|
|
47
|
+
table: string;
|
|
48
|
+
column: string;
|
|
49
|
+
to: number;
|
|
50
|
+
from?: number;
|
|
51
|
+
} | {
|
|
52
|
+
type: 'narrow_varchar';
|
|
53
|
+
table: string;
|
|
54
|
+
column: string;
|
|
55
|
+
to: number;
|
|
56
|
+
from?: number;
|
|
57
|
+
} | {
|
|
58
|
+
type: 'drop_column';
|
|
59
|
+
table: string;
|
|
60
|
+
column: string;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* A managed-schema drift finding: a {@link SchemaDiffEntry} enriched with the
|
|
64
|
+
* owning table, a reconcile {@link DriftOp}, and a {@link DriftCategory}.
|
|
65
|
+
*/
|
|
66
|
+
interface ManagedDriftEntry extends SchemaDiffEntry {
|
|
67
|
+
table: string;
|
|
68
|
+
category: DriftCategory;
|
|
69
|
+
op: DriftOp;
|
|
70
|
+
/** Human one-liner with an actionable hint. */
|
|
71
|
+
message: string;
|
|
72
|
+
}
|
|
73
|
+
/** Columns the driver creates unconditionally — never metadata fields. */
|
|
74
|
+
declare const BUILTIN_COLUMNS: Set<string>;
|
|
75
|
+
/** Minimal shape of an introspected physical column (see SqlDriver.introspectColumns). */
|
|
76
|
+
interface PhysicalColumn {
|
|
77
|
+
name: string;
|
|
78
|
+
type: string;
|
|
79
|
+
nullable: boolean;
|
|
80
|
+
maxLength?: number;
|
|
81
|
+
}
|
|
82
|
+
/** Minimal shape of a metadata field definition. */
|
|
83
|
+
interface FieldDef {
|
|
84
|
+
type?: string;
|
|
85
|
+
required?: boolean;
|
|
86
|
+
multiple?: boolean;
|
|
87
|
+
maxLength?: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Does this metadata field materialise a physical column? Mirrors
|
|
91
|
+
* `SqlDriver.createColumn` exactly: `formula` is virtual (computed, no column);
|
|
92
|
+
* everything else — including `multiple` (a JSON column) — gets one.
|
|
93
|
+
*/
|
|
94
|
+
declare function fieldHasColumn(field: FieldDef): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Diff one table's metadata fields against its physical columns and return the
|
|
97
|
+
* set of *drift* findings. Metadata is authoritative.
|
|
98
|
+
*
|
|
99
|
+
* Note: a metadata field with no physical column is NOT reported — the
|
|
100
|
+
* additive sync (`ALTER TABLE ADD COLUMN`) already covers added fields, so by
|
|
101
|
+
* the time this runs every expected column exists. We only surface the
|
|
102
|
+
* non-additive divergences the additive sync can never fix.
|
|
103
|
+
*/
|
|
104
|
+
declare function diffManagedTable(args: {
|
|
105
|
+
table: string;
|
|
106
|
+
fields: Record<string, FieldDef>;
|
|
107
|
+
columns: PhysicalColumn[];
|
|
108
|
+
dialect: SqlDialectName;
|
|
109
|
+
}): ManagedDriftEntry[];
|
|
110
|
+
/** Stable de-dup / sort key for a drift entry. */
|
|
111
|
+
declare function driftKey(d: ManagedDriftEntry): string;
|
|
112
|
+
|
|
5
113
|
/**
|
|
6
114
|
* SQL Driver for ObjectStack
|
|
7
115
|
*
|
|
@@ -44,6 +152,14 @@ interface IntrospectedSchema {
|
|
|
44
152
|
*/
|
|
45
153
|
type SqlDriverConfig = Knex.Config & {
|
|
46
154
|
schemaMode?: SchemaMode;
|
|
155
|
+
/**
|
|
156
|
+
* Dev-only schema auto-reconcile (issue #2186). When `'safe'`, `initObjects`
|
|
157
|
+
* automatically applies *non-destructive* alters (relax NOT NULL, widen
|
|
158
|
+
* varchar) so an existing database self-heals after a metadata change
|
|
159
|
+
* loosens a constraint. `'off'` (default) only warns. Never applies
|
|
160
|
+
* destructive DDL, and is force-disabled when `NODE_ENV==='production'`.
|
|
161
|
+
*/
|
|
162
|
+
autoMigrate?: 'off' | 'safe';
|
|
47
163
|
};
|
|
48
164
|
/**
|
|
49
165
|
* SQL Driver for ObjectStack.
|
|
@@ -171,6 +287,7 @@ declare class SqlDriver implements IDataDriver {
|
|
|
171
287
|
*/
|
|
172
288
|
protected logger: {
|
|
173
289
|
warn: (msg: string, meta?: any) => void;
|
|
290
|
+
info?: (msg: string, meta?: any) => void;
|
|
174
291
|
};
|
|
175
292
|
/** Whether the underlying database is a SQLite variant (sqlite3 or better-sqlite3). */
|
|
176
293
|
protected get isSqlite(): boolean;
|
|
@@ -212,6 +329,20 @@ declare class SqlDriver implements IDataDriver {
|
|
|
212
329
|
* `'managed'` so existing callers are unaffected.
|
|
213
330
|
*/
|
|
214
331
|
protected readonly schemaMode: SchemaMode;
|
|
332
|
+
/**
|
|
333
|
+
* Dev-only auto-reconcile policy (issue #2186). See {@link SqlDriverConfig.autoMigrate}.
|
|
334
|
+
*/
|
|
335
|
+
protected readonly autoMigrate: 'off' | 'safe';
|
|
336
|
+
/**
|
|
337
|
+
* Metadata field defs for every table this driver manages, captured during
|
|
338
|
+
* `initObjects` (tableName → fields). The source of truth that
|
|
339
|
+
* {@link detectManagedDrift} diffs the physical schema against.
|
|
340
|
+
*/
|
|
341
|
+
protected managedObjectFields: Map<string, Record<string, any>>;
|
|
342
|
+
/** Declared indexes per managed table (tableName → indexes[]), captured in `initObjects`. Used to recreate indexes after a SQLite table rebuild. */
|
|
343
|
+
protected managedObjectIndexes: Map<string, any[]>;
|
|
344
|
+
/** De-dup set for boot-time drift warnings (keyed by {@link driftKey}). */
|
|
345
|
+
protected driftWarned: Set<string>;
|
|
215
346
|
constructor(config: SqlDriverConfig);
|
|
216
347
|
/**
|
|
217
348
|
* DDL gate (ADR-0015 §5.1). Single choke-point asserting that
|
|
@@ -376,6 +507,61 @@ declare class SqlDriver implements IDataDriver {
|
|
|
376
507
|
name: string;
|
|
377
508
|
fields?: Record<string, any>;
|
|
378
509
|
}>): Promise<void>;
|
|
510
|
+
/** Canonical dialect name for the drift differ. */
|
|
511
|
+
protected get dialectName(): SqlDialectName;
|
|
512
|
+
/** True only when running under `NODE_ENV=production` — auto-DDL is force-disabled there. */
|
|
513
|
+
protected isProductionEnv(): boolean;
|
|
514
|
+
/** Diff one table's metadata fields against its physical columns. */
|
|
515
|
+
protected detectTableDrift(tableName: string, fields: Record<string, any>): Promise<ManagedDriftEntry[]>;
|
|
516
|
+
/**
|
|
517
|
+
* Detect every managed-schema divergence between metadata and the physical
|
|
518
|
+
* database. Metadata is the source of truth. Returns one entry per drift,
|
|
519
|
+
* sorted by table then column. Used by `os migrate` (P3) and tests.
|
|
520
|
+
*
|
|
521
|
+
* @param objects optional explicit object list; defaults to whatever
|
|
522
|
+
* `initObjects` last synced (captured in {@link managedObjectFields}).
|
|
523
|
+
*/
|
|
524
|
+
detectManagedDrift(objects?: Array<{
|
|
525
|
+
name: string;
|
|
526
|
+
fields?: Record<string, any>;
|
|
527
|
+
}>): Promise<ManagedDriftEntry[]>;
|
|
528
|
+
/**
|
|
529
|
+
* Boot-time per-table drift handling (P1 + P2): detect divergence, in dev
|
|
530
|
+
* auto-reconcile the *safe* (loosening) subset when `autoMigrate==='safe'`,
|
|
531
|
+
* then WARN once per remaining divergence with an actionable hint.
|
|
532
|
+
*/
|
|
533
|
+
protected reconcileAndWarnDrift(tableName: string, fields: Record<string, any>): Promise<void>;
|
|
534
|
+
/**
|
|
535
|
+
* Apply a set of drift entries to the physical schema. Destructive entries
|
|
536
|
+
* are skipped unless `allowDestructive` is set. Postgres/MySQL alter columns
|
|
537
|
+
* in place; SQLite (which cannot alter constraints in place) rebuilds each
|
|
538
|
+
* affected table (copy → swap) applying only the requested edits.
|
|
539
|
+
*
|
|
540
|
+
* @returns the entries actually applied and those skipped (e.g. destructive
|
|
541
|
+
* without `allowDestructive`, or unsupported on the dialect).
|
|
542
|
+
*/
|
|
543
|
+
applyMigrationEntries(entries: ManagedDriftEntry[], opts?: {
|
|
544
|
+
allowDestructive?: boolean;
|
|
545
|
+
}): Promise<{
|
|
546
|
+
applied: ManagedDriftEntry[];
|
|
547
|
+
skipped: ManagedDriftEntry[];
|
|
548
|
+
}>;
|
|
549
|
+
/** Apply a single drift op in place (Postgres / MySQL). Returns false if unsupported. */
|
|
550
|
+
protected applyDriftOpInPlace(op: DriftOp): Promise<boolean>;
|
|
551
|
+
/**
|
|
552
|
+
* Rebuild a SQLite table applying a set of column edits (relax/tighten NOT
|
|
553
|
+
* NULL, drop column), preserving all other columns and their data. Follows
|
|
554
|
+
* the official SQLite procedure: create patched table → copy → drop → rename.
|
|
555
|
+
* varchar widen/narrow are no-ops on SQLite (dynamic typing) and ignored.
|
|
556
|
+
*
|
|
557
|
+
* Unique field-level constraints and declared indexes are recreated from
|
|
558
|
+
* metadata afterwards (the source of truth). DB-level foreign keys declared
|
|
559
|
+
* by `lookup` fields are not re-added (ObjectStack enforces relationships at
|
|
560
|
+
* the application layer, not via SQLite FK constraints).
|
|
561
|
+
*/
|
|
562
|
+
protected rebuildSqliteTablePatched(table: string, ents: ManagedDriftEntry[]): Promise<void>;
|
|
563
|
+
/** Map an introspected SQLite column to a knex builder for the rebuilt table. */
|
|
564
|
+
protected buildRebuiltColumn(t: Knex.CreateTableBuilder, c: IntrospectedColumn): any;
|
|
379
565
|
/**
|
|
380
566
|
* Build a deterministic index name for a declared index so repeated
|
|
381
567
|
* `initObjects` runs converge on the same identifier (and can detect an
|
|
@@ -579,4 +765,4 @@ declare const _default: {
|
|
|
579
765
|
onEnable: (context: any) => Promise<void>;
|
|
580
766
|
};
|
|
581
767
|
|
|
582
|
-
export { type IntrospectedColumn, type IntrospectedForeignKey, type IntrospectedSchema, type IntrospectedTable, SqlDriver, type SqlDriverConfig, _default as default };
|
|
768
|
+
export { BUILTIN_COLUMNS, type DriftCategory, type FieldDef as DriftFieldDef, type DriftOp, type IntrospectedColumn, type IntrospectedForeignKey, type IntrospectedSchema, type IntrospectedTable, type ManagedDriftEntry, type PhysicalColumn, type SqlDialectName, SqlDriver, type SqlDriverConfig, _default as default, diffManagedTable, driftKey, fieldHasColumn };
|