@metaobjectsdev/migrate-ts 0.15.21-rc.1 → 0.16.0-rc.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/dist/diff/index.d.ts.map +1 -1
- package/dist/diff/index.js +141 -16
- package/dist/diff/index.js.map +1 -1
- package/dist/diff/status.js +28 -2
- package/dist/diff/status.js.map +1 -1
- package/dist/drift/drift.d.ts +2 -2
- package/dist/drift/drift.d.ts.map +1 -1
- package/dist/emit/postgres.d.ts.map +1 -1
- package/dist/emit/postgres.js +94 -4
- package/dist/emit/postgres.js.map +1 -1
- package/dist/expected-schema.d.ts +19 -2
- package/dist/expected-schema.d.ts.map +1 -1
- package/dist/expected-schema.js +26 -2
- package/dist/expected-schema.js.map +1 -1
- package/dist/introspect/postgres.d.ts +15 -1
- package/dist/introspect/postgres.d.ts.map +1 -1
- package/dist/introspect/postgres.js +132 -11
- package/dist/introspect/postgres.js.map +1 -1
- package/dist/snapshot/plan.d.ts +4 -3
- package/dist/snapshot/plan.d.ts.map +1 -1
- package/dist/snapshot/plan.js.map +1 -1
- package/dist/snapshot/serialize.d.ts +15 -1
- package/dist/snapshot/serialize.d.ts.map +1 -1
- package/dist/snapshot/serialize.js +15 -1
- package/dist/snapshot/serialize.js.map +1 -1
- package/dist/types.d.ts +95 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/view-column-types.d.ts +40 -0
- package/dist/view-column-types.d.ts.map +1 -0
- package/dist/view-column-types.js +100 -0
- package/dist/view-column-types.js.map +1 -0
- package/dist/view-fingerprint.d.ts +40 -0
- package/dist/view-fingerprint.d.ts.map +1 -0
- package/dist/view-fingerprint.js +88 -0
- package/dist/view-fingerprint.js.map +1 -0
- package/dist/view-sql-compare.d.ts.map +1 -1
- package/dist/view-sql-compare.js +24 -19
- package/dist/view-sql-compare.js.map +1 -1
- package/package.json +2 -2
- package/src/diff/index.ts +151 -19
- package/src/diff/status.ts +29 -2
- package/src/drift/drift.ts +2 -2
- package/src/emit/postgres.ts +102 -4
- package/src/expected-schema.ts +44 -3
- package/src/introspect/postgres.ts +148 -10
- package/src/snapshot/plan.ts +4 -3
- package/src/snapshot/serialize.ts +15 -1
- package/src/types.ts +109 -9
- package/src/view-column-types.ts +110 -0
- package/src/view-fingerprint.ts +97 -0
- package/src/view-sql-compare.ts +24 -19
|
@@ -2,8 +2,22 @@
|
|
|
2
2
|
* On-disk format version for the committed schema snapshot. Bump when the
|
|
3
3
|
* SchemaSnapshot descriptor gains a field (a DDL-coverage feature); add the
|
|
4
4
|
* matching upgrade branch in parseSnapshot at the same time.
|
|
5
|
+
*
|
|
6
|
+
* v3 — ViewDescriptor gained `fingerprint`, `columns` and `dependents`. The
|
|
7
|
+
* fingerprint is how Postgres decides whether a view is up to date (Postgres deparses
|
|
8
|
+
* view SQL, so the emitted text can never be compared against what it stores). A
|
|
9
|
+
* toolchain that does not understand these fields would silently fall back to the old
|
|
10
|
+
* text comparison and re-propose every view on every migrate — so a v3 snapshot must
|
|
11
|
+
* hard-fail on an older reader rather than be quietly misread. Reading an OLDER (v2)
|
|
12
|
+
* snapshot stays fine: the missing fields read as `undefined`, which every consumer
|
|
13
|
+
* treats as "unknown" and fails safe on.
|
|
14
|
+
*
|
|
15
|
+
* NOTE for anyone touching canonicalize(): a view's `columns` array is ORDER-SENSITIVE.
|
|
16
|
+
* Postgres allows a non-destructive CREATE OR REPLACE only when the old column list is
|
|
17
|
+
* a PREFIX of the new one, so sorting that array would destroy the very information the
|
|
18
|
+
* decision rests on.
|
|
5
19
|
*/
|
|
6
|
-
export const SNAPSHOT_FORMAT_VERSION =
|
|
20
|
+
export const SNAPSHOT_FORMAT_VERSION = 3;
|
|
7
21
|
function sortByName(arr) {
|
|
8
22
|
return [...arr].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
9
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/snapshot/serialize.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/snapshot/serialize.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -96,6 +96,25 @@ export interface FkDescriptor {
|
|
|
96
96
|
onUpdate?: FkAction;
|
|
97
97
|
}
|
|
98
98
|
export type FkAction = "cascade" | "set-null" | "restrict" | "no-action";
|
|
99
|
+
/** One output column of a view, in SELECT order. */
|
|
100
|
+
export interface ViewColumnDescriptor {
|
|
101
|
+
name: string;
|
|
102
|
+
sqlType: SqlType;
|
|
103
|
+
}
|
|
104
|
+
/** A relation that depends on a view — i.e. what a `DROP ... CASCADE` would destroy. */
|
|
105
|
+
export interface DependentRelation {
|
|
106
|
+
schema: string;
|
|
107
|
+
name: string;
|
|
108
|
+
/** 'v' = view, 'm' = materialized view. */
|
|
109
|
+
relkind: "v" | "m";
|
|
110
|
+
/**
|
|
111
|
+
* True when this dependent is a view MetaObjects manages (it carries our
|
|
112
|
+
* fingerprint). A managed dependent that the same migration recreates is
|
|
113
|
+
* harmless; an UNMANAGED one is somebody else's object and a CASCADE destroys
|
|
114
|
+
* it irrecoverably.
|
|
115
|
+
*/
|
|
116
|
+
managed: boolean;
|
|
117
|
+
}
|
|
99
118
|
export interface ViewDescriptor {
|
|
100
119
|
name: string;
|
|
101
120
|
/** Same semantics as TableDescriptor.schema. */
|
|
@@ -104,16 +123,49 @@ export interface ViewDescriptor {
|
|
|
104
123
|
* View definition SQL.
|
|
105
124
|
*
|
|
106
125
|
* On the EXPECTED side (`buildExpectedSchema` / `buildExpectedViews`) this is
|
|
107
|
-
* the view body — the SELECT clause through the FROM/WHERE/GROUP-BY tail.
|
|
126
|
+
* the view body — the SELECT clause through the FROM/WHERE/GROUP-BY tail. It is
|
|
127
|
+
* the input to `viewFingerprint()`.
|
|
128
|
+
*
|
|
129
|
+
* On the ACTUAL side (`introspect`) this is whatever the DB catalog stores.
|
|
130
|
+
* Its role is DIALECT-DEPENDENT, and this is load-bearing:
|
|
131
|
+
*
|
|
132
|
+
* - SQLite/D1 store `sqlite_master.sql` VERBATIM — the exact text we wrote —
|
|
133
|
+
* so there the body is a sound basis for comparison (`viewSqlEquals`).
|
|
108
134
|
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* body
|
|
135
|
+
* - Postgres does NOT store view SQL. It stores the parse tree, and
|
|
136
|
+
* `pg_get_viewdef()` DEPARSES it back into Postgres's own canonical style
|
|
137
|
+
* (lowercased functions, `LEFT OUTER JOIN` → `LEFT JOIN`, parenthesized FROM
|
|
138
|
+
* items and ON predicates, dropped redundant aliases). It can never equal
|
|
139
|
+
* what we emitted, so on Postgres the body is NOT used for comparison —
|
|
140
|
+
* `fingerprint` is. The deparsed body is still carried, as the RESTORE
|
|
141
|
+
* payload for a down migration (it is valid SQL that reproduces the view).
|
|
115
142
|
*/
|
|
116
143
|
sql?: string;
|
|
144
|
+
/**
|
|
145
|
+
* Content hash of the generated body — `metaobjects:v1:sha256:<hex>` — stamped
|
|
146
|
+
* into the view's `COMMENT ON VIEW` at emit time and read back at introspect
|
|
147
|
+
* time. This, not the body text, is how Postgres decides whether a view is
|
|
148
|
+
* up to date (see view-fingerprint.ts).
|
|
149
|
+
*
|
|
150
|
+
* Absent on the actual side means the view carries NO MetaObjects stamp: either
|
|
151
|
+
* it is hand-written, or it predates fingerprinting. The two are
|
|
152
|
+
* indistinguishable on Postgres, so the diff fails CLOSED and blocks pending
|
|
153
|
+
* `allow.adoptView`.
|
|
154
|
+
*/
|
|
155
|
+
fingerprint?: string;
|
|
156
|
+
/**
|
|
157
|
+
* The view's output columns, in SELECT order. Drives the replace-vs-drop
|
|
158
|
+
* decision: Postgres permits `CREATE OR REPLACE VIEW` only when the existing
|
|
159
|
+
* columns are a PREFIX of the new ones (same names, same types, same order,
|
|
160
|
+
* additions at the end only). Undefined = unknown → fail safe to drop+create.
|
|
161
|
+
*/
|
|
162
|
+
columns?: readonly ViewColumnDescriptor[];
|
|
163
|
+
/**
|
|
164
|
+
* Relations that depend on this view (transitively). Populated on the ACTUAL
|
|
165
|
+
* side by introspection. A `DROP VIEW` with dependents needs CASCADE, which
|
|
166
|
+
* destroys every one of them — including views owned by other applications.
|
|
167
|
+
*/
|
|
168
|
+
dependents?: readonly DependentRelation[];
|
|
117
169
|
/**
|
|
118
170
|
* Physical tables this view reads (base + joined tables). Populated on the
|
|
119
171
|
* EXPECTED side only (the view producer knows the join graph; introspection
|
|
@@ -244,11 +296,29 @@ export type Change = {
|
|
|
244
296
|
view: string;
|
|
245
297
|
schema?: string;
|
|
246
298
|
status: ChangeStatus;
|
|
299
|
+
/** The view as it exists in the DB — lets the down migration recreate it. */
|
|
300
|
+
restore?: ViewDescriptor;
|
|
301
|
+
/**
|
|
302
|
+
* Relations a CASCADE would destroy. EXTERNAL dependents only: a managed view
|
|
303
|
+
* this same migration recreates is filtered out (it comes back). Non-empty ⇒
|
|
304
|
+
* a plain DROP VIEW would fail at apply, and CASCADE would destroy objects we
|
|
305
|
+
* do not manage — so this is blocked pending `allow.dropViewCascade`.
|
|
306
|
+
*/
|
|
307
|
+
dependents?: readonly DependentRelation[];
|
|
247
308
|
} | {
|
|
248
309
|
kind: "replace-view";
|
|
249
310
|
view: ViewDescriptor;
|
|
250
311
|
schema?: string;
|
|
251
312
|
status: ChangeStatus;
|
|
313
|
+
/** The view as it exists in the DB — lets the down migration restore the old body. */
|
|
314
|
+
restore?: ViewDescriptor;
|
|
315
|
+
/**
|
|
316
|
+
* The DB view carries no MetaObjects fingerprint — hand-written, or created
|
|
317
|
+
* before fingerprinting existed. We cannot tell which (Postgres deparses away
|
|
318
|
+
* the text evidence), and overwriting a hand-written view destroys SQL no down
|
|
319
|
+
* migration can recover. Blocked pending `allow.adoptView`.
|
|
320
|
+
*/
|
|
321
|
+
unmanagedActual?: boolean;
|
|
252
322
|
};
|
|
253
323
|
export type ChangeKind = Change["kind"];
|
|
254
324
|
export interface ChangeStatus {
|
|
@@ -270,6 +340,24 @@ export interface AllowOptions {
|
|
|
270
340
|
* view is re-created in the same migration).
|
|
271
341
|
*/
|
|
272
342
|
dropView?: boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Gates `DROP VIEW ... CASCADE`. A view with dependents cannot be dropped plainly
|
|
345
|
+
* (Postgres refuses), and CASCADE destroys every dependent — including views and
|
|
346
|
+
* materialized views owned by OTHER applications, which this tool does not manage
|
|
347
|
+
* and cannot restore. Strictly ADDITIONAL to `dropView`: `--allow drop-view` alone
|
|
348
|
+
* never cascades, and a plain non-cascading DROP VIEW stays the emitted form
|
|
349
|
+
* whenever there are no dependents, so Postgres itself backstops a stale
|
|
350
|
+
* dependents snapshot rather than silently cascading.
|
|
351
|
+
*/
|
|
352
|
+
dropViewCascade?: boolean;
|
|
353
|
+
/**
|
|
354
|
+
* Gates overwriting an existing view that carries NO MetaObjects fingerprint —
|
|
355
|
+
* i.e. taking ownership of it. It is either hand-written or predates
|
|
356
|
+
* fingerprinting, and on Postgres those are indistinguishable. Every environment
|
|
357
|
+
* upgrading from an older toolchain needs exactly one `--allow adopt-view` run to
|
|
358
|
+
* stamp its existing views; after that they are fingerprinted and silent.
|
|
359
|
+
*/
|
|
360
|
+
adoptView?: boolean;
|
|
273
361
|
/** Existing data must satisfy NOT NULL; diff cannot verify this. */
|
|
274
362
|
nullableToNotNull?: boolean;
|
|
275
363
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAO7C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,8EAA8E;IAC9E,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAChC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC;IAC5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { TableDescriptor, ViewColumnDescriptor } from "./types.js";
|
|
2
|
+
/** The codegen-side description of a view column: physical, but untyped. */
|
|
3
|
+
export type ExpectedViewColumnInput = {
|
|
4
|
+
kind: "passthrough";
|
|
5
|
+
name: string;
|
|
6
|
+
sourceTable: string;
|
|
7
|
+
sourceColumn: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "aggregate";
|
|
10
|
+
name: string;
|
|
11
|
+
sourceTable: string;
|
|
12
|
+
sourceColumn: string;
|
|
13
|
+
agg: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Can `existing` be turned into `target` with a `CREATE OR REPLACE VIEW`?
|
|
17
|
+
*
|
|
18
|
+
* Postgres permits it only when the new query produces the same columns as the existing
|
|
19
|
+
* view — same names, same types, same order — with additions allowed at the END.
|
|
20
|
+
* Formally: `existing` must be a PREFIX of `target`.
|
|
21
|
+
* https://www.postgresql.org/docs/current/sql-createview.html
|
|
22
|
+
*
|
|
23
|
+
* Used in BOTH directions. Forward (target = expected, existing = live) it decides
|
|
24
|
+
* replace-vs-drop. Backward, in a down migration (target = the old view, existing = the
|
|
25
|
+
* one we just created), it decides the same thing — and usually says NO, because undoing
|
|
26
|
+
* an append means REMOVING a column, which OR REPLACE cannot do.
|
|
27
|
+
*
|
|
28
|
+
* Fails SAFE: unknown columns on either side → false → the caller uses drop+create.
|
|
29
|
+
* A wrong "yes" is not a failed check, it is a statement Postgres rejects at APPLY time,
|
|
30
|
+
* aborting the migration with no plan-time warning.
|
|
31
|
+
*/
|
|
32
|
+
export declare function viewReplaceIsLegal(target: readonly ViewColumnDescriptor[] | undefined, existing: readonly ViewColumnDescriptor[] | undefined): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve every view column against the expected TABLE descriptors.
|
|
35
|
+
*
|
|
36
|
+
* Returns undefined if ANY column cannot be resolved — a partial list is worse than
|
|
37
|
+
* none, because the prefix comparison would silently compare the wrong positions.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveViewColumns(inputs: readonly ExpectedViewColumnInput[] | undefined, tables: readonly TableDescriptor[]): ViewColumnDescriptor[] | undefined;
|
|
40
|
+
//# sourceMappingURL=view-column-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-column-types.d.ts","sourceRoot":"","sources":["../src/view-column-types.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAExE,4EAA4E;AAC5E,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhG;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,oBAAoB,EAAE,GAAG,SAAS,EACnD,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GAAG,SAAS,GACpD,OAAO,CAOT;AAoCD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,uBAAuB,EAAE,GAAG,SAAS,EACtD,MAAM,EAAE,SAAS,eAAe,EAAE,GACjC,oBAAoB,EAAE,GAAG,SAAS,CAiBpC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// view-column-types.ts — resolve a view's output columns to SqlTypes.
|
|
2
|
+
//
|
|
3
|
+
// Needed to decide whether a view change is non-destructively REPLACEABLE. Postgres
|
|
4
|
+
// permits `CREATE OR REPLACE VIEW` only when the existing output columns are a prefix
|
|
5
|
+
// of the new ones on (name, type, position); getting the types wrong would make the
|
|
6
|
+
// diff propose an OR REPLACE that Postgres rejects at APPLY time
|
|
7
|
+
// ("cannot change data type of view column ..."), aborting the migration mid-flight
|
|
8
|
+
// with no plan-time warning. So every resolution failure here degrades to `undefined`
|
|
9
|
+
// — "unknown" — which the diff treats as not-replaceable and routes through a gated,
|
|
10
|
+
// loud drop+create. Wrong-but-confident is the only outcome we must never produce.
|
|
11
|
+
import { sqlTypeEquals } from "./sql-type.js";
|
|
12
|
+
/**
|
|
13
|
+
* Can `existing` be turned into `target` with a `CREATE OR REPLACE VIEW`?
|
|
14
|
+
*
|
|
15
|
+
* Postgres permits it only when the new query produces the same columns as the existing
|
|
16
|
+
* view — same names, same types, same order — with additions allowed at the END.
|
|
17
|
+
* Formally: `existing` must be a PREFIX of `target`.
|
|
18
|
+
* https://www.postgresql.org/docs/current/sql-createview.html
|
|
19
|
+
*
|
|
20
|
+
* Used in BOTH directions. Forward (target = expected, existing = live) it decides
|
|
21
|
+
* replace-vs-drop. Backward, in a down migration (target = the old view, existing = the
|
|
22
|
+
* one we just created), it decides the same thing — and usually says NO, because undoing
|
|
23
|
+
* an append means REMOVING a column, which OR REPLACE cannot do.
|
|
24
|
+
*
|
|
25
|
+
* Fails SAFE: unknown columns on either side → false → the caller uses drop+create.
|
|
26
|
+
* A wrong "yes" is not a failed check, it is a statement Postgres rejects at APPLY time,
|
|
27
|
+
* aborting the migration with no plan-time warning.
|
|
28
|
+
*/
|
|
29
|
+
export function viewReplaceIsLegal(target, existing) {
|
|
30
|
+
if (target === undefined || existing === undefined)
|
|
31
|
+
return false;
|
|
32
|
+
if (existing.length > target.length)
|
|
33
|
+
return false;
|
|
34
|
+
return existing.every((ec, i) => {
|
|
35
|
+
const tc = target[i];
|
|
36
|
+
return ec.name === tc.name && sqlTypeEquals(ec.sqlType, tc.sqlType);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Postgres aggregate result types. Not the argument type — `count(int)` is bigint and
|
|
41
|
+
* `avg(int)` is numeric — so a naive "same as input" rule would mis-type the column and
|
|
42
|
+
* mis-plan the replace.
|
|
43
|
+
*
|
|
44
|
+
* https://www.postgresql.org/docs/current/functions-aggregate.html
|
|
45
|
+
*/
|
|
46
|
+
function aggregateResultType(agg, arg) {
|
|
47
|
+
switch (agg) {
|
|
48
|
+
// count() is bigint regardless of its argument — it need not even resolve.
|
|
49
|
+
case "count":
|
|
50
|
+
return { kind: "integer", bits: 64 };
|
|
51
|
+
case "min":
|
|
52
|
+
case "max":
|
|
53
|
+
return arg; // same as the argument type
|
|
54
|
+
case "sum":
|
|
55
|
+
if (arg === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
if (arg.kind === "integer") {
|
|
58
|
+
// smallint/integer → bigint; bigint → numeric (sum can overflow).
|
|
59
|
+
return arg.bits === 64 ? { kind: "numeric" } : { kind: "integer", bits: 64 };
|
|
60
|
+
}
|
|
61
|
+
// numeric → numeric, real → real, double → double.
|
|
62
|
+
if (arg.kind === "numeric" || arg.kind === "real" || arg.kind === "real4")
|
|
63
|
+
return arg;
|
|
64
|
+
return undefined;
|
|
65
|
+
case "avg":
|
|
66
|
+
if (arg === undefined)
|
|
67
|
+
return undefined;
|
|
68
|
+
if (arg.kind === "integer" || arg.kind === "numeric")
|
|
69
|
+
return { kind: "numeric" };
|
|
70
|
+
if (arg.kind === "real" || arg.kind === "real4")
|
|
71
|
+
return { kind: "real" };
|
|
72
|
+
return undefined;
|
|
73
|
+
default:
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve every view column against the expected TABLE descriptors.
|
|
79
|
+
*
|
|
80
|
+
* Returns undefined if ANY column cannot be resolved — a partial list is worse than
|
|
81
|
+
* none, because the prefix comparison would silently compare the wrong positions.
|
|
82
|
+
*/
|
|
83
|
+
export function resolveViewColumns(inputs, tables) {
|
|
84
|
+
if (inputs === undefined || inputs.length === 0)
|
|
85
|
+
return undefined;
|
|
86
|
+
const byTable = new Map(tables.map((t) => [t.name, t]));
|
|
87
|
+
const columnType = (table, column) => byTable.get(table)?.columns.find((c) => c.name === column)?.sqlType;
|
|
88
|
+
const out = [];
|
|
89
|
+
for (const input of inputs) {
|
|
90
|
+
const arg = columnType(input.sourceTable, input.sourceColumn);
|
|
91
|
+
const sqlType = input.kind === "aggregate"
|
|
92
|
+
? aggregateResultType(input.agg, arg)
|
|
93
|
+
: arg;
|
|
94
|
+
if (sqlType === undefined)
|
|
95
|
+
return undefined;
|
|
96
|
+
out.push({ name: input.name, sqlType });
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=view-column-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-column-types.js","sourceRoot":"","sources":["../src/view-column-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marker format version. Bump ONLY if the normalization rules or the marker grammar
|
|
3
|
+
* change — i.e. if the same body would hash differently. The algorithm is tagged
|
|
4
|
+
* separately (`sha256:`), so swapping algorithms does not need a version bump.
|
|
5
|
+
*/
|
|
6
|
+
export declare const FINGERPRINT_FORMAT_VERSION = 1;
|
|
7
|
+
/**
|
|
8
|
+
* Canonicalize a view body for hashing.
|
|
9
|
+
*
|
|
10
|
+
* Collapses whitespace (so reindenting the emitter does not re-stamp every deployed
|
|
11
|
+
* view) and strips an optional CREATE VIEW wrapper and trailing semicolon — and
|
|
12
|
+
* NOTHING else.
|
|
13
|
+
*
|
|
14
|
+
* Deliberately does NOT lowercase, unlike `normalizeViewSql`. That lowercasing exists
|
|
15
|
+
* only to chase Postgres's deparser, and it masks drift inside case-sensitive string
|
|
16
|
+
* literals — which `origin.aggregate @filter` predicates now carry (`status = 'Active'`
|
|
17
|
+
* and `status = 'active'` are different views). We never chase the deparser here, so
|
|
18
|
+
* there is nothing to buy and real drift to lose.
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeForFingerprint(body: string): string;
|
|
21
|
+
/** sha256 of the normalized body, lowercase hex. */
|
|
22
|
+
export declare function viewFingerprint(body: string): string;
|
|
23
|
+
/** The marker line stamped into `COMMENT ON VIEW`. */
|
|
24
|
+
export declare function renderFingerprintMarker(fingerprint: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Read a fingerprint marker out of a view's comment.
|
|
27
|
+
*
|
|
28
|
+
* Returns null when there is no marker — meaning the view carries no MetaObjects
|
|
29
|
+
* stamp and is therefore either hand-written or older than fingerprinting. Callers
|
|
30
|
+
* MUST fail closed on null: on Postgres those two cases are indistinguishable, and
|
|
31
|
+
* overwriting the first destroys hand-written SQL nothing can restore.
|
|
32
|
+
*
|
|
33
|
+
* An unknown VERSION still parses (the view is ours, stamped by a different
|
|
34
|
+
* toolchain) — the caller re-stamps it, which makes format migration self-healing.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseFingerprintMarker(comment: string | null | undefined): {
|
|
37
|
+
version: number;
|
|
38
|
+
fingerprint: string;
|
|
39
|
+
} | null;
|
|
40
|
+
//# sourceMappingURL=view-fingerprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-fingerprint.d.ts","sourceRoot":"","sources":["../src/view-fingerprint.ts"],"names":[],"mappings":"AAgCA;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAU5C;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,sDAAsD;AACtD,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACjC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKjD"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// view-fingerprint.ts — how Postgres decides whether a managed view is up to date.
|
|
2
|
+
//
|
|
3
|
+
// WHY THIS EXISTS
|
|
4
|
+
//
|
|
5
|
+
// Postgres does not store view SQL. It stores the parse tree (as the view's `_RETURN`
|
|
6
|
+
// rewrite rule), and `pg_get_viewdef()` DEPARSES that back into Postgres's own
|
|
7
|
+
// canonical style. For one of our generated projection views, live PG 16 returns:
|
|
8
|
+
//
|
|
9
|
+
// we emit : SELECT p.id AS "programId", COUNT(DISTINCT w.id) AS "weekCount"
|
|
10
|
+
// FROM programs p LEFT OUTER JOIN weeks w ON w."programId" = p.id
|
|
11
|
+
// PG says : SELECT p.id AS "programId", count(DISTINCT w.id) AS "weekCount"
|
|
12
|
+
// FROM (programs p LEFT JOIN weeks w ON ((w."programId" = p.id)))
|
|
13
|
+
//
|
|
14
|
+
// — lowercased functions, LEFT OUTER JOIN rewritten, FROM item and ON predicate
|
|
15
|
+
// parenthesized. No textual normalizer can bridge that without reimplementing the
|
|
16
|
+
// deparser, so comparing our text against PG's text ALWAYS reports a difference. That
|
|
17
|
+
// is what made `replace-view` fire on every migrate for every view, forever, and kept
|
|
18
|
+
// `verify --db` permanently red for any project with a projection.
|
|
19
|
+
//
|
|
20
|
+
// THE FIX: never compare against the deparser. Hash the body WE generate, stamp the
|
|
21
|
+
// hash into the view's COMMENT at emit time, and read the stamp back at introspect
|
|
22
|
+
// time. Both sides of the comparison then come from the same emitter, and the
|
|
23
|
+
// deparsed body is never an input.
|
|
24
|
+
//
|
|
25
|
+
// The deparsed body is still useful — it is valid SQL that reproduces the view — so it
|
|
26
|
+
// is carried as the RESTORE payload for down migrations.
|
|
27
|
+
//
|
|
28
|
+
// SQLite/D1 need none of this: `sqlite_master.sql` is the verbatim text we wrote, so
|
|
29
|
+
// the body comparator (view-sql-compare.ts) is exact there.
|
|
30
|
+
import { createHash } from "node:crypto";
|
|
31
|
+
/**
|
|
32
|
+
* Marker format version. Bump ONLY if the normalization rules or the marker grammar
|
|
33
|
+
* change — i.e. if the same body would hash differently. The algorithm is tagged
|
|
34
|
+
* separately (`sha256:`), so swapping algorithms does not need a version bump.
|
|
35
|
+
*/
|
|
36
|
+
export const FINGERPRINT_FORMAT_VERSION = 1;
|
|
37
|
+
const MARKER_PREFIX = "metaobjects";
|
|
38
|
+
/** Trailing-line marker: any human comment text may sit ABOVE it. */
|
|
39
|
+
const MARKER_RE = /(?:^|\n)metaobjects:v(\d+):sha256:([0-9a-f]{64})\s*$/;
|
|
40
|
+
const CREATE_VIEW_PREFIX = /^\s*create\s+(?:or\s+replace\s+)?(?:temp(?:orary)?\s+)?view\s+(?:if\s+not\s+exists\s+)?[^\s(]+(?:\s*\([^)]*\))?\s+as\s+/i;
|
|
41
|
+
/**
|
|
42
|
+
* Canonicalize a view body for hashing.
|
|
43
|
+
*
|
|
44
|
+
* Collapses whitespace (so reindenting the emitter does not re-stamp every deployed
|
|
45
|
+
* view) and strips an optional CREATE VIEW wrapper and trailing semicolon — and
|
|
46
|
+
* NOTHING else.
|
|
47
|
+
*
|
|
48
|
+
* Deliberately does NOT lowercase, unlike `normalizeViewSql`. That lowercasing exists
|
|
49
|
+
* only to chase Postgres's deparser, and it masks drift inside case-sensitive string
|
|
50
|
+
* literals — which `origin.aggregate @filter` predicates now carry (`status = 'Active'`
|
|
51
|
+
* and `status = 'active'` are different views). We never chase the deparser here, so
|
|
52
|
+
* there is nothing to buy and real drift to lose.
|
|
53
|
+
*/
|
|
54
|
+
export function normalizeForFingerprint(body) {
|
|
55
|
+
return body
|
|
56
|
+
.replace(CREATE_VIEW_PREFIX, "")
|
|
57
|
+
.replace(/\s+/g, " ")
|
|
58
|
+
.replace(/;\s*$/, "")
|
|
59
|
+
.trim();
|
|
60
|
+
}
|
|
61
|
+
/** sha256 of the normalized body, lowercase hex. */
|
|
62
|
+
export function viewFingerprint(body) {
|
|
63
|
+
return createHash("sha256").update(normalizeForFingerprint(body), "utf8").digest("hex");
|
|
64
|
+
}
|
|
65
|
+
/** The marker line stamped into `COMMENT ON VIEW`. */
|
|
66
|
+
export function renderFingerprintMarker(fingerprint) {
|
|
67
|
+
return `${MARKER_PREFIX}:v${FINGERPRINT_FORMAT_VERSION}:sha256:${fingerprint}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Read a fingerprint marker out of a view's comment.
|
|
71
|
+
*
|
|
72
|
+
* Returns null when there is no marker — meaning the view carries no MetaObjects
|
|
73
|
+
* stamp and is therefore either hand-written or older than fingerprinting. Callers
|
|
74
|
+
* MUST fail closed on null: on Postgres those two cases are indistinguishable, and
|
|
75
|
+
* overwriting the first destroys hand-written SQL nothing can restore.
|
|
76
|
+
*
|
|
77
|
+
* An unknown VERSION still parses (the view is ours, stamped by a different
|
|
78
|
+
* toolchain) — the caller re-stamps it, which makes format migration self-healing.
|
|
79
|
+
*/
|
|
80
|
+
export function parseFingerprintMarker(comment) {
|
|
81
|
+
if (typeof comment !== "string" || comment.length === 0)
|
|
82
|
+
return null;
|
|
83
|
+
const m = MARKER_RE.exec(comment.trim());
|
|
84
|
+
if (m === null)
|
|
85
|
+
return null;
|
|
86
|
+
return { version: parseInt(m[1], 10), fingerprint: m[2] };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=view-fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-fingerprint.js","sourceRoot":"","sources":["../src/view-fingerprint.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,EAAE;AACF,kBAAkB;AAClB,EAAE;AACF,sFAAsF;AACtF,+EAA+E;AAC/E,kFAAkF;AAClF,EAAE;AACF,+EAA+E;AAC/E,iFAAiF;AACjF,+EAA+E;AAC/E,iFAAiF;AACjF,EAAE;AACF,gFAAgF;AAChF,kFAAkF;AAClF,sFAAsF;AACtF,sFAAsF;AACtF,mEAAmE;AACnE,EAAE;AACF,oFAAoF;AACpF,mFAAmF;AACnF,8EAA8E;AAC9E,mCAAmC;AACnC,EAAE;AACF,uFAAuF;AACvF,yDAAyD;AACzD,EAAE;AACF,qFAAqF;AACrF,4DAA4D;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAE5C,MAAM,aAAa,GAAG,aAAa,CAAC;AAEpC,qEAAqE;AACrE,MAAM,SAAS,GAAG,sDAAsD,CAAC;AAEzE,MAAM,kBAAkB,GACtB,0HAA0H,CAAC;AAE7H;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,IAAI;SACR,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,uBAAuB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1F,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,uBAAuB,CAAC,WAAmB;IACzD,OAAO,GAAG,aAAa,KAAK,0BAA0B,WAAW,WAAW,EAAE,CAAC;AACjF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAkC;IAElC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrE,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC;AAC9D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-sql-compare.d.ts","sourceRoot":"","sources":["../src/view-sql-compare.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"view-sql-compare.d.ts","sourceRoot":"","sources":["../src/view-sql-compare.ts"],"names":[],"mappings":"AA+BA;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAGnF"}
|
package/dist/view-sql-compare.js
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
|
-
// view-sql-compare.ts — the
|
|
1
|
+
// view-sql-compare.ts — the SQLITE/D1 comparator for view definition SQL.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// SCOPE — read this before reusing it. This comparator is sound ONLY on engines that
|
|
4
|
+
// store view SQL VERBATIM. SQLite and D1 do: `sqlite_master.sql` hands back the exact
|
|
5
|
+
// `CREATE VIEW <name> AS <body>` text we wrote, so normalizing away whitespace and the
|
|
6
|
+
// CREATE wrapper leaves two strings that genuinely can be equal.
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// `
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
8
|
+
// It is NOT usable on Postgres, and used to be. Postgres does not store view SQL — it
|
|
9
|
+
// stores the parse tree, and `pg_get_viewdef()` DEPARSES it back in Postgres's own
|
|
10
|
+
// style (lowercased functions, `LEFT OUTER JOIN` rewritten to `LEFT JOIN`,
|
|
11
|
+
// parenthesized FROM items and ON predicates, redundant aliases dropped). The text we
|
|
12
|
+
// emitted therefore NEVER comes back, this comparator returned false every single
|
|
13
|
+
// time, and `replace-view` fired on every migrate for every view, forever — while
|
|
14
|
+
// `verify --db` stayed permanently red for any project with a projection. Postgres now
|
|
15
|
+
// compares FINGERPRINTS instead (see view-fingerprint.ts), which never consults the
|
|
16
|
+
// deparser at all. Do not point this function at Postgres again.
|
|
14
17
|
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
18
|
+
// normalizeViewSql strips a leading `CREATE [OR REPLACE] VIEW <name> AS`, collapses
|
|
19
|
+
// whitespace runs, drops a trailing `;`, and lower-cases.
|
|
20
|
+
//
|
|
21
|
+
// CAVEAT (accepted tradeoff): lower-casing can mask a difference living ONLY in a
|
|
22
|
+
// case-sensitive string literal (e.g. `WHERE status = 'Active'` vs `'active'`), which
|
|
23
|
+
// an `origin.aggregate @filter` predicate can now carry. The fingerprint path
|
|
24
|
+
// deliberately does NOT lowercase for exactly this reason; this SQLite path keeps it
|
|
25
|
+
// for backwards-compatible behavior. The name regex matches one whitespace/`(`-free
|
|
26
|
+
// token, so a quoted view name containing a space would not strip cleanly — a non-issue
|
|
27
|
+
// for generated identifiers.
|
|
23
28
|
const CREATE_VIEW_PREFIX = /^\s*create\s+(?:or\s+replace\s+)?(?:temp(?:orary)?\s+)?view\s+(?:if\s+not\s+exists\s+)?[^\s(]+(?:\s*\([^)]*\))?\s+as\s+/i;
|
|
24
29
|
/**
|
|
25
30
|
* Collapse a view definition (full `CREATE VIEW ... AS body` OR a bare body)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-sql-compare.js","sourceRoot":"","sources":["../src/view-sql-compare.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"view-sql-compare.js","sourceRoot":"","sources":["../src/view-sql-compare.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,qFAAqF;AACrF,sFAAsF;AACtF,uFAAuF;AACvF,iEAAiE;AACjE,EAAE;AACF,sFAAsF;AACtF,mFAAmF;AACnF,2EAA2E;AAC3E,sFAAsF;AACtF,kFAAkF;AAClF,kFAAkF;AAClF,uFAAuF;AACvF,oFAAoF;AACpF,iEAAiE;AACjE,EAAE;AACF,oFAAoF;AACpF,0DAA0D;AAC1D,EAAE;AACF,kFAAkF;AAClF,sFAAsF;AACtF,8EAA8E;AAC9E,qFAAqF;AACrF,oFAAoF;AACpF,wFAAwF;AACxF,6BAA6B;AAE7B,MAAM,kBAAkB,GACtB,0HAA0H,CAAC;AAE7H;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,GAAG;SACP,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,CAAqB,EAAE,CAAqB;IACxE,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACrD,OAAO,gBAAgB,CAAC,CAAC,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/migrate-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0-rc.1",
|
|
4
4
|
"description": "Schema migration tooling for MetaObjects: diff metadata vs DB and emit SQL for Postgres and SQLite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@iarna/toml": "^2.2.5",
|
|
48
|
-
"@metaobjectsdev/metadata": "0.
|
|
48
|
+
"@metaobjectsdev/metadata": "0.16.0-rc.1"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"kysely": ">=0.27.0"
|