@tanstack/db 0.0.29 → 0.0.30

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.
Files changed (38) hide show
  1. package/dist/cjs/collection.cjs +6 -6
  2. package/dist/cjs/collection.cjs.map +1 -1
  3. package/dist/cjs/collection.d.cts +4 -4
  4. package/dist/cjs/index.cjs +2 -2
  5. package/dist/cjs/index.d.cts +1 -1
  6. package/dist/cjs/indexes/auto-index.cjs +2 -2
  7. package/dist/cjs/indexes/auto-index.cjs.map +1 -1
  8. package/dist/cjs/indexes/{ordered-index.cjs → btree-index.cjs} +27 -63
  9. package/dist/cjs/indexes/btree-index.cjs.map +1 -0
  10. package/dist/{esm/indexes/ordered-index.d.ts → cjs/indexes/btree-index.d.cts} +6 -4
  11. package/dist/cjs/utils/btree.cjs +677 -0
  12. package/dist/cjs/utils/btree.cjs.map +1 -0
  13. package/dist/cjs/utils/btree.d.cts +197 -0
  14. package/dist/esm/collection.d.ts +4 -4
  15. package/dist/esm/collection.js +6 -6
  16. package/dist/esm/collection.js.map +1 -1
  17. package/dist/esm/index.d.ts +1 -1
  18. package/dist/esm/index.js +2 -2
  19. package/dist/esm/indexes/auto-index.js +2 -2
  20. package/dist/esm/indexes/auto-index.js.map +1 -1
  21. package/dist/{cjs/indexes/ordered-index.d.cts → esm/indexes/btree-index.d.ts} +6 -4
  22. package/dist/esm/indexes/{ordered-index.js → btree-index.js} +27 -63
  23. package/dist/esm/indexes/btree-index.js.map +1 -0
  24. package/dist/esm/utils/btree.d.ts +197 -0
  25. package/dist/esm/utils/btree.js +677 -0
  26. package/dist/esm/utils/btree.js.map +1 -0
  27. package/package.json +1 -1
  28. package/src/collection.ts +9 -11
  29. package/src/index.ts +1 -1
  30. package/src/indexes/auto-index.ts +2 -2
  31. package/src/indexes/{ordered-index.ts → btree-index.ts} +42 -84
  32. package/src/utils/btree.ts +1010 -0
  33. package/dist/cjs/indexes/ordered-index.cjs.map +0 -1
  34. package/dist/cjs/utils/array-utils.cjs +0 -18
  35. package/dist/cjs/utils/array-utils.cjs.map +0 -1
  36. package/dist/esm/indexes/ordered-index.js.map +0 -1
  37. package/dist/esm/utils/array-utils.js +0 -18
  38. package/dist/esm/utils/array-utils.js.map +0 -1
@@ -1,9 +1,9 @@
1
1
  import { ascComparator } from "../utils/comparison.js";
2
- import { findInsertPosition } from "../utils/array-utils.js";
2
+ import { BTree } from "../utils/btree.js";
3
3
  import { BaseIndex } from "./base-index.js";
4
- class OrderedIndex extends BaseIndex {
5
- constructor() {
6
- super(...arguments);
4
+ class BTreeIndex extends BaseIndex {
5
+ constructor(id, expression, name, options) {
6
+ super(id, expression, name, options);
7
7
  this.supportedOperations = /* @__PURE__ */ new Set([
8
8
  `eq`,
9
9
  `gt`,
@@ -12,13 +12,13 @@ class OrderedIndex extends BaseIndex {
12
12
  `lte`,
13
13
  `in`
14
14
  ]);
15
- this.orderedEntries = [];
16
15
  this.valueMap = /* @__PURE__ */ new Map();
17
16
  this.indexedKeys = /* @__PURE__ */ new Set();
18
17
  this.compareFn = ascComparator;
19
- }
20
- initialize(options) {
21
18
  this.compareFn = (options == null ? void 0 : options.compareFn) ?? ascComparator;
19
+ this.orderedEntries = new BTree(this.compareFn);
20
+ }
21
+ initialize(_options) {
22
22
  }
23
23
  /**
24
24
  * Adds a value to the index
@@ -37,12 +37,7 @@ class OrderedIndex extends BaseIndex {
37
37
  } else {
38
38
  const keySet = /* @__PURE__ */ new Set([key]);
39
39
  this.valueMap.set(indexedValue, keySet);
40
- const insertIndex = findInsertPosition(
41
- this.orderedEntries,
42
- indexedValue,
43
- this.compareFn
44
- );
45
- this.orderedEntries.splice(insertIndex, 0, [indexedValue, keySet]);
40
+ this.orderedEntries.set(indexedValue, void 0);
46
41
  }
47
42
  this.indexedKeys.add(key);
48
43
  this.updateTimestamp();
@@ -66,12 +61,7 @@ class OrderedIndex extends BaseIndex {
66
61
  keySet.delete(key);
67
62
  if (keySet.size === 0) {
68
63
  this.valueMap.delete(indexedValue);
69
- const index = this.orderedEntries.findIndex(
70
- ([value]) => this.compareFn(value, indexedValue) === 0
71
- );
72
- if (index !== -1) {
73
- this.orderedEntries.splice(index, 1);
74
- }
64
+ this.orderedEntries.delete(indexedValue);
75
65
  }
76
66
  }
77
67
  this.indexedKeys.delete(key);
@@ -97,7 +87,7 @@ class OrderedIndex extends BaseIndex {
97
87
  * Clears all data from the index
98
88
  */
99
89
  clear() {
100
- this.orderedEntries = [];
90
+ this.orderedEntries.clear();
101
91
  this.valueMap.clear();
102
92
  this.indexedKeys.clear();
103
93
  this.updateTimestamp();
@@ -128,7 +118,7 @@ class OrderedIndex extends BaseIndex {
128
118
  result = this.inArrayLookup(value);
129
119
  break;
130
120
  default:
131
- throw new Error(`Operation ${operation} not supported by OrderedIndex`);
121
+ throw new Error(`Operation ${operation} not supported by BTreeIndex`);
132
122
  }
133
123
  this.trackLookup(startTime);
134
124
  return result;
@@ -153,48 +143,22 @@ class OrderedIndex extends BaseIndex {
153
143
  rangeQuery(options = {}) {
154
144
  const { from, to, fromInclusive = true, toInclusive = true } = options;
155
145
  const result = /* @__PURE__ */ new Set();
156
- if (this.orderedEntries.length === 0) {
157
- return result;
158
- }
159
- let startIndex = 0;
160
- if (from !== void 0) {
161
- const fromInsertIndex = findInsertPosition(
162
- this.orderedEntries,
163
- from,
164
- this.compareFn
165
- );
166
- if (fromInclusive) {
167
- startIndex = fromInsertIndex;
168
- } else {
169
- startIndex = fromInsertIndex;
170
- if (startIndex < this.orderedEntries.length && this.compareFn(this.orderedEntries[startIndex][0], from) === 0) {
171
- startIndex++;
146
+ const fromKey = from ?? this.orderedEntries.minKey();
147
+ const toKey = to ?? this.orderedEntries.maxKey();
148
+ this.orderedEntries.forRange(
149
+ fromKey,
150
+ toKey,
151
+ toInclusive,
152
+ (indexedValue, _) => {
153
+ if (!fromInclusive && this.compareFn(indexedValue, from) === 0) {
154
+ return;
172
155
  }
173
- }
174
- }
175
- let endIndex = this.orderedEntries.length;
176
- if (to !== void 0) {
177
- const toInsertIndex = findInsertPosition(
178
- this.orderedEntries,
179
- to,
180
- this.compareFn
181
- );
182
- if (toInclusive) {
183
- endIndex = toInsertIndex;
184
- if (toInsertIndex < this.orderedEntries.length && this.compareFn(this.orderedEntries[toInsertIndex][0], to) === 0) {
185
- endIndex = toInsertIndex + 1;
156
+ const keys = this.valueMap.get(indexedValue);
157
+ if (keys) {
158
+ keys.forEach((key) => result.add(key));
186
159
  }
187
- } else {
188
- endIndex = toInsertIndex;
189
160
  }
190
- }
191
- if (startIndex >= endIndex) {
192
- return result;
193
- }
194
- for (let i = startIndex; i < endIndex; i++) {
195
- const keys = this.orderedEntries[i][1];
196
- keys.forEach((key) => result.add(key));
197
- }
161
+ );
198
162
  return result;
199
163
  }
200
164
  /**
@@ -215,13 +179,13 @@ class OrderedIndex extends BaseIndex {
215
179
  return this.indexedKeys;
216
180
  }
217
181
  get orderedEntriesArray() {
218
- return this.orderedEntries;
182
+ return this.orderedEntries.keysArray().map((key) => [key, this.valueMap.get(key) ?? /* @__PURE__ */ new Set()]);
219
183
  }
220
184
  get valueMapData() {
221
185
  return this.valueMap;
222
186
  }
223
187
  }
224
188
  export {
225
- OrderedIndex
189
+ BTreeIndex
226
190
  };
227
- //# sourceMappingURL=ordered-index.js.map
191
+ //# sourceMappingURL=btree-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"btree-index.js","sources":["../../../src/indexes/btree-index.ts"],"sourcesContent":["import { ascComparator } from \"../utils/comparison.js\"\nimport { BTree } from \"../utils/btree.js\"\nimport { BaseIndex } from \"./base-index.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}\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 = ascComparator\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 ?? ascComparator\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 // Check if this value already exists\n if (this.valueMap.has(indexedValue)) {\n // Add to existing set\n this.valueMap.get(indexedValue)!.add(key)\n } else {\n // Create new set for this value\n const keySet = new Set<TKey>([key])\n this.valueMap.set(indexedValue, keySet)\n this.orderedEntries.set(indexedValue, 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 if (this.valueMap.has(indexedValue)) {\n const keySet = this.valueMap.get(indexedValue)!\n keySet.delete(key)\n\n // If set is now empty, remove the entry entirely\n if (keySet.size === 0) {\n this.valueMap.delete(indexedValue)\n\n // Remove from ordered entries\n this.orderedEntries.delete(indexedValue)\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 return new Set(this.valueMap.get(value) ?? [])\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 fromKey = from ?? this.orderedEntries.minKey()\n const toKey = 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 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 keys = this.valueMap.get(value)\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 valueMapData(): Map<any, Set<TKey>> {\n return this.valueMap\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ type EditRangeResult<V, R = number> = {
2
+ value?: V;
3
+ break?: R;
4
+ delete?: boolean;
5
+ };
6
+ /**
7
+ * A reasonably fast collection of key-value pairs with a powerful API.
8
+ * Largely compatible with the standard Map. BTree is a B+ tree data structure,
9
+ * so the collection is sorted by key.
10
+ *
11
+ * B+ trees tend to use memory more efficiently than hashtables such as the
12
+ * standard Map, especially when the collection contains a large number of
13
+ * items. However, maintaining the sort order makes them modestly slower:
14
+ * O(log size) rather than O(1). This B+ tree implementation supports O(1)
15
+ * fast cloning. It also supports freeze(), which can be used to ensure that
16
+ * a BTree is not changed accidentally.
17
+ *
18
+ * Confusingly, the ES6 Map.forEach(c) method calls c(value,key) instead of
19
+ * c(key,value), in contrast to other methods such as set() and entries()
20
+ * which put the key first. I can only assume that the order was reversed on
21
+ * the theory that users would usually want to examine values and ignore keys.
22
+ * BTree's forEach() therefore works the same way, but a second method
23
+ * `.forEachPair((key,value)=>{...})` is provided which sends you the key
24
+ * first and the value second; this method is slightly faster because it is
25
+ * the "native" for-each method for this class.
26
+ *
27
+ * Out of the box, BTree supports keys that are numbers, strings, arrays of
28
+ * numbers/strings, Date, and objects that have a valueOf() method returning a
29
+ * number or string. Other data types, such as arrays of Date or custom
30
+ * objects, require a custom comparator, which you must pass as the second
31
+ * argument to the constructor (the first argument is an optional list of
32
+ * initial items). Symbols cannot be used as keys because they are unordered
33
+ * (one Symbol is never "greater" or "less" than another).
34
+ *
35
+ * @example
36
+ * Given a {name: string, age: number} object, you can create a tree sorted by
37
+ * name and then by age like this:
38
+ *
39
+ * var tree = new BTree(undefined, (a, b) => {
40
+ * if (a.name > b.name)
41
+ * return 1; // Return a number >0 when a > b
42
+ * else if (a.name < b.name)
43
+ * return -1; // Return a number <0 when a < b
44
+ * else // names are equal (or incomparable)
45
+ * return a.age - b.age; // Return >0 when a.age > b.age
46
+ * });
47
+ *
48
+ * tree.set({name:"Bill", age:17}, "happy");
49
+ * tree.set({name:"Fran", age:40}, "busy & stressed");
50
+ * tree.set({name:"Bill", age:55}, "recently laid off");
51
+ * tree.forEachPair((k, v) => {
52
+ * console.log(`Name: ${k.name} Age: ${k.age} Status: ${v}`);
53
+ * });
54
+ *
55
+ * @description
56
+ * The "range" methods (`forEach, forRange, editRange`) will return the number
57
+ * of elements that were scanned. In addition, the callback can return {break:R}
58
+ * to stop early and return R from the outer function.
59
+ *
60
+ * - TODO: Test performance of preallocating values array at max size
61
+ * - TODO: Add fast initialization when a sorted array is provided to constructor
62
+ *
63
+ * For more documentation see https://github.com/qwertie/btree-typescript
64
+ *
65
+ * Are you a C# developer? You might like the similar data structures I made for C#:
66
+ * BDictionary, BList, etc. See http://core.loyc.net/collections/
67
+ *
68
+ * @author David Piepgrass
69
+ */
70
+ export declare class BTree<K = any, V = any> {
71
+ private _root;
72
+ _size: number;
73
+ _maxNodeSize: number;
74
+ /**
75
+ * provides a total order over keys (and a strict partial order over the type K)
76
+ * @returns a negative value if a < b, 0 if a === b and a positive value if a > b
77
+ */
78
+ _compare: (a: K, b: K) => number;
79
+ /**
80
+ * Initializes an empty B+ tree.
81
+ * @param compare Custom function to compare pairs of elements in the tree.
82
+ * If not specified, defaultComparator will be used which is valid as long as K extends DefaultComparable.
83
+ * @param entries A set of key-value pairs to initialize the tree
84
+ * @param maxNodeSize Branching factor (maximum items or children per node)
85
+ * Must be in range 4..256. If undefined or <4 then default is used; if >256 then 256.
86
+ */
87
+ constructor(compare: (a: K, b: K) => number, entries?: Array<[K, V]>, maxNodeSize?: number);
88
+ /** Gets the number of key-value pairs in the tree. */
89
+ get size(): number;
90
+ /** Gets the number of key-value pairs in the tree. */
91
+ get length(): number;
92
+ /** Returns true iff the tree contains no key-value pairs. */
93
+ get isEmpty(): boolean;
94
+ /** Releases the tree so that its size is 0. */
95
+ clear(): void;
96
+ /**
97
+ * Finds a pair in the tree and returns the associated value.
98
+ * @param defaultValue a value to return if the key was not found.
99
+ * @returns the value, or defaultValue if the key was not found.
100
+ * @description Computational complexity: O(log size)
101
+ */
102
+ get(key: K, defaultValue?: V): V | undefined;
103
+ /**
104
+ * Adds or overwrites a key-value pair in the B+ tree.
105
+ * @param key the key is used to determine the sort order of
106
+ * data in the tree.
107
+ * @param value data to associate with the key (optional)
108
+ * @param overwrite Whether to overwrite an existing key-value pair
109
+ * (default: true). If this is false and there is an existing
110
+ * key-value pair then this method has no effect.
111
+ * @returns true if a new key-value pair was added.
112
+ * @description Computational complexity: O(log size)
113
+ * Note: when overwriting a previous entry, the key is updated
114
+ * as well as the value. This has no effect unless the new key
115
+ * has data that does not affect its sort order.
116
+ */
117
+ set(key: K, value: V, overwrite?: boolean): boolean;
118
+ /**
119
+ * Returns true if the key exists in the B+ tree, false if not.
120
+ * Use get() for best performance; use has() if you need to
121
+ * distinguish between "undefined value" and "key not present".
122
+ * @param key Key to detect
123
+ * @description Computational complexity: O(log size)
124
+ */
125
+ has(key: K): boolean;
126
+ /**
127
+ * Removes a single key-value pair from the B+ tree.
128
+ * @param key Key to find
129
+ * @returns true if a pair was found and removed, false otherwise.
130
+ * @description Computational complexity: O(log size)
131
+ */
132
+ delete(key: K): boolean;
133
+ /** Returns the maximum number of children/values before nodes will split. */
134
+ get maxNodeSize(): number;
135
+ /** Gets the lowest key in the tree. Complexity: O(log size) */
136
+ minKey(): K | undefined;
137
+ /** Gets the highest key in the tree. Complexity: O(1) */
138
+ maxKey(): K | undefined;
139
+ /** Gets an array of all keys, sorted */
140
+ keysArray(): K[];
141
+ /** Returns the next pair whose key is larger than the specified key (or undefined if there is none).
142
+ * If key === undefined, this function returns the lowest pair.
143
+ * @param key The key to search for.
144
+ * @param reusedArray Optional array used repeatedly to store key-value pairs, to
145
+ * avoid creating a new array on every iteration.
146
+ */
147
+ nextHigherPair(key: K | undefined, reusedArray?: [K, V]): [K, V] | undefined;
148
+ /** Returns the next pair whose key is smaller than the specified key (or undefined if there is none).
149
+ * If key === undefined, this function returns the highest pair.
150
+ * @param key The key to search for.
151
+ * @param reusedArray Optional array used repeatedly to store key-value pairs, to
152
+ * avoid creating a new array each time you call this method.
153
+ */
154
+ nextLowerPair(key: K | undefined, reusedArray?: [K, V]): [K, V] | undefined;
155
+ /** Adds all pairs from a list of key-value pairs.
156
+ * @param pairs Pairs to add to this tree. If there are duplicate keys,
157
+ * later pairs currently overwrite earlier ones (e.g. [[0,1],[0,7]]
158
+ * associates 0 with 7.)
159
+ * @param overwrite Whether to overwrite pairs that already exist (if false,
160
+ * pairs[i] is ignored when the key pairs[i][0] already exists.)
161
+ * @returns The number of pairs added to the collection.
162
+ * @description Computational complexity: O(pairs.length * log(size + pairs.length))
163
+ */
164
+ setPairs(pairs: Array<[K, V]>, overwrite?: boolean): number;
165
+ forRange(low: K, high: K, includeHigh: boolean, onFound?: (k: K, v: V, counter: number) => void, initialCounter?: number): number;
166
+ /**
167
+ * Scans and potentially modifies values for a subsequence of keys.
168
+ * Note: the callback `onFound` should ideally be a pure function.
169
+ * Specfically, it must not insert items, call clone(), or change
170
+ * the collection except via return value; out-of-band editing may
171
+ * cause an exception or may cause incorrect data to be sent to
172
+ * the callback (duplicate or missed items). It must not cause a
173
+ * clone() of the collection, otherwise the clone could be modified
174
+ * by changes requested by the callback.
175
+ * @param low The first key scanned will be greater than or equal to `low`.
176
+ * @param high Scanning stops when a key larger than this is reached.
177
+ * @param includeHigh If the `high` key is present, `onFound` is called for
178
+ * that final pair if and only if this parameter is true.
179
+ * @param onFound A function that is called for each key-value pair. This
180
+ * function can return `{value:v}` to change the value associated
181
+ * with the current key, `{delete:true}` to delete the current pair,
182
+ * `{break:R}` to stop early with result R, or it can return nothing
183
+ * (undefined or {}) to cause no effect and continue iterating.
184
+ * `{break:R}` can be combined with one of the other two commands.
185
+ * The third argument `counter` is the number of items iterated
186
+ * previously; it equals 0 when `onFound` is called the first time.
187
+ * @returns The number of values scanned, or R if the callback returned
188
+ * `{break:R}` to stop early.
189
+ * @description
190
+ * Computational complexity: O(number of items scanned + log size)
191
+ * Note: if the tree has been cloned with clone(), any shared
192
+ * nodes are copied before `onFound` is called. This takes O(n) time
193
+ * where n is proportional to the amount of shared data scanned.
194
+ */
195
+ editRange<R = V>(low: K, high: K, includeHigh: boolean, onFound: (k: K, v: V, counter: number) => EditRangeResult<V, R> | void, initialCounter?: number): R | number;
196
+ }
197
+ export {};