@tanstack/db 0.5.23 → 0.5.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/collection/change-events.cjs +1 -1
- package/dist/cjs/collection/change-events.cjs.map +1 -1
- package/dist/cjs/collection/changes.cjs +6 -1
- package/dist/cjs/collection/changes.cjs.map +1 -1
- package/dist/cjs/collection/lifecycle.cjs +11 -0
- package/dist/cjs/collection/lifecycle.cjs.map +1 -1
- package/dist/cjs/collection/subscription.cjs +18 -5
- package/dist/cjs/collection/subscription.cjs.map +1 -1
- package/dist/cjs/collection/subscription.d.cts +7 -1
- package/dist/cjs/indexes/base-index.cjs.map +1 -1
- package/dist/cjs/indexes/base-index.d.cts +10 -6
- package/dist/cjs/indexes/btree-index.cjs +64 -24
- package/dist/cjs/indexes/btree-index.cjs.map +1 -1
- package/dist/cjs/indexes/btree-index.d.cts +31 -9
- package/dist/cjs/indexes/reverse-index.cjs +6 -0
- package/dist/cjs/indexes/reverse-index.cjs.map +1 -1
- package/dist/cjs/indexes/reverse-index.d.cts +4 -2
- package/dist/cjs/query/builder/index.cjs +2 -2
- package/dist/cjs/query/builder/index.cjs.map +1 -1
- package/dist/cjs/query/live/collection-config-builder.cjs +4 -1
- package/dist/cjs/query/live/collection-config-builder.cjs.map +1 -1
- package/dist/cjs/query/live/collection-subscriber.cjs +111 -30
- package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
- package/dist/cjs/query/live/collection-subscriber.d.cts +5 -0
- package/dist/cjs/types.d.cts +16 -0
- package/dist/cjs/utils/comparison.cjs +16 -0
- package/dist/cjs/utils/comparison.cjs.map +1 -1
- package/dist/cjs/utils/comparison.d.cts +21 -0
- package/dist/esm/collection/change-events.js +1 -1
- package/dist/esm/collection/change-events.js.map +1 -1
- package/dist/esm/collection/changes.js +6 -1
- package/dist/esm/collection/changes.js.map +1 -1
- package/dist/esm/collection/lifecycle.js +11 -0
- package/dist/esm/collection/lifecycle.js.map +1 -1
- package/dist/esm/collection/subscription.d.ts +7 -1
- package/dist/esm/collection/subscription.js +18 -5
- package/dist/esm/collection/subscription.js.map +1 -1
- package/dist/esm/indexes/base-index.d.ts +10 -6
- package/dist/esm/indexes/base-index.js.map +1 -1
- package/dist/esm/indexes/btree-index.d.ts +31 -9
- package/dist/esm/indexes/btree-index.js +65 -25
- package/dist/esm/indexes/btree-index.js.map +1 -1
- package/dist/esm/indexes/reverse-index.d.ts +4 -2
- package/dist/esm/indexes/reverse-index.js +6 -0
- package/dist/esm/indexes/reverse-index.js.map +1 -1
- package/dist/esm/query/builder/index.js +2 -2
- package/dist/esm/query/builder/index.js.map +1 -1
- package/dist/esm/query/live/collection-config-builder.js +4 -1
- package/dist/esm/query/live/collection-config-builder.js.map +1 -1
- package/dist/esm/query/live/collection-subscriber.d.ts +5 -0
- package/dist/esm/query/live/collection-subscriber.js +112 -31
- package/dist/esm/query/live/collection-subscriber.js.map +1 -1
- package/dist/esm/types.d.ts +16 -0
- package/dist/esm/utils/comparison.d.ts +21 -0
- package/dist/esm/utils/comparison.js +16 -0
- package/dist/esm/utils/comparison.js.map +1 -1
- package/package.json +1 -1
- package/src/collection/change-events.ts +1 -1
- package/src/collection/changes.ts +6 -1
- package/src/collection/lifecycle.ts +14 -0
- package/src/collection/subscription.ts +38 -10
- package/src/indexes/base-index.ts +19 -6
- package/src/indexes/btree-index.ts +101 -30
- package/src/indexes/reverse-index.ts +13 -2
- package/src/query/builder/index.ts +4 -4
- package/src/query/live/collection-config-builder.ts +4 -5
- package/src/query/live/collection-subscriber.ts +173 -50
- package/src/types.ts +16 -0
- package/src/utils/comparison.ts +34 -0
|
@@ -19,7 +19,7 @@ export interface IndexStats {
|
|
|
19
19
|
readonly averageLookupTime: number;
|
|
20
20
|
readonly lastUpdated: Date;
|
|
21
21
|
}
|
|
22
|
-
export interface IndexInterface<TKey extends string | number = string | number> {
|
|
22
|
+
export interface IndexInterface<TKey extends string | number | undefined = string | number | undefined> {
|
|
23
23
|
add: (key: TKey, item: any) => void;
|
|
24
24
|
remove: (key: TKey, item: any) => void;
|
|
25
25
|
update: (key: TKey, oldItem: any, newItem: any) => void;
|
|
@@ -30,8 +30,10 @@ export interface IndexInterface<TKey extends string | number = string | number>
|
|
|
30
30
|
inArrayLookup: (values: Array<any>) => Set<TKey>;
|
|
31
31
|
rangeQuery: (options: RangeQueryOptions) => Set<TKey>;
|
|
32
32
|
rangeQueryReversed: (options: RangeQueryOptions) => Set<TKey>;
|
|
33
|
-
take: (n: number, from
|
|
34
|
-
|
|
33
|
+
take: (n: number, from: TKey, filterFn?: (key: TKey) => boolean) => Array<TKey>;
|
|
34
|
+
takeFromStart: (n: number, filterFn?: (key: TKey) => boolean) => Array<TKey>;
|
|
35
|
+
takeReversed: (n: number, from: TKey, filterFn?: (key: TKey) => boolean) => Array<TKey>;
|
|
36
|
+
takeReversedFromEnd: (n: number, filterFn?: (key: TKey) => boolean) => Array<TKey>;
|
|
35
37
|
get keyCount(): number;
|
|
36
38
|
get orderedEntriesArray(): Array<[any, Set<TKey>]>;
|
|
37
39
|
get orderedEntriesArrayReversed(): Array<[any, Set<TKey>]>;
|
|
@@ -46,7 +48,7 @@ export interface IndexInterface<TKey extends string | number = string | number>
|
|
|
46
48
|
/**
|
|
47
49
|
* Base abstract class that all index types extend
|
|
48
50
|
*/
|
|
49
|
-
export declare abstract class BaseIndex<TKey extends string | number = string | number> implements IndexInterface<TKey> {
|
|
51
|
+
export declare abstract class BaseIndex<TKey extends string | number | undefined = string | number | undefined> implements IndexInterface<TKey> {
|
|
50
52
|
readonly id: number;
|
|
51
53
|
readonly name?: string;
|
|
52
54
|
readonly expression: BasicExpression;
|
|
@@ -62,8 +64,10 @@ export declare abstract class BaseIndex<TKey extends string | number = string |
|
|
|
62
64
|
abstract build(entries: Iterable<[TKey, any]>): void;
|
|
63
65
|
abstract clear(): void;
|
|
64
66
|
abstract lookup(operation: IndexOperation, value: any): Set<TKey>;
|
|
65
|
-
abstract take(n: number, from
|
|
66
|
-
abstract
|
|
67
|
+
abstract take(n: number, from: TKey, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
68
|
+
abstract takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
69
|
+
abstract takeReversed(n: number, from: TKey, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
70
|
+
abstract takeReversedFromEnd(n: number, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
67
71
|
abstract get keyCount(): number;
|
|
68
72
|
abstract equalityLookup(value: any): Set<TKey>;
|
|
69
73
|
abstract inArrayLookup(values: Array<any>): Set<TKey>;
|
|
@@ -18,7 +18,8 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
18
18
|
this.valueMap = /* @__PURE__ */ new Map();
|
|
19
19
|
this.indexedKeys = /* @__PURE__ */ new Set();
|
|
20
20
|
this.compareFn = comparison.defaultComparator;
|
|
21
|
-
|
|
21
|
+
const baseCompareFn = options?.compareFn ?? comparison.defaultComparator;
|
|
22
|
+
this.compareFn = (a, b) => baseCompareFn(comparison.denormalizeUndefined(a), comparison.denormalizeUndefined(b));
|
|
22
23
|
if (options?.compareOptions) {
|
|
23
24
|
this.compareOptions = options.compareOptions;
|
|
24
25
|
}
|
|
@@ -38,7 +39,7 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
38
39
|
`Failed to evaluate index expression for key ${key}: ${error}`
|
|
39
40
|
);
|
|
40
41
|
}
|
|
41
|
-
const normalizedValue = comparison.
|
|
42
|
+
const normalizedValue = comparison.normalizeForBTree(indexedValue);
|
|
42
43
|
if (this.valueMap.has(normalizedValue)) {
|
|
43
44
|
this.valueMap.get(normalizedValue).add(key);
|
|
44
45
|
} else {
|
|
@@ -63,7 +64,7 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
63
64
|
);
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
|
-
const normalizedValue = comparison.
|
|
67
|
+
const normalizedValue = comparison.normalizeForBTree(indexedValue);
|
|
67
68
|
if (this.valueMap.has(normalizedValue)) {
|
|
68
69
|
const keySet = this.valueMap.get(normalizedValue);
|
|
69
70
|
keySet.delete(key);
|
|
@@ -142,7 +143,7 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
142
143
|
* Performs an equality lookup
|
|
143
144
|
*/
|
|
144
145
|
equalityLookup(value) {
|
|
145
|
-
const normalizedValue = comparison.
|
|
146
|
+
const normalizedValue = comparison.normalizeForBTree(value);
|
|
146
147
|
return new Set(this.valueMap.get(normalizedValue) ?? []);
|
|
147
148
|
}
|
|
148
149
|
/**
|
|
@@ -152,10 +153,10 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
152
153
|
rangeQuery(options = {}) {
|
|
153
154
|
const { from, to, fromInclusive = true, toInclusive = true } = options;
|
|
154
155
|
const result = /* @__PURE__ */ new Set();
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
const fromKey =
|
|
158
|
-
const toKey =
|
|
156
|
+
const hasFrom = `from` in options;
|
|
157
|
+
const hasTo = `to` in options;
|
|
158
|
+
const fromKey = hasFrom ? comparison.normalizeForBTree(from) : this.orderedEntries.minKey();
|
|
159
|
+
const toKey = hasTo ? comparison.normalizeForBTree(to) : this.orderedEntries.maxKey();
|
|
159
160
|
this.orderedEntries.forRange(
|
|
160
161
|
fromKey,
|
|
161
162
|
toKey,
|
|
@@ -177,18 +178,28 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
177
178
|
*/
|
|
178
179
|
rangeQueryReversed(options = {}) {
|
|
179
180
|
const { from, to, fromInclusive = true, toInclusive = true } = options;
|
|
181
|
+
const hasFrom = `from` in options;
|
|
182
|
+
const hasTo = `to` in options;
|
|
180
183
|
return this.rangeQuery({
|
|
181
|
-
from: to
|
|
182
|
-
to: from
|
|
184
|
+
from: hasTo ? to : this.orderedEntries.maxKey(),
|
|
185
|
+
to: hasFrom ? from : this.orderedEntries.minKey(),
|
|
183
186
|
fromInclusive: toInclusive,
|
|
184
187
|
toInclusive: fromInclusive
|
|
185
188
|
});
|
|
186
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Internal method for taking items from the index.
|
|
192
|
+
* @param n - The number of items to return
|
|
193
|
+
* @param nextPair - Function to get the next pair from the BTree
|
|
194
|
+
* @param from - Already normalized! undefined means "start from beginning/end", sentinel means "start from the key undefined"
|
|
195
|
+
* @param filterFn - Optional filter function
|
|
196
|
+
* @param reversed - Whether to reverse the order of keys within each value
|
|
197
|
+
*/
|
|
187
198
|
takeInternal(n, nextPair, from, filterFn, reversed = false) {
|
|
188
199
|
const keysInResult = /* @__PURE__ */ new Set();
|
|
189
200
|
const result = [];
|
|
190
201
|
let pair;
|
|
191
|
-
let key =
|
|
202
|
+
let key = from;
|
|
192
203
|
while ((pair = nextPair(key)) !== void 0 && result.length < n) {
|
|
193
204
|
key = pair[0];
|
|
194
205
|
const keys = this.valueMap.get(key);
|
|
@@ -207,24 +218,46 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
207
218
|
return result;
|
|
208
219
|
}
|
|
209
220
|
/**
|
|
210
|
-
* Returns the next n items after the provided item
|
|
221
|
+
* Returns the next n items after the provided item.
|
|
211
222
|
* @param n - The number of items to return
|
|
212
|
-
* @param from - The item to start from (exclusive).
|
|
213
|
-
* @returns The next n items after the provided key.
|
|
223
|
+
* @param from - The item to start from (exclusive).
|
|
224
|
+
* @returns The next n items after the provided key.
|
|
214
225
|
*/
|
|
215
226
|
take(n, from, filterFn) {
|
|
216
227
|
const nextPair = (k) => this.orderedEntries.nextHigherPair(k);
|
|
217
|
-
|
|
228
|
+
const normalizedFrom = comparison.normalizeForBTree(from);
|
|
229
|
+
return this.takeInternal(n, nextPair, normalizedFrom, filterFn);
|
|
218
230
|
}
|
|
219
231
|
/**
|
|
220
|
-
* Returns the
|
|
232
|
+
* Returns the first n items from the beginning.
|
|
221
233
|
* @param n - The number of items to return
|
|
222
|
-
* @param
|
|
223
|
-
* @returns The
|
|
234
|
+
* @param filterFn - Optional filter function
|
|
235
|
+
* @returns The first n items
|
|
236
|
+
*/
|
|
237
|
+
takeFromStart(n, filterFn) {
|
|
238
|
+
const nextPair = (k) => this.orderedEntries.nextHigherPair(k);
|
|
239
|
+
return this.takeInternal(n, nextPair, void 0, filterFn);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Returns the next n items **before** the provided item (in descending order).
|
|
243
|
+
* @param n - The number of items to return
|
|
244
|
+
* @param from - The item to start from (exclusive). Required.
|
|
245
|
+
* @returns The next n items **before** the provided key.
|
|
224
246
|
*/
|
|
225
247
|
takeReversed(n, from, filterFn) {
|
|
226
248
|
const nextPair = (k) => this.orderedEntries.nextLowerPair(k);
|
|
227
|
-
|
|
249
|
+
const normalizedFrom = comparison.normalizeForBTree(from);
|
|
250
|
+
return this.takeInternal(n, nextPair, normalizedFrom, filterFn, true);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Returns the last n items from the end.
|
|
254
|
+
* @param n - The number of items to return
|
|
255
|
+
* @param filterFn - Optional filter function
|
|
256
|
+
* @returns The last n items
|
|
257
|
+
*/
|
|
258
|
+
takeReversedFromEnd(n, filterFn) {
|
|
259
|
+
const nextPair = (k) => this.orderedEntries.nextLowerPair(k);
|
|
260
|
+
return this.takeInternal(n, nextPair, void 0, filterFn, true);
|
|
228
261
|
}
|
|
229
262
|
/**
|
|
230
263
|
* Performs an IN array lookup
|
|
@@ -232,7 +265,7 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
232
265
|
inArrayLookup(values) {
|
|
233
266
|
const result = /* @__PURE__ */ new Set();
|
|
234
267
|
for (const value of values) {
|
|
235
|
-
const normalizedValue = comparison.
|
|
268
|
+
const normalizedValue = comparison.normalizeForBTree(value);
|
|
236
269
|
const keys = this.valueMap.get(normalizedValue);
|
|
237
270
|
if (keys) {
|
|
238
271
|
keys.forEach((key) => result.add(key));
|
|
@@ -245,16 +278,23 @@ class BTreeIndex extends baseIndex.BaseIndex {
|
|
|
245
278
|
return this.indexedKeys;
|
|
246
279
|
}
|
|
247
280
|
get orderedEntriesArray() {
|
|
248
|
-
return this.orderedEntries.keysArray().map((key) => [
|
|
281
|
+
return this.orderedEntries.keysArray().map((key) => [
|
|
282
|
+
comparison.denormalizeUndefined(key),
|
|
283
|
+
this.valueMap.get(key) ?? /* @__PURE__ */ new Set()
|
|
284
|
+
]);
|
|
249
285
|
}
|
|
250
286
|
get orderedEntriesArrayReversed() {
|
|
251
|
-
return this.
|
|
252
|
-
key,
|
|
287
|
+
return this.takeReversedFromEnd(this.orderedEntries.size).map((key) => [
|
|
288
|
+
comparison.denormalizeUndefined(key),
|
|
253
289
|
this.valueMap.get(key) ?? /* @__PURE__ */ new Set()
|
|
254
290
|
]);
|
|
255
291
|
}
|
|
256
292
|
get valueMapData() {
|
|
257
|
-
|
|
293
|
+
const result = /* @__PURE__ */ new Map();
|
|
294
|
+
for (const [key, value] of this.valueMap) {
|
|
295
|
+
result.set(comparison.denormalizeUndefined(key), value);
|
|
296
|
+
}
|
|
297
|
+
return result;
|
|
258
298
|
}
|
|
259
299
|
}
|
|
260
300
|
exports.BTreeIndex = BTreeIndex;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"btree-index.cjs","sources":["../../../src/indexes/btree-index.ts"],"sourcesContent":["import { compareKeys } from '@tanstack/db-ivm'\nimport { BTree } from '../utils/btree.js'\nimport { defaultComparator, normalizeValue } from '../utils/comparison.js'\nimport { BaseIndex } from './base-index.js'\nimport type { CompareOptions } from '../query/builder/types.js'\nimport type { BasicExpression } from '../query/ir.js'\nimport type { IndexOperation } from './base-index.js'\n\n/**\n * Options for Ordered index\n */\nexport interface BTreeIndexOptions {\n compareFn?: (a: any, b: any) => number\n compareOptions?: CompareOptions\n}\n\n/**\n * Options for range queries\n */\nexport interface RangeQueryOptions {\n from?: any\n to?: any\n fromInclusive?: boolean\n toInclusive?: boolean\n}\n\n/**\n * B+Tree index for sorted data with range queries\n * This maintains items in sorted order and provides efficient range operations\n */\nexport class BTreeIndex<\n TKey extends string | number = string | number,\n> extends BaseIndex<TKey> {\n public readonly supportedOperations = new Set<IndexOperation>([\n `eq`,\n `gt`,\n `gte`,\n `lt`,\n `lte`,\n `in`,\n ])\n\n // Internal data structures - private to hide implementation details\n // The `orderedEntries` B+ tree is used for efficient range queries\n // The `valueMap` is used for O(1) lookups of PKs by indexed value\n private orderedEntries: BTree<any, undefined> // we don't associate values with the keys of the B+ tree (the keys are indexed values)\n private valueMap = new Map<any, Set<TKey>>() // instead we store a mapping of indexed values to a set of PKs\n private indexedKeys = new Set<TKey>()\n private compareFn: (a: any, b: any) => number = defaultComparator\n\n constructor(\n id: number,\n expression: BasicExpression,\n name?: string,\n options?: any,\n ) {\n super(id, expression, name, options)\n this.compareFn = options?.compareFn ?? defaultComparator\n if (options?.compareOptions) {\n this.compareOptions = options!.compareOptions\n }\n this.orderedEntries = new BTree(this.compareFn)\n }\n\n protected initialize(_options?: BTreeIndexOptions): void {}\n\n /**\n * Adds a value to the index\n */\n add(key: TKey, item: any): void {\n let indexedValue: any\n try {\n indexedValue = this.evaluateIndexExpression(item)\n } catch (error) {\n throw new Error(\n `Failed to evaluate index expression for key ${key}: ${error}`,\n )\n }\n\n // Normalize the value for Map key usage\n const normalizedValue = normalizeValue(indexedValue)\n\n // Check if this value already exists\n if (this.valueMap.has(normalizedValue)) {\n // Add to existing set\n this.valueMap.get(normalizedValue)!.add(key)\n } else {\n // Create new set for this value\n const keySet = new Set<TKey>([key])\n this.valueMap.set(normalizedValue, keySet)\n this.orderedEntries.set(normalizedValue, undefined)\n }\n\n this.indexedKeys.add(key)\n this.updateTimestamp()\n }\n\n /**\n * Removes a value from the index\n */\n remove(key: TKey, item: any): void {\n let indexedValue: any\n try {\n indexedValue = this.evaluateIndexExpression(item)\n } catch (error) {\n console.warn(\n `Failed to evaluate index expression for key ${key} during removal:`,\n error,\n )\n return\n }\n\n // Normalize the value for Map key usage\n const normalizedValue = normalizeValue(indexedValue)\n\n if (this.valueMap.has(normalizedValue)) {\n const keySet = this.valueMap.get(normalizedValue)!\n keySet.delete(key)\n\n // If set is now empty, remove the entry entirely\n if (keySet.size === 0) {\n this.valueMap.delete(normalizedValue)\n\n // Remove from ordered entries\n this.orderedEntries.delete(normalizedValue)\n }\n }\n\n this.indexedKeys.delete(key)\n this.updateTimestamp()\n }\n\n /**\n * Updates a value in the index\n */\n update(key: TKey, oldItem: any, newItem: any): void {\n this.remove(key, oldItem)\n this.add(key, newItem)\n }\n\n /**\n * Builds the index from a collection of entries\n */\n build(entries: Iterable<[TKey, any]>): void {\n this.clear()\n\n for (const [key, item] of entries) {\n this.add(key, item)\n }\n }\n\n /**\n * Clears all data from the index\n */\n clear(): void {\n this.orderedEntries.clear()\n this.valueMap.clear()\n this.indexedKeys.clear()\n this.updateTimestamp()\n }\n\n /**\n * Performs a lookup operation\n */\n lookup(operation: IndexOperation, value: any): Set<TKey> {\n const startTime = performance.now()\n\n let result: Set<TKey>\n\n switch (operation) {\n case `eq`:\n result = this.equalityLookup(value)\n break\n case `gt`:\n result = this.rangeQuery({ from: value, fromInclusive: false })\n break\n case `gte`:\n result = this.rangeQuery({ from: value, fromInclusive: true })\n break\n case `lt`:\n result = this.rangeQuery({ to: value, toInclusive: false })\n break\n case `lte`:\n result = this.rangeQuery({ to: value, toInclusive: true })\n break\n case `in`:\n result = this.inArrayLookup(value)\n break\n default:\n throw new Error(`Operation ${operation} not supported by BTreeIndex`)\n }\n\n this.trackLookup(startTime)\n return result\n }\n\n /**\n * Gets the number of indexed keys\n */\n get keyCount(): number {\n return this.indexedKeys.size\n }\n\n // Public methods for backward compatibility (used by tests)\n\n /**\n * Performs an equality lookup\n */\n equalityLookup(value: any): Set<TKey> {\n const normalizedValue = normalizeValue(value)\n return new Set(this.valueMap.get(normalizedValue) ?? [])\n }\n\n /**\n * Performs a range query with options\n * This is more efficient for compound queries like \"WHERE a > 5 AND a < 10\"\n */\n rangeQuery(options: RangeQueryOptions = {}): Set<TKey> {\n const { from, to, fromInclusive = true, toInclusive = true } = options\n const result = new Set<TKey>()\n\n const normalizedFrom = normalizeValue(from)\n const normalizedTo = normalizeValue(to)\n const fromKey = normalizedFrom ?? this.orderedEntries.minKey()\n const toKey = normalizedTo ?? this.orderedEntries.maxKey()\n\n this.orderedEntries.forRange(\n fromKey,\n toKey,\n toInclusive,\n (indexedValue, _) => {\n if (!fromInclusive && this.compareFn(indexedValue, from) === 0) {\n // the B+ tree `forRange` method does not support exclusive lower bounds\n // so we need to exclude it manually\n return\n }\n\n const keys = this.valueMap.get(indexedValue)\n if (keys) {\n keys.forEach((key) => result.add(key))\n }\n },\n )\n\n return result\n }\n\n /**\n * Performs a reversed range query\n */\n rangeQueryReversed(options: RangeQueryOptions = {}): Set<TKey> {\n const { from, to, fromInclusive = true, toInclusive = true } = options\n return this.rangeQuery({\n from: to ?? this.orderedEntries.maxKey(),\n to: from ?? this.orderedEntries.minKey(),\n fromInclusive: toInclusive,\n toInclusive: fromInclusive,\n })\n }\n\n private takeInternal(\n n: number,\n nextPair: (k?: any) => [any, any] | undefined,\n from?: any,\n filterFn?: (key: TKey) => boolean,\n reversed: boolean = false,\n ): Array<TKey> {\n const keysInResult: Set<TKey> = new Set()\n const result: Array<TKey> = []\n let pair: [any, any] | undefined\n let key = normalizeValue(from)\n\n while ((pair = nextPair(key)) !== undefined && result.length < n) {\n key = pair[0]\n const keys = this.valueMap.get(key)\n if (keys && keys.size > 0) {\n // Sort keys for deterministic order, reverse if needed\n const sorted = Array.from(keys).sort(compareKeys)\n if (reversed) sorted.reverse()\n for (const ks of sorted) {\n if (result.length >= n) break\n if (!keysInResult.has(ks) && (filterFn?.(ks) ?? true)) {\n result.push(ks)\n keysInResult.add(ks)\n }\n }\n }\n }\n\n return result\n }\n\n /**\n * Returns the next n items after the provided item or the first n items if no from item is provided.\n * @param n - The number of items to return\n * @param from - The item to start from (exclusive). Starts from the smallest item (inclusive) if not provided.\n * @returns The next n items after the provided key. Returns the first n items if no from item is provided.\n */\n take(n: number, from?: any, filterFn?: (key: TKey) => boolean): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextHigherPair(k)\n return this.takeInternal(n, nextPair, from, filterFn)\n }\n\n /**\n * Returns the next n items **before** the provided item (in descending order) or the last n items if no from item is provided.\n * @param n - The number of items to return\n * @param from - The item to start from (exclusive). Starts from the largest item (inclusive) if not provided.\n * @returns The next n items **before** the provided key. Returns the last n items if no from item is provided.\n */\n takeReversed(\n n: number,\n from?: any,\n filterFn?: (key: TKey) => boolean,\n ): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextLowerPair(k)\n return this.takeInternal(n, nextPair, from, filterFn, true)\n }\n\n /**\n * Performs an IN array lookup\n */\n inArrayLookup(values: Array<any>): Set<TKey> {\n const result = new Set<TKey>()\n\n for (const value of values) {\n const normalizedValue = normalizeValue(value)\n const keys = this.valueMap.get(normalizedValue)\n if (keys) {\n keys.forEach((key) => result.add(key))\n }\n }\n\n return result\n }\n\n // Getter methods for testing compatibility\n get indexedKeysSet(): Set<TKey> {\n return this.indexedKeys\n }\n\n get orderedEntriesArray(): Array<[any, Set<TKey>]> {\n return this.orderedEntries\n .keysArray()\n .map((key) => [key, this.valueMap.get(key) ?? new Set()])\n }\n\n get orderedEntriesArrayReversed(): Array<[any, Set<TKey>]> {\n return this.takeReversed(this.orderedEntries.size).map((key) => [\n key,\n this.valueMap.get(key) ?? new Set(),\n ])\n }\n\n get valueMapData(): Map<any, Set<TKey>> {\n return this.valueMap\n }\n}\n"],"names":["BaseIndex","defaultComparator","BTree","normalizeValue","compareKeys"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"btree-index.cjs","sources":["../../../src/indexes/btree-index.ts"],"sourcesContent":["import { compareKeys } from '@tanstack/db-ivm'\nimport { BTree } from '../utils/btree.js'\nimport {\n defaultComparator,\n denormalizeUndefined,\n normalizeForBTree,\n} from '../utils/comparison.js'\nimport { BaseIndex } from './base-index.js'\nimport type { CompareOptions } from '../query/builder/types.js'\nimport type { BasicExpression } from '../query/ir.js'\nimport type { IndexOperation } from './base-index.js'\n\n/**\n * Options for Ordered index\n */\nexport interface BTreeIndexOptions {\n compareFn?: (a: any, b: any) => number\n compareOptions?: CompareOptions\n}\n\n/**\n * Options for range queries\n */\nexport interface RangeQueryOptions {\n from?: any\n to?: any\n fromInclusive?: boolean\n toInclusive?: boolean\n}\n\n/**\n * B+Tree index for sorted data with range queries\n * This maintains items in sorted order and provides efficient range operations\n */\nexport class BTreeIndex<\n TKey extends string | number | undefined = string | number | undefined,\n> extends BaseIndex<TKey> {\n public readonly supportedOperations = new Set<IndexOperation>([\n `eq`,\n `gt`,\n `gte`,\n `lt`,\n `lte`,\n `in`,\n ])\n\n // Internal data structures - private to hide implementation details\n // The `orderedEntries` B+ tree is used for efficient range queries\n // The `valueMap` is used for O(1) lookups of PKs by indexed value\n private orderedEntries: BTree<any, undefined> // we don't associate values with the keys of the B+ tree (the keys are indexed values)\n private valueMap = new Map<any, Set<TKey>>() // instead we store a mapping of indexed values to a set of PKs\n private indexedKeys = new Set<TKey>()\n private compareFn: (a: any, b: any) => number = defaultComparator\n\n constructor(\n id: number,\n expression: BasicExpression,\n name?: string,\n options?: any,\n ) {\n super(id, expression, name, options)\n\n // Get the base compare function\n const baseCompareFn = options?.compareFn ?? defaultComparator\n\n // Wrap it to denormalize sentinels before comparison\n // This ensures UNDEFINED_SENTINEL is converted back to undefined\n // before being passed to the baseCompareFn (which can be user-provided and is unaware of the UNDEFINED_SENTINEL)\n this.compareFn = (a: any, b: any) =>\n baseCompareFn(denormalizeUndefined(a), denormalizeUndefined(b))\n\n if (options?.compareOptions) {\n this.compareOptions = options!.compareOptions\n }\n this.orderedEntries = new BTree(this.compareFn)\n }\n\n protected initialize(_options?: BTreeIndexOptions): void {}\n\n /**\n * Adds a value to the index\n */\n add(key: TKey, item: any): void {\n let indexedValue: any\n try {\n indexedValue = this.evaluateIndexExpression(item)\n } catch (error) {\n throw new Error(\n `Failed to evaluate index expression for key ${key}: ${error}`,\n )\n }\n\n // Normalize the value for Map key usage\n const normalizedValue = normalizeForBTree(indexedValue)\n\n // Check if this value already exists\n if (this.valueMap.has(normalizedValue)) {\n // Add to existing set\n this.valueMap.get(normalizedValue)!.add(key)\n } else {\n // Create new set for this value\n const keySet = new Set<TKey>([key])\n this.valueMap.set(normalizedValue, keySet)\n this.orderedEntries.set(normalizedValue, undefined)\n }\n\n this.indexedKeys.add(key)\n this.updateTimestamp()\n }\n\n /**\n * Removes a value from the index\n */\n remove(key: TKey, item: any): void {\n let indexedValue: any\n try {\n indexedValue = this.evaluateIndexExpression(item)\n } catch (error) {\n console.warn(\n `Failed to evaluate index expression for key ${key} during removal:`,\n error,\n )\n return\n }\n\n // Normalize the value for Map key usage\n const normalizedValue = normalizeForBTree(indexedValue)\n\n if (this.valueMap.has(normalizedValue)) {\n const keySet = this.valueMap.get(normalizedValue)!\n keySet.delete(key)\n\n // If set is now empty, remove the entry entirely\n if (keySet.size === 0) {\n this.valueMap.delete(normalizedValue)\n\n // Remove from ordered entries\n this.orderedEntries.delete(normalizedValue)\n }\n }\n\n this.indexedKeys.delete(key)\n this.updateTimestamp()\n }\n\n /**\n * Updates a value in the index\n */\n update(key: TKey, oldItem: any, newItem: any): void {\n this.remove(key, oldItem)\n this.add(key, newItem)\n }\n\n /**\n * Builds the index from a collection of entries\n */\n build(entries: Iterable<[TKey, any]>): void {\n this.clear()\n\n for (const [key, item] of entries) {\n this.add(key, item)\n }\n }\n\n /**\n * Clears all data from the index\n */\n clear(): void {\n this.orderedEntries.clear()\n this.valueMap.clear()\n this.indexedKeys.clear()\n this.updateTimestamp()\n }\n\n /**\n * Performs a lookup operation\n */\n lookup(operation: IndexOperation, value: any): Set<TKey> {\n const startTime = performance.now()\n\n let result: Set<TKey>\n\n switch (operation) {\n case `eq`:\n result = this.equalityLookup(value)\n break\n case `gt`:\n result = this.rangeQuery({ from: value, fromInclusive: false })\n break\n case `gte`:\n result = this.rangeQuery({ from: value, fromInclusive: true })\n break\n case `lt`:\n result = this.rangeQuery({ to: value, toInclusive: false })\n break\n case `lte`:\n result = this.rangeQuery({ to: value, toInclusive: true })\n break\n case `in`:\n result = this.inArrayLookup(value)\n break\n default:\n throw new Error(`Operation ${operation} not supported by BTreeIndex`)\n }\n\n this.trackLookup(startTime)\n return result\n }\n\n /**\n * Gets the number of indexed keys\n */\n get keyCount(): number {\n return this.indexedKeys.size\n }\n\n // Public methods for backward compatibility (used by tests)\n\n /**\n * Performs an equality lookup\n */\n equalityLookup(value: any): Set<TKey> {\n const normalizedValue = normalizeForBTree(value)\n return new Set(this.valueMap.get(normalizedValue) ?? [])\n }\n\n /**\n * Performs a range query with options\n * This is more efficient for compound queries like \"WHERE a > 5 AND a < 10\"\n */\n rangeQuery(options: RangeQueryOptions = {}): Set<TKey> {\n const { from, to, fromInclusive = true, toInclusive = true } = options\n const result = new Set<TKey>()\n\n // Check if from/to were explicitly provided (even if undefined)\n // vs not provided at all (should use min/max key)\n const hasFrom = `from` in options\n const hasTo = `to` in options\n\n const fromKey = hasFrom\n ? normalizeForBTree(from)\n : this.orderedEntries.minKey()\n const toKey = hasTo ? normalizeForBTree(to) : this.orderedEntries.maxKey()\n\n this.orderedEntries.forRange(\n fromKey,\n toKey,\n toInclusive,\n (indexedValue, _) => {\n if (!fromInclusive && this.compareFn(indexedValue, from) === 0) {\n // the B+ tree `forRange` method does not support exclusive lower bounds\n // so we need to exclude it manually\n return\n }\n\n const keys = this.valueMap.get(indexedValue)\n if (keys) {\n keys.forEach((key) => result.add(key))\n }\n },\n )\n\n return result\n }\n\n /**\n * Performs a reversed range query\n */\n rangeQueryReversed(options: RangeQueryOptions = {}): Set<TKey> {\n const { from, to, fromInclusive = true, toInclusive = true } = options\n const hasFrom = `from` in options\n const hasTo = `to` in options\n\n // Swap from/to for reversed query, respecting explicit undefined values\n return this.rangeQuery({\n from: hasTo ? to : this.orderedEntries.maxKey(),\n to: hasFrom ? from : this.orderedEntries.minKey(),\n fromInclusive: toInclusive,\n toInclusive: fromInclusive,\n })\n }\n\n /**\n * Internal method for taking items from the index.\n * @param n - The number of items to return\n * @param nextPair - Function to get the next pair from the BTree\n * @param from - Already normalized! undefined means \"start from beginning/end\", sentinel means \"start from the key undefined\"\n * @param filterFn - Optional filter function\n * @param reversed - Whether to reverse the order of keys within each value\n */\n private takeInternal(\n n: number,\n nextPair: (k?: any) => [any, any] | undefined,\n from: any,\n filterFn?: (key: TKey) => boolean,\n reversed: boolean = false,\n ): Array<TKey> {\n const keysInResult: Set<TKey> = new Set()\n const result: Array<TKey> = []\n let pair: [any, any] | undefined\n let key = from // Use as-is - it's already normalized by the caller\n\n while ((pair = nextPair(key)) !== undefined && result.length < n) {\n key = pair[0]\n const keys = this.valueMap.get(key) as\n | Set<Exclude<TKey, undefined>>\n | undefined\n if (keys && keys.size > 0) {\n // Sort keys for deterministic order, reverse if needed\n const sorted = Array.from(keys).sort(compareKeys)\n if (reversed) sorted.reverse()\n for (const ks of sorted) {\n if (result.length >= n) break\n if (!keysInResult.has(ks) && (filterFn?.(ks) ?? true)) {\n result.push(ks)\n keysInResult.add(ks)\n }\n }\n }\n }\n\n return result\n }\n\n /**\n * Returns the next n items after the provided item.\n * @param n - The number of items to return\n * @param from - The item to start from (exclusive).\n * @returns The next n items after the provided key.\n */\n take(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextHigherPair(k)\n // Normalize the from value\n const normalizedFrom = normalizeForBTree(from)\n return this.takeInternal(n, nextPair, normalizedFrom, filterFn)\n }\n\n /**\n * Returns the first n items from the beginning.\n * @param n - The number of items to return\n * @param filterFn - Optional filter function\n * @returns The first n items\n */\n takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextHigherPair(k)\n // Pass undefined to mean \"start from beginning\" (BTree's native behavior)\n return this.takeInternal(n, nextPair, undefined, filterFn)\n }\n\n /**\n * Returns the next n items **before** the provided item (in descending order).\n * @param n - The number of items to return\n * @param from - The item to start from (exclusive). Required.\n * @returns The next n items **before** the provided key.\n */\n takeReversed(\n n: number,\n from: any,\n filterFn?: (key: TKey) => boolean,\n ): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextLowerPair(k)\n // Normalize the from value\n const normalizedFrom = normalizeForBTree(from)\n return this.takeInternal(n, nextPair, normalizedFrom, filterFn, true)\n }\n\n /**\n * Returns the last n items from the end.\n * @param n - The number of items to return\n * @param filterFn - Optional filter function\n * @returns The last n items\n */\n takeReversedFromEnd(\n n: number,\n filterFn?: (key: TKey) => boolean,\n ): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextLowerPair(k)\n // Pass undefined to mean \"start from end\" (BTree's native behavior)\n return this.takeInternal(n, nextPair, undefined, filterFn, true)\n }\n\n /**\n * Performs an IN array lookup\n */\n inArrayLookup(values: Array<any>): Set<TKey> {\n const result = new Set<TKey>()\n\n for (const value of values) {\n const normalizedValue = normalizeForBTree(value)\n const keys = this.valueMap.get(normalizedValue)\n if (keys) {\n keys.forEach((key) => result.add(key))\n }\n }\n\n return result\n }\n\n // Getter methods for testing compatibility\n get indexedKeysSet(): Set<TKey> {\n return this.indexedKeys\n }\n\n get orderedEntriesArray(): Array<[any, Set<TKey>]> {\n return this.orderedEntries\n .keysArray()\n .map((key) => [\n denormalizeUndefined(key),\n this.valueMap.get(key) ?? new Set(),\n ])\n }\n\n get orderedEntriesArrayReversed(): Array<[any, Set<TKey>]> {\n return this.takeReversedFromEnd(this.orderedEntries.size).map((key) => [\n denormalizeUndefined(key),\n this.valueMap.get(key) ?? new Set(),\n ])\n }\n\n get valueMapData(): Map<any, Set<TKey>> {\n // Return a new Map with denormalized keys\n const result = new Map<any, Set<TKey>>()\n for (const [key, value] of this.valueMap) {\n result.set(denormalizeUndefined(key), value)\n }\n return result\n }\n}\n"],"names":["BaseIndex","defaultComparator","denormalizeUndefined","BTree","normalizeForBTree","compareKeys"],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ export interface RangeQueryOptions {
|
|
|
21
21
|
* B+Tree index for sorted data with range queries
|
|
22
22
|
* This maintains items in sorted order and provides efficient range operations
|
|
23
23
|
*/
|
|
24
|
-
export declare class BTreeIndex<TKey extends string | number = string | number> extends BaseIndex<TKey> {
|
|
24
|
+
export declare class BTreeIndex<TKey extends string | number | undefined = string | number | undefined> extends BaseIndex<TKey> {
|
|
25
25
|
readonly supportedOperations: Set<"eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "ilike">;
|
|
26
26
|
private orderedEntries;
|
|
27
27
|
private valueMap;
|
|
@@ -70,21 +70,43 @@ export declare class BTreeIndex<TKey extends string | number = string | number>
|
|
|
70
70
|
* Performs a reversed range query
|
|
71
71
|
*/
|
|
72
72
|
rangeQueryReversed(options?: RangeQueryOptions): Set<TKey>;
|
|
73
|
+
/**
|
|
74
|
+
* Internal method for taking items from the index.
|
|
75
|
+
* @param n - The number of items to return
|
|
76
|
+
* @param nextPair - Function to get the next pair from the BTree
|
|
77
|
+
* @param from - Already normalized! undefined means "start from beginning/end", sentinel means "start from the key undefined"
|
|
78
|
+
* @param filterFn - Optional filter function
|
|
79
|
+
* @param reversed - Whether to reverse the order of keys within each value
|
|
80
|
+
*/
|
|
73
81
|
private takeInternal;
|
|
74
82
|
/**
|
|
75
|
-
* Returns the next n items after the provided item
|
|
83
|
+
* Returns the next n items after the provided item.
|
|
84
|
+
* @param n - The number of items to return
|
|
85
|
+
* @param from - The item to start from (exclusive).
|
|
86
|
+
* @returns The next n items after the provided key.
|
|
87
|
+
*/
|
|
88
|
+
take(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
89
|
+
/**
|
|
90
|
+
* Returns the first n items from the beginning.
|
|
91
|
+
* @param n - The number of items to return
|
|
92
|
+
* @param filterFn - Optional filter function
|
|
93
|
+
* @returns The first n items
|
|
94
|
+
*/
|
|
95
|
+
takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
96
|
+
/**
|
|
97
|
+
* Returns the next n items **before** the provided item (in descending order).
|
|
76
98
|
* @param n - The number of items to return
|
|
77
|
-
* @param from - The item to start from (exclusive).
|
|
78
|
-
* @returns The next n items
|
|
99
|
+
* @param from - The item to start from (exclusive). Required.
|
|
100
|
+
* @returns The next n items **before** the provided key.
|
|
79
101
|
*/
|
|
80
|
-
|
|
102
|
+
takeReversed(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
81
103
|
/**
|
|
82
|
-
* Returns the
|
|
104
|
+
* Returns the last n items from the end.
|
|
83
105
|
* @param n - The number of items to return
|
|
84
|
-
* @param
|
|
85
|
-
* @returns The
|
|
106
|
+
* @param filterFn - Optional filter function
|
|
107
|
+
* @returns The last n items
|
|
86
108
|
*/
|
|
87
|
-
|
|
109
|
+
takeReversedFromEnd(n: number, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
88
110
|
/**
|
|
89
111
|
* Performs an IN array lookup
|
|
90
112
|
*/
|
|
@@ -18,9 +18,15 @@ class ReverseIndex {
|
|
|
18
18
|
take(n, from, filterFn) {
|
|
19
19
|
return this.originalIndex.takeReversed(n, from, filterFn);
|
|
20
20
|
}
|
|
21
|
+
takeFromStart(n, filterFn) {
|
|
22
|
+
return this.originalIndex.takeReversedFromEnd(n, filterFn);
|
|
23
|
+
}
|
|
21
24
|
takeReversed(n, from, filterFn) {
|
|
22
25
|
return this.originalIndex.take(n, from, filterFn);
|
|
23
26
|
}
|
|
27
|
+
takeReversedFromEnd(n, filterFn) {
|
|
28
|
+
return this.originalIndex.takeFromStart(n, filterFn);
|
|
29
|
+
}
|
|
24
30
|
get orderedEntriesArray() {
|
|
25
31
|
return this.originalIndex.orderedEntriesArrayReversed;
|
|
26
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reverse-index.cjs","sources":["../../../src/indexes/reverse-index.ts"],"sourcesContent":["import type { CompareOptions } from '../query/builder/types'\nimport type { OrderByDirection } from '../query/ir'\nimport type { IndexInterface, IndexOperation, IndexStats } from './base-index'\nimport type { RangeQueryOptions } from './btree-index'\n\nexport class ReverseIndex<\n TKey extends string | number,\n> implements IndexInterface<TKey> {\n private originalIndex: IndexInterface<TKey>\n\n constructor(index: IndexInterface<TKey>) {\n this.originalIndex = index\n }\n\n // Define the reversed operations\n\n lookup(operation: IndexOperation, value: any): Set<TKey> {\n const reverseOperation =\n operation === `gt`\n ? `lt`\n : operation === `gte`\n ? `lte`\n : operation === `lt`\n ? `gt`\n : operation === `lte`\n ? `gte`\n : operation\n return this.originalIndex.lookup(reverseOperation, value)\n }\n\n rangeQuery(options: RangeQueryOptions = {}): Set<TKey> {\n return this.originalIndex.rangeQueryReversed(options)\n }\n\n rangeQueryReversed(options: RangeQueryOptions = {}): Set<TKey> {\n return this.originalIndex.rangeQuery(options)\n }\n\n take(n: number, from
|
|
1
|
+
{"version":3,"file":"reverse-index.cjs","sources":["../../../src/indexes/reverse-index.ts"],"sourcesContent":["import type { CompareOptions } from '../query/builder/types'\nimport type { OrderByDirection } from '../query/ir'\nimport type { IndexInterface, IndexOperation, IndexStats } from './base-index'\nimport type { RangeQueryOptions } from './btree-index'\n\nexport class ReverseIndex<\n TKey extends string | number,\n> implements IndexInterface<TKey> {\n private originalIndex: IndexInterface<TKey>\n\n constructor(index: IndexInterface<TKey>) {\n this.originalIndex = index\n }\n\n // Define the reversed operations\n\n lookup(operation: IndexOperation, value: any): Set<TKey> {\n const reverseOperation =\n operation === `gt`\n ? `lt`\n : operation === `gte`\n ? `lte`\n : operation === `lt`\n ? `gt`\n : operation === `lte`\n ? `gte`\n : operation\n return this.originalIndex.lookup(reverseOperation, value)\n }\n\n rangeQuery(options: RangeQueryOptions = {}): Set<TKey> {\n return this.originalIndex.rangeQueryReversed(options)\n }\n\n rangeQueryReversed(options: RangeQueryOptions = {}): Set<TKey> {\n return this.originalIndex.rangeQuery(options)\n }\n\n take(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey> {\n return this.originalIndex.takeReversed(n, from, filterFn)\n }\n\n takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey> {\n return this.originalIndex.takeReversedFromEnd(n, filterFn)\n }\n\n takeReversed(\n n: number,\n from: any,\n filterFn?: (key: TKey) => boolean,\n ): Array<TKey> {\n return this.originalIndex.take(n, from, filterFn)\n }\n\n takeReversedFromEnd(\n n: number,\n filterFn?: (key: TKey) => boolean,\n ): Array<TKey> {\n return this.originalIndex.takeFromStart(n, filterFn)\n }\n\n get orderedEntriesArray(): Array<[any, Set<TKey>]> {\n return this.originalIndex.orderedEntriesArrayReversed\n }\n\n get orderedEntriesArrayReversed(): Array<[any, Set<TKey>]> {\n return this.originalIndex.orderedEntriesArray\n }\n\n // All operations below delegate to the original index\n\n supports(operation: IndexOperation): boolean {\n return this.originalIndex.supports(operation)\n }\n\n matchesField(fieldPath: Array<string>): boolean {\n return this.originalIndex.matchesField(fieldPath)\n }\n\n matchesCompareOptions(compareOptions: CompareOptions): boolean {\n return this.originalIndex.matchesCompareOptions(compareOptions)\n }\n\n matchesDirection(direction: OrderByDirection): boolean {\n return this.originalIndex.matchesDirection(direction)\n }\n\n getStats(): IndexStats {\n return this.originalIndex.getStats()\n }\n\n add(key: TKey, item: any): void {\n this.originalIndex.add(key, item)\n }\n\n remove(key: TKey, item: any): void {\n this.originalIndex.remove(key, item)\n }\n\n update(key: TKey, oldItem: any, newItem: any): void {\n this.originalIndex.update(key, oldItem, newItem)\n }\n\n build(entries: Iterable<[TKey, any]>): void {\n this.originalIndex.build(entries)\n }\n\n clear(): void {\n this.originalIndex.clear()\n }\n\n get keyCount(): number {\n return this.originalIndex.keyCount\n }\n\n equalityLookup(value: any): Set<TKey> {\n return this.originalIndex.equalityLookup(value)\n }\n\n inArrayLookup(values: Array<any>): Set<TKey> {\n return this.originalIndex.inArrayLookup(values)\n }\n\n get indexedKeysSet(): Set<TKey> {\n return this.originalIndex.indexedKeysSet\n }\n\n get valueMapData(): Map<any, Set<TKey>> {\n return this.originalIndex.valueMapData\n }\n}\n"],"names":[],"mappings":";;AAKO,MAAM,aAEqB;AAAA,EAGhC,YAAY,OAA6B;AACvC,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAIA,OAAO,WAA2B,OAAuB;AACvD,UAAM,mBACJ,cAAc,OACV,OACA,cAAc,QACZ,QACA,cAAc,OACZ,OACA,cAAc,QACZ,QACA;AACZ,WAAO,KAAK,cAAc,OAAO,kBAAkB,KAAK;AAAA,EAC1D;AAAA,EAEA,WAAW,UAA6B,IAAe;AACrD,WAAO,KAAK,cAAc,mBAAmB,OAAO;AAAA,EACtD;AAAA,EAEA,mBAAmB,UAA6B,IAAe;AAC7D,WAAO,KAAK,cAAc,WAAW,OAAO;AAAA,EAC9C;AAAA,EAEA,KAAK,GAAW,MAAW,UAAgD;AACzE,WAAO,KAAK,cAAc,aAAa,GAAG,MAAM,QAAQ;AAAA,EAC1D;AAAA,EAEA,cAAc,GAAW,UAAgD;AACvE,WAAO,KAAK,cAAc,oBAAoB,GAAG,QAAQ;AAAA,EAC3D;AAAA,EAEA,aACE,GACA,MACA,UACa;AACb,WAAO,KAAK,cAAc,KAAK,GAAG,MAAM,QAAQ;AAAA,EAClD;AAAA,EAEA,oBACE,GACA,UACa;AACb,WAAO,KAAK,cAAc,cAAc,GAAG,QAAQ;AAAA,EACrD;AAAA,EAEA,IAAI,sBAA+C;AACjD,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA,EAEA,IAAI,8BAAuD;AACzD,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA;AAAA,EAIA,SAAS,WAAoC;AAC3C,WAAO,KAAK,cAAc,SAAS,SAAS;AAAA,EAC9C;AAAA,EAEA,aAAa,WAAmC;AAC9C,WAAO,KAAK,cAAc,aAAa,SAAS;AAAA,EAClD;AAAA,EAEA,sBAAsB,gBAAyC;AAC7D,WAAO,KAAK,cAAc,sBAAsB,cAAc;AAAA,EAChE;AAAA,EAEA,iBAAiB,WAAsC;AACrD,WAAO,KAAK,cAAc,iBAAiB,SAAS;AAAA,EACtD;AAAA,EAEA,WAAuB;AACrB,WAAO,KAAK,cAAc,SAAA;AAAA,EAC5B;AAAA,EAEA,IAAI,KAAW,MAAiB;AAC9B,SAAK,cAAc,IAAI,KAAK,IAAI;AAAA,EAClC;AAAA,EAEA,OAAO,KAAW,MAAiB;AACjC,SAAK,cAAc,OAAO,KAAK,IAAI;AAAA,EACrC;AAAA,EAEA,OAAO,KAAW,SAAc,SAAoB;AAClD,SAAK,cAAc,OAAO,KAAK,SAAS,OAAO;AAAA,EACjD;AAAA,EAEA,MAAM,SAAsC;AAC1C,SAAK,cAAc,MAAM,OAAO;AAAA,EAClC;AAAA,EAEA,QAAc;AACZ,SAAK,cAAc,MAAA;AAAA,EACrB;AAAA,EAEA,IAAI,WAAmB;AACrB,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA,EAEA,eAAe,OAAuB;AACpC,WAAO,KAAK,cAAc,eAAe,KAAK;AAAA,EAChD;AAAA,EAEA,cAAc,QAA+B;AAC3C,WAAO,KAAK,cAAc,cAAc,MAAM;AAAA,EAChD;AAAA,EAEA,IAAI,iBAA4B;AAC9B,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA,EAEA,IAAI,eAAoC;AACtC,WAAO,KAAK,cAAc;AAAA,EAC5B;AACF;;"}
|
|
@@ -8,8 +8,10 @@ export declare class ReverseIndex<TKey extends string | number> implements Index
|
|
|
8
8
|
lookup(operation: IndexOperation, value: any): Set<TKey>;
|
|
9
9
|
rangeQuery(options?: RangeQueryOptions): Set<TKey>;
|
|
10
10
|
rangeQueryReversed(options?: RangeQueryOptions): Set<TKey>;
|
|
11
|
-
take(n: number, from
|
|
12
|
-
|
|
11
|
+
take(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
12
|
+
takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
13
|
+
takeReversed(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
14
|
+
takeReversedFromEnd(n: number, filterFn?: (key: TKey) => boolean): Array<TKey>;
|
|
13
15
|
get orderedEntriesArray(): Array<[any, Set<TKey>]>;
|
|
14
16
|
get orderedEntriesArrayReversed(): Array<[any, Set<TKey>]>;
|
|
15
17
|
supports(operation: IndexOperation): boolean;
|
|
@@ -270,7 +270,7 @@ class BaseQueryBuilder {
|
|
|
270
270
|
*/
|
|
271
271
|
having(callback) {
|
|
272
272
|
const aliases = this._getCurrentAliases();
|
|
273
|
-
const refProxy$1 = this.query.select ? refProxy.createRefProxyWithSelected(aliases) : refProxy.createRefProxy(aliases);
|
|
273
|
+
const refProxy$1 = this.query.select || this.query.fnSelect ? refProxy.createRefProxyWithSelected(aliases) : refProxy.createRefProxy(aliases);
|
|
274
274
|
const expression = callback(refProxy$1);
|
|
275
275
|
if (!ir.isExpressionLike(expression)) {
|
|
276
276
|
throw new errors.InvalidWhereExpressionError(getValueTypeName(expression));
|
|
@@ -355,7 +355,7 @@ class BaseQueryBuilder {
|
|
|
355
355
|
*/
|
|
356
356
|
orderBy(callback, options = `asc`) {
|
|
357
357
|
const aliases = this._getCurrentAliases();
|
|
358
|
-
const refProxy$1 = this.query.select ? refProxy.createRefProxyWithSelected(aliases) : refProxy.createRefProxy(aliases);
|
|
358
|
+
const refProxy$1 = this.query.select || this.query.fnSelect ? refProxy.createRefProxyWithSelected(aliases) : refProxy.createRefProxy(aliases);
|
|
359
359
|
const result = callback(refProxy$1);
|
|
360
360
|
const opts = typeof options === `string` ? { direction: options, nulls: `first` } : {
|
|
361
361
|
direction: options.direction ?? `asc`,
|