@quereus/store 4.5.0 → 4.6.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/README.md +30 -4
- package/dist/src/common/encoding.d.ts +4 -3
- package/dist/src/common/encoding.d.ts.map +1 -1
- package/dist/src/common/encoding.js +17 -13
- package/dist/src/common/encoding.js.map +1 -1
- package/dist/src/common/events.d.ts +5 -1
- package/dist/src/common/events.d.ts.map +1 -1
- package/dist/src/common/events.js.map +1 -1
- package/dist/src/common/implicit-unique-index.d.ts +80 -0
- package/dist/src/common/implicit-unique-index.d.ts.map +1 -0
- package/dist/src/common/implicit-unique-index.js +148 -0
- package/dist/src/common/implicit-unique-index.js.map +1 -0
- package/dist/src/common/index.d.ts +7 -3
- package/dist/src/common/index.d.ts.map +1 -1
- package/dist/src/common/index.js +5 -2
- package/dist/src/common/index.js.map +1 -1
- package/dist/src/common/json-key.d.ts +2 -2
- package/dist/src/common/json-key.js +2 -2
- package/dist/src/common/key-builder.d.ts +33 -14
- package/dist/src/common/key-builder.d.ts.map +1 -1
- package/dist/src/common/key-builder.js +24 -17
- package/dist/src/common/key-builder.js.map +1 -1
- package/dist/src/common/kv-store.d.ts +10 -0
- package/dist/src/common/kv-store.d.ts.map +1 -1
- package/dist/src/common/pk-key-resolution.d.ts +275 -0
- package/dist/src/common/pk-key-resolution.d.ts.map +1 -0
- package/dist/src/common/pk-key-resolution.js +389 -0
- package/dist/src/common/pk-key-resolution.js.map +1 -0
- package/dist/src/common/store-module-access-plan.d.ts +32 -0
- package/dist/src/common/store-module-access-plan.d.ts.map +1 -0
- package/dist/src/common/store-module-access-plan.js +424 -0
- package/dist/src/common/store-module-access-plan.js.map +1 -0
- package/dist/src/common/store-module-alter-column.d.ts +23 -0
- package/dist/src/common/store-module-alter-column.d.ts.map +1 -0
- package/dist/src/common/store-module-alter-column.js +393 -0
- package/dist/src/common/store-module-alter-column.js.map +1 -0
- package/dist/src/common/store-module-alter.d.ts +55 -0
- package/dist/src/common/store-module-alter.d.ts.map +1 -0
- package/dist/src/common/store-module-alter.js +519 -0
- package/dist/src/common/store-module-alter.js.map +1 -0
- package/dist/src/common/store-module-base.d.ts +268 -0
- package/dist/src/common/store-module-base.d.ts.map +1 -0
- package/dist/src/common/store-module-base.js +362 -0
- package/dist/src/common/store-module-base.js.map +1 -0
- package/dist/src/common/store-module-catalog.d.ts +269 -0
- package/dist/src/common/store-module-catalog.d.ts.map +1 -0
- package/dist/src/common/store-module-catalog.js +462 -0
- package/dist/src/common/store-module-catalog.js.map +1 -0
- package/dist/src/common/store-module-index-build.d.ts +88 -0
- package/dist/src/common/store-module-index-build.d.ts.map +1 -0
- package/dist/src/common/store-module-index-build.js +280 -0
- package/dist/src/common/store-module-index-build.js.map +1 -0
- package/dist/src/common/store-module-index.d.ts +116 -0
- package/dist/src/common/store-module-index.d.ts.map +1 -0
- package/dist/src/common/store-module-index.js +373 -0
- package/dist/src/common/store-module-index.js.map +1 -0
- package/dist/src/common/store-module-rename.d.ts +49 -0
- package/dist/src/common/store-module-rename.d.ts.map +1 -0
- package/dist/src/common/store-module-rename.js +244 -0
- package/dist/src/common/store-module-rename.js.map +1 -0
- package/dist/src/common/store-module-schema-rewrite.d.ts +57 -0
- package/dist/src/common/store-module-schema-rewrite.d.ts.map +1 -0
- package/dist/src/common/store-module-schema-rewrite.js +140 -0
- package/dist/src/common/store-module-schema-rewrite.js.map +1 -0
- package/dist/src/common/store-module-schema-sync.d.ts +232 -0
- package/dist/src/common/store-module-schema-sync.d.ts.map +1 -0
- package/dist/src/common/store-module-schema-sync.js +529 -0
- package/dist/src/common/store-module-schema-sync.js.map +1 -0
- package/dist/src/common/store-module.d.ts +43 -909
- package/dist/src/common/store-module.d.ts.map +1 -1
- package/dist/src/common/store-module.js +184 -3276
- package/dist/src/common/store-module.js.map +1 -1
- package/dist/src/common/store-table-base.d.ts +523 -0
- package/dist/src/common/store-table-base.d.ts.map +1 -0
- package/dist/src/common/store-table-base.js +878 -0
- package/dist/src/common/store-table-base.js.map +1 -0
- package/dist/src/common/store-table-constraints.d.ts +237 -0
- package/dist/src/common/store-table-constraints.d.ts.map +1 -0
- package/dist/src/common/store-table-constraints.js +624 -0
- package/dist/src/common/store-table-constraints.js.map +1 -0
- package/dist/src/common/store-table-scan.d.ts +415 -0
- package/dist/src/common/store-table-scan.d.ts.map +1 -0
- package/dist/src/common/store-table-scan.js +821 -0
- package/dist/src/common/store-table-scan.js.map +1 -0
- package/dist/src/common/store-table.d.ts +71 -1144
- package/dist/src/common/store-table.d.ts.map +1 -1
- package/dist/src/common/store-table.js +166 -2383
- package/dist/src/common/store-table.js.map +1 -1
- package/dist/src/testing/index.d.ts +12 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +12 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/kv-assert.d.ts +19 -0
- package/dist/src/testing/kv-assert.d.ts.map +1 -0
- package/dist/src/testing/kv-assert.js +25 -0
- package/dist/src/testing/kv-assert.js.map +1 -0
- package/dist/src/testing/kv-conformance.d.ts.map +1 -1
- package/dist/src/testing/kv-conformance.js +1 -15
- package/dist/src/testing/kv-conformance.js.map +1 -1
- package/dist/src/testing/kv-provider-conformance.d.ts +54 -0
- package/dist/src/testing/kv-provider-conformance.d.ts.map +1 -0
- package/dist/src/testing/kv-provider-conformance.js +183 -0
- package/dist/src/testing/kv-provider-conformance.js.map +1 -0
- package/package.json +8 -8
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone index-population and uniqueness-validation helpers: streaming a table's
|
|
3
|
+
* committed rows into a secondary index's physical store in bounded batches, and the
|
|
4
|
+
* duplicate probes that judge a UNIQUE constraint or UNIQUE index against a row stream
|
|
5
|
+
* before it is enforced.
|
|
6
|
+
*
|
|
7
|
+
* Free functions rather than a layer of the store-module chain — none of them reads
|
|
8
|
+
* module state; each takes the stores and schema it needs.
|
|
9
|
+
*/
|
|
10
|
+
import { QuereusError, StatusCode, compilePredicate, logicalTypeCanHoldText, serializeKey } from '@quereus/quereus';
|
|
11
|
+
import { resolveIndexKeyCollations, resolveDedupeKeyTransforms, resolveIndexKeyTransforms, resolvePkKeyCollations, resolvePkKeyTransforms, } from './pk-key-resolution.js';
|
|
12
|
+
import { buildDataKey, buildFullScanBounds, buildIndexKey } from './key-builder.js';
|
|
13
|
+
import { deserializeRow } from './serialization.js';
|
|
14
|
+
// NOTE: this one constant is the only thing tying this file to the module chain (the graph
|
|
15
|
+
// stays acyclic — the base layer is a leaf). If these helpers ever need to be usable without
|
|
16
|
+
// loading the chain, move `DEFAULT_MAX_BATCH_BYTES` to a constants leaf and have the base
|
|
17
|
+
// import it from there instead.
|
|
18
|
+
import { DEFAULT_MAX_BATCH_BYTES } from './store-module-base.js';
|
|
19
|
+
/**
|
|
20
|
+
* Build index entries for all existing rows in a table.
|
|
21
|
+
*
|
|
22
|
+
* `dataEntries` is the row stream to index. Callers choose its visibility:
|
|
23
|
+
* `createIndex` passes the table's EFFECTIVE stream (committed + pending, so
|
|
24
|
+
* an open transaction's rows are indexed too), while `rebuildSecondaryIndexes`
|
|
25
|
+
* passes the raw committed stream — it runs immediately after an ALTER has
|
|
26
|
+
* re-encoded the data store in place, and any pending ops still address the
|
|
27
|
+
* pre-ALTER key bytes.
|
|
28
|
+
*
|
|
29
|
+
* For UNIQUE indexes, performs an in-pass duplicate check (honoring partial
|
|
30
|
+
* predicates and SQL NULL semantics: multiple NULLs are allowed) and throws
|
|
31
|
+
* CONSTRAINT before any entries are written. Mirrors the memory module's
|
|
32
|
+
* populateNewIndex so `CREATE UNIQUE INDEX` over duplicated data fails
|
|
33
|
+
* atomically. `skipDuplicateCheck` suppresses it: `createIndex` sets it when a
|
|
34
|
+
* wrapper module supplied the rows to judge, having already validated them (see
|
|
35
|
+
* {@link validateUniqueIndexOverRows}). Judging `dataEntries` too would reject a
|
|
36
|
+
* committed duplicate the wrapper's transaction has already deleted.
|
|
37
|
+
*
|
|
38
|
+
* `normalizers` MUST be the owning connection's `db.getKeyNormalizerResolver()` —
|
|
39
|
+
* the same resolver `StoreTable.encodeOptions` carries. A rebuild that resolved
|
|
40
|
+
* collations any other way would re-encode the PK suffix under different bytes than
|
|
41
|
+
* the table writes at maintenance time, silently corrupting the index.
|
|
42
|
+
*/
|
|
43
|
+
export async function buildIndexEntries(dataEntries, indexStore, tableSchema, indexSchema, keyCollation, normalizers, skipDuplicateCheck = false, maxBatchBytes = DEFAULT_MAX_BATCH_BYTES) {
|
|
44
|
+
// Both halves key per-column: each index COLUMN under its own key collation
|
|
45
|
+
// (`resolveIndexKeyCollations` — index COLLATE ?? table column collation ?? BINARY)
|
|
46
|
+
// and the PK SUFFIX under each PK column's own key collation, so the suffix bytes
|
|
47
|
+
// match the data-store keys — and both halves match
|
|
48
|
+
// `StoreTable.updateSecondaryIndexes`' maintenance writes exactly. Those two call
|
|
49
|
+
// sites are the pair whose drift silently corrupts an index; change one and the
|
|
50
|
+
// other must change with it. `keyCollation` (the table key collation K) remains
|
|
51
|
+
// only as the `EncodeOptions` fallback for entries the resolvers leave undefined.
|
|
52
|
+
const encodeOptions = { collation: keyCollation, normalizers };
|
|
53
|
+
const pkDirections = tableSchema.primaryKeyDefinition.map(pk => !!pk.desc);
|
|
54
|
+
const pkCollations = resolvePkKeyCollations(tableSchema.primaryKeyDefinition, tableSchema.columns, keyCollation);
|
|
55
|
+
const indexCollations = resolveIndexKeyCollations(indexSchema, tableSchema.columns);
|
|
56
|
+
// Key-identity transforms for both halves, mirroring `StoreTable`'s maintenance
|
|
57
|
+
// writes (`updateSecondaryIndexes` / `encodeDataKey`) — a rebuild that skipped them
|
|
58
|
+
// would re-encode a TIMESPAN member under different bytes than DML writes.
|
|
59
|
+
const pkTransforms = resolvePkKeyTransforms(tableSchema.primaryKeyDefinition, tableSchema.columns);
|
|
60
|
+
const indexTransforms = resolveIndexKeyTransforms(indexSchema, tableSchema.columns);
|
|
61
|
+
const indexDirections = indexSchema.columns.map(col => !!col.desc);
|
|
62
|
+
const predicate = indexSchema.predicate
|
|
63
|
+
? compilePredicate(indexSchema.predicate, tableSchema.columns, tableSchema.name)
|
|
64
|
+
: undefined;
|
|
65
|
+
// NOTE: `seen` holds one signature per DISTINCT indexed key for the WHOLE build and
|
|
66
|
+
// is NOT bounded by the maxBatchBytes chunking below (that bounds only the write
|
|
67
|
+
// batch). A very large UNIQUE index still spikes memory on this set. Bounding it
|
|
68
|
+
// needs a sort- or store-probe-based dedup (a separate design), not a batch knob.
|
|
69
|
+
const seen = (indexSchema.unique && !skipDuplicateCheck) ? new Set() : undefined;
|
|
70
|
+
const indexColIndices = indexSchema.columns.map(col => col.index);
|
|
71
|
+
const indexNormalizers = seen
|
|
72
|
+
? indexDedupeNormalizers(tableSchema, indexSchema, normalizers)
|
|
73
|
+
: undefined;
|
|
74
|
+
// Deliberately NOT `indexTransforms`: the dedupe signature must reproduce
|
|
75
|
+
// `JSON_TYPE.compare`'s collation-honoring string-scalar case (which `serializeKey`'s
|
|
76
|
+
// normalizer applies), while `indexTransforms` stays the hard-structural physical key
|
|
77
|
+
// bytes `buildIndexKey` persists. See `storeDedupeKeyTransform`'s docstring.
|
|
78
|
+
const dedupeTransforms = seen
|
|
79
|
+
? resolveDedupeKeyTransforms(indexColIndices, tableSchema.columns)
|
|
80
|
+
: undefined;
|
|
81
|
+
let batch = indexStore.batch();
|
|
82
|
+
// Serialized key bytes accumulated in the CURRENT batch. Flushed and reset once it
|
|
83
|
+
// crosses maxBatchBytes so a table larger than memory never buffers its whole index.
|
|
84
|
+
let batchBytes = 0;
|
|
85
|
+
for await (const entry of dataEntries) {
|
|
86
|
+
const row = deserializeRow(entry.value);
|
|
87
|
+
// Partial index: skip rows whose predicate is not unambiguously TRUE.
|
|
88
|
+
if (predicate && predicate.evaluate(row) !== true)
|
|
89
|
+
continue;
|
|
90
|
+
// Extract PK values
|
|
91
|
+
const pkValues = tableSchema.primaryKeyDefinition.map(pk => row[pk.index]);
|
|
92
|
+
// Extract index column values
|
|
93
|
+
const indexValues = indexSchema.columns.map(col => row[col.index]);
|
|
94
|
+
if (seen) {
|
|
95
|
+
// The signature returns null when any indexed column is NULL —
|
|
96
|
+
// SQL UNIQUE allows multiple NULLs, so those rows never collide.
|
|
97
|
+
const keySig = dedupeRowSignature(row, indexColIndices, indexNormalizers, dedupeTransforms);
|
|
98
|
+
if (keySig !== null) {
|
|
99
|
+
if (seen.has(keySig)) {
|
|
100
|
+
const colNames = indexSchema.columns
|
|
101
|
+
.map(c => tableSchema.columns[c.index]?.name ?? String(c.index))
|
|
102
|
+
.join(', ');
|
|
103
|
+
throw new QuereusError(`UNIQUE constraint failed: ${tableSchema.name} (${colNames})`, StatusCode.CONSTRAINT);
|
|
104
|
+
}
|
|
105
|
+
seen.add(keySig);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Build and store index key
|
|
109
|
+
const indexKey = buildIndexKey({ values: indexValues, directions: indexDirections, collations: indexCollations, transforms: indexTransforms }, { values: pkValues, directions: pkDirections, collations: pkCollations, transforms: pkTransforms }, encodeOptions);
|
|
110
|
+
// Index value = the row's encoded DATA key, so an index scan resolves each
|
|
111
|
+
// entry back to its base row via a direct data-store read (see
|
|
112
|
+
// `StoreTable.scanIndex`). Encoded under the same PK directions + per-column
|
|
113
|
+
// PK collations + key transforms as `buildDataKey` / `updateSecondaryIndexes`,
|
|
114
|
+
// so the value byte-matches the data store's key for this row.
|
|
115
|
+
const dataKey = buildDataKey(pkValues, encodeOptions, pkDirections, pkCollations, pkTransforms);
|
|
116
|
+
batch.put(indexKey, dataKey);
|
|
117
|
+
// Bound heap: once the accumulated serialized key bytes cross the budget, flush
|
|
118
|
+
// the batch and start a fresh one. Both callers ITERATE the data store and WRITE
|
|
119
|
+
// the index store — different stores — so a mid-stream flush never mutates the
|
|
120
|
+
// stream being read, and this is safe on every provider. A mid-stream flush
|
|
121
|
+
// failure in `createIndex` is torn down by its try/catch (the whole fresh index
|
|
122
|
+
// store is deleted); in `rebuildSecondaryIndexes` it leaves a partial-but-
|
|
123
|
+
// recoverable index (re-run the rebuild — clear + rebuild is idempotent).
|
|
124
|
+
batchBytes += indexKey.length + dataKey.length;
|
|
125
|
+
if (batchBytes >= maxBatchBytes) {
|
|
126
|
+
await batch.write();
|
|
127
|
+
batch = indexStore.batch();
|
|
128
|
+
batchBytes = 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Final flush of the residual. May be empty (an empty table, or a build whose last
|
|
132
|
+
// row exactly hit the budget and flushed) — providers accept an empty write.
|
|
133
|
+
await batch.write();
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Validates `rows` against a UNIQUE constraint, throwing `CONSTRAINT` on the first
|
|
137
|
+
* duplicate before any schema mutation. Used by `ADD CONSTRAINT UNIQUE` (validate
|
|
138
|
+
* against the current collation) and by `SET COLLATE` (pass an `updatedSchema` whose
|
|
139
|
+
* altered column carries the NEW collation, so the dedup is performed under it).
|
|
140
|
+
* Mirrors the duplicate detection in {@link buildIndexEntries}: a `seen` Set keyed on
|
|
141
|
+
* a per-column collation-aware signature of the constrained values, with SQL NULL
|
|
142
|
+
* semantics (a row with any NULL constrained value never counts as a duplicate) and
|
|
143
|
+
* the partial `predicate` honored.
|
|
144
|
+
*
|
|
145
|
+
* `rows` MUST be the rows the DDL-issuing connection can SEE. Ordinarily that is this
|
|
146
|
+
* table's EFFECTIVE stream (committed rows merged with the open transaction's own
|
|
147
|
+
* pending puts/deletes — `StoreTable.iterateEffectiveEntries`, adapted by
|
|
148
|
+
* {@link rowsFromEntries}); when a wrapper module holds the pending rows outside this
|
|
149
|
+
* module it hands them down as an `EffectiveRowSource` instead. Either way, a
|
|
150
|
+
* committed-only stream would let a duplicate inserted earlier in the same transaction
|
|
151
|
+
* slip past validation and land in the table once the transaction commits.
|
|
152
|
+
*
|
|
153
|
+
* No index store is written — store UNIQUE enforcement is a full-scan over
|
|
154
|
+
* `uniqueConstraints` at write time. The signature is built by
|
|
155
|
+
* {@link dedupeRowSignature} with one normalizer per constrained column, resolved from
|
|
156
|
+
* `tableSchema.columns[idx].collation` through the connection's
|
|
157
|
+
* `db.getKeyNormalizerResolver()`, so a per-column collation registered with
|
|
158
|
+
* `db.registerCollation` is honored (matching write-time `compareSqlValues`
|
|
159
|
+
* enforcement). A comparator-only collation raises: rows that cannot be bucketed
|
|
160
|
+
* cannot be deduped. Columns whose declared type can never hold text take the
|
|
161
|
+
* identity normalizer and so never raise.
|
|
162
|
+
*/
|
|
163
|
+
export async function validateUniqueOverExistingRows(rows, tableSchema, uc, keyNormalizers) {
|
|
164
|
+
await assertNoDuplicateRows(rows, tableSchema, uc.columns, uc.columns.map(idx => {
|
|
165
|
+
const column = tableSchema.columns[idx];
|
|
166
|
+
return keyNormalizers(logicalTypeCanHoldText(column.logicalType) ? column.collation : undefined);
|
|
167
|
+
}), uc.predicate ? compilePredicate(uc.predicate, tableSchema.columns, tableSchema.name) : undefined);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Index-shaped twin of {@link validateUniqueOverExistingRows}, used by
|
|
171
|
+
* `StoreModuleIndex.createIndex` when a wrapper module supplies the rows to judge. Dedupes on the
|
|
172
|
+
* index's own columns under the index column's COLLATE (falling back to the table
|
|
173
|
+
* column's), so it enforces exactly what `buildIndexEntries`' suppressed in-pass check
|
|
174
|
+
* would have — over the wrapper's rows instead of this module's committed ones.
|
|
175
|
+
*/
|
|
176
|
+
export async function validateUniqueIndexOverRows(rows, tableSchema, indexSchema, keyNormalizers) {
|
|
177
|
+
await assertNoDuplicateRows(rows, tableSchema, indexSchema.columns.map(col => col.index), indexDedupeNormalizers(tableSchema, indexSchema, keyNormalizers), indexSchema.predicate ? compilePredicate(indexSchema.predicate, tableSchema.columns, tableSchema.name) : undefined);
|
|
178
|
+
}
|
|
179
|
+
/** Adapts a raw KV entry stream into the row stream the uniqueness validators consume. */
|
|
180
|
+
export async function* rowsFromEntries(entries) {
|
|
181
|
+
for await (const entry of entries) {
|
|
182
|
+
yield deserializeRow(entry.value);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* The rows a DDL-issuing connection can SEE, as every pre-mutation probe in the ALTER
|
|
187
|
+
* path needs them: a wrapper module's `EffectiveRowSource` when the isolation layer
|
|
188
|
+
* holds this transaction's staged rows outside the store, else this table's own
|
|
189
|
+
* effective stream (committed rows merged with the module's buffered puts/deletes).
|
|
190
|
+
*
|
|
191
|
+
* One fresh stream per call — an async generator is single-shot, and an
|
|
192
|
+
* `EffectiveRowSource` is re-callable for exactly that reason, so a probe that needs
|
|
193
|
+
* two walks calls this twice.
|
|
194
|
+
*/
|
|
195
|
+
export function effectiveDdlRows(table, rows) {
|
|
196
|
+
return rows ? rows() : rowsFromEntries(table.iterateEffectiveEntries(buildFullScanBounds()));
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Per-column key normalizers for a UNIQUE INDEX dedupe signature, drawing each column's
|
|
200
|
+
* collation from the index column (if it carries one) else the underlying table column —
|
|
201
|
+
* so the signature honors a per-column collation registered on this connection, matching
|
|
202
|
+
* write-time enforcement.
|
|
203
|
+
*
|
|
204
|
+
* A column whose declared type can never hold text takes the identity normalizer regardless
|
|
205
|
+
* of its collation (the signature serializer normalizes only string values), so a comparator-only
|
|
206
|
+
* collation named on an integer column is not rejected here when the engine's own hash sites
|
|
207
|
+
* would accept it.
|
|
208
|
+
*
|
|
209
|
+
* NOTE: a JSON (or other collation-blind-but-text-capable) index column with a
|
|
210
|
+
* comparator-only custom collation (registered with no key normalizer) passes DDL —
|
|
211
|
+
* `assertIndexKeyCollationsCanKey` checks `resolveIndexKeyCollations`, which keys such a
|
|
212
|
+
* column hard-`BINARY` regardless of the declared name, and `BINARY` always has a
|
|
213
|
+
* normalizer — but THIS resolver looks up the column's own declared name (JSON can hold
|
|
214
|
+
* text, so it takes the textual branch above), and `keyNormalizers` throws for a name with
|
|
215
|
+
* no registered normalizer. The DDL-time check and this one are asking two different
|
|
216
|
+
* questions (can the physical key encode vs. can the dedupe signature encode) and can
|
|
217
|
+
* disagree. Confirmed by inspection, not exercised by a test: this surfaces as a thrown
|
|
218
|
+
* error at `CREATE UNIQUE INDEX` — confusing, since the same statement's key-collation gate
|
|
219
|
+
* just passed — but not a correctness hole (no bad state is built). If this needs a
|
|
220
|
+
* friendlier message, that is a follow-up, not implied by this ticket.
|
|
221
|
+
*/
|
|
222
|
+
function indexDedupeNormalizers(tableSchema, indexSchema, keyNormalizers) {
|
|
223
|
+
return indexSchema.columns.map(col => {
|
|
224
|
+
const column = tableSchema.columns[col.index];
|
|
225
|
+
return keyNormalizers(logicalTypeCanHoldText(column.logicalType)
|
|
226
|
+
? (col.collation ?? column.collation)
|
|
227
|
+
: undefined);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Collation- and identity-aware dedupe signature of `row` over `colIndices`: each value
|
|
232
|
+
* runs through its column's key transform (`storeDedupeKeyTransform` — TIMESPAN's
|
|
233
|
+
* total-seconds `groupKey`, so 'PT1H' and 'PT60M' sign identically; JSON's structural
|
|
234
|
+
* bytes for everything but a string scalar, so reorder-equal objects sign identically
|
|
235
|
+
* while a string scalar is left for `serializeKey`'s normalizer) before `serializeKey`
|
|
236
|
+
* applies the per-column normalizer. Returns null when any covered value
|
|
237
|
+
* is NULL (SQL UNIQUE allows multiple NULLs). The build/validate-time twin of the
|
|
238
|
+
* write-time typed compare in `StoreTable.uniqueColumnComparators`.
|
|
239
|
+
*
|
|
240
|
+
* NOTE: `transforms` normalizes STRING values only through `serializeKey`'s collation
|
|
241
|
+
* normalizer — a transform whose output is a `Uint8Array` (as `storeSemanticKeyTransform`
|
|
242
|
+
* would produce) bypasses that normalizer entirely (`serializeKey` tags a byte array
|
|
243
|
+
* `x:` and never consults it). So any future semantic-ordering logical type that BOTH
|
|
244
|
+
* carries a key transform AND honors a collation in its `compare` (like JSON_TYPE) needs
|
|
245
|
+
* its own `storeDedupeKeyTransform` branch, or its build-time UNIQUE check silently
|
|
246
|
+
* degrades to BINARY while the write-time check honors the collation.
|
|
247
|
+
*/
|
|
248
|
+
function dedupeRowSignature(row, colIndices, normalizers, transforms) {
|
|
249
|
+
const values = colIndices.map((c, i) => {
|
|
250
|
+
const v = row[c];
|
|
251
|
+
const transform = transforms[i];
|
|
252
|
+
return transform && v !== null ? transform(v) : v;
|
|
253
|
+
});
|
|
254
|
+
return serializeKey(values, normalizers);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Throws CONSTRAINT on the first pair of `rows` that share a signature over `columnIndices`.
|
|
258
|
+
*
|
|
259
|
+
* SQL NULL semantics: {@link dedupeRowSignature} returns null when any constrained column is
|
|
260
|
+
* NULL, and such rows never collide. A partial `predicate` restricts the judged set to rows
|
|
261
|
+
* it accepts unambiguously. Shared by {@link validateUniqueOverExistingRows}
|
|
262
|
+
* (constraint columns) and {@link validateUniqueIndexOverRows} (index columns).
|
|
263
|
+
*/
|
|
264
|
+
async function assertNoDuplicateRows(rows, tableSchema, columnIndices, normalizers, predicate) {
|
|
265
|
+
const transforms = resolveDedupeKeyTransforms(columnIndices, tableSchema.columns);
|
|
266
|
+
const seen = new Set();
|
|
267
|
+
for await (const row of rows) {
|
|
268
|
+
if (predicate && predicate.evaluate(row) !== true)
|
|
269
|
+
continue;
|
|
270
|
+
const keySig = dedupeRowSignature(row, columnIndices, normalizers, transforms);
|
|
271
|
+
if (keySig === null)
|
|
272
|
+
continue;
|
|
273
|
+
if (seen.has(keySig)) {
|
|
274
|
+
const colNames = columnIndices.map(i => tableSchema.columns[i]?.name ?? String(i)).join(', ');
|
|
275
|
+
throw new QuereusError(`UNIQUE constraint failed: ${tableSchema.name} (${colNames})`, StatusCode.CONSTRAINT);
|
|
276
|
+
}
|
|
277
|
+
seen.add(keySig);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=store-module-index-build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-module-index-build.js","sourceRoot":"","sources":["../../../src/common/store-module-index-build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CREATE INDEX / DROP INDEX over a store-backed table, and the physical index stores
|
|
3
|
+
* they bring into (and out of) existence — including the hidden `_uc_*` stores that
|
|
4
|
+
* back a plain UNIQUE constraint, whose set is reconciled against the schema after
|
|
5
|
+
* every DDL that can change it.
|
|
6
|
+
*
|
|
7
|
+
* Fourth layer of the store-module chain:
|
|
8
|
+
* StoreModuleBase -> StoreModuleCatalog -> StoreModuleSchemaSync -> StoreModuleIndex
|
|
9
|
+
* -> StoreModuleAlterColumn -> StoreModuleAlter -> StoreModuleRename -> StoreModule
|
|
10
|
+
*/
|
|
11
|
+
import type { Database, EffectiveRowSource, KeyNormalizerResolver, TableIndexSchema, TableSchema } from '@quereus/quereus';
|
|
12
|
+
import { StoreTable } from './store-table.js';
|
|
13
|
+
import { StoreModuleSchemaSync } from './store-module-schema-sync.js';
|
|
14
|
+
export declare abstract class StoreModuleIndex extends StoreModuleSchemaSync {
|
|
15
|
+
/**
|
|
16
|
+
* Creates an index on a store-backed table.
|
|
17
|
+
*
|
|
18
|
+
* `rows` — an {@link EffectiveRowSource} supplied by a wrapper module (the isolation
|
|
19
|
+
* layer) — replaces this module's own rows as the set the UNIQUE duplicate check judges.
|
|
20
|
+
* When present the check runs UP FRONT, before `getIndexStore` opens the index-store
|
|
21
|
+
* directory, so a rejection leaves no directory behind; and `buildIndexEntries` then
|
|
22
|
+
* populates the physical index from this module's own (committed) rows with its in-pass
|
|
23
|
+
* dup check disabled. Those two row sets legitimately differ — the wrapper's transaction
|
|
24
|
+
* may have deleted a committed duplicate — and an index entry with no live row behind it
|
|
25
|
+
* is harmless (see the entry-resolution note in `buildIndexEntries`).
|
|
26
|
+
*/
|
|
27
|
+
createIndex(db: Database, schemaName: string, tableName: string, indexSchema: TableIndexSchema, rows?: EffectiveRowSource): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Drops an index on a store-backed table.
|
|
30
|
+
*
|
|
31
|
+
* Mirrors createIndex: refreshes the connected StoreTable's cached
|
|
32
|
+
* tableSchema (removing the index entry and any UNIQUE constraint
|
|
33
|
+
* synthesized from it, tagged with `derivedFromIndex`), releases the
|
|
34
|
+
* cached index-store handle, and tears down the underlying index store.
|
|
35
|
+
*/
|
|
36
|
+
dropIndex(db: Database, schemaName: string, tableName: string, indexName: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Clear and rebuild every secondary index of `schema` against the (already
|
|
39
|
+
* re-encoded) data store. Secondary-index keys embed the PK suffix, so they must
|
|
40
|
+
* be rewritten whenever the data-store PK key bytes change — which happens both
|
|
41
|
+
* on `ALTER PRIMARY KEY` (the PK columns change) and on an `ALTER COLUMN … SET
|
|
42
|
+
* COLLATE` on a PK member (a PK column's key collation changes). Shared by both
|
|
43
|
+
* arms so the clear-then-rebuild stays identical. `schema` must already be the
|
|
44
|
+
* post-ALTER schema (its `primaryKeyDefinition` + column collations drive the new
|
|
45
|
+
* PK-suffix encoding via {@link buildIndexEntries}). `normalizers` is the owning
|
|
46
|
+
* connection's `db.getKeyNormalizerResolver()` — see {@link buildIndexEntries}.
|
|
47
|
+
*
|
|
48
|
+
* NOTE: reads the data store committed-only and writes the index stores outside the
|
|
49
|
+
* coordinator. Sound only because every caller calls `StoreModuleBase.ddlCommitPendingOps`
|
|
50
|
+
* first, so this module's "committed" is "everything live". A caller that skips that
|
|
51
|
+
* flush would rebuild an index missing its transaction's pending rows.
|
|
52
|
+
*
|
|
53
|
+
* `skipDuplicateCheck` suppresses {@link buildIndexEntries}' in-pass UNIQUE check.
|
|
54
|
+
* Both ALTER COLUMN rebuild callers set it — the value-rewriting / key-transform
|
|
55
|
+
* arm and the PK re-key arm (`SET COLLATE` on a PK member): each runs a
|
|
56
|
+
* pre-mutation UNIQUE re-validation that already judged the ISSUING connection's
|
|
57
|
+
* effective rows (a wrapper's overlay included), and this rebuild sees only THIS
|
|
58
|
+
* module's committed rows — a set that may retain a row the wrapper's transaction
|
|
59
|
+
* has deleted, so judging it here would spuriously reject a duplicate pair the
|
|
60
|
+
* probe correctly accepted (and, worse, reject AFTER the data store was already
|
|
61
|
+
* re-keyed). Mirrors the memory module's deliberately non-enforcing base rebuild
|
|
62
|
+
* (the probe is the only guard). `ALTER PRIMARY KEY`'s rebuild still enforces:
|
|
63
|
+
* that arm has no effective-row UNIQUE probe of its own.
|
|
64
|
+
*/
|
|
65
|
+
protected rebuildSecondaryIndexes(schemaName: string, tableName: string, table: StoreTable, schema: TableSchema, normalizers: KeyNormalizerResolver, skipDuplicateCheck?: boolean): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Build / tear down the physical index stores backing implicit UNIQUE indexes
|
|
68
|
+
* (`_uc_*`) after a DDL statement, by diffing the implicit-index NAMES the old vs
|
|
69
|
+
* new schema call for ({@link implicitUniqueIndexNameMap}):
|
|
70
|
+
* - a name newly PRESENT (ADD CONSTRAINT UNIQUE, the target half of a
|
|
71
|
+
* RENAME CONSTRAINT / rename of an unnamed UC's column, or a DROP INDEX that
|
|
72
|
+
* retires the explicit index a UNIQUE was reusing) has its physical store
|
|
73
|
+
* populated from this module's effective rows;
|
|
74
|
+
* - a name newly ABSENT (DROP CONSTRAINT UNIQUE, the source half of a rename, or
|
|
75
|
+
* a CREATE INDEX whose new index now realizes the UNIQUE) has its store torn
|
|
76
|
+
* down, so nothing maintains it and a later rebuild does not reopen stale
|
|
77
|
+
* entries.
|
|
78
|
+
*
|
|
79
|
+
* The SCHEMA entry itself is materialized/removed by `withImplicitUniqueIndexes`
|
|
80
|
+
* on the caller's `table.updateSchema`; only the physical store needs this. Called
|
|
81
|
+
* after every ALTER TABLE and after `createIndex` / `dropIndex`, and a no-op
|
|
82
|
+
* whenever the implicit-index name set is unchanged — the common case, including
|
|
83
|
+
* every PK / collation / data-type ALTER (whose same-name physical re-encode is
|
|
84
|
+
* already done by {@link rebuildSecondaryIndexes}) and every CREATE / DROP INDEX
|
|
85
|
+
* that does not cover a plain UNIQUE's columns.
|
|
86
|
+
*
|
|
87
|
+
* `oldSchema` is the pre-DDL schema: its `uniqueConstraints` give the old names and
|
|
88
|
+
* its `.indexes` the old reuse decisions. Either the engine-facing or the
|
|
89
|
+
* materialized copy works — `findReusableIndexForUnique` skips a constraint's own
|
|
90
|
+
* `_uc_*`, so a materialized input yields the same name set.
|
|
91
|
+
*
|
|
92
|
+
* NOTE: the build populates from THIS module's own effective rows (committed + this
|
|
93
|
+
* transaction's pending), never a wrapper's — mirroring `createIndex`. Under the
|
|
94
|
+
* isolation layer the wrapper's rows are what ADD CONSTRAINT's validation judged;
|
|
95
|
+
* the physical index legitimately fills from this module's committed rows and an
|
|
96
|
+
* entry with no live row behind it is harmless (both readers resolve to the live
|
|
97
|
+
* row). Duplicates were already rejected by `validateUniqueOverExistingRows` (ADD)
|
|
98
|
+
* or cannot exist (RENAME leaves data unchanged), so the in-pass check is skipped.
|
|
99
|
+
*/
|
|
100
|
+
protected reconcileImplicitUniqueIndexStores(db: Database, schemaName: string, tableName: string, table: StoreTable, oldSchema: TableSchema): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Close + delete one index's physical store: release the table's cached handle, then
|
|
103
|
+
* `deleteIndexStore` when the provider implements it (it closes the handle before
|
|
104
|
+
* removing the directory), else just `closeIndexStore`.
|
|
105
|
+
*
|
|
106
|
+
* The single teardown every path shares — `dropIndex`, `createIndex`'s build-failure
|
|
107
|
+
* rollback, the implicit `_uc_*` reconcile above, and `DROP COLUMN`'s removed-index
|
|
108
|
+
* pass (`StoreModuleAlter.alterDropColumn`). Each caller owns the surrounding
|
|
109
|
+
* posture, which deliberately differs: the DDL-commit flush (buffered ops are keyed
|
|
110
|
+
* on the KVStore HANDLE, so a doomed store's queued ops would replay into a closed
|
|
111
|
+
* store at commit — see `StoreModuleBase.ddlCommitPendingOps`) and, for
|
|
112
|
+
* `createIndex`, swallowing a teardown throw so it cannot mask the build error.
|
|
113
|
+
*/
|
|
114
|
+
protected tearDownIndexStore(schemaName: string, tableName: string, table: StoreTable, indexName: string): Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=store-module-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-module-index.d.ts","sourceRoot":"","sources":["../../../src/common/store-module-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACX,QAAQ,EACR,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,WAAW,EACX,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AA6BtE,8BAAsB,gBAAiB,SAAQ,qBAAqB;IACnE;;;;;;;;;;;OAWG;IACG,WAAW,CAChB,EAAE,EAAE,QAAQ,EACZ,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,gBAAgB,EAC7B,IAAI,CAAC,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC;IAmIhB;;;;;;;OAOG;IACG,SAAS,CACd,EAAE,EAAE,QAAQ,EACZ,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAyEhB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;cACa,uBAAuB,CACtC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,qBAAqB,EAClC,kBAAkB,UAAQ,GACxB,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;cACa,kCAAkC,CACjD,EAAE,EAAE,QAAQ,EACZ,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,WAAW,GACpB,OAAO,CAAC,IAAI,CAAC;IAsDhB;;;;;;;;;;;;OAYG;cACa,kBAAkB,CACjC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;CAQhB"}
|