@tanstack/db 0.0.27 → 0.0.29
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/change-events.cjs +141 -0
- package/dist/cjs/change-events.cjs.map +1 -0
- package/dist/cjs/change-events.d.cts +49 -0
- package/dist/cjs/collection.cjs +234 -86
- package/dist/cjs/collection.cjs.map +1 -1
- package/dist/cjs/collection.d.cts +95 -20
- package/dist/cjs/errors.cjs +509 -1
- package/dist/cjs/errors.cjs.map +1 -1
- package/dist/cjs/errors.d.cts +225 -1
- package/dist/cjs/index.cjs +82 -3
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +5 -1
- package/dist/cjs/indexes/auto-index.cjs +64 -0
- package/dist/cjs/indexes/auto-index.cjs.map +1 -0
- package/dist/cjs/indexes/auto-index.d.cts +9 -0
- package/dist/cjs/indexes/base-index.cjs +46 -0
- package/dist/cjs/indexes/base-index.cjs.map +1 -0
- package/dist/cjs/indexes/base-index.d.cts +54 -0
- package/dist/cjs/indexes/index-options.d.cts +13 -0
- package/dist/cjs/indexes/lazy-index.cjs +193 -0
- package/dist/cjs/indexes/lazy-index.cjs.map +1 -0
- package/dist/cjs/indexes/lazy-index.d.cts +96 -0
- package/dist/cjs/indexes/ordered-index.cjs +227 -0
- package/dist/cjs/indexes/ordered-index.cjs.map +1 -0
- package/dist/cjs/indexes/ordered-index.d.cts +72 -0
- package/dist/cjs/local-storage.cjs +9 -15
- package/dist/cjs/local-storage.cjs.map +1 -1
- package/dist/cjs/query/builder/functions.cjs +11 -0
- package/dist/cjs/query/builder/functions.cjs.map +1 -1
- package/dist/cjs/query/builder/functions.d.cts +4 -0
- package/dist/cjs/query/builder/index.cjs +6 -7
- package/dist/cjs/query/builder/index.cjs.map +1 -1
- package/dist/cjs/query/builder/ref-proxy.cjs +37 -0
- package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -1
- package/dist/cjs/query/builder/ref-proxy.d.cts +12 -0
- package/dist/cjs/query/compiler/evaluators.cjs +83 -58
- package/dist/cjs/query/compiler/evaluators.cjs.map +1 -1
- package/dist/cjs/query/compiler/evaluators.d.cts +8 -0
- package/dist/cjs/query/compiler/expressions.cjs +61 -0
- package/dist/cjs/query/compiler/expressions.cjs.map +1 -0
- package/dist/cjs/query/compiler/expressions.d.cts +25 -0
- package/dist/cjs/query/compiler/group-by.cjs +5 -10
- package/dist/cjs/query/compiler/group-by.cjs.map +1 -1
- package/dist/cjs/query/compiler/index.cjs +23 -17
- package/dist/cjs/query/compiler/index.cjs.map +1 -1
- package/dist/cjs/query/compiler/index.d.cts +12 -3
- package/dist/cjs/query/compiler/joins.cjs +61 -12
- package/dist/cjs/query/compiler/joins.cjs.map +1 -1
- package/dist/cjs/query/compiler/order-by.cjs +4 -34
- package/dist/cjs/query/compiler/order-by.cjs.map +1 -1
- package/dist/cjs/query/compiler/types.d.cts +2 -2
- package/dist/cjs/query/live-query-collection.cjs +54 -12
- package/dist/cjs/query/live-query-collection.cjs.map +1 -1
- package/dist/cjs/query/optimizer.cjs +45 -7
- package/dist/cjs/query/optimizer.cjs.map +1 -1
- package/dist/cjs/query/optimizer.d.cts +13 -3
- package/dist/cjs/transactions.cjs +5 -4
- package/dist/cjs/transactions.cjs.map +1 -1
- package/dist/cjs/types.d.cts +31 -0
- package/dist/cjs/utils/array-utils.cjs +18 -0
- package/dist/cjs/utils/array-utils.cjs.map +1 -0
- package/dist/cjs/utils/array-utils.d.cts +8 -0
- package/dist/cjs/utils/comparison.cjs +52 -0
- package/dist/cjs/utils/comparison.cjs.map +1 -0
- package/dist/cjs/utils/comparison.d.cts +11 -0
- package/dist/cjs/utils/index-optimization.cjs +270 -0
- package/dist/cjs/utils/index-optimization.cjs.map +1 -0
- package/dist/cjs/utils/index-optimization.d.cts +29 -0
- package/dist/esm/change-events.d.ts +49 -0
- package/dist/esm/change-events.js +141 -0
- package/dist/esm/change-events.js.map +1 -0
- package/dist/esm/collection.d.ts +95 -20
- package/dist/esm/collection.js +232 -84
- package/dist/esm/collection.js.map +1 -1
- package/dist/esm/errors.d.ts +225 -1
- package/dist/esm/errors.js +510 -2
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +5 -1
- package/dist/esm/index.js +81 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/indexes/auto-index.d.ts +9 -0
- package/dist/esm/indexes/auto-index.js +64 -0
- package/dist/esm/indexes/auto-index.js.map +1 -0
- package/dist/esm/indexes/base-index.d.ts +54 -0
- package/dist/esm/indexes/base-index.js +46 -0
- package/dist/esm/indexes/base-index.js.map +1 -0
- package/dist/esm/indexes/index-options.d.ts +13 -0
- package/dist/esm/indexes/lazy-index.d.ts +96 -0
- package/dist/esm/indexes/lazy-index.js +193 -0
- package/dist/esm/indexes/lazy-index.js.map +1 -0
- package/dist/esm/indexes/ordered-index.d.ts +72 -0
- package/dist/esm/indexes/ordered-index.js +227 -0
- package/dist/esm/indexes/ordered-index.js.map +1 -0
- package/dist/esm/local-storage.js +9 -15
- package/dist/esm/local-storage.js.map +1 -1
- package/dist/esm/query/builder/functions.d.ts +4 -0
- package/dist/esm/query/builder/functions.js +11 -0
- package/dist/esm/query/builder/functions.js.map +1 -1
- package/dist/esm/query/builder/index.js +6 -7
- package/dist/esm/query/builder/index.js.map +1 -1
- package/dist/esm/query/builder/ref-proxy.d.ts +12 -0
- package/dist/esm/query/builder/ref-proxy.js +37 -0
- package/dist/esm/query/builder/ref-proxy.js.map +1 -1
- package/dist/esm/query/compiler/evaluators.d.ts +8 -0
- package/dist/esm/query/compiler/evaluators.js +84 -59
- package/dist/esm/query/compiler/evaluators.js.map +1 -1
- package/dist/esm/query/compiler/expressions.d.ts +25 -0
- package/dist/esm/query/compiler/expressions.js +61 -0
- package/dist/esm/query/compiler/expressions.js.map +1 -0
- package/dist/esm/query/compiler/group-by.js +5 -10
- package/dist/esm/query/compiler/group-by.js.map +1 -1
- package/dist/esm/query/compiler/index.d.ts +12 -3
- package/dist/esm/query/compiler/index.js +23 -17
- package/dist/esm/query/compiler/index.js.map +1 -1
- package/dist/esm/query/compiler/joins.js +61 -12
- package/dist/esm/query/compiler/joins.js.map +1 -1
- package/dist/esm/query/compiler/order-by.js +1 -31
- package/dist/esm/query/compiler/order-by.js.map +1 -1
- package/dist/esm/query/compiler/types.d.ts +2 -2
- package/dist/esm/query/live-query-collection.js +54 -12
- package/dist/esm/query/live-query-collection.js.map +1 -1
- package/dist/esm/query/optimizer.d.ts +13 -3
- package/dist/esm/query/optimizer.js +40 -2
- package/dist/esm/query/optimizer.js.map +1 -1
- package/dist/esm/transactions.js +5 -4
- package/dist/esm/transactions.js.map +1 -1
- package/dist/esm/types.d.ts +31 -0
- package/dist/esm/utils/array-utils.d.ts +8 -0
- package/dist/esm/utils/array-utils.js +18 -0
- package/dist/esm/utils/array-utils.js.map +1 -0
- package/dist/esm/utils/comparison.d.ts +11 -0
- package/dist/esm/utils/comparison.js +52 -0
- package/dist/esm/utils/comparison.js.map +1 -0
- package/dist/esm/utils/index-optimization.d.ts +29 -0
- package/dist/esm/utils/index-optimization.js +270 -0
- package/dist/esm/utils/index-optimization.js.map +1 -0
- package/package.json +1 -1
- package/src/change-events.ts +257 -0
- package/src/collection.ts +318 -105
- package/src/errors.ts +545 -1
- package/src/index.ts +7 -1
- package/src/indexes/auto-index.ts +108 -0
- package/src/indexes/base-index.ts +119 -0
- package/src/indexes/index-options.ts +42 -0
- package/src/indexes/lazy-index.ts +251 -0
- package/src/indexes/ordered-index.ts +305 -0
- package/src/local-storage.ts +16 -17
- package/src/query/builder/functions.ts +14 -0
- package/src/query/builder/index.ts +12 -7
- package/src/query/builder/ref-proxy.ts +65 -0
- package/src/query/compiler/evaluators.ts +114 -62
- package/src/query/compiler/expressions.ts +92 -0
- package/src/query/compiler/group-by.ts +10 -10
- package/src/query/compiler/index.ts +52 -22
- package/src/query/compiler/joins.ts +114 -15
- package/src/query/compiler/order-by.ts +1 -45
- package/src/query/compiler/types.ts +2 -2
- package/src/query/live-query-collection.ts +95 -15
- package/src/query/optimizer.ts +94 -5
- package/src/transactions.ts +10 -4
- package/src/types.ts +38 -0
- package/src/utils/array-utils.ts +28 -0
- package/src/utils/comparison.ts +79 -0
- package/src/utils/index-optimization.ts +546 -0
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BasicExpression } from '../query/ir.js';
|
|
2
|
+
import { CollectionImpl } from '../collection.js';
|
|
3
|
+
export interface AutoIndexConfig {
|
|
4
|
+
autoIndex?: `off` | `eager`;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Analyzes a where expression and creates indexes for all simple operations on single fields
|
|
8
|
+
*/
|
|
9
|
+
export declare function ensureIndexForExpression<T extends Record<string, any>, TKey extends string | number>(expression: BasicExpression, collection: CollectionImpl<T, TKey, any, any, any>): void;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { OrderedIndex } from "./ordered-index.js";
|
|
2
|
+
function ensureIndexForExpression(expression, collection) {
|
|
3
|
+
if (collection.config.autoIndex !== `eager`) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
if (collection.status === `loading` || collection.status === `initialCommit`) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const indexableExpressions = extractIndexableExpressions(expression);
|
|
10
|
+
for (const { fieldName, fieldPath } of indexableExpressions) {
|
|
11
|
+
const existingIndex = Array.from(collection.indexes.values()).find(
|
|
12
|
+
(index) => index.matchesField(fieldPath)
|
|
13
|
+
);
|
|
14
|
+
if (existingIndex) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
collection.createIndex((row) => row[fieldName], {
|
|
19
|
+
name: `auto_${fieldName}`,
|
|
20
|
+
indexType: OrderedIndex
|
|
21
|
+
});
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.warn(
|
|
24
|
+
`Failed to create auto-index for field "${fieldName}":`,
|
|
25
|
+
error
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function extractIndexableExpressions(expression) {
|
|
31
|
+
const results = [];
|
|
32
|
+
function extractFromExpression(expr) {
|
|
33
|
+
if (expr.type !== `func`) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const func = expr;
|
|
37
|
+
if (func.name === `and`) {
|
|
38
|
+
for (const arg of func.args) {
|
|
39
|
+
extractFromExpression(arg);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const supportedOperations = [`eq`, `gt`, `gte`, `lt`, `lte`, `in`];
|
|
44
|
+
if (!supportedOperations.includes(func.name)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (func.args.length < 1 || func.args[0].type !== `ref`) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const fieldRef = func.args[0];
|
|
51
|
+
const fieldPath = fieldRef.path;
|
|
52
|
+
if (fieldPath.length !== 1) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const fieldName = fieldPath[0];
|
|
56
|
+
results.push({ fieldName, fieldPath });
|
|
57
|
+
}
|
|
58
|
+
extractFromExpression(expression);
|
|
59
|
+
return results;
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
ensureIndexForExpression
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=auto-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-index.js","sources":["../../../src/indexes/auto-index.ts"],"sourcesContent":["import { OrderedIndex } from \"./ordered-index\"\nimport type { BasicExpression } from \"../query/ir\"\nimport type { CollectionImpl } from \"../collection\"\n\nexport interface AutoIndexConfig {\n autoIndex?: `off` | `eager`\n}\n\n/**\n * Analyzes a where expression and creates indexes for all simple operations on single fields\n */\nexport function ensureIndexForExpression<\n T extends Record<string, any>,\n TKey extends string | number,\n>(\n expression: BasicExpression,\n collection: CollectionImpl<T, TKey, any, any, any>\n): void {\n // Only proceed if auto-indexing is enabled\n if (collection.config.autoIndex !== `eager`) {\n return\n }\n\n // Don't auto-index during sync operations\n if (\n collection.status === `loading` ||\n collection.status === `initialCommit`\n ) {\n return\n }\n\n // Extract all indexable expressions and create indexes for them\n const indexableExpressions = extractIndexableExpressions(expression)\n\n for (const { fieldName, fieldPath } of indexableExpressions) {\n // Check if we already have an index for this field\n const existingIndex = Array.from(collection.indexes.values()).find(\n (index) => index.matchesField(fieldPath)\n )\n\n if (existingIndex) {\n continue // Index already exists\n }\n\n // Create a new index for this field using the collection's createIndex method\n try {\n collection.createIndex((row) => (row as any)[fieldName], {\n name: `auto_${fieldName}`,\n indexType: OrderedIndex,\n })\n } catch (error) {\n console.warn(\n `Failed to create auto-index for field \"${fieldName}\":`,\n error\n )\n }\n }\n}\n\n/**\n * Extracts all indexable expressions from a where expression\n */\nfunction extractIndexableExpressions(\n expression: BasicExpression\n): Array<{ fieldName: string; fieldPath: Array<string> }> {\n const results: Array<{ fieldName: string; fieldPath: Array<string> }> = []\n\n function extractFromExpression(expr: BasicExpression): void {\n if (expr.type !== `func`) {\n return\n }\n\n const func = expr as any\n\n // Handle 'and' expressions by recursively processing all arguments\n if (func.name === `and`) {\n for (const arg of func.args) {\n extractFromExpression(arg)\n }\n return\n }\n\n // Check if this is a supported operation\n const supportedOperations = [`eq`, `gt`, `gte`, `lt`, `lte`, `in`]\n if (!supportedOperations.includes(func.name)) {\n return\n }\n\n // Check if the first argument is a property reference (single field)\n if (func.args.length < 1 || func.args[0].type !== `ref`) {\n return\n }\n\n const fieldRef = func.args[0]\n const fieldPath = fieldRef.path\n\n // Skip if it's not a simple field (e.g., nested properties or array access)\n if (fieldPath.length !== 1) {\n return\n }\n\n const fieldName = fieldPath[0]\n results.push({ fieldName, fieldPath })\n }\n\n extractFromExpression(expression)\n return results\n}\n"],"names":[],"mappings":";AAWO,SAAS,yBAId,YACA,YACM;AAEN,MAAI,WAAW,OAAO,cAAc,SAAS;AAC3C;AAAA,EACF;AAGA,MACE,WAAW,WAAW,aACtB,WAAW,WAAW,iBACtB;AACA;AAAA,EACF;AAGA,QAAM,uBAAuB,4BAA4B,UAAU;AAEnE,aAAW,EAAE,WAAW,UAAA,KAAe,sBAAsB;AAE3D,UAAM,gBAAgB,MAAM,KAAK,WAAW,QAAQ,OAAA,CAAQ,EAAE;AAAA,MAC5D,CAAC,UAAU,MAAM,aAAa,SAAS;AAAA,IAAA;AAGzC,QAAI,eAAe;AACjB;AAAA,IACF;AAGA,QAAI;AACF,iBAAW,YAAY,CAAC,QAAS,IAAY,SAAS,GAAG;AAAA,QACvD,MAAM,QAAQ,SAAS;AAAA,QACvB,WAAW;AAAA,MAAA,CACZ;AAAA,IACH,SAAS,OAAO;AACd,cAAQ;AAAA,QACN,0CAA0C,SAAS;AAAA,QACnD;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AACF;AAKA,SAAS,4BACP,YACwD;AACxD,QAAM,UAAkE,CAAA;AAExE,WAAS,sBAAsB,MAA6B;AAC1D,QAAI,KAAK,SAAS,QAAQ;AACxB;AAAA,IACF;AAEA,UAAM,OAAO;AAGb,QAAI,KAAK,SAAS,OAAO;AACvB,iBAAW,OAAO,KAAK,MAAM;AAC3B,8BAAsB,GAAG;AAAA,MAC3B;AACA;AAAA,IACF;AAGA,UAAM,sBAAsB,CAAC,MAAM,MAAM,OAAO,MAAM,OAAO,IAAI;AACjE,QAAI,CAAC,oBAAoB,SAAS,KAAK,IAAI,GAAG;AAC5C;AAAA,IACF;AAGA,QAAI,KAAK,KAAK,SAAS,KAAK,KAAK,KAAK,CAAC,EAAE,SAAS,OAAO;AACvD;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,KAAK,CAAC;AAC5B,UAAM,YAAY,SAAS;AAG3B,QAAI,UAAU,WAAW,GAAG;AAC1B;AAAA,IACF;AAEA,UAAM,YAAY,UAAU,CAAC;AAC7B,YAAQ,KAAK,EAAE,WAAW,UAAA,CAAW;AAAA,EACvC;AAEA,wBAAsB,UAAU;AAChC,SAAO;AACT;"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { comparisonFunctions } from '../query/builder/functions.js';
|
|
2
|
+
import { BasicExpression } from '../query/ir.js';
|
|
3
|
+
/**
|
|
4
|
+
* Operations that indexes can support, imported from available comparison functions
|
|
5
|
+
*/
|
|
6
|
+
export declare const IndexOperation: readonly ["eq", "gt", "gte", "lt", "lte", "in", "like", "ilike"];
|
|
7
|
+
/**
|
|
8
|
+
* Type for index operation values
|
|
9
|
+
*/
|
|
10
|
+
export type IndexOperation = (typeof comparisonFunctions)[number];
|
|
11
|
+
/**
|
|
12
|
+
* Statistics about index usage and performance
|
|
13
|
+
*/
|
|
14
|
+
export interface IndexStats {
|
|
15
|
+
readonly entryCount: number;
|
|
16
|
+
readonly lookupCount: number;
|
|
17
|
+
readonly averageLookupTime: number;
|
|
18
|
+
readonly lastUpdated: Date;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Base abstract class that all index types extend
|
|
22
|
+
*/
|
|
23
|
+
export declare abstract class BaseIndex<TKey extends string | number = string | number> {
|
|
24
|
+
readonly id: number;
|
|
25
|
+
readonly name?: string;
|
|
26
|
+
readonly expression: BasicExpression;
|
|
27
|
+
abstract readonly supportedOperations: Set<IndexOperation>;
|
|
28
|
+
protected lookupCount: number;
|
|
29
|
+
protected totalLookupTime: number;
|
|
30
|
+
protected lastUpdated: Date;
|
|
31
|
+
constructor(id: number, expression: BasicExpression, name?: string, options?: any);
|
|
32
|
+
abstract add(key: TKey, item: any): void;
|
|
33
|
+
abstract remove(key: TKey, item: any): void;
|
|
34
|
+
abstract update(key: TKey, oldItem: any, newItem: any): void;
|
|
35
|
+
abstract build(entries: Iterable<[TKey, any]>): void;
|
|
36
|
+
abstract clear(): void;
|
|
37
|
+
abstract lookup(operation: IndexOperation, value: any): Set<TKey>;
|
|
38
|
+
abstract get keyCount(): number;
|
|
39
|
+
supports(operation: IndexOperation): boolean;
|
|
40
|
+
matchesField(fieldPath: Array<string>): boolean;
|
|
41
|
+
getStats(): IndexStats;
|
|
42
|
+
protected abstract initialize(options?: any): void;
|
|
43
|
+
protected evaluateIndexExpression(item: any): any;
|
|
44
|
+
protected trackLookup(startTime: number): void;
|
|
45
|
+
protected updateTimestamp(): void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Type for index constructor
|
|
49
|
+
*/
|
|
50
|
+
export type IndexConstructor<TKey extends string | number = string | number> = new (id: number, expression: BasicExpression, name?: string, options?: any) => BaseIndex<TKey>;
|
|
51
|
+
/**
|
|
52
|
+
* Index resolver can be either a class constructor or async loader
|
|
53
|
+
*/
|
|
54
|
+
export type IndexResolver<TKey extends string | number = string | number> = IndexConstructor<TKey> | (() => Promise<IndexConstructor<TKey>>);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { compileSingleRowExpression } from "../query/compiler/evaluators.js";
|
|
2
|
+
import { comparisonFunctions } from "../query/builder/functions.js";
|
|
3
|
+
const IndexOperation = comparisonFunctions;
|
|
4
|
+
class BaseIndex {
|
|
5
|
+
constructor(id, expression, name, options) {
|
|
6
|
+
this.lookupCount = 0;
|
|
7
|
+
this.totalLookupTime = 0;
|
|
8
|
+
this.lastUpdated = /* @__PURE__ */ new Date();
|
|
9
|
+
this.id = id;
|
|
10
|
+
this.expression = expression;
|
|
11
|
+
this.name = name;
|
|
12
|
+
this.initialize(options);
|
|
13
|
+
}
|
|
14
|
+
// Common methods
|
|
15
|
+
supports(operation) {
|
|
16
|
+
return this.supportedOperations.has(operation);
|
|
17
|
+
}
|
|
18
|
+
matchesField(fieldPath) {
|
|
19
|
+
return this.expression.type === `ref` && this.expression.path.length === fieldPath.length && this.expression.path.every((part, i) => part === fieldPath[i]);
|
|
20
|
+
}
|
|
21
|
+
getStats() {
|
|
22
|
+
return {
|
|
23
|
+
entryCount: this.keyCount,
|
|
24
|
+
lookupCount: this.lookupCount,
|
|
25
|
+
averageLookupTime: this.lookupCount > 0 ? this.totalLookupTime / this.lookupCount : 0,
|
|
26
|
+
lastUpdated: this.lastUpdated
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
evaluateIndexExpression(item) {
|
|
30
|
+
const evaluator = compileSingleRowExpression(this.expression);
|
|
31
|
+
return evaluator(item);
|
|
32
|
+
}
|
|
33
|
+
trackLookup(startTime) {
|
|
34
|
+
const duration = performance.now() - startTime;
|
|
35
|
+
this.lookupCount++;
|
|
36
|
+
this.totalLookupTime += duration;
|
|
37
|
+
}
|
|
38
|
+
updateTimestamp() {
|
|
39
|
+
this.lastUpdated = /* @__PURE__ */ new Date();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
BaseIndex,
|
|
44
|
+
IndexOperation
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=base-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-index.js","sources":["../../../src/indexes/base-index.ts"],"sourcesContent":["import { compileSingleRowExpression } from \"../query/compiler/evaluators.js\"\nimport { comparisonFunctions } from \"../query/builder/functions.js\"\nimport type { BasicExpression } from \"../query/ir.js\"\n\n/**\n * Operations that indexes can support, imported from available comparison functions\n */\nexport const IndexOperation = comparisonFunctions\n\n/**\n * Type for index operation values\n */\nexport type IndexOperation = (typeof comparisonFunctions)[number]\n\n/**\n * Statistics about index usage and performance\n */\nexport interface IndexStats {\n readonly entryCount: number\n readonly lookupCount: number\n readonly averageLookupTime: number\n readonly lastUpdated: Date\n}\n\n/**\n * Base abstract class that all index types extend\n */\nexport abstract class BaseIndex<\n TKey extends string | number = string | number,\n> {\n public readonly id: number\n public readonly name?: string\n public readonly expression: BasicExpression\n public abstract readonly supportedOperations: Set<IndexOperation>\n\n protected lookupCount = 0\n protected totalLookupTime = 0\n protected lastUpdated = new Date()\n\n constructor(\n id: number,\n expression: BasicExpression,\n name?: string,\n options?: any\n ) {\n this.id = id\n this.expression = expression\n this.name = name\n this.initialize(options)\n }\n\n // Abstract methods that each index type must implement\n abstract add(key: TKey, item: any): void\n abstract remove(key: TKey, item: any): void\n abstract update(key: TKey, oldItem: any, newItem: any): void\n abstract build(entries: Iterable<[TKey, any]>): void\n abstract clear(): void\n abstract lookup(operation: IndexOperation, value: any): Set<TKey>\n abstract get keyCount(): number\n\n // Common methods\n supports(operation: IndexOperation): boolean {\n return this.supportedOperations.has(operation)\n }\n\n matchesField(fieldPath: Array<string>): boolean {\n return (\n this.expression.type === `ref` &&\n this.expression.path.length === fieldPath.length &&\n this.expression.path.every((part, i) => part === fieldPath[i])\n )\n }\n\n getStats(): IndexStats {\n return {\n entryCount: this.keyCount,\n lookupCount: this.lookupCount,\n averageLookupTime:\n this.lookupCount > 0 ? this.totalLookupTime / this.lookupCount : 0,\n lastUpdated: this.lastUpdated,\n }\n }\n\n // Protected methods for subclasses\n protected abstract initialize(options?: any): void\n\n protected evaluateIndexExpression(item: any): any {\n const evaluator = compileSingleRowExpression(this.expression)\n return evaluator(item as Record<string, unknown>)\n }\n\n protected trackLookup(startTime: number): void {\n const duration = performance.now() - startTime\n this.lookupCount++\n this.totalLookupTime += duration\n }\n\n protected updateTimestamp(): void {\n this.lastUpdated = new Date()\n }\n}\n\n/**\n * Type for index constructor\n */\nexport type IndexConstructor<TKey extends string | number = string | number> =\n new (\n id: number,\n expression: BasicExpression,\n name?: string,\n options?: any\n ) => BaseIndex<TKey>\n\n/**\n * Index resolver can be either a class constructor or async loader\n */\nexport type IndexResolver<TKey extends string | number = string | number> =\n | IndexConstructor<TKey>\n | (() => Promise<IndexConstructor<TKey>>)\n"],"names":[],"mappings":";;AAOO,MAAM,iBAAiB;AAoBvB,MAAe,UAEpB;AAAA,EAUA,YACE,IACA,YACA,MACA,SACA;AATF,SAAU,cAAc;AACxB,SAAU,kBAAkB;AAC5B,SAAU,kCAAkB,KAAA;AAQ1B,SAAK,KAAK;AACV,SAAK,aAAa;AAClB,SAAK,OAAO;AACZ,SAAK,WAAW,OAAO;AAAA,EACzB;AAAA;AAAA,EAYA,SAAS,WAAoC;AAC3C,WAAO,KAAK,oBAAoB,IAAI,SAAS;AAAA,EAC/C;AAAA,EAEA,aAAa,WAAmC;AAC9C,WACE,KAAK,WAAW,SAAS,SACzB,KAAK,WAAW,KAAK,WAAW,UAAU,UAC1C,KAAK,WAAW,KAAK,MAAM,CAAC,MAAM,MAAM,SAAS,UAAU,CAAC,CAAC;AAAA,EAEjE;AAAA,EAEA,WAAuB;AACrB,WAAO;AAAA,MACL,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBACE,KAAK,cAAc,IAAI,KAAK,kBAAkB,KAAK,cAAc;AAAA,MACnE,aAAa,KAAK;AAAA,IAAA;AAAA,EAEtB;AAAA,EAKU,wBAAwB,MAAgB;AAChD,UAAM,YAAY,2BAA2B,KAAK,UAAU;AAC5D,WAAO,UAAU,IAA+B;AAAA,EAClD;AAAA,EAEU,YAAY,WAAyB;AAC7C,UAAM,WAAW,YAAY,IAAA,IAAQ;AACrC,SAAK;AACL,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEU,kBAAwB;AAChC,SAAK,kCAAkB,KAAA;AAAA,EACzB;AACF;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IndexConstructor, IndexResolver } from './base-index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced index options that support both sync and async resolvers
|
|
4
|
+
*/
|
|
5
|
+
export interface IndexOptions<TResolver extends IndexResolver = IndexResolver> {
|
|
6
|
+
name?: string;
|
|
7
|
+
indexType?: TResolver;
|
|
8
|
+
options?: TResolver extends IndexConstructor<any> ? TResolver extends new (id: string, expr: any, name?: string, options?: infer O) => any ? O : never : TResolver extends () => Promise<infer TCtor> ? TCtor extends new (id: string, expr: any, name?: string, options?: infer O) => any ? O : never : never;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Utility type to extract the constructed index type from a resolver
|
|
12
|
+
*/
|
|
13
|
+
export type ResolvedIndexType<TResolver extends IndexResolver> = TResolver extends IndexConstructor<any> ? InstanceType<TResolver> : TResolver extends () => Promise<IndexConstructor<any>> ? TResolver extends () => Promise<infer TCtor> ? TCtor extends IndexConstructor<any> ? InstanceType<TCtor> : never : never : never;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { BaseIndex, IndexResolver } from './base-index.js';
|
|
2
|
+
import { BasicExpression } from '../query/ir.js';
|
|
3
|
+
/**
|
|
4
|
+
* Wrapper that defers index creation until first sync
|
|
5
|
+
*/
|
|
6
|
+
export declare class LazyIndexWrapper<TKey extends string | number = string | number> {
|
|
7
|
+
private id;
|
|
8
|
+
private expression;
|
|
9
|
+
private name;
|
|
10
|
+
private resolver;
|
|
11
|
+
private options;
|
|
12
|
+
private collectionEntries?;
|
|
13
|
+
private indexPromise;
|
|
14
|
+
private resolvedIndex;
|
|
15
|
+
constructor(id: number, expression: BasicExpression, name: string | undefined, resolver: IndexResolver<TKey>, options: any, collectionEntries?: Iterable<[TKey, any]> | undefined);
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the actual index
|
|
18
|
+
*/
|
|
19
|
+
resolve(): Promise<BaseIndex<TKey>>;
|
|
20
|
+
/**
|
|
21
|
+
* Check if already resolved
|
|
22
|
+
*/
|
|
23
|
+
isResolved(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Get resolved index (throws if not ready)
|
|
26
|
+
*/
|
|
27
|
+
getResolved(): BaseIndex<TKey>;
|
|
28
|
+
/**
|
|
29
|
+
* Get the index ID
|
|
30
|
+
*/
|
|
31
|
+
getId(): number;
|
|
32
|
+
/**
|
|
33
|
+
* Get the index name
|
|
34
|
+
*/
|
|
35
|
+
getName(): string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Get the index expression
|
|
38
|
+
*/
|
|
39
|
+
getExpression(): BasicExpression;
|
|
40
|
+
private createIndex;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Proxy that provides synchronous interface while index loads asynchronously
|
|
44
|
+
*/
|
|
45
|
+
export declare class IndexProxy<TKey extends string | number = string | number> {
|
|
46
|
+
private indexId;
|
|
47
|
+
private lazyIndex;
|
|
48
|
+
constructor(indexId: number, lazyIndex: LazyIndexWrapper<TKey>);
|
|
49
|
+
/**
|
|
50
|
+
* Get the resolved index (throws if not ready)
|
|
51
|
+
*/
|
|
52
|
+
get index(): BaseIndex<TKey>;
|
|
53
|
+
/**
|
|
54
|
+
* Check if index is ready
|
|
55
|
+
*/
|
|
56
|
+
get isReady(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Wait for index to be ready
|
|
59
|
+
*/
|
|
60
|
+
whenReady(): Promise<BaseIndex<TKey>>;
|
|
61
|
+
/**
|
|
62
|
+
* Get the index ID
|
|
63
|
+
*/
|
|
64
|
+
get id(): number;
|
|
65
|
+
/**
|
|
66
|
+
* Get the index name (throws if not ready)
|
|
67
|
+
*/
|
|
68
|
+
get name(): string | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Get the index expression (available immediately)
|
|
71
|
+
*/
|
|
72
|
+
get expression(): BasicExpression;
|
|
73
|
+
/**
|
|
74
|
+
* Check if index supports an operation (throws if not ready)
|
|
75
|
+
*/
|
|
76
|
+
supports(operation: any): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Get index statistics (throws if not ready)
|
|
79
|
+
*/
|
|
80
|
+
getStats(): import('./base-index.js').IndexStats;
|
|
81
|
+
/**
|
|
82
|
+
* Check if index matches a field path (available immediately)
|
|
83
|
+
*/
|
|
84
|
+
matchesField(fieldPath: Array<string>): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Get the key count (throws if not ready)
|
|
87
|
+
*/
|
|
88
|
+
get keyCount(): number;
|
|
89
|
+
get indexedKeysSet(): Set<TKey>;
|
|
90
|
+
get orderedEntriesArray(): Array<[any, Set<TKey>]>;
|
|
91
|
+
get valueMapData(): Map<any, Set<TKey>>;
|
|
92
|
+
equalityLookup(value: any): Set<TKey>;
|
|
93
|
+
rangeQuery(options: any): Set<TKey>;
|
|
94
|
+
inArrayLookup(values: Array<any>): Set<TKey>;
|
|
95
|
+
_getLazyWrapper(): LazyIndexWrapper<TKey>;
|
|
96
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
function isConstructor(resolver) {
|
|
2
|
+
return typeof resolver === `function` && resolver.prototype !== void 0 && resolver.prototype.constructor === resolver;
|
|
3
|
+
}
|
|
4
|
+
async function resolveIndexConstructor(resolver) {
|
|
5
|
+
if (isConstructor(resolver)) {
|
|
6
|
+
return resolver;
|
|
7
|
+
} else {
|
|
8
|
+
return await resolver();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
class LazyIndexWrapper {
|
|
12
|
+
constructor(id, expression, name, resolver, options, collectionEntries) {
|
|
13
|
+
this.id = id;
|
|
14
|
+
this.expression = expression;
|
|
15
|
+
this.name = name;
|
|
16
|
+
this.resolver = resolver;
|
|
17
|
+
this.options = options;
|
|
18
|
+
this.collectionEntries = collectionEntries;
|
|
19
|
+
this.indexPromise = null;
|
|
20
|
+
this.resolvedIndex = null;
|
|
21
|
+
if (isConstructor(this.resolver)) {
|
|
22
|
+
this.resolvedIndex = new this.resolver(
|
|
23
|
+
this.id,
|
|
24
|
+
this.expression,
|
|
25
|
+
this.name,
|
|
26
|
+
this.options
|
|
27
|
+
);
|
|
28
|
+
if (this.collectionEntries) {
|
|
29
|
+
this.resolvedIndex.build(this.collectionEntries);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the actual index
|
|
35
|
+
*/
|
|
36
|
+
async resolve() {
|
|
37
|
+
if (this.resolvedIndex) {
|
|
38
|
+
return this.resolvedIndex;
|
|
39
|
+
}
|
|
40
|
+
if (!this.indexPromise) {
|
|
41
|
+
this.indexPromise = this.createIndex();
|
|
42
|
+
}
|
|
43
|
+
this.resolvedIndex = await this.indexPromise;
|
|
44
|
+
return this.resolvedIndex;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if already resolved
|
|
48
|
+
*/
|
|
49
|
+
isResolved() {
|
|
50
|
+
return this.resolvedIndex !== null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get resolved index (throws if not ready)
|
|
54
|
+
*/
|
|
55
|
+
getResolved() {
|
|
56
|
+
if (!this.resolvedIndex) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Index ${this.id} has not been resolved yet. Ensure collection is synced.`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return this.resolvedIndex;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get the index ID
|
|
65
|
+
*/
|
|
66
|
+
getId() {
|
|
67
|
+
return this.id;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the index name
|
|
71
|
+
*/
|
|
72
|
+
getName() {
|
|
73
|
+
return this.name;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get the index expression
|
|
77
|
+
*/
|
|
78
|
+
getExpression() {
|
|
79
|
+
return this.expression;
|
|
80
|
+
}
|
|
81
|
+
async createIndex() {
|
|
82
|
+
const IndexClass = await resolveIndexConstructor(this.resolver);
|
|
83
|
+
return new IndexClass(this.id, this.expression, this.name, this.options);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
class IndexProxy {
|
|
87
|
+
constructor(indexId, lazyIndex) {
|
|
88
|
+
this.indexId = indexId;
|
|
89
|
+
this.lazyIndex = lazyIndex;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the resolved index (throws if not ready)
|
|
93
|
+
*/
|
|
94
|
+
get index() {
|
|
95
|
+
return this.lazyIndex.getResolved();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if index is ready
|
|
99
|
+
*/
|
|
100
|
+
get isReady() {
|
|
101
|
+
return this.lazyIndex.isResolved();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Wait for index to be ready
|
|
105
|
+
*/
|
|
106
|
+
async whenReady() {
|
|
107
|
+
return await this.lazyIndex.resolve();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get the index ID
|
|
111
|
+
*/
|
|
112
|
+
get id() {
|
|
113
|
+
return this.indexId;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the index name (throws if not ready)
|
|
117
|
+
*/
|
|
118
|
+
get name() {
|
|
119
|
+
if (this.isReady) {
|
|
120
|
+
return this.index.name;
|
|
121
|
+
}
|
|
122
|
+
return this.lazyIndex.getName();
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get the index expression (available immediately)
|
|
126
|
+
*/
|
|
127
|
+
get expression() {
|
|
128
|
+
return this.lazyIndex.getExpression();
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if index supports an operation (throws if not ready)
|
|
132
|
+
*/
|
|
133
|
+
supports(operation) {
|
|
134
|
+
return this.index.supports(operation);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get index statistics (throws if not ready)
|
|
138
|
+
*/
|
|
139
|
+
getStats() {
|
|
140
|
+
return this.index.getStats();
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Check if index matches a field path (available immediately)
|
|
144
|
+
*/
|
|
145
|
+
matchesField(fieldPath) {
|
|
146
|
+
const expr = this.expression;
|
|
147
|
+
return expr.type === `ref` && expr.path.length === fieldPath.length && expr.path.every((part, i) => part === fieldPath[i]);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get the key count (throws if not ready)
|
|
151
|
+
*/
|
|
152
|
+
get keyCount() {
|
|
153
|
+
return this.index.keyCount;
|
|
154
|
+
}
|
|
155
|
+
// Test compatibility properties - delegate to resolved index
|
|
156
|
+
get indexedKeysSet() {
|
|
157
|
+
const resolved = this.index;
|
|
158
|
+
return resolved.indexedKeysSet;
|
|
159
|
+
}
|
|
160
|
+
get orderedEntriesArray() {
|
|
161
|
+
const resolved = this.index;
|
|
162
|
+
return resolved.orderedEntriesArray;
|
|
163
|
+
}
|
|
164
|
+
get valueMapData() {
|
|
165
|
+
const resolved = this.index;
|
|
166
|
+
return resolved.valueMapData;
|
|
167
|
+
}
|
|
168
|
+
// BTreeIndex compatibility methods
|
|
169
|
+
equalityLookup(value) {
|
|
170
|
+
var _a;
|
|
171
|
+
const resolved = this.index;
|
|
172
|
+
return ((_a = resolved.equalityLookup) == null ? void 0 : _a.call(resolved, value)) ?? /* @__PURE__ */ new Set();
|
|
173
|
+
}
|
|
174
|
+
rangeQuery(options) {
|
|
175
|
+
var _a;
|
|
176
|
+
const resolved = this.index;
|
|
177
|
+
return ((_a = resolved.rangeQuery) == null ? void 0 : _a.call(resolved, options)) ?? /* @__PURE__ */ new Set();
|
|
178
|
+
}
|
|
179
|
+
inArrayLookup(values) {
|
|
180
|
+
var _a;
|
|
181
|
+
const resolved = this.index;
|
|
182
|
+
return ((_a = resolved.inArrayLookup) == null ? void 0 : _a.call(resolved, values)) ?? /* @__PURE__ */ new Set();
|
|
183
|
+
}
|
|
184
|
+
// Internal method for the collection to get the lazy wrapper
|
|
185
|
+
_getLazyWrapper() {
|
|
186
|
+
return this.lazyIndex;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export {
|
|
190
|
+
IndexProxy,
|
|
191
|
+
LazyIndexWrapper
|
|
192
|
+
};
|
|
193
|
+
//# sourceMappingURL=lazy-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy-index.js","sources":["../../../src/indexes/lazy-index.ts"],"sourcesContent":["import type {\n BaseIndex,\n IndexConstructor,\n IndexResolver,\n} from \"./base-index.js\"\nimport type { BasicExpression } from \"../query/ir.js\"\n\n/**\n * Utility to determine if a resolver is a constructor or async loader\n */\nfunction isConstructor<TKey extends string | number>(\n resolver: IndexResolver<TKey>\n): resolver is IndexConstructor<TKey> {\n // Check if it's a function with a prototype (constructor)\n return (\n typeof resolver === `function` &&\n resolver.prototype !== undefined &&\n resolver.prototype.constructor === resolver\n )\n}\n\n/**\n * Resolve index constructor from resolver\n */\nasync function resolveIndexConstructor<TKey extends string | number>(\n resolver: IndexResolver<TKey>\n): Promise<IndexConstructor<TKey>> {\n if (isConstructor(resolver)) {\n return resolver\n } else {\n // It's an async loader function\n return await resolver()\n }\n}\n\n/**\n * Wrapper that defers index creation until first sync\n */\nexport class LazyIndexWrapper<TKey extends string | number = string | number> {\n private indexPromise: Promise<BaseIndex<TKey>> | null = null\n private resolvedIndex: BaseIndex<TKey> | null = null\n\n constructor(\n private id: number,\n private expression: BasicExpression,\n private name: string | undefined,\n private resolver: IndexResolver<TKey>,\n private options: any,\n private collectionEntries?: Iterable<[TKey, any]>\n ) {\n // For synchronous constructors, resolve immediately\n if (isConstructor(this.resolver)) {\n this.resolvedIndex = new this.resolver(\n this.id,\n this.expression,\n this.name,\n this.options\n )\n // Build with initial data if provided\n if (this.collectionEntries) {\n this.resolvedIndex.build(this.collectionEntries)\n }\n }\n }\n\n /**\n * Resolve the actual index\n */\n async resolve(): Promise<BaseIndex<TKey>> {\n if (this.resolvedIndex) {\n return this.resolvedIndex\n }\n\n if (!this.indexPromise) {\n this.indexPromise = this.createIndex()\n }\n\n this.resolvedIndex = await this.indexPromise\n return this.resolvedIndex\n }\n\n /**\n * Check if already resolved\n */\n isResolved(): boolean {\n return this.resolvedIndex !== null\n }\n\n /**\n * Get resolved index (throws if not ready)\n */\n getResolved(): BaseIndex<TKey> {\n if (!this.resolvedIndex) {\n throw new Error(\n `Index ${this.id} has not been resolved yet. Ensure collection is synced.`\n )\n }\n return this.resolvedIndex\n }\n\n /**\n * Get the index ID\n */\n getId(): number {\n return this.id\n }\n\n /**\n * Get the index name\n */\n getName(): string | undefined {\n return this.name\n }\n\n /**\n * Get the index expression\n */\n getExpression(): BasicExpression {\n return this.expression\n }\n\n private async createIndex(): Promise<BaseIndex<TKey>> {\n const IndexClass = await resolveIndexConstructor(this.resolver)\n return new IndexClass(this.id, this.expression, this.name, this.options)\n }\n}\n\n/**\n * Proxy that provides synchronous interface while index loads asynchronously\n */\nexport class IndexProxy<TKey extends string | number = string | number> {\n constructor(\n private indexId: number,\n private lazyIndex: LazyIndexWrapper<TKey>\n ) {}\n\n /**\n * Get the resolved index (throws if not ready)\n */\n get index(): BaseIndex<TKey> {\n return this.lazyIndex.getResolved()\n }\n\n /**\n * Check if index is ready\n */\n get isReady(): boolean {\n return this.lazyIndex.isResolved()\n }\n\n /**\n * Wait for index to be ready\n */\n async whenReady(): Promise<BaseIndex<TKey>> {\n return await this.lazyIndex.resolve()\n }\n\n /**\n * Get the index ID\n */\n get id(): number {\n return this.indexId\n }\n\n /**\n * Get the index name (throws if not ready)\n */\n get name(): string | undefined {\n if (this.isReady) {\n return this.index.name\n }\n return this.lazyIndex.getName()\n }\n\n /**\n * Get the index expression (available immediately)\n */\n get expression(): BasicExpression {\n return this.lazyIndex.getExpression()\n }\n\n /**\n * Check if index supports an operation (throws if not ready)\n */\n supports(operation: any): boolean {\n return this.index.supports(operation)\n }\n\n /**\n * Get index statistics (throws if not ready)\n */\n getStats() {\n return this.index.getStats()\n }\n\n /**\n * Check if index matches a field path (available immediately)\n */\n matchesField(fieldPath: Array<string>): boolean {\n const expr = this.expression\n return (\n expr.type === `ref` &&\n expr.path.length === fieldPath.length &&\n expr.path.every((part, i) => part === fieldPath[i])\n )\n }\n\n /**\n * Get the key count (throws if not ready)\n */\n get keyCount(): number {\n return this.index.keyCount\n }\n\n // Test compatibility properties - delegate to resolved index\n get indexedKeysSet(): Set<TKey> {\n const resolved = this.index as any\n return resolved.indexedKeysSet\n }\n\n get orderedEntriesArray(): Array<[any, Set<TKey>]> {\n const resolved = this.index as any\n return resolved.orderedEntriesArray\n }\n\n get valueMapData(): Map<any, Set<TKey>> {\n const resolved = this.index as any\n return resolved.valueMapData\n }\n\n // BTreeIndex compatibility methods\n equalityLookup(value: any): Set<TKey> {\n const resolved = this.index as any\n return resolved.equalityLookup?.(value) ?? new Set()\n }\n\n rangeQuery(options: any): Set<TKey> {\n const resolved = this.index as any\n return resolved.rangeQuery?.(options) ?? new Set()\n }\n\n inArrayLookup(values: Array<any>): Set<TKey> {\n const resolved = this.index as any\n return resolved.inArrayLookup?.(values) ?? new Set()\n }\n\n // Internal method for the collection to get the lazy wrapper\n _getLazyWrapper(): LazyIndexWrapper<TKey> {\n return this.lazyIndex\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { BaseIndex, IndexOperation } from './base-index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Options for Ordered index
|
|
4
|
+
*/
|
|
5
|
+
export interface OrderedIndexOptions {
|
|
6
|
+
compareFn?: (a: any, b: any) => number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Options for range queries
|
|
10
|
+
*/
|
|
11
|
+
export interface RangeQueryOptions {
|
|
12
|
+
from?: any;
|
|
13
|
+
to?: any;
|
|
14
|
+
fromInclusive?: boolean;
|
|
15
|
+
toInclusive?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Ordered index for sorted data with range queries
|
|
19
|
+
* This maintains items in sorted order and provides efficient range operations
|
|
20
|
+
*/
|
|
21
|
+
export declare class OrderedIndex<TKey extends string | number = string | number> extends BaseIndex<TKey> {
|
|
22
|
+
readonly supportedOperations: Set<"eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "ilike">;
|
|
23
|
+
private orderedEntries;
|
|
24
|
+
private valueMap;
|
|
25
|
+
private indexedKeys;
|
|
26
|
+
private compareFn;
|
|
27
|
+
protected initialize(options?: OrderedIndexOptions): void;
|
|
28
|
+
/**
|
|
29
|
+
* Adds a value to the index
|
|
30
|
+
*/
|
|
31
|
+
add(key: TKey, item: any): void;
|
|
32
|
+
/**
|
|
33
|
+
* Removes a value from the index
|
|
34
|
+
*/
|
|
35
|
+
remove(key: TKey, item: any): void;
|
|
36
|
+
/**
|
|
37
|
+
* Updates a value in the index
|
|
38
|
+
*/
|
|
39
|
+
update(key: TKey, oldItem: any, newItem: any): void;
|
|
40
|
+
/**
|
|
41
|
+
* Builds the index from a collection of entries
|
|
42
|
+
*/
|
|
43
|
+
build(entries: Iterable<[TKey, any]>): void;
|
|
44
|
+
/**
|
|
45
|
+
* Clears all data from the index
|
|
46
|
+
*/
|
|
47
|
+
clear(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Performs a lookup operation
|
|
50
|
+
*/
|
|
51
|
+
lookup(operation: IndexOperation, value: any): Set<TKey>;
|
|
52
|
+
/**
|
|
53
|
+
* Gets the number of indexed keys
|
|
54
|
+
*/
|
|
55
|
+
get keyCount(): number;
|
|
56
|
+
/**
|
|
57
|
+
* Performs an equality lookup
|
|
58
|
+
*/
|
|
59
|
+
equalityLookup(value: any): Set<TKey>;
|
|
60
|
+
/**
|
|
61
|
+
* Performs a range query with options
|
|
62
|
+
* This is more efficient for compound queries like "WHERE a > 5 AND a < 10"
|
|
63
|
+
*/
|
|
64
|
+
rangeQuery(options?: RangeQueryOptions): Set<TKey>;
|
|
65
|
+
/**
|
|
66
|
+
* Performs an IN array lookup
|
|
67
|
+
*/
|
|
68
|
+
inArrayLookup(values: Array<any>): Set<TKey>;
|
|
69
|
+
get indexedKeysSet(): Set<TKey>;
|
|
70
|
+
get orderedEntriesArray(): Array<[any, Set<TKey>]>;
|
|
71
|
+
get valueMapData(): Map<any, Set<TKey>>;
|
|
72
|
+
}
|