@happyvertical/smrt-core 0.50.0 → 0.51.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/AGENTS.md +1 -0
- package/dist/index.js +2 -1
- package/dist/knowledge-graph.d.ts +95 -0
- package/dist/knowledge-graph.d.ts.map +1 -0
- package/dist/knowledge-graph.js +268 -0
- package/dist/knowledge-graph.js.map +1 -0
- package/dist/knowledge.d.ts +1 -0
- package/dist/knowledge.d.ts.map +1 -1
- package/dist/knowledge.js +57 -4
- package/dist/knowledge.js.map +1 -1
- package/dist/manifest/static-manifest.js +1 -1
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/migrations/differ.d.ts +127 -21
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +379 -84
- package/dist/migrations/differ.js.map +1 -1
- package/dist/schema/column-data-probes.d.ts +38 -0
- package/dist/schema/column-data-probes.d.ts.map +1 -0
- package/dist/schema/column-data-probes.js +106 -0
- package/dist/schema/column-data-probes.js.map +1 -0
- package/dist/schema/live-parity.d.ts.map +1 -1
- package/dist/schema/live-parity.js +37 -46
- package/dist/schema/live-parity.js.map +1 -1
- package/dist/smrt-knowledge.json +12 -7
- package/package.json +4 -4
|
@@ -156,6 +156,40 @@ export declare class SchemaComparer {
|
|
|
156
156
|
private liveSchemas;
|
|
157
157
|
/** Convergence plan for this run; `null` on non-PostgreSQL engines. */
|
|
158
158
|
private uuidConvergence;
|
|
159
|
+
/**
|
|
160
|
+
* Rename-pending advisory findings for this `compare()` run, keyed by
|
|
161
|
+
* table name (#2878). `compareTable()` reads from here when it is being
|
|
162
|
+
* driven by `compare()` over the full manifest, which lets the probe be
|
|
163
|
+
* batched *across every table in one round trip* instead of paying at
|
|
164
|
+
* least one round trip per table (#2876 batched a table's own columns
|
|
165
|
+
* into one round trip but never batched across tables — with a
|
|
166
|
+
* realistic 71-table schema that per-table floor was itself the entire
|
|
167
|
+
* residual). `null` means "not precomputed for this run" (a standalone
|
|
168
|
+
* `compareTable()` call outside `compare()`, or a non-PostgreSQL/SQLite
|
|
169
|
+
* engine), in which case `detectRenameDataPending()` falls back to the
|
|
170
|
+
* original single-table probe so standalone callers keep working
|
|
171
|
+
* unchanged. Cleared every `compare()` call, same as `liveSchemas` —
|
|
172
|
+
* this is a per-run cache, never reused across runs, so a live schema
|
|
173
|
+
* change is always seen on the next comparison (no invalidation story
|
|
174
|
+
* needed because nothing survives past one `compare()` call).
|
|
175
|
+
*/
|
|
176
|
+
private renameDataPendingCache;
|
|
177
|
+
/**
|
|
178
|
+
* Cross-table batch queries stay bounded regardless of schema shape: this
|
|
179
|
+
* caps how many scalar-subquery columns one probe statement packs into a
|
|
180
|
+
* single row. Conservative relative to PostgreSQL's ~1600 column limit
|
|
181
|
+
* per result row, and SQLite has no such ceiling but benefits from the
|
|
182
|
+
* same bound for query-text size. Applied twice (PR #2888 review): once
|
|
183
|
+
* per table, so a single pathologically wide table (more probed columns
|
|
184
|
+
* than this cap) is itself sliced across more than one statement rather
|
|
185
|
+
* than landing in one oversized chunk; and again across tables, packing
|
|
186
|
+
* every (possibly sliced) entry into as few chunks as this cap allows.
|
|
187
|
+
* A schema with no single table wider than this cap needs more than
|
|
188
|
+
* `MAX_CROSS_TABLE_PROBE_COLUMNS` probed columns *in total* before a
|
|
189
|
+
* second statement is needed at all — still O(1)-ish round trips for a
|
|
190
|
+
* realistic schema.
|
|
191
|
+
*/
|
|
192
|
+
private static readonly MAX_CROSS_TABLE_PROBE_COLUMNS;
|
|
159
193
|
constructor(db: DatabaseInterface, options?: DiffOptions);
|
|
160
194
|
/**
|
|
161
195
|
* Compare manifest schemas to database and return differences
|
|
@@ -226,6 +260,15 @@ export declare class SchemaComparer {
|
|
|
226
260
|
* that orphan gets an executable `DROP NOT NULL` where the engine allows.
|
|
227
261
|
*/
|
|
228
262
|
private compareColumns;
|
|
263
|
+
/**
|
|
264
|
+
* Detect a pending rename backfill (#2752) for one table. Reads
|
|
265
|
+
* `renameDataPendingCache` when `compare()` has already batched this
|
|
266
|
+
* table's probe across the whole manifest (#2878); otherwise falls back
|
|
267
|
+
* to {@link detectRenameDataPendingSingleTable}, so a standalone
|
|
268
|
+
* `compareTable()` call (outside `compare()`) still gets a correct
|
|
269
|
+
* answer, just without the cross-table batching.
|
|
270
|
+
*/
|
|
271
|
+
private detectRenameDataPending;
|
|
229
272
|
/**
|
|
230
273
|
* Detect a pending rename backfill (#2752): a manifest-declared column
|
|
231
274
|
* that exists live but holds no data, paired with an orphan (undeclared)
|
|
@@ -238,26 +281,89 @@ export declare class SchemaComparer {
|
|
|
238
281
|
* `DO $$ ... $$` block); SQLite has no conditional-DDL construct, so its
|
|
239
282
|
* repair is operator-mediated instead — a guard query plus instructions,
|
|
240
283
|
* not a blind-rerun-safe statement. See {@link describeRenameDataPending}.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*/
|
|
248
|
-
private
|
|
249
|
-
/**
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
|
|
260
|
-
|
|
284
|
+
*
|
|
285
|
+
* Single-table probe: at least one round trip for this table alone.
|
|
286
|
+
* `compare()` does not call this directly — see
|
|
287
|
+
* {@link precomputeRenameDataPending} for the cross-table batched path
|
|
288
|
+
* that every ordinary `compare()` run takes instead (#2878). This stays
|
|
289
|
+
* as the fallback for a standalone `compareTable()` call.
|
|
290
|
+
*/
|
|
291
|
+
private detectRenameDataPendingSingleTable;
|
|
292
|
+
/**
|
|
293
|
+
* Batch every table's rename-pending advisory probe (#2752/#2878) into a
|
|
294
|
+
* small, table-count-independent number of round trips, and populate
|
|
295
|
+
* {@link renameDataPendingCache} so `compareTable()`'s per-table
|
|
296
|
+
* `detectRenameDataPending()` call becomes a cache read for the rest of
|
|
297
|
+
* this `compare()` run.
|
|
298
|
+
*
|
|
299
|
+
* Mirrors {@link detectRenameDataPendingSingleTable}'s phases exactly —
|
|
300
|
+
* same gates, same type-compatibility rules, same per-column `LIMIT 1`
|
|
301
|
+
* early exit — just resequenced so each phase's *query* covers every
|
|
302
|
+
* table that needs it in one statement, instead of one statement per
|
|
303
|
+
* table. With a 71-table schema this is the difference between a
|
|
304
|
+
* 71-statement floor (#2878) and a handful of statements for the whole
|
|
305
|
+
* schema, independent of table count.
|
|
306
|
+
*
|
|
307
|
+
* No caching beyond this: the cache this populates is cleared at the top
|
|
308
|
+
* of every `compare()` call, so a live schema change is always visible
|
|
309
|
+
* on the next comparison.
|
|
310
|
+
*/
|
|
311
|
+
private precomputeRenameDataPending;
|
|
312
|
+
/**
|
|
313
|
+
* Cross-table variant of {@link columnsHaveNonEmptyValueBatch}: the same
|
|
314
|
+
* uncorrelated-scalar-subquery, per-column `LIMIT 1` shape, but packed
|
|
315
|
+
* into one row *per query* across every named table's columns instead of
|
|
316
|
+
* one row per table — the #2878 lever. Chunks at
|
|
317
|
+
* {@link MAX_CROSS_TABLE_PROBE_COLUMNS} columns per statement so a very
|
|
318
|
+
* large schema still issues a small, bounded number of round trips
|
|
319
|
+
* rather than one arbitrarily wide row.
|
|
320
|
+
*
|
|
321
|
+
* Falls back to the existing per-table batch (itself falling back
|
|
322
|
+
* further to per-column) for any chunk whose combined statement fails,
|
|
323
|
+
* so one bad table never discards another table's detection — the same
|
|
324
|
+
* failure-isolation guarantee {@link columnsHaveNonEmptyValueBatch}
|
|
325
|
+
* already gives per-column, extended one level up.
|
|
326
|
+
*/
|
|
327
|
+
private crossTableColumnsHaveNonEmptyValueBatch;
|
|
328
|
+
/**
|
|
329
|
+
* Cross-table variant of {@link columnsAllValuesUuidShapedBatch} — same
|
|
330
|
+
* shape as {@link crossTableColumnsHaveNonEmptyValueBatch}, engine-aware
|
|
331
|
+
* invalid-shape predicate included.
|
|
332
|
+
*/
|
|
333
|
+
private crossTableColumnsAllValuesUuidShapedBatch;
|
|
334
|
+
/**
|
|
335
|
+
* Shared cross-table batching engine for the two probes above. Builds one
|
|
336
|
+
* `SELECT` per chunk with a scalar subquery per (table, column) pair,
|
|
337
|
+
* globally aliased `t{tableIndex}_c{colIndex}` — PostgreSQL truncates a
|
|
338
|
+
* `name` identifier to 63 bytes, so a positional alias is used instead of
|
|
339
|
+
* the real column name for the same reason the single-table batch does
|
|
340
|
+
* (#2874 review finding F2'). On a chunk's query failure, that chunk's
|
|
341
|
+
* tables fall back to the single-table batch path individually (each of
|
|
342
|
+
* which falls back further to per-column) rather than discarding every
|
|
343
|
+
* table's result.
|
|
344
|
+
*
|
|
345
|
+
* Known lock-footprint change (#2878 final review F2, deferred to
|
|
346
|
+
* #2887): one chunked statement takes `ACCESS SHARE` on every
|
|
347
|
+
* table in that chunk *simultaneously*, where the pre-#2878 per-table
|
|
348
|
+
* probe held at most one table's `ACCESS SHARE` at a time (each
|
|
349
|
+
* autocommitted statement releases its lock before the next one runs).
|
|
350
|
+
* That is a materially different PostgreSQL locking pattern: it is now
|
|
351
|
+
* possible, in principle, for this session to be one side of a deadlock
|
|
352
|
+
* with a concurrent multi-table DDL transaction (e.g. a `db:migrate` in
|
|
353
|
+
* flight) in a way the old per-table probe structurally could not be.
|
|
354
|
+
* PostgreSQL's deadlock detector resolves any such cycle by aborting one
|
|
355
|
+
* side with a loud `deadlock detected` error — never silently, and never
|
|
356
|
+
* with partial/corrupt state — so if this session is the victim, the
|
|
357
|
+
* `catch` above already degrades it to the safe per-table fallback; if
|
|
358
|
+
* the *other* side (the migration) is the victim, that transaction rolls
|
|
359
|
+
* back cleanly and is safe to re-run. No test in this repository exercises
|
|
360
|
+
* concurrent DDL against the probed tables, so this risk is unverified by
|
|
361
|
+
* suite rather than disproven. Bounding it further — chunking by table
|
|
362
|
+
* count as well as column count, and/or a short `lock_timeout` on these
|
|
363
|
+
* statements so this session always yields first — is deferred to #2887
|
|
364
|
+
* rather than fixed here.
|
|
365
|
+
*/
|
|
366
|
+
private crossTableProbeBatch;
|
|
261
367
|
/**
|
|
262
368
|
* Render the repair for one rename-data-pending pair (#2752): copy
|
|
263
369
|
* non-empty `oldColumn` into `newColumn` only where `newColumn` is still
|
|
@@ -272,7 +378,7 @@ export declare class SchemaComparer {
|
|
|
272
378
|
* for `integer`/`boolean`/`timestamp`/etc. before a same-type rename
|
|
273
379
|
* pair of one of those types ever copies anything. Fixed by comparing
|
|
274
380
|
* `CAST(col AS TEXT) = ''` instead, mirroring the same portable
|
|
275
|
-
* emptiness check {@link
|
|
381
|
+
* emptiness check {@link columnsHaveNonEmptyValueBatch} already uses for
|
|
276
382
|
* detection, so the predicate is valid for every column type.
|
|
277
383
|
* - (P2) An `UPDATE` unconditionally naming `oldColumn` fails once that
|
|
278
384
|
* column is gone, on either engine, regardless of the DROP's own
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"differ.d.ts","sourceRoot":"","sources":["../../src/migrations/differ.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"differ.d.ts","sourceRoot":"","sources":["../../src/migrations/differ.ts"],"names":[],"mappings":"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"}
|