@quereus/store 4.5.0 → 4.7.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 +34 -6
- 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 +31 -25
- package/dist/src/common/events.d.ts.map +1 -1
- package/dist/src/common/events.js +38 -39
- 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 +30 -2
- package/dist/src/common/json-key.d.ts.map +1 -1
- package/dist/src/common/json-key.js +49 -2
- package/dist/src/common/json-key.js.map +1 -1
- package/dist/src/common/key-builder.d.ts +40 -20
- package/dist/src/common/key-builder.d.ts.map +1 -1
- package/dist/src/common/key-builder.js +31 -23
- 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 +348 -0
- package/dist/src/common/pk-key-resolution.d.ts.map +1 -0
- package/dist/src/common/pk-key-resolution.js +481 -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 +428 -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 +389 -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 +504 -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 +268 -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 +539 -0
- package/dist/src/common/store-table-base.d.ts.map +1 -0
- package/dist/src/common/store-table-base.js +900 -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 +452 -0
- package/dist/src/common/store-table-scan.d.ts.map +1 -0
- package/dist/src/common/store-table-scan.js +901 -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 +168 -2385
- 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,481 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolution of the physical KEY properties of a table's primary-key and
|
|
3
|
+
* secondary-index columns: the per-column key collation, the key-identity value
|
|
4
|
+
* transform for semantic-ordering types, and the order-safety predicates that
|
|
5
|
+
* decide whether a byte window may stand in for a comparator range.
|
|
6
|
+
*
|
|
7
|
+
* Shared by the store table (data-key + index-maintenance encoding) and
|
|
8
|
+
* `StoreModule` (index rebuild, access planning) so key encoding can never drift
|
|
9
|
+
* between the two.
|
|
10
|
+
*/
|
|
11
|
+
import { createTypedComparator, hasSemanticOrdering, semanticKeyTransform, logicalTypeCanHoldText, pkKeyCollationName, JSON_TYPE, TIMESPAN_TYPE, } from '@quereus/quereus';
|
|
12
|
+
import { jsonKeyEncodable, jsonStructuralKey } from './json-key.js';
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the per-column KEY collation for each primary-key column.
|
|
15
|
+
*
|
|
16
|
+
* The store encodes PRIMARY KEY uniqueness/ordering PHYSICALLY in the key bytes, so each
|
|
17
|
+
* text-capable PK column's key must be encoded under the collation the engine actually
|
|
18
|
+
* COMPARES that column under. Returns one entry per PK member, in `pkDef` order:
|
|
19
|
+
* - collation-aware member (`text`, `any` — the types whose `compare` applies the
|
|
20
|
+
* collation it is handed, `LogicalType.collationAware`) → its declared `collation`
|
|
21
|
+
* (normalized upper-case), or `fallback` (the table key collation K) when the
|
|
22
|
+
* column carries none.
|
|
23
|
+
* - text-capable but collation-blind member — `json` and the temporal types
|
|
24
|
+
* (`date` / `time` / `datetime` / `timespan`) → hard-coded `'BINARY'`: those
|
|
25
|
+
* types' `compare` is not the generic storage-class + collation comparison (the
|
|
26
|
+
* temporals ignore the argument; JSON ranks structurally), and their empty
|
|
27
|
+
* `supportedCollations` list keeps a non-BINARY column COLLATE out at DDL time.
|
|
28
|
+
* - never-text member → `undefined`: collation is meaningless for
|
|
29
|
+
* integer/real/blob keys (they encode type-natively), so the encoder ignores
|
|
30
|
+
* it and the data/index key bytes are identical regardless.
|
|
31
|
+
*
|
|
32
|
+
* Note that `undefined` does NOT mean "encode type-natively" to `encodeValue` — it means
|
|
33
|
+
* "fall back to `options.collation`", the table key collation K. Only a never-text column
|
|
34
|
+
* may be left `undefined`, because only it never reaches the collation branch.
|
|
35
|
+
*
|
|
36
|
+
* Every name returned here is encoded through the key-normalizer resolver carried
|
|
37
|
+
* in `EncodeOptions.normalizers` (`db.getKeyNormalizerResolver()`), so a collation
|
|
38
|
+
* registered or overridden with `db.registerCollation` produces key bytes that agree
|
|
39
|
+
* with the comparator the store's UNIQUE enforcement uses. A collation that cannot
|
|
40
|
+
* key — unregistered, or registered with a comparator but no normalizer — is rejected
|
|
41
|
+
* at DDL time by `StoreTableBase.validateKeyCollations`, so no encode call ever has
|
|
42
|
+
* to fall back. Shared by `StoreTable` (data-key + index-maintenance) and
|
|
43
|
+
* the index rebuild `buildIndexEntries` (store-module-index-build.ts) so the PK suffix
|
|
44
|
+
* encoding can never drift between the two.
|
|
45
|
+
*/
|
|
46
|
+
export function resolvePkKeyCollations(pkDef, columns, fallback) {
|
|
47
|
+
return pkDef.map(def => {
|
|
48
|
+
const col = columns[def.index];
|
|
49
|
+
// Delegates the collation-aware/collation-blind/never-text branch to the engine's
|
|
50
|
+
// `pkKeyCollationName` — the same decision `quereus-isolation`'s modified-PK set
|
|
51
|
+
// makes for its own key normalizers, so the two can never drift apart again. Only
|
|
52
|
+
// the fallback-to-K and uppercase-normalization are store-specific.
|
|
53
|
+
const name = pkKeyCollationName(col);
|
|
54
|
+
return name === undefined ? undefined : (name || fallback).toUpperCase();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Per-column KEY collation for a secondary index's OWN columns (the index half of
|
|
59
|
+
* `buildIndexKey`), positionally aligned with `index.columns` — the index twin of
|
|
60
|
+
* {@link resolvePkKeyCollations}. Same three-way branch, delegated to the engine's
|
|
61
|
+
* `pkKeyCollationName`:
|
|
62
|
+
* - never-text column (`integer`, `real`, `blob`) → `undefined`: encoded
|
|
63
|
+
* type-natively, collation is moot.
|
|
64
|
+
* - text-capable but collation-blind (`json`, the temporal types) → hard-coded
|
|
65
|
+
* `'BINARY'` — those types' `compare` is not the generic collation comparison.
|
|
66
|
+
* - collation-aware (`text`, `any`) → the index column's own COLLATE, else the
|
|
67
|
+
* table column's declared collation, else `'BINARY'`.
|
|
68
|
+
*
|
|
69
|
+
* The fallback is `BINARY`, NOT the table key collation K — deliberately asymmetric
|
|
70
|
+
* with {@link resolvePkKeyCollations}, whose fallback IS K. For a PK member the
|
|
71
|
+
* asymmetry is illusory: `reconcilePkCollations` (store-module-schema-rewrite.ts)
|
|
72
|
+
* rewrites an undecorated text PK column's declared collation to K at CREATE time, so
|
|
73
|
+
* for a PK member K *is* the declared collation. No such rewrite exists for non-PK
|
|
74
|
+
* columns — an undecorated `text` column genuinely compares under BINARY (in the
|
|
75
|
+
* engine's operators and in the store's `matchesFilters` residual alike), so BINARY is
|
|
76
|
+
* what its index bytes must encode under, or the stored order/equality disagrees with
|
|
77
|
+
* every comparison made against it.
|
|
78
|
+
*/
|
|
79
|
+
export function resolveIndexKeyCollations(index, columns) {
|
|
80
|
+
return index.columns.map(col => {
|
|
81
|
+
const tableCol = columns[col.index];
|
|
82
|
+
// The collation handed to `pkKeyCollationName` is always defined, so an
|
|
83
|
+
// `undefined` answer means never-text (its textual branch returns the collation
|
|
84
|
+
// verbatim; passing a bare `col.collation ?? tableCol.collation` would conflate
|
|
85
|
+
// "undecorated text column" with "never-text" and silently fall back to K at
|
|
86
|
+
// encode time — the exact drift this resolver exists to remove).
|
|
87
|
+
const name = pkKeyCollationName(tableCol === undefined ? undefined : {
|
|
88
|
+
logicalType: tableCol.logicalType,
|
|
89
|
+
collation: col.collation ?? tableCol.collation ?? 'BINARY',
|
|
90
|
+
});
|
|
91
|
+
return name === undefined ? undefined : (name || 'BINARY').toUpperCase();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The store's per-type key VALUE TRANSFORM for a semantic-ordering logical type, or
|
|
96
|
+
* `undefined` when raw values already key faithfully.
|
|
97
|
+
*
|
|
98
|
+
* The contract is TWO-sided — identity AND order. `StoreTable` implements no
|
|
99
|
+
* `comparePrimaryKey`, so the isolation layer merges overlay against underlying with
|
|
100
|
+
* its own fallback comparator (the PK type's `compare` via `createTypedComparator`)
|
|
101
|
+
* and needs this table's key BYTE order to agree with it; and byte equality must be
|
|
102
|
+
* exactly the type's equality, or two spellings of one value land on two keys.
|
|
103
|
+
*
|
|
104
|
+
* - JSON → the store-local structural encoder ({@link jsonStructuralKey}): a
|
|
105
|
+
* `Uint8Array` whose memcmp order reproduces the type's structural `compare`
|
|
106
|
+
* (canonical-text bytes are identity-faithful but sort `[10]` before `[2]`,
|
|
107
|
+
* which broke overlay shadowing — see json-key.ts).
|
|
108
|
+
* - Everything else → the engine's {@link semanticKeyTransform} (the type's
|
|
109
|
+
* `groupKey`). Today that is TIMESPAN: total seconds against the same reference
|
|
110
|
+
* date as `TIMESPAN.compare`, so 'PT1H' and 'PT60M' collide on one key AND byte
|
|
111
|
+
* order is elapsed-time order.
|
|
112
|
+
*
|
|
113
|
+
* JSON deliberately gets NO engine `groupKey` — `groupKey` also drives GROUP BY /
|
|
114
|
+
* `IN` / hash-join identity, where canonical-text identity is already correct and a
|
|
115
|
+
* `Uint8Array` key would be a behaviour change for no benefit. Hence this
|
|
116
|
+
* store-local seam. A semantic-ordering type with NEITHER a `groupKey` nor an entry
|
|
117
|
+
* here cannot key a persisted structure soundly; `StoreTable` rejects it at DDL time
|
|
118
|
+
* (see `validateSemanticKeyTransforms`).
|
|
119
|
+
*
|
|
120
|
+
* This is the PHYSICAL KEY BYTES resolver — it feeds `buildIndexKey` / `buildDataKey`
|
|
121
|
+
* and its output is memcmp-ordered and persisted. {@link storeDedupeKeyTransform} is
|
|
122
|
+
* its build/validate-time twin: same job, but for the transient UNIQUE dedupe
|
|
123
|
+
* signature, which is free to leave a comparable value for `serializeKey`'s collation
|
|
124
|
+
* normalizer instead of committing to structural bytes.
|
|
125
|
+
*/
|
|
126
|
+
export function storeSemanticKeyTransform(type) {
|
|
127
|
+
// Matched by NAME, not object identity (`type === JSON_TYPE`): the engine and this
|
|
128
|
+
// package can be loaded as two module instances (e.g. the logic suite runs the
|
|
129
|
+
// engine from src via ts-node while the store resolves `@quereus/quereus` to dist),
|
|
130
|
+
// and each instance carries its own JSON_TYPE singleton. The `hasSemanticOrdering`
|
|
131
|
+
// gate keeps a hypothetical plain custom type named 'JSON' out of this branch.
|
|
132
|
+
if (hasSemanticOrdering(type) && type.name === JSON_TYPE.name)
|
|
133
|
+
return jsonStructuralKey;
|
|
134
|
+
return semanticKeyTransform(type);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The build/validate-time twin of {@link storeSemanticKeyTransform}, for the UNIQUE
|
|
138
|
+
* dedupe SIGNATURE rather than physical key bytes (`buildIndexEntries`'s in-pass
|
|
139
|
+
* `seen` check and `assertNoDuplicateRows`, both in store-module-index-build.ts).
|
|
140
|
+
*
|
|
141
|
+
* The signature is a `serializeKey` call over the (possibly transformed) values, and
|
|
142
|
+
* `serializeKey` applies a column's collation NORMALIZER only to a raw `string` value
|
|
143
|
+
* — a transform that returns a `Uint8Array` (as {@link storeSemanticKeyTransform} does
|
|
144
|
+
* for JSON, via {@link jsonStructuralKey}) is tagged as an opaque byte array instead,
|
|
145
|
+
* and the normalizer never runs. For JSON that would silently drop the index
|
|
146
|
+
* COLLATE on exactly the case `JSON_TYPE.compare` treats as text (a string-scalar
|
|
147
|
+
* pair) and let a build-time UNIQUE index admit rows a write-time insert would then
|
|
148
|
+
* reject (bug-store-index-build-dedupe-skips-collation) — so this resolver special-
|
|
149
|
+
* cases JSON: a string scalar is left AS a string, so `serializeKey`'s normalizer
|
|
150
|
+
* still runs; every other JSON value (object, array, number, boolean, or null) falls
|
|
151
|
+
* back to the structural bytes, matching `JSON_TYPE.compare`'s non-text ranking.
|
|
152
|
+
*
|
|
153
|
+
* Every other semantic-ordering type (TIMESPAN today) is unaffected: its `compare`
|
|
154
|
+
* ignores the collation it is handed, and its `groupKey` transform already collides
|
|
155
|
+
* every equal-identity spelling onto one value on both the build and write paths, so
|
|
156
|
+
* this resolver defers to {@link storeSemanticKeyTransform} unchanged.
|
|
157
|
+
*/
|
|
158
|
+
export function storeDedupeKeyTransform(type) {
|
|
159
|
+
if (hasSemanticOrdering(type) && type.name === JSON_TYPE.name)
|
|
160
|
+
return jsonDedupeKey;
|
|
161
|
+
return storeSemanticKeyTransform(type);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A declared-JSON value as the UNIQUE dedupe signature must see it: a top-level string
|
|
165
|
+
* scalar verbatim (so `serializeKey` runs the column's collation normalizer over it,
|
|
166
|
+
* mirroring `JSON_TYPE.compare`'s collation-honoring string/string branch), every other
|
|
167
|
+
* node as {@link jsonStructuralKey}'s bytes (mirroring `deepCompareJson`, which takes no
|
|
168
|
+
* collation — a NESTED string leaf is code-point-compared even under an index COLLATE).
|
|
169
|
+
*/
|
|
170
|
+
function jsonDedupeKey(value) {
|
|
171
|
+
return typeof value === 'string' ? value : jsonStructuralKey(value);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Resolve the per-column key value transform for each primary-key column —
|
|
175
|
+
* {@link storeSemanticKeyTransform} of the member's logical type. One entry per PK
|
|
176
|
+
* member in `pkDef` order; `undefined` for every type whose raw value already keys
|
|
177
|
+
* faithfully. The companion of {@link resolvePkKeyCollations}: every call site that
|
|
178
|
+
* threads the collations MUST thread these too, or key identity/order drifts
|
|
179
|
+
* between the write path and the rebuild/lookup path.
|
|
180
|
+
*/
|
|
181
|
+
export function resolvePkKeyTransforms(pkDef, columns) {
|
|
182
|
+
return pkDef.map(def => storeSemanticKeyTransform(columns[def.index]?.logicalType));
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Per-column key value transforms for a secondary index's OWN columns (the
|
|
186
|
+
* index half of `buildIndexKey`), positionally aligned with `index.columns`.
|
|
187
|
+
* Same rule as {@link resolvePkKeyTransforms}: a semantic-ordering member
|
|
188
|
+
* canonicalizes through {@link storeSemanticKeyTransform}, everything else
|
|
189
|
+
* encodes raw.
|
|
190
|
+
*/
|
|
191
|
+
export function resolveIndexKeyTransforms(index, columns) {
|
|
192
|
+
return index.columns.map(col => storeSemanticKeyTransform(columns[col.index]?.logicalType));
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Per-column {@link storeDedupeKeyTransform} for an arbitrary column-index list —
|
|
196
|
+
* the UNIQUE dedupe-signature counterpart of {@link resolveIndexKeyTransforms},
|
|
197
|
+
* shared by both build/validate-time dedupe sites (`buildIndexEntries`' in-pass
|
|
198
|
+
* `seen` check over an index's columns, `assertNoDuplicateRows` over a constraint's)
|
|
199
|
+
* so the two cannot drift onto different transforms.
|
|
200
|
+
*/
|
|
201
|
+
export function resolveDedupeKeyTransforms(colIndices, columns) {
|
|
202
|
+
return colIndices.map(i => storeDedupeKeyTransform(columns[i]?.logicalType));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Per-PK-column typed equality comparator for semantic-ordering members, `undefined`
|
|
206
|
+
* elsewhere. Backs `StoreTableConstraints.keysEqual`: two PK arrays naming the same
|
|
207
|
+
* physical key under {@link resolvePkKeyTransforms} ('PT1H' / 'PT60M') must also
|
|
208
|
+
* answer "same row" here, or self-PK exclusion in the UNIQUE checks false-conflicts
|
|
209
|
+
* a row against its own differently-spelled image.
|
|
210
|
+
*/
|
|
211
|
+
export function resolvePkSemanticEquality(pkDef, columns) {
|
|
212
|
+
return pkDef.map(def => {
|
|
213
|
+
const logicalType = columns[def.index]?.logicalType;
|
|
214
|
+
return hasSemanticOrdering(logicalType) ? createTypedComparator(logicalType) : undefined;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* True when `col` can produce a TEXT value at runtime, and so when its physical
|
|
219
|
+
* key bytes are produced by a collation normalizer rather than a type-native
|
|
220
|
+
* encoding. The `ColumnSchema`-shaped wrapper over the engine's
|
|
221
|
+
* {@link logicalTypeCanHoldText}; both collation-safety guards over the store's
|
|
222
|
+
* secondary indexes — the write-side `StoreTableConstraints.indexSeekHonorsEnforcementCollation`
|
|
223
|
+
* and the read-side {@link keyOrderMatchesCollation} — exempt a never-text column from their
|
|
224
|
+
* key-vs-comparison collation test, so a false "non-text" answer is a silent wrong-result
|
|
225
|
+
* (a seek under the wrong collation, with the residual dropped).
|
|
226
|
+
*/
|
|
227
|
+
export function columnCanHoldText(col) {
|
|
228
|
+
return logicalTypeCanHoldText(col?.logicalType);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* True when this semantic-ordering type's store key bytes memcmp in EXACTLY the type's
|
|
232
|
+
* `compare` order — and byte-equal exactly when `compare` says equal — for every value a
|
|
233
|
+
* store-backed table can HOLD.
|
|
234
|
+
*
|
|
235
|
+
* An explicit per-type assertion, deliberately NOT
|
|
236
|
+
* `storeSemanticKeyTransform(type) !== undefined`: a transform is only required to be
|
|
237
|
+
* identity-faithful, and `validateSemanticKeyTransforms` can check only that one exists —
|
|
238
|
+
* nothing forces a future type's transform to be order-preserving. A type absent here
|
|
239
|
+
* keeps the pre-existing blanket decline in {@link keyOrderMatchesCollation} — no byte
|
|
240
|
+
* window, no ordering advertisement, answered by full scan + the type-aware residual.
|
|
241
|
+
*
|
|
242
|
+
* Why the stored-value claim holds for the two listed types:
|
|
243
|
+
* - TIMESPAN — every write path coerces through `TIMESPAN_TYPE.parse` (row coercion,
|
|
244
|
+
* the engine's pre-coerced UPDATE fast path, the ALTER retype backfill's
|
|
245
|
+
* `validateAndParse`), which raises on anything unparseable. So every stored value
|
|
246
|
+
* parses, `groupKey` returns total seconds for all of them, and every stored key
|
|
247
|
+
* member is a fixed-width NUMERIC whose memcmp order is elapsed-time order. The
|
|
248
|
+
* raw-text fallback branch of `groupKey` is unreachable for stored values.
|
|
249
|
+
* - JSON — every stored value is a `JSON_TYPE.parse` output (never a blob, never a
|
|
250
|
+
* bigint), all of which {@link jsonStructuralKey} encodes; its tag order reproduces
|
|
251
|
+
* both `deepCompareJson`'s rank order and, for cross-storage-class pairs (where
|
|
252
|
+
* `createTypedComparator` short-circuits before reaching `JSON_TYPE.compare`),
|
|
253
|
+
* `getStorageClass`'s NULL < NUMERIC < TEXT < BLOB < OBJECT. SQL NULL never reaches
|
|
254
|
+
* a transform (`encodeCompositeKey` exempts it) and its `0x00` tag sorts below the
|
|
255
|
+
* BLOB tag the structural bytes travel under, matching NULL-first placement.
|
|
256
|
+
*
|
|
257
|
+
* Matched by NAME, not object identity, for the same dual-module-instance reason
|
|
258
|
+
* {@link storeSemanticKeyTransform} documents. This is a claim about values the table
|
|
259
|
+
* holds; a query-supplied seek bound needs {@link semanticProbeIsKeyFaithful} on top.
|
|
260
|
+
*/
|
|
261
|
+
export function semanticKeyOrderIsFaithful(type) {
|
|
262
|
+
return hasSemanticOrdering(type)
|
|
263
|
+
&& (type.name === TIMESPAN_TYPE.name || type.name === JSON_TYPE.name);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* True when `probe`'s key bytes sit at the position the type's `compare` gives it
|
|
267
|
+
* relative to every STORED value — the per-VALUE precondition every re-opened seek
|
|
268
|
+
* window (range bound AND equality probe) needs on top of
|
|
269
|
+
* {@link semanticKeyOrderIsFaithful}, which is a claim about stored values only. A probe
|
|
270
|
+
* comes from the query, and nothing coerces it to the column's declared type, so an
|
|
271
|
+
* unfaithful probe is reachable where an unfaithful stored value is not. Two concrete
|
|
272
|
+
* TIMESPAN under-fetches motivate the gate:
|
|
273
|
+
*
|
|
274
|
+
* - `where d > 5`: `createTypedComparator` short-circuits on the storage-class
|
|
275
|
+
* mismatch before `TIMESPAN.compare` runs, so every stored (TEXT-class) value ranks
|
|
276
|
+
* ABOVE the NUMERIC probe and the predicate admits every row — but `groupKey(5)`
|
|
277
|
+
* passes the non-string through unchanged, so the byte window is `> NUMERIC(5)` and
|
|
278
|
+
* a row storing 'PT1S' (total 1) falls outside it. Rows lost.
|
|
279
|
+
* - `where d > 'not a duration'`: `TIMESPAN.compare` falls back to BINARY text against
|
|
280
|
+
* the canonical stored text, while `groupKey` falls back to the raw text, which
|
|
281
|
+
* encodes TEXT-tagged and sorts above every NUMERIC-tagged stored key. Different
|
|
282
|
+
* position, rows lost.
|
|
283
|
+
*
|
|
284
|
+
* THE canonical statement of how each arm degrades on `false` — the call sites point
|
|
285
|
+
* here rather than restating it. A window may only ever be WIDENED, never narrowed, and
|
|
286
|
+
* the type-aware residual (`StoreTableScan.matchesFilters`) decides rows in every case:
|
|
287
|
+
*
|
|
288
|
+
* - a RANGE bound is SKIPPED (`buildPKRangeBounds`, `buildIndexRangeBounds`) — dropping
|
|
289
|
+
* one bound only widens the window, worst case back to the full scan.
|
|
290
|
+
* - a full-PK EQUALITY declines the WHOLE point arm (`analyzePKAccess`) — a point window
|
|
291
|
+
* is a single byte position, so it cannot be widened, only under-fetched.
|
|
292
|
+
* - a secondary index's EQ PREFIX stops SHORT at that column (`analyzeIndexAccess`) — a
|
|
293
|
+
* window over the columns before it is a strict superset.
|
|
294
|
+
* - an IN-list MULTI-SEEK has none of the three available (its merged windows are the
|
|
295
|
+
* whole access) and so never reaches this gate: it is declined per SCHEMA upstream.
|
|
296
|
+
*
|
|
297
|
+
* The TIMESPAN arm calls the COLUMN's own `groupKey`, not the imported singleton's,
|
|
298
|
+
* for the dual-module-instance reason {@link storeSemanticKeyTransform} documents.
|
|
299
|
+
* A semantic-ordering type outside the {@link semanticKeyOrderIsFaithful} allow-list
|
|
300
|
+
* answers `false`, consistent with that predicate — no window is built for it anyway.
|
|
301
|
+
*/
|
|
302
|
+
export function semanticProbeIsKeyFaithful(type, probe) {
|
|
303
|
+
if (!hasSemanticOrdering(type))
|
|
304
|
+
return true;
|
|
305
|
+
if (type.name === TIMESPAN_TYPE.name) {
|
|
306
|
+
// A number out of groupKey means the probe parsed; the raw-string fallback (or
|
|
307
|
+
// a non-string probe) means it has no faithful byte position.
|
|
308
|
+
return typeof probe === 'string' && typeof type.groupKey?.(probe) === 'number';
|
|
309
|
+
}
|
|
310
|
+
if (type.name === JSON_TYPE.name)
|
|
311
|
+
return jsonKeyEncodable(probe);
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* True when a byte window — or a byte-order advertisement — over `column` is SOUND.
|
|
316
|
+
*
|
|
317
|
+
* The store physically orders rows by memcmp of each column's key bytes, which for a
|
|
318
|
+
* text-capable column are produced by `keyCollation`'s normalizer. A range seek (and the
|
|
319
|
+
* `providesOrdering` / `monotonicOn` advertisement) equates that byte order with the order
|
|
320
|
+
* `compareCollation`'s comparator defines. Two things must hold for that equation:
|
|
321
|
+
*
|
|
322
|
+
* - **Same collation on both sides** (`compareCollation === keyCollation`). A `keyCollation`
|
|
323
|
+
* merely COARSER than `compareCollation` is not enough: it would need the key normalizer
|
|
324
|
+
* to be monotone with respect to the OTHER collation's order. It generally is not, even
|
|
325
|
+
* for built-ins: with `keyCollation = NOCASE` and `compareCollation = BINARY`,
|
|
326
|
+
* 'K' (U+212A KELVIN SIGN) is `> 'z'` under BINARY, yet its key bytes are
|
|
327
|
+
* `toLowerCase('K') = 'k'`, which sorts BEFORE 'z' — the row falls outside a `> 'z'`
|
|
328
|
+
* window and is silently dropped.
|
|
329
|
+
* - **The normalizer preserves order** (`db._isCollationOrderPreserving`). `registerCollation`
|
|
330
|
+
* promises only that a normalizer partitions strings the way the comparator calls them
|
|
331
|
+
* equal; a custom pair may agree on equality and disagree on order.
|
|
332
|
+
*
|
|
333
|
+
* A never-text column is exempt: its key bytes are type-native and collation-independent.
|
|
334
|
+
*
|
|
335
|
+
* Returning `false` costs an optimization (the caller full-scans and lets the
|
|
336
|
+
* collation-aware `matchesFilters` residual decide); returning `true` wrongly is a silent
|
|
337
|
+
* wrong-result. Shared by `StoreTable`'s read arms and `StoreModule`'s access planner so the
|
|
338
|
+
* "mark handled" and "build a window" decisions can never disagree.
|
|
339
|
+
*
|
|
340
|
+
* The PK caller ({@link pkOrderPreservingPrefixLength}) can genuinely pass two DIFFERENT
|
|
341
|
+
* collations, because {@link resolvePkKeyCollations} still falls back to the table key
|
|
342
|
+
* collation K for an undecorated text PK member. The secondary-index caller
|
|
343
|
+
* ({@link indexLeadingRangeIsOrderSafe}) usually passes the same name on both sides — index
|
|
344
|
+
* key bytes encode under the index column's own effective collation, which is what the scan
|
|
345
|
+
* residual re-compares under — so for a `text` or `any` column it reduces to the
|
|
346
|
+
* `orderPreserving` assertion alone. The one index shape where the two sides still differ is
|
|
347
|
+
* a collation-blind column (`json`, the temporal types) under an index column carrying an
|
|
348
|
+
* explicit non-BINARY COLLATE (index DDL does not type-gate the way column DDL does): its
|
|
349
|
+
* key bytes are hard-`BINARY` while its residual compares under the declared name, and this
|
|
350
|
+
* predicate correctly declines it.
|
|
351
|
+
*/
|
|
352
|
+
export function keyOrderMatchesCollation(db, column, keyCollation, compareCollation) {
|
|
353
|
+
// A semantic-ordering logical type (TIMESPAN, JSON — see docs/types.md "Semantic
|
|
354
|
+
// ordering") is ordered by its `compare` (elapsed time / structural), which the
|
|
355
|
+
// engine's Sort, comparison operators, and the memory backend all use. Byte order
|
|
356
|
+
// stands in for that order only for the types `semanticKeyOrderIsFaithful` asserts
|
|
357
|
+
// it for; any other semantic-ordering type keeps the blanket decline — no byte
|
|
358
|
+
// window, no ordering advertisement, full scan + the type-aware residual. A
|
|
359
|
+
// faithful type FALLS THROUGH to the collation checks below rather than returning
|
|
360
|
+
// true: `logicalTypeCanHoldText` admits both types (json is OBJECT-physical but
|
|
361
|
+
// text-capable; timespan is TEXT-physical), and the collation comparison is what
|
|
362
|
+
// correctly declines a collation-blind column under an INDEX column carrying an
|
|
363
|
+
// explicit non-BINARY COLLATE (index DDL does not type-gate the way column DDL
|
|
364
|
+
// does) — its key bytes are hard-BINARY while the residual re-compares under the
|
|
365
|
+
// declared name. Seek BOUNDS additionally pass through the per-value
|
|
366
|
+
// `semanticProbeIsKeyFaithful` gate at window-build time.
|
|
367
|
+
if (hasSemanticOrdering(column?.logicalType) && !semanticKeyOrderIsFaithful(column?.logicalType))
|
|
368
|
+
return false;
|
|
369
|
+
if (!columnCanHoldText(column))
|
|
370
|
+
return true;
|
|
371
|
+
if (compareCollation.toUpperCase() !== keyCollation.toUpperCase())
|
|
372
|
+
return false;
|
|
373
|
+
return db._isCollationOrderPreserving(keyCollation);
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* The collation `StoreTableScan.matchesFilters` re-compares index position `position`
|
|
377
|
+
* under — the index column's own `COLLATE`, else the table column's declared collation,
|
|
378
|
+
* else BINARY (see `indexColumnCollations`). The same resolution the planner used when it
|
|
379
|
+
* decided the residual Filter could be dropped, so it is the order/equality a byte window
|
|
380
|
+
* over that position has to reproduce.
|
|
381
|
+
*
|
|
382
|
+
* NOTE: this duplicates {@link resolveIndexKeyCollations}' collation-aware branch — same
|
|
383
|
+
* three-step fallback, same BINARY default — which is why both gates below admit every
|
|
384
|
+
* `text` and `any` column. Change either fallback without the other and the gates start
|
|
385
|
+
* declining (or, worse, admitting) shapes nobody intended; keep the two in step.
|
|
386
|
+
*/
|
|
387
|
+
function indexResidualCollation(columns, index, position) {
|
|
388
|
+
const spec = index.columns[position];
|
|
389
|
+
return (spec?.collation ?? columns[spec?.index ?? -1]?.collation ?? 'BINARY').toUpperCase();
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* True when an EQUALITY/prefix byte window over the leading `prefixLength` columns of
|
|
393
|
+
* secondary `index` is EXACTLY the qualifying set — the condition under which the access
|
|
394
|
+
* planner may claim the equality filters handled and drop the residual Filter.
|
|
395
|
+
*
|
|
396
|
+
* `keyCollations` is {@link resolveIndexKeyCollations}' output for `index` (the scan passes
|
|
397
|
+
* its memoized copy, the access planner resolves one on the spot): the collation each
|
|
398
|
+
* position's key bytes are ACTUALLY encoded under. The window equals the qualifying set iff
|
|
399
|
+
* that agrees, per position, with {@link indexResidualCollation}.
|
|
400
|
+
*
|
|
401
|
+
* For a `text` or `any` column the two agree by construction — both resolve to the index
|
|
402
|
+
* `COLLATE` else the declared collation else BINARY — so those admit, including the
|
|
403
|
+
* `text` column of a table whose key collation K is something else entirely, and an
|
|
404
|
+
* `x any collate nocase` index column (whose window is now genuinely the NOCASE-equal
|
|
405
|
+
* set — ANY's `compare` honors the collation, so key bytes, residual, and enforcement
|
|
406
|
+
* all agree). The shape that does NOT agree is a collation-blind column (`json`, the
|
|
407
|
+
* temporal types) under an index column carrying an explicit non-BINARY COLLATE:
|
|
408
|
+
* `pkKeyCollationName` keys those hard-`BINARY` while the residual still compares under
|
|
409
|
+
* the declared name, so the window would be byte-equal only and miss rows the residual
|
|
410
|
+
* admits — declined. Never-text columns are exempt — their key bytes are type-native.
|
|
411
|
+
*/
|
|
412
|
+
export function indexPrefixSeekIsCollationExact(columns, index, keyCollations, prefixLength) {
|
|
413
|
+
for (let i = 0; i < prefixLength; i++) {
|
|
414
|
+
const spec = index.columns[i];
|
|
415
|
+
if (!spec)
|
|
416
|
+
return false;
|
|
417
|
+
if (!columnCanHoldText(columns[spec.index]))
|
|
418
|
+
continue;
|
|
419
|
+
if ((keyCollations[i] ?? 'BINARY').toUpperCase() !== indexResidualCollation(columns, index, i))
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* True when a byte RANGE window over the LEADING column of secondary `index` is SOUND.
|
|
426
|
+
*
|
|
427
|
+
* Strictly stronger than {@link indexPrefixSeekIsCollationExact} at position 0: the same
|
|
428
|
+
* key-vs-residual collation agreement, PLUS the collation's `orderPreserving` assertion,
|
|
429
|
+
* because a range window also equates memcmp of the key bytes with the residual
|
|
430
|
+
* comparator's ORDER. Both halves are {@link keyOrderMatchesCollation}, which admits a
|
|
431
|
+
* semantic-ordering column only when {@link semanticKeyOrderIsFaithful} asserts its key
|
|
432
|
+
* bytes order as the type's `compare` does (and the collation sides agree — a `collate`
|
|
433
|
+
* decoration on the index column still declines it).
|
|
434
|
+
*
|
|
435
|
+
* THE shared predicate for the two decision sites: `tryIndexAccessPlan`
|
|
436
|
+
* (store-module-access-plan.ts) marks the range filters handled only when it holds, and
|
|
437
|
+
* `StoreTableScan.analyzeIndexAccess` builds a window only when it holds. They must agree —
|
|
438
|
+
* a plan that claims a filter the scan then declines to window loses the residual Filter and
|
|
439
|
+
* returns the whole table — so they call this rather than each restating it.
|
|
440
|
+
*/
|
|
441
|
+
export function indexLeadingRangeIsOrderSafe(db, columns, index, keyCollations) {
|
|
442
|
+
const leading = index.columns[0];
|
|
443
|
+
if (!leading)
|
|
444
|
+
return false;
|
|
445
|
+
return keyOrderMatchesCollation(db, columns[leading.index], keyCollations[0] ?? 'BINARY', indexResidualCollation(columns, index, 0));
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* How many LEADING primary-key members have key bytes whose memcmp order matches their
|
|
449
|
+
* declared collation's comparator order, per {@link keyOrderMatchesCollation}.
|
|
450
|
+
*
|
|
451
|
+
* `pkKeyCollations` is {@link resolvePkKeyCollations}' output for this table; an `undefined`
|
|
452
|
+
* entry belongs to a never-text member, which {@link keyOrderMatchesCollation} exempts
|
|
453
|
+
* outright — `tableKeyCollation` is passed only so the exempt branch has a name to ignore.
|
|
454
|
+
* The comparison collation is the column's declared one, which `reconcilePkCollations` has
|
|
455
|
+
* already aligned with the key collation for every *textual* PK member.
|
|
456
|
+
*
|
|
457
|
+
* What the advertisement is measured against is the order the planner's `Sort` would have
|
|
458
|
+
* produced. For most members Sort orders under the operand's COLLATION, so a collation match
|
|
459
|
+
* is the question; for a member whose logical type carries SEMANTIC ordering (TIMESPAN, JSON
|
|
460
|
+
* — see docs/types.md "Semantic ordering") Sort ranks by `logicalType.compare`, and the
|
|
461
|
+
* member counts only when {@link semanticKeyOrderIsFaithful} asserts the stored key bytes
|
|
462
|
+
* memcmp in exactly that order (TIMESPAN's total-seconds transform, JSON's structural
|
|
463
|
+
* encoding). A semantic-ordering type outside that allow-list breaks the prefix, and the
|
|
464
|
+
* memory backend's typed BTree order remains the canonical order for it.
|
|
465
|
+
*
|
|
466
|
+
* `0` ⇒ even the leading member is unsafe: no range seek, no PK-order advertisement.
|
|
467
|
+
* A prefix shorter than the PK truncates the ordering advertisement rather than voiding it.
|
|
468
|
+
*/
|
|
469
|
+
export function pkOrderPreservingPrefixLength(db, schema, pkKeyCollations, tableKeyCollation) {
|
|
470
|
+
const pk = schema.primaryKeyDefinition;
|
|
471
|
+
let n = 0;
|
|
472
|
+
while (n < pk.length) {
|
|
473
|
+
const col = schema.columns[pk[n].index];
|
|
474
|
+
const keyCollation = pkKeyCollations[n] ?? tableKeyCollation;
|
|
475
|
+
if (!keyOrderMatchesCollation(db, col, keyCollation, col?.collation ?? 'BINARY'))
|
|
476
|
+
break;
|
|
477
|
+
n++;
|
|
478
|
+
}
|
|
479
|
+
return n;
|
|
480
|
+
}
|
|
481
|
+
//# sourceMappingURL=pk-key-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pk-key-resolution.js","sourceRoot":"","sources":["../../../src/common/pk-key-resolution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access planning for a store-backed table: which physical access path
|
|
3
|
+
* (`_primary_` point / range seek, a secondary-index seek or multi-seek, or a full
|
|
4
|
+
* scan) this module advertises for a pushed predicate, which of the pushed filters it
|
|
5
|
+
* claims as handled, and what ordering the chosen path provides.
|
|
6
|
+
*
|
|
7
|
+
* The mirror of `store-table-scan.ts`: the planner here decides which access path to
|
|
8
|
+
* advertise, and the scan layer there executes it. A plan that claims a filter the scan
|
|
9
|
+
* cannot honor drops the residual Filter and returns wrong rows, so every soundness
|
|
10
|
+
* predicate the two share lives in `pk-key-resolution.ts` (`keyOrderMatchesCollation`,
|
|
11
|
+
* `indexLeadingRangeIsOrderSafe`, `pkOrderPreservingPrefixLength`) rather than being
|
|
12
|
+
* restated here. The declines that are NOT shared — partial indexes, the multi-seek cap,
|
|
13
|
+
* and the semantic-ordering column ban on multi-seeks specifically — are stated in both
|
|
14
|
+
* files, and changing one means changing the other.
|
|
15
|
+
*
|
|
16
|
+
* Free functions rather than a layer of the store-module chain — access planning reads
|
|
17
|
+
* no module state beyond the table's configured key collation, which the caller passes in.
|
|
18
|
+
*/
|
|
19
|
+
import type { BestAccessPlanRequest, BestAccessPlanResult, Database, TableSchema } from '@quereus/quereus';
|
|
20
|
+
/**
|
|
21
|
+
* The access plan this module advertises for `request`, before the caller stamps the
|
|
22
|
+
* module-wide `honorsCollatedRangeBounds` flag onto it.
|
|
23
|
+
*
|
|
24
|
+
* `tableKeyCollation` is the table's resolved key collation K, passed in rather than
|
|
25
|
+
* looked up: the caller (`StoreModule.getBestAccessPlan`) owns the module's table map.
|
|
26
|
+
* It is the PRIMARY-KEY arms' concern only — `resolvePkKeyCollations` still falls back to
|
|
27
|
+
* K for an undecorated text PK member. The secondary-index arm never sees it: index key
|
|
28
|
+
* bytes encode under each index column's own collation, so {@link tryIndexAccessPlan}
|
|
29
|
+
* judges its filters against that instead.
|
|
30
|
+
*/
|
|
31
|
+
export declare function computeBestAccessPlan(db: Database, tableInfo: TableSchema, request: BestAccessPlanRequest, tableKeyCollation: string): BestAccessPlanResult;
|
|
32
|
+
//# sourceMappingURL=store-module-access-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-module-access-plan.d.ts","sourceRoot":"","sources":["../../../src/common/store-module-access-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACX,qBAAqB,EACrB,oBAAoB,EACpB,QAAQ,EAIR,WAAW,EACX,MAAM,kBAAkB,CAAC;AAoG1B;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACpC,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,qBAAqB,EAC9B,iBAAiB,EAAE,MAAM,GACvB,oBAAoB,CAoHtB"}
|