@tanstack/db-ivm 0.0.0 → 0.1.1

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 (157) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/d2.cjs +111 -0
  3. package/dist/cjs/d2.cjs.map +1 -0
  4. package/dist/cjs/d2.d.cts +45 -0
  5. package/dist/cjs/graph.cjs +90 -0
  6. package/dist/cjs/graph.cjs.map +1 -0
  7. package/dist/cjs/graph.d.cts +57 -0
  8. package/dist/cjs/index.cjs +72 -0
  9. package/dist/cjs/index.cjs.map +1 -0
  10. package/dist/cjs/index.d.cts +4 -0
  11. package/dist/cjs/indexes.cjs +104 -0
  12. package/dist/cjs/indexes.cjs.map +1 -0
  13. package/dist/cjs/indexes.d.cts +20 -0
  14. package/dist/cjs/multiset.cjs +173 -0
  15. package/dist/cjs/multiset.cjs.map +1 -0
  16. package/dist/cjs/multiset.d.cts +36 -0
  17. package/dist/cjs/operators/concat.cjs +37 -0
  18. package/dist/cjs/operators/concat.cjs.map +1 -0
  19. package/dist/cjs/operators/concat.d.cts +13 -0
  20. package/dist/cjs/operators/consolidate.cjs +40 -0
  21. package/dist/cjs/operators/consolidate.cjs.map +1 -0
  22. package/dist/cjs/operators/consolidate.d.cts +12 -0
  23. package/dist/cjs/operators/count.cjs +36 -0
  24. package/dist/cjs/operators/count.cjs.map +1 -0
  25. package/dist/cjs/operators/count.d.cts +13 -0
  26. package/dist/cjs/operators/debug.cjs +50 -0
  27. package/dist/cjs/operators/debug.cjs.map +1 -0
  28. package/dist/cjs/operators/debug.d.cts +16 -0
  29. package/dist/cjs/operators/distinct.cjs +78 -0
  30. package/dist/cjs/operators/distinct.cjs.map +1 -0
  31. package/dist/cjs/operators/distinct.d.cts +14 -0
  32. package/dist/cjs/operators/filter.cjs +43 -0
  33. package/dist/cjs/operators/filter.cjs.map +1 -0
  34. package/dist/cjs/operators/filter.d.cts +16 -0
  35. package/dist/cjs/operators/filterBy.cjs +19 -0
  36. package/dist/cjs/operators/filterBy.cjs.map +1 -0
  37. package/dist/cjs/operators/filterBy.d.cts +10 -0
  38. package/dist/cjs/operators/groupBy.cjs +225 -0
  39. package/dist/cjs/operators/groupBy.cjs.map +1 -0
  40. package/dist/cjs/operators/groupBy.d.cts +68 -0
  41. package/dist/cjs/operators/index.d.cts +18 -0
  42. package/dist/cjs/operators/join.cjs +145 -0
  43. package/dist/cjs/operators/join.cjs.map +1 -0
  44. package/dist/cjs/operators/join.d.cts +48 -0
  45. package/dist/cjs/operators/keying.cjs +16 -0
  46. package/dist/cjs/operators/keying.cjs.map +1 -0
  47. package/dist/cjs/operators/keying.d.cts +19 -0
  48. package/dist/cjs/operators/map.cjs +43 -0
  49. package/dist/cjs/operators/map.cjs.map +1 -0
  50. package/dist/cjs/operators/map.d.cts +16 -0
  51. package/dist/cjs/operators/negate.cjs +28 -0
  52. package/dist/cjs/operators/negate.cjs.map +1 -0
  53. package/dist/cjs/operators/negate.d.cts +13 -0
  54. package/dist/cjs/operators/orderBy.cjs +102 -0
  55. package/dist/cjs/operators/orderBy.cjs.map +1 -0
  56. package/dist/cjs/operators/orderBy.d.cts +38 -0
  57. package/dist/cjs/operators/orderByBTree.d.cts +3 -0
  58. package/dist/cjs/operators/output.cjs +46 -0
  59. package/dist/cjs/operators/output.cjs.map +1 -0
  60. package/dist/cjs/operators/output.d.cts +16 -0
  61. package/dist/cjs/operators/pipe.cjs +9 -0
  62. package/dist/cjs/operators/pipe.cjs.map +1 -0
  63. package/dist/cjs/operators/pipe.d.cts +21 -0
  64. package/dist/cjs/operators/reduce.cjs +99 -0
  65. package/dist/cjs/operators/reduce.cjs.map +1 -0
  66. package/dist/cjs/operators/reduce.d.cts +14 -0
  67. package/dist/cjs/operators/topK.cjs +39 -0
  68. package/dist/cjs/operators/topK.cjs.map +1 -0
  69. package/dist/cjs/operators/topK.d.cts +32 -0
  70. package/dist/cjs/operators/topKWithFractionalIndex.cjs +218 -0
  71. package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -0
  72. package/dist/cjs/operators/topKWithFractionalIndex.d.cts +58 -0
  73. package/dist/cjs/operators/topKWithFractionalIndexBTree.d.cts +27 -0
  74. package/dist/cjs/types.d.cts +30 -0
  75. package/dist/cjs/utils.cjs +125 -0
  76. package/dist/cjs/utils.cjs.map +1 -0
  77. package/dist/cjs/utils.d.cts +40 -0
  78. package/dist/esm/d2.d.ts +45 -0
  79. package/dist/esm/d2.js +111 -0
  80. package/dist/esm/d2.js.map +1 -0
  81. package/dist/esm/graph.d.ts +57 -0
  82. package/dist/esm/graph.js +90 -0
  83. package/dist/esm/graph.js.map +1 -0
  84. package/dist/esm/index.d.ts +4 -0
  85. package/dist/esm/index.js +72 -0
  86. package/dist/esm/index.js.map +1 -0
  87. package/dist/esm/indexes.d.ts +20 -0
  88. package/dist/esm/indexes.js +104 -0
  89. package/dist/esm/indexes.js.map +1 -0
  90. package/dist/esm/multiset.d.ts +36 -0
  91. package/dist/esm/multiset.js +173 -0
  92. package/dist/esm/multiset.js.map +1 -0
  93. package/dist/esm/operators/concat.d.ts +13 -0
  94. package/dist/esm/operators/concat.js +37 -0
  95. package/dist/esm/operators/concat.js.map +1 -0
  96. package/dist/esm/operators/consolidate.d.ts +12 -0
  97. package/dist/esm/operators/consolidate.js +40 -0
  98. package/dist/esm/operators/consolidate.js.map +1 -0
  99. package/dist/esm/operators/count.d.ts +13 -0
  100. package/dist/esm/operators/count.js +36 -0
  101. package/dist/esm/operators/count.js.map +1 -0
  102. package/dist/esm/operators/debug.d.ts +16 -0
  103. package/dist/esm/operators/debug.js +50 -0
  104. package/dist/esm/operators/debug.js.map +1 -0
  105. package/dist/esm/operators/distinct.d.ts +14 -0
  106. package/dist/esm/operators/distinct.js +78 -0
  107. package/dist/esm/operators/distinct.js.map +1 -0
  108. package/dist/esm/operators/filter.d.ts +16 -0
  109. package/dist/esm/operators/filter.js +43 -0
  110. package/dist/esm/operators/filter.js.map +1 -0
  111. package/dist/esm/operators/filterBy.d.ts +10 -0
  112. package/dist/esm/operators/filterBy.js +19 -0
  113. package/dist/esm/operators/filterBy.js.map +1 -0
  114. package/dist/esm/operators/groupBy.d.ts +68 -0
  115. package/dist/esm/operators/groupBy.js +225 -0
  116. package/dist/esm/operators/groupBy.js.map +1 -0
  117. package/dist/esm/operators/index.d.ts +18 -0
  118. package/dist/esm/operators/join.d.ts +48 -0
  119. package/dist/esm/operators/join.js +145 -0
  120. package/dist/esm/operators/join.js.map +1 -0
  121. package/dist/esm/operators/keying.d.ts +19 -0
  122. package/dist/esm/operators/keying.js +16 -0
  123. package/dist/esm/operators/keying.js.map +1 -0
  124. package/dist/esm/operators/map.d.ts +16 -0
  125. package/dist/esm/operators/map.js +43 -0
  126. package/dist/esm/operators/map.js.map +1 -0
  127. package/dist/esm/operators/negate.d.ts +13 -0
  128. package/dist/esm/operators/negate.js +28 -0
  129. package/dist/esm/operators/negate.js.map +1 -0
  130. package/dist/esm/operators/orderBy.d.ts +38 -0
  131. package/dist/esm/operators/orderBy.js +102 -0
  132. package/dist/esm/operators/orderBy.js.map +1 -0
  133. package/dist/esm/operators/orderByBTree.d.ts +3 -0
  134. package/dist/esm/operators/output.d.ts +16 -0
  135. package/dist/esm/operators/output.js +46 -0
  136. package/dist/esm/operators/output.js.map +1 -0
  137. package/dist/esm/operators/pipe.d.ts +21 -0
  138. package/dist/esm/operators/pipe.js +9 -0
  139. package/dist/esm/operators/pipe.js.map +1 -0
  140. package/dist/esm/operators/reduce.d.ts +14 -0
  141. package/dist/esm/operators/reduce.js +99 -0
  142. package/dist/esm/operators/reduce.js.map +1 -0
  143. package/dist/esm/operators/topK.d.ts +32 -0
  144. package/dist/esm/operators/topK.js +39 -0
  145. package/dist/esm/operators/topK.js.map +1 -0
  146. package/dist/esm/operators/topKWithFractionalIndex.d.ts +58 -0
  147. package/dist/esm/operators/topKWithFractionalIndex.js +218 -0
  148. package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -0
  149. package/dist/esm/operators/topKWithFractionalIndexBTree.d.ts +27 -0
  150. package/dist/esm/types.d.ts +30 -0
  151. package/dist/esm/utils.d.ts +40 -0
  152. package/dist/esm/utils.js +125 -0
  153. package/dist/esm/utils.js.map +1 -0
  154. package/package.json +6 -7
  155. package/src/operators/orderBy.ts +11 -29
  156. package/src/operators/topKWithFractionalIndex.ts +69 -57
  157. package/src/operators/topKWithFractionalIndexBTree.ts +14 -19
@@ -0,0 +1,58 @@
1
+ import { DifferenceStreamWriter, UnaryOperator, DifferenceStreamReader } from '../graph.js';
2
+ import { PipedOperator } from '../types.js';
3
+ export interface TopKWithFractionalIndexOptions {
4
+ limit?: number;
5
+ offset?: number;
6
+ }
7
+ export type TopKChanges<V> = {
8
+ /** Indicates which element moves into the topK (if any) */
9
+ moveIn: IndexedValue<V> | null;
10
+ /** Indicates which element moves out of the topK (if any) */
11
+ moveOut: IndexedValue<V> | null;
12
+ };
13
+ /**
14
+ * A topK data structure that supports insertions and deletions
15
+ * and returns changes to the topK.
16
+ */
17
+ export interface TopK<V> {
18
+ insert: (value: V) => TopKChanges<V>;
19
+ delete: (value: V) => TopKChanges<V>;
20
+ }
21
+ /**
22
+ * Operator for fractional indexed topK operations
23
+ * This operator maintains fractional indices for sorted elements
24
+ * and only updates indices when elements move position
25
+ */
26
+ export declare class TopKWithFractionalIndexOperator<K, T> extends UnaryOperator<[
27
+ K,
28
+ T
29
+ ], [
30
+ K,
31
+ IndexedValue<T>
32
+ ]> {
33
+ #private;
34
+ constructor(id: number, inputA: DifferenceStreamReader<[K, T]>, output: DifferenceStreamWriter<[K, IndexedValue<T>]>, comparator: (a: T, b: T) => number, options: TopKWithFractionalIndexOptions);
35
+ protected createTopK(offset: number, limit: number, comparator: (a: TaggedValue<K, T>, b: TaggedValue<K, T>) => number): TopK<TaggedValue<K, T>>;
36
+ run(): void;
37
+ processElement(key: K, value: T, multiplicity: number, result: Array<[[K, IndexedValue<T>], number]>): void;
38
+ private getMultiplicity;
39
+ private addKey;
40
+ }
41
+ /**
42
+ * Limits the number of results based on a comparator, with optional offset.
43
+ * Uses fractional indexing to minimize the number of changes when elements move positions.
44
+ * Each element is assigned a fractional index that is lexicographically sortable.
45
+ * When elements move, only the indices of the moved elements are updated, not all elements.
46
+ *
47
+ * @param comparator - A function that compares two elements
48
+ * @param options - An optional object containing limit and offset properties
49
+ * @returns A piped operator that orders the elements and limits the number of results
50
+ */
51
+ export declare function topKWithFractionalIndex<KType, T>(comparator: (a: T, b: T) => number, options?: TopKWithFractionalIndexOptions): PipedOperator<[KType, T], [KType, IndexedValue<T>]>;
52
+ export type FractionalIndex = string;
53
+ export type IndexedValue<V> = [V, FractionalIndex];
54
+ export declare function indexedValue<V>(value: V, index: FractionalIndex): IndexedValue<V>;
55
+ export declare function getValue<V>(indexedVal: IndexedValue<V>): V;
56
+ export declare function getIndex<V>(indexedVal: IndexedValue<V>): FractionalIndex;
57
+ export type Tag = number;
58
+ export type TaggedValue<K, V> = [K, V, Tag];
@@ -0,0 +1,218 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
+ var _sortedValues, _comparator, _topKStart, _topKEnd, _TopKArray_instances, findIndex_fn, _index, _topK;
10
+ import { generateKeyBetween } from "fractional-indexing";
11
+ import { UnaryOperator, DifferenceStreamWriter } from "../graph.js";
12
+ import { StreamBuilder } from "../d2.js";
13
+ import { MultiSet } from "../multiset.js";
14
+ import { binarySearch, globalObjectIdGenerator } from "../utils.js";
15
+ class TopKArray {
16
+ constructor(offset, limit, comparator) {
17
+ __privateAdd(this, _TopKArray_instances);
18
+ __privateAdd(this, _sortedValues, []);
19
+ __privateAdd(this, _comparator);
20
+ __privateAdd(this, _topKStart);
21
+ __privateAdd(this, _topKEnd);
22
+ __privateSet(this, _topKStart, offset);
23
+ __privateSet(this, _topKEnd, offset + limit);
24
+ __privateSet(this, _comparator, comparator);
25
+ }
26
+ insert(value) {
27
+ const result = { moveIn: null, moveOut: null };
28
+ const index = __privateMethod(this, _TopKArray_instances, findIndex_fn).call(this, value);
29
+ const indexBefore = index === 0 ? null : getIndex(__privateGet(this, _sortedValues)[index - 1]);
30
+ const indexAfter = index === __privateGet(this, _sortedValues).length ? null : getIndex(__privateGet(this, _sortedValues)[index]);
31
+ const fractionalIndex = generateKeyBetween(indexBefore, indexAfter);
32
+ const val = indexedValue(value, fractionalIndex);
33
+ __privateGet(this, _sortedValues).splice(index, 0, val);
34
+ if (index < __privateGet(this, _topKEnd)) {
35
+ const moveInIndex = Math.max(index, __privateGet(this, _topKStart));
36
+ if (moveInIndex < __privateGet(this, _sortedValues).length) {
37
+ result.moveIn = __privateGet(this, _sortedValues)[moveInIndex];
38
+ if (__privateGet(this, _topKEnd) < __privateGet(this, _sortedValues).length) {
39
+ result.moveOut = __privateGet(this, _sortedValues)[__privateGet(this, _topKEnd)];
40
+ }
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ /**
46
+ * Deletes a value that may or may not be in the topK.
47
+ * IMPORTANT: this assumes that the value is present in the collection
48
+ * if it's not the case it will remove the element
49
+ * that is on the position where the provided `value` would be.
50
+ */
51
+ delete(value) {
52
+ const result = { moveIn: null, moveOut: null };
53
+ const index = __privateMethod(this, _TopKArray_instances, findIndex_fn).call(this, value);
54
+ const [removedElem] = __privateGet(this, _sortedValues).splice(index, 1);
55
+ if (index < __privateGet(this, _topKEnd)) {
56
+ result.moveOut = removedElem;
57
+ if (index < __privateGet(this, _topKStart)) {
58
+ const moveOutIndex = __privateGet(this, _topKStart) - 1;
59
+ if (moveOutIndex < __privateGet(this, _sortedValues).length) {
60
+ result.moveOut = __privateGet(this, _sortedValues)[moveOutIndex];
61
+ } else {
62
+ result.moveOut = null;
63
+ }
64
+ }
65
+ const moveInIndex = __privateGet(this, _topKEnd) - 1;
66
+ if (moveInIndex < __privateGet(this, _sortedValues).length) {
67
+ result.moveIn = __privateGet(this, _sortedValues)[moveInIndex];
68
+ }
69
+ }
70
+ return result;
71
+ }
72
+ }
73
+ _sortedValues = new WeakMap();
74
+ _comparator = new WeakMap();
75
+ _topKStart = new WeakMap();
76
+ _topKEnd = new WeakMap();
77
+ _TopKArray_instances = new WeakSet();
78
+ // TODO: see if there is a way to refactor the code for insert and delete in the topK above
79
+ // because they are very similar, one is shifting the topK window to the left and the other is shifting it to the right
80
+ // so i have the feeling there is a common pattern here and we can implement both cases using that pattern
81
+ findIndex_fn = function(value) {
82
+ return binarySearch(
83
+ __privateGet(this, _sortedValues),
84
+ indexedValue(value, ``),
85
+ (a, b) => __privateGet(this, _comparator).call(this, getValue(a), getValue(b))
86
+ );
87
+ };
88
+ class TopKWithFractionalIndexOperator extends UnaryOperator {
89
+ constructor(id, inputA, output, comparator, options) {
90
+ super(id, inputA, output);
91
+ __privateAdd(this, _index, /* @__PURE__ */ new Map());
92
+ // maps keys to their multiplicity
93
+ /**
94
+ * topK data structure that supports insertions and deletions
95
+ * and returns changes to the topK.
96
+ */
97
+ __privateAdd(this, _topK);
98
+ const limit = options.limit ?? Infinity;
99
+ const offset = options.offset ?? 0;
100
+ const compareTaggedValues = (a, b) => {
101
+ const valueComparison = comparator(getVal(a), getVal(b));
102
+ if (valueComparison !== 0) {
103
+ return valueComparison;
104
+ }
105
+ const tieBreakerA = getTag(a);
106
+ const tieBreakerB = getTag(b);
107
+ return tieBreakerA - tieBreakerB;
108
+ };
109
+ __privateSet(this, _topK, this.createTopK(offset, limit, compareTaggedValues));
110
+ }
111
+ createTopK(offset, limit, comparator) {
112
+ return new TopKArray(offset, limit, comparator);
113
+ }
114
+ run() {
115
+ const result = [];
116
+ for (const message of this.inputMessages()) {
117
+ for (const [item, multiplicity] of message.getInner()) {
118
+ const [key, value] = item;
119
+ this.processElement(key, value, multiplicity, result);
120
+ }
121
+ }
122
+ if (result.length > 0) {
123
+ this.output.sendData(new MultiSet(result));
124
+ }
125
+ }
126
+ processElement(key, value, multiplicity, result) {
127
+ const { oldMultiplicity, newMultiplicity } = this.addKey(key, multiplicity);
128
+ let res = {
129
+ moveIn: null,
130
+ moveOut: null
131
+ };
132
+ if (oldMultiplicity <= 0 && newMultiplicity > 0) {
133
+ const taggedValue = tagValue(key, value);
134
+ res = __privateGet(this, _topK).insert(taggedValue);
135
+ } else if (oldMultiplicity > 0 && newMultiplicity <= 0) {
136
+ const taggedValue = tagValue(key, value);
137
+ res = __privateGet(this, _topK).delete(taggedValue);
138
+ } else ;
139
+ if (res.moveIn) {
140
+ const index = getIndex(res.moveIn);
141
+ const taggedValue = getValue(res.moveIn);
142
+ const k = getKey(taggedValue);
143
+ const val = getVal(taggedValue);
144
+ result.push([[k, [val, index]], 1]);
145
+ }
146
+ if (res.moveOut) {
147
+ const index = getIndex(res.moveOut);
148
+ const taggedValue = getValue(res.moveOut);
149
+ const k = getKey(taggedValue);
150
+ const val = getVal(taggedValue);
151
+ result.push([[k, [val, index]], -1]);
152
+ }
153
+ return;
154
+ }
155
+ getMultiplicity(key) {
156
+ return __privateGet(this, _index).get(key) ?? 0;
157
+ }
158
+ addKey(key, multiplicity) {
159
+ const oldMultiplicity = this.getMultiplicity(key);
160
+ const newMultiplicity = oldMultiplicity + multiplicity;
161
+ if (newMultiplicity === 0) {
162
+ __privateGet(this, _index).delete(key);
163
+ } else {
164
+ __privateGet(this, _index).set(key, newMultiplicity);
165
+ }
166
+ return { oldMultiplicity, newMultiplicity };
167
+ }
168
+ }
169
+ _index = new WeakMap();
170
+ _topK = new WeakMap();
171
+ function topKWithFractionalIndex(comparator, options) {
172
+ const opts = options || {};
173
+ return (stream) => {
174
+ const output = new StreamBuilder(
175
+ stream.graph,
176
+ new DifferenceStreamWriter()
177
+ );
178
+ const operator = new TopKWithFractionalIndexOperator(
179
+ stream.graph.getNextOperatorId(),
180
+ stream.connectReader(),
181
+ output.writer,
182
+ comparator,
183
+ opts
184
+ );
185
+ stream.graph.addOperator(operator);
186
+ stream.graph.addStream(output.connectReader());
187
+ return output;
188
+ };
189
+ }
190
+ function indexedValue(value, index) {
191
+ return [value, index];
192
+ }
193
+ function getValue(indexedVal) {
194
+ return indexedVal[0];
195
+ }
196
+ function getIndex(indexedVal) {
197
+ return indexedVal[1];
198
+ }
199
+ function tagValue(key, value) {
200
+ return [key, value, globalObjectIdGenerator.getId(key)];
201
+ }
202
+ function getKey(tieBreakerTaggedValue) {
203
+ return tieBreakerTaggedValue[0];
204
+ }
205
+ function getVal(tieBreakerTaggedValue) {
206
+ return tieBreakerTaggedValue[1];
207
+ }
208
+ function getTag(tieBreakerTaggedValue) {
209
+ return tieBreakerTaggedValue[2];
210
+ }
211
+ export {
212
+ TopKWithFractionalIndexOperator,
213
+ getIndex,
214
+ getValue,
215
+ indexedValue,
216
+ topKWithFractionalIndex
217
+ };
218
+ //# sourceMappingURL=topKWithFractionalIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topKWithFractionalIndex.js","sources":["../../../src/operators/topKWithFractionalIndex.ts"],"sourcesContent":["import { generateKeyBetween } from \"fractional-indexing\"\nimport { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport { MultiSet } from \"../multiset.js\"\nimport { binarySearch, globalObjectIdGenerator } from \"../utils.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types.js\"\n\nexport interface TopKWithFractionalIndexOptions {\n limit?: number\n offset?: number\n}\n\nexport type TopKChanges<V> = {\n /** Indicates which element moves into the topK (if any) */\n moveIn: IndexedValue<V> | null\n /** Indicates which element moves out of the topK (if any) */\n moveOut: IndexedValue<V> | null\n}\n\n/**\n * A topK data structure that supports insertions and deletions\n * and returns changes to the topK.\n */\nexport interface TopK<V> {\n insert: (value: V) => TopKChanges<V>\n delete: (value: V) => TopKChanges<V>\n}\n\n/**\n * Implementation of a topK data structure.\n * Uses a sorted array internally to store the values and keeps a topK window over that array.\n * Inserts and deletes are O(n) operations because worst case an element is inserted/deleted\n * at the start of the array which causes all the elements to shift to the right/left.\n */\nclass TopKArray<V> implements TopK<V> {\n #sortedValues: Array<IndexedValue<V>> = []\n #comparator: (a: V, b: V) => number\n #topKStart: number\n #topKEnd: number\n\n constructor(\n offset: number,\n limit: number,\n comparator: (a: V, b: V) => number\n ) {\n this.#topKStart = offset\n this.#topKEnd = offset + limit\n this.#comparator = comparator\n }\n\n insert(value: V): TopKChanges<V> {\n const result: TopKChanges<V> = { moveIn: null, moveOut: null }\n\n // Lookup insert position\n const index = this.#findIndex(value)\n // Generate fractional index based on the fractional indices of the elements before and after it\n const indexBefore =\n index === 0 ? null : getIndex(this.#sortedValues[index - 1]!)\n const indexAfter =\n index === this.#sortedValues.length\n ? null\n : getIndex(this.#sortedValues[index]!)\n const fractionalIndex = generateKeyBetween(indexBefore, indexAfter)\n\n // Insert the value at the correct position\n const val = indexedValue(value, fractionalIndex)\n // Splice is O(n) where n = all elements in the collection (i.e. n >= k) !\n this.#sortedValues.splice(index, 0, val)\n\n // Check if the topK changed\n if (index < this.#topKEnd) {\n // The inserted element is either before the top K or within the top K\n // If it is before the top K then it moves the element that was right before the topK into the topK\n // If it is within the top K then the inserted element moves into the top K\n // In both cases the last element of the old top K now moves out of the top K\n const moveInIndex = Math.max(index, this.#topKStart)\n if (moveInIndex < this.#sortedValues.length) {\n // We actually have a topK\n // because in some cases there may not be enough elements in the array to reach the start of the topK\n // e.g. [1, 2, 3] with K = 2 and offset = 3 does not have a topK\n result.moveIn = this.#sortedValues[moveInIndex]!\n\n // We need to remove the element that falls out of the top K\n // The element that falls out of the top K has shifted one to the right\n // because of the element we inserted, so we find it at index topKEnd\n if (this.#topKEnd < this.#sortedValues.length) {\n result.moveOut = this.#sortedValues[this.#topKEnd]!\n }\n }\n }\n\n return result\n }\n\n /**\n * Deletes a value that may or may not be in the topK.\n * IMPORTANT: this assumes that the value is present in the collection\n * if it's not the case it will remove the element\n * that is on the position where the provided `value` would be.\n */\n delete(value: V): TopKChanges<V> {\n const result: TopKChanges<V> = { moveIn: null, moveOut: null }\n\n // Lookup delete position\n const index = this.#findIndex(value)\n // Remove the value at that position\n const [removedElem] = this.#sortedValues.splice(index, 1)\n\n // Check if the topK changed\n if (index < this.#topKEnd) {\n // The removed element is either before the top K or within the top K\n // If it is before the top K then the first element of the topK moves out of the topK\n // If it is within the top K then the removed element moves out of the topK\n result.moveOut = removedElem!\n if (index < this.#topKStart) {\n // The removed element is before the topK\n // so actually, the first element of the topK moves out of the topK\n // and not the element that we removed\n // The first element of the topK is now at index topKStart - 1\n // since we removed an element before the topK\n const moveOutIndex = this.#topKStart - 1\n if (moveOutIndex < this.#sortedValues.length) {\n result.moveOut = this.#sortedValues[moveOutIndex]!\n } else {\n // No value is moving out of the topK\n // because there are no elements in the topK\n result.moveOut = null\n }\n }\n\n // Since we removed an element that was before or in the topK\n // the first element after the topK moved one position to the left\n // and thus falls into the topK now\n const moveInIndex = this.#topKEnd - 1\n if (moveInIndex < this.#sortedValues.length) {\n result.moveIn = this.#sortedValues[moveInIndex]!\n }\n }\n\n return result\n }\n\n // TODO: see if there is a way to refactor the code for insert and delete in the topK above\n // because they are very similar, one is shifting the topK window to the left and the other is shifting it to the right\n // so i have the feeling there is a common pattern here and we can implement both cases using that pattern\n\n #findIndex(value: V): number {\n return binarySearch(this.#sortedValues, indexedValue(value, ``), (a, b) =>\n this.#comparator(getValue(a), getValue(b))\n )\n }\n}\n\n/**\n * Operator for fractional indexed topK operations\n * This operator maintains fractional indices for sorted elements\n * and only updates indices when elements move position\n */\nexport class TopKWithFractionalIndexOperator<K, T> extends UnaryOperator<\n [K, T],\n [K, IndexedValue<T>]\n> {\n #index: Map<K, number> = new Map() // maps keys to their multiplicity\n\n /**\n * topK data structure that supports insertions and deletions\n * and returns changes to the topK.\n */\n #topK: TopK<TaggedValue<K, T>>\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<[K, T]>,\n output: DifferenceStreamWriter<[K, IndexedValue<T>]>,\n comparator: (a: T, b: T) => number,\n options: TopKWithFractionalIndexOptions\n ) {\n super(id, inputA, output)\n const limit = options.limit ?? Infinity\n const offset = options.offset ?? 0\n const compareTaggedValues = (\n a: TaggedValue<K, T>,\n b: TaggedValue<K, T>\n ) => {\n // First compare on the value\n const valueComparison = comparator(getVal(a), getVal(b))\n if (valueComparison !== 0) {\n return valueComparison\n }\n // If the values are equal, compare on the tag (object identity)\n const tieBreakerA = getTag(a)\n const tieBreakerB = getTag(b)\n return tieBreakerA - tieBreakerB\n }\n this.#topK = this.createTopK(offset, limit, compareTaggedValues)\n }\n\n protected createTopK(\n offset: number,\n limit: number,\n comparator: (a: TaggedValue<K, T>, b: TaggedValue<K, T>) => number\n ): TopK<TaggedValue<K, T>> {\n return new TopKArray(offset, limit, comparator)\n }\n\n run(): void {\n const result: Array<[[K, IndexedValue<T>], number]> = []\n for (const message of this.inputMessages()) {\n for (const [item, multiplicity] of message.getInner()) {\n const [key, value] = item\n this.processElement(key, value, multiplicity, result)\n }\n }\n\n if (result.length > 0) {\n this.output.sendData(new MultiSet(result))\n }\n }\n\n processElement(\n key: K,\n value: T,\n multiplicity: number,\n result: Array<[[K, IndexedValue<T>], number]>\n ): void {\n const { oldMultiplicity, newMultiplicity } = this.addKey(key, multiplicity)\n\n let res: TopKChanges<TaggedValue<K, T>> = {\n moveIn: null,\n moveOut: null,\n }\n if (oldMultiplicity <= 0 && newMultiplicity > 0) {\n // The value was invisible but should now be visible\n // Need to insert it into the array of sorted values\n const taggedValue = tagValue(key, value)\n res = this.#topK.insert(taggedValue)\n } else if (oldMultiplicity > 0 && newMultiplicity <= 0) {\n // The value was visible but should now be invisible\n // Need to remove it from the array of sorted values\n const taggedValue = tagValue(key, value)\n res = this.#topK.delete(taggedValue)\n } else {\n // The value was invisible and it remains invisible\n // or it was visible and remains visible\n // so it doesn't affect the topK\n }\n\n if (res.moveIn) {\n const index = getIndex(res.moveIn)\n const taggedValue = getValue(res.moveIn)\n const k = getKey(taggedValue)\n const val = getVal(taggedValue)\n result.push([[k, [val, index]], 1])\n }\n\n if (res.moveOut) {\n const index = getIndex(res.moveOut)\n const taggedValue = getValue(res.moveOut)\n const k = getKey(taggedValue)\n const val = getVal(taggedValue)\n result.push([[k, [val, index]], -1])\n }\n\n return\n }\n\n private getMultiplicity(key: K): number {\n return this.#index.get(key) ?? 0\n }\n\n private addKey(\n key: K,\n multiplicity: number\n ): { oldMultiplicity: number; newMultiplicity: number } {\n const oldMultiplicity = this.getMultiplicity(key)\n const newMultiplicity = oldMultiplicity + multiplicity\n if (newMultiplicity === 0) {\n this.#index.delete(key)\n } else {\n this.#index.set(key, newMultiplicity)\n }\n return { oldMultiplicity, newMultiplicity }\n }\n}\n\n/**\n * Limits the number of results based on a comparator, with optional offset.\n * Uses fractional indexing to minimize the number of changes when elements move positions.\n * Each element is assigned a fractional index that is lexicographically sortable.\n * When elements move, only the indices of the moved elements are updated, not all elements.\n *\n * @param comparator - A function that compares two elements\n * @param options - An optional object containing limit and offset properties\n * @returns A piped operator that orders the elements and limits the number of results\n */\nexport function topKWithFractionalIndex<KType, T>(\n comparator: (a: T, b: T) => number,\n options?: TopKWithFractionalIndexOptions\n): PipedOperator<[KType, T], [KType, IndexedValue<T>]> {\n const opts = options || {}\n\n return (\n stream: IStreamBuilder<[KType, T]>\n ): IStreamBuilder<[KType, IndexedValue<T>]> => {\n const output = new StreamBuilder<[KType, IndexedValue<T>]>(\n stream.graph,\n new DifferenceStreamWriter<[KType, IndexedValue<T>]>()\n )\n const operator = new TopKWithFractionalIndexOperator<KType, T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n comparator,\n opts\n )\n stream.graph.addOperator(operator)\n stream.graph.addStream(output.connectReader())\n return output\n }\n}\n\n// Abstraction for fractionally indexed values\nexport type FractionalIndex = string\nexport type IndexedValue<V> = [V, FractionalIndex]\n\nexport function indexedValue<V>(\n value: V,\n index: FractionalIndex\n): IndexedValue<V> {\n return [value, index]\n}\n\nexport function getValue<V>(indexedVal: IndexedValue<V>): V {\n return indexedVal[0]\n}\n\nexport function getIndex<V>(indexedVal: IndexedValue<V>): FractionalIndex {\n return indexedVal[1]\n}\n\nexport type Tag = number\nexport type TaggedValue<K, V> = [K, V, Tag]\n\nfunction tagValue<K, V>(key: K, value: V): TaggedValue<K, V> {\n return [key, value, globalObjectIdGenerator.getId(key)]\n}\n\nfunction getKey<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): K {\n return tieBreakerTaggedValue[0]\n}\n\nfunction getVal<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): V {\n return tieBreakerTaggedValue[1]\n}\n\nfunction getTag<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): Tag {\n return tieBreakerTaggedValue[2]\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { TopKWithFractionalIndexOperator, IndexedValue, TaggedValue, TopK, TopKWithFractionalIndexOptions } from './topKWithFractionalIndex.js';
2
+ import { PipedOperator } from '../types.js';
3
+ export declare function loadBTree(): Promise<void>;
4
+ /**
5
+ * Operator for fractional indexed topK operations
6
+ * This operator maintains fractional indices for sorted elements
7
+ * and only updates indices when elements move position
8
+ */
9
+ export declare class TopKWithFractionalIndexBTreeOperator<K, T> extends TopKWithFractionalIndexOperator<K, T> {
10
+ protected createTopK(offset: number, limit: number, comparator: (a: TaggedValue<K, T>, b: TaggedValue<K, T>) => number): TopK<TaggedValue<K, T>>;
11
+ }
12
+ /**
13
+ * Limits the number of results based on a comparator, with optional offset.
14
+ * This works on a keyed stream, where the key is the first element of the tuple.
15
+ * The ordering is within a key group, i.e. elements are sorted within a key group
16
+ * and the limit + offset is applied to that sorted group.
17
+ * To order the entire stream, key by the same value for all elements such as null.
18
+ *
19
+ * Uses fractional indexing to minimize the number of changes when elements move positions.
20
+ * Each element is assigned a fractional index that is lexicographically sortable.
21
+ * When elements move, only the indices of the moved elements are updated, not all elements.
22
+ *
23
+ * @param comparator - A function that compares two elements
24
+ * @param options - An optional object containing limit and offset properties
25
+ * @returns A piped operator that orders the elements and limits the number of results
26
+ */
27
+ export declare function topKWithFractionalIndexBTree<KType, T>(comparator: (a: T, b: T) => number, options?: TopKWithFractionalIndexOptions): PipedOperator<[KType, T], [KType, IndexedValue<T>]>;
@@ -0,0 +1,30 @@
1
+ import { MultiSet, MultiSetArray } from './multiset.js';
2
+ import { BinaryOperator, DifferenceStreamReader, DifferenceStreamWriter, UnaryOperator } from './graph.js';
3
+ export type KeyValue<K, V> = [K, V];
4
+ export interface IOperator<_T> {
5
+ run: () => void;
6
+ hasPendingWork: () => boolean;
7
+ }
8
+ export interface IDifferenceStreamReader<T> {
9
+ drain: () => Array<MultiSet<T>>;
10
+ isEmpty: () => boolean;
11
+ }
12
+ export interface IDifferenceStreamWriter<T> {
13
+ sendData: (collection: MultiSet<T> | MultiSetArray<T>) => void;
14
+ newReader: () => IDifferenceStreamReader<T>;
15
+ }
16
+ export interface ID2 {
17
+ getNextOperatorId: () => number;
18
+ newInput: <T>() => IStreamBuilder<T>;
19
+ addOperator: (operator: UnaryOperator<any> | BinaryOperator<any>) => void;
20
+ addStream: (stream: DifferenceStreamReader<any>) => void;
21
+ finalize: () => void;
22
+ step: () => void;
23
+ }
24
+ export interface IStreamBuilder<T> {
25
+ writer: DifferenceStreamWriter<T>;
26
+ connectReader: () => DifferenceStreamReader<T>;
27
+ graph: ID2;
28
+ pipe: (<O>(o1: PipedOperator<T, O>) => IStreamBuilder<O>) & (<T2, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, O>) => IStreamBuilder<O>) & (<T2, T3, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, O>) => IStreamBuilder<O>) & (<T2, T3, T4, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, T19>, o19: PipedOperator<T19, O>) => IStreamBuilder<O>) & (<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, T19>, o19: PipedOperator<T19, T20>, o20: PipedOperator<T20, O>) => IStreamBuilder<O>) & (<O>(...operators: Array<PipedOperator<any, any>>) => IStreamBuilder<O>);
29
+ }
30
+ export type PipedOperator<I, O> = (stream: IStreamBuilder<I>) => IStreamBuilder<O>;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * A map that returns a default value for keys that are not present.
3
+ */
4
+ export declare class DefaultMap<K, V> extends Map<K, V> {
5
+ private defaultValue;
6
+ constructor(defaultValue: () => V, entries?: Iterable<[K, V]>);
7
+ get(key: K): V;
8
+ /**
9
+ * Update the value for a key using a function.
10
+ */
11
+ update(key: K, updater: (value: V) => V): V;
12
+ }
13
+ export declare function chunkedArrayPush(array: Array<unknown>, other: Array<unknown>): void;
14
+ /**
15
+ * A hash method that caches the hash of a value in a week map
16
+ */
17
+ export declare function hash(data: any): string;
18
+ export declare function binarySearch<T>(array: Array<T>, value: T, comparator: (a: T, b: T) => number): number;
19
+ /**
20
+ * Utility for generating unique IDs for objects and values.
21
+ * Uses WeakMap for object reference tracking and consistent hashing for primitives.
22
+ */
23
+ export declare class ObjectIdGenerator {
24
+ private objectIds;
25
+ private nextId;
26
+ /**
27
+ * Get a unique identifier for any value.
28
+ * - Objects: Uses WeakMap for reference-based identity
29
+ * - Primitives: Uses consistent string-based hashing
30
+ */
31
+ getId(value: any): number;
32
+ /**
33
+ * Get a string representation of the ID for use in composite keys.
34
+ */
35
+ getStringId(value: any): string;
36
+ }
37
+ /**
38
+ * Global instance for cases where a shared object ID space is needed.
39
+ */
40
+ export declare const globalObjectIdGenerator: ObjectIdGenerator;
@@ -0,0 +1,125 @@
1
+ import murmurhash from "murmurhash-js";
2
+ class DefaultMap extends Map {
3
+ constructor(defaultValue, entries) {
4
+ super(entries);
5
+ this.defaultValue = defaultValue;
6
+ }
7
+ get(key) {
8
+ if (!this.has(key)) {
9
+ this.set(key, this.defaultValue());
10
+ }
11
+ return super.get(key);
12
+ }
13
+ /**
14
+ * Update the value for a key using a function.
15
+ */
16
+ update(key, updater) {
17
+ const value = this.get(key);
18
+ const newValue = updater(value);
19
+ this.set(key, newValue);
20
+ return newValue;
21
+ }
22
+ }
23
+ const chunkSize = 3e4;
24
+ function chunkedArrayPush(array, other) {
25
+ if (other.length <= chunkSize) {
26
+ array.push(...other);
27
+ } else {
28
+ for (let i = 0; i < other.length; i += chunkSize) {
29
+ const chunk = other.slice(i, i + chunkSize);
30
+ array.push(...chunk);
31
+ }
32
+ }
33
+ }
34
+ const hashCache = /* @__PURE__ */ new WeakMap();
35
+ function hashReplacer(_key, value) {
36
+ if (typeof value === `bigint`) {
37
+ return String(value);
38
+ } else if (typeof value === `symbol`) {
39
+ return String(value);
40
+ } else if (typeof value === `function`) {
41
+ return String(value);
42
+ } else if (value === void 0) {
43
+ return `undefined`;
44
+ } else if (value instanceof Map) {
45
+ return `Map(${JSON.stringify(Array.from(value.entries()), hashReplacer)})`;
46
+ } else if (value instanceof Set) {
47
+ return `Set(${JSON.stringify(Array.from(value.values()), hashReplacer)})`;
48
+ }
49
+ return value;
50
+ }
51
+ function hash(data) {
52
+ if (data === null || data === void 0 || typeof data !== `object` && typeof data !== `function`) {
53
+ const serialized2 = JSON.stringify(data, hashReplacer);
54
+ return murmurhash.murmur3(serialized2).toString(16);
55
+ }
56
+ if (hashCache.has(data)) {
57
+ return hashCache.get(data);
58
+ }
59
+ const serialized = JSON.stringify(data, hashReplacer);
60
+ const hashValue = murmurhash.murmur3(serialized).toString(16);
61
+ hashCache.set(data, hashValue);
62
+ return hashValue;
63
+ }
64
+ function binarySearch(array, value, comparator) {
65
+ let low = 0;
66
+ let high = array.length;
67
+ while (low < high) {
68
+ const mid = Math.floor((low + high) / 2);
69
+ const comparison = comparator(array[mid], value);
70
+ if (comparison < 0) {
71
+ low = mid + 1;
72
+ } else if (comparison > 0) {
73
+ high = mid;
74
+ } else {
75
+ return mid;
76
+ }
77
+ }
78
+ return low;
79
+ }
80
+ class ObjectIdGenerator {
81
+ constructor() {
82
+ this.objectIds = /* @__PURE__ */ new WeakMap();
83
+ this.nextId = 0;
84
+ }
85
+ /**
86
+ * Get a unique identifier for any value.
87
+ * - Objects: Uses WeakMap for reference-based identity
88
+ * - Primitives: Uses consistent string-based hashing
89
+ */
90
+ getId(value) {
91
+ if (typeof value !== `object` || value === null) {
92
+ const str = String(value);
93
+ let hashValue = 0;
94
+ for (let i = 0; i < str.length; i++) {
95
+ const char = str.charCodeAt(i);
96
+ hashValue = (hashValue << 5) - hashValue + char;
97
+ hashValue = hashValue & hashValue;
98
+ }
99
+ return hashValue;
100
+ }
101
+ if (!this.objectIds.has(value)) {
102
+ this.objectIds.set(value, this.nextId++);
103
+ }
104
+ return this.objectIds.get(value);
105
+ }
106
+ /**
107
+ * Get a string representation of the ID for use in composite keys.
108
+ */
109
+ getStringId(value) {
110
+ if (value === null) return `null`;
111
+ if (value === void 0) return `undefined`;
112
+ if (typeof value !== `object`) return `str_${String(value)}`;
113
+ return `obj_${this.getId(value)}`;
114
+ }
115
+ }
116
+ const globalObjectIdGenerator = new ObjectIdGenerator();
117
+ export {
118
+ DefaultMap,
119
+ ObjectIdGenerator,
120
+ binarySearch,
121
+ chunkedArrayPush,
122
+ globalObjectIdGenerator,
123
+ hash
124
+ };
125
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import murmurhash from \"murmurhash-js\"\n\n/**\n * A map that returns a default value for keys that are not present.\n */\nexport class DefaultMap<K, V> extends Map<K, V> {\n constructor(\n private defaultValue: () => V,\n entries?: Iterable<[K, V]>\n ) {\n super(entries)\n }\n\n get(key: K): V {\n if (!this.has(key)) {\n this.set(key, this.defaultValue())\n }\n return super.get(key)!\n }\n\n /**\n * Update the value for a key using a function.\n */\n update(key: K, updater: (value: V) => V): V {\n const value = this.get(key)\n const newValue = updater(value)\n this.set(key, newValue)\n return newValue\n }\n}\n\n// JS engines have various limits on how many args can be passed to a function\n// with a spread operator, so we need to split the operation into chunks\n// 32767 is the max for Chrome 14, all others are higher\n// TODO: investigate the performance of this and other approaches\nconst chunkSize = 30000\nexport function chunkedArrayPush(array: Array<unknown>, other: Array<unknown>) {\n if (other.length <= chunkSize) {\n array.push(...other)\n } else {\n for (let i = 0; i < other.length; i += chunkSize) {\n const chunk = other.slice(i, i + chunkSize)\n array.push(...chunk)\n }\n }\n}\n\nconst hashCache = new WeakMap()\n\n/**\n * Replacer function for JSON.stringify that converts unsupported types to strings\n */\nfunction hashReplacer(_key: string, value: any): any {\n if (typeof value === `bigint`) {\n return String(value)\n } else if (typeof value === `symbol`) {\n return String(value)\n } else if (typeof value === `function`) {\n return String(value)\n } else if (value === undefined) {\n return `undefined`\n } else if (value instanceof Map) {\n return `Map(${JSON.stringify(Array.from(value.entries()), hashReplacer)})`\n } else if (value instanceof Set) {\n return `Set(${JSON.stringify(Array.from(value.values()), hashReplacer)})`\n }\n return value\n}\n\n/**\n * A hash method that caches the hash of a value in a week map\n */\nexport function hash(data: any): string {\n if (\n data === null ||\n data === undefined ||\n (typeof data !== `object` && typeof data !== `function`)\n ) {\n // Can't be cached in the weak map because it's not an object\n const serialized = JSON.stringify(data, hashReplacer)\n return murmurhash.murmur3(serialized).toString(16)\n }\n\n if (hashCache.has(data)) {\n return hashCache.get(data)\n }\n\n const serialized = JSON.stringify(data, hashReplacer)\n const hashValue = murmurhash.murmur3(serialized).toString(16)\n hashCache.set(data, hashValue)\n return hashValue\n}\n\nexport function binarySearch<T>(\n array: Array<T>,\n value: T,\n comparator: (a: T, b: T) => number\n): number {\n let low = 0\n let high = array.length\n while (low < high) {\n const mid = Math.floor((low + high) / 2)\n const comparison = comparator(array[mid]!, value)\n if (comparison < 0) {\n low = mid + 1\n } else if (comparison > 0) {\n high = mid\n } else {\n return mid\n }\n }\n return low\n}\n\n/**\n * Utility for generating unique IDs for objects and values.\n * Uses WeakMap for object reference tracking and consistent hashing for primitives.\n */\nexport class ObjectIdGenerator {\n private objectIds = new WeakMap<object, number>()\n private nextId = 0\n\n /**\n * Get a unique identifier for any value.\n * - Objects: Uses WeakMap for reference-based identity\n * - Primitives: Uses consistent string-based hashing\n */\n getId(value: any): number {\n // For primitives, use a simple hash of their string representation\n if (typeof value !== `object` || value === null) {\n const str = String(value)\n let hashValue = 0\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i)\n hashValue = (hashValue << 5) - hashValue + char\n hashValue = hashValue & hashValue // Convert to 32-bit integer\n }\n return hashValue\n }\n\n // For objects, use WeakMap to assign unique IDs\n if (!this.objectIds.has(value)) {\n this.objectIds.set(value, this.nextId++)\n }\n return this.objectIds.get(value)!\n }\n\n /**\n * Get a string representation of the ID for use in composite keys.\n */\n getStringId(value: any): string {\n if (value === null) return `null`\n if (value === undefined) return `undefined`\n if (typeof value !== `object`) return `str_${String(value)}`\n\n return `obj_${this.getId(value)}`\n }\n}\n\n/**\n * Global instance for cases where a shared object ID space is needed.\n */\nexport const globalObjectIdGenerator = new ObjectIdGenerator()\n"],"names":["serialized"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/db-ivm",
3
3
  "description": "Incremental View Maintenance for TanStack DB based on Differential Dataflow",
4
- "version": "0.0.0",
4
+ "version": "0.1.1",
5
5
  "dependencies": {
6
6
  "fractional-indexing": "^3.2.0",
7
7
  "murmurhash-js": "^1.0.0",
@@ -31,7 +31,6 @@
31
31
  ],
32
32
  "main": "dist/cjs/index.cjs",
33
33
  "module": "dist/esm/index.js",
34
- "packageManager": "pnpm@10.6.3",
35
34
  "peerDependencies": {
36
35
  "typescript": ">=4.7"
37
36
  },
@@ -51,13 +50,13 @@
51
50
  "ivm",
52
51
  "differential-dataflow"
53
52
  ],
53
+ "sideEffects": false,
54
+ "type": "module",
55
+ "types": "dist/esm/index.d.ts",
54
56
  "scripts": {
55
57
  "build": "vite build",
56
58
  "dev": "vite build --watch",
57
59
  "lint": "eslint . --fix",
58
60
  "test": "npx vitest --run"
59
- },
60
- "sideEffects": false,
61
- "type": "module",
62
- "types": "dist/esm/index.d.ts"
63
- }
61
+ }
62
+ }