@tanstack/db-ivm 0.1.19 → 0.1.22
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/hashing/hash.cjs +114 -45
- package/dist/cjs/hashing/hash.cjs.map +1 -1
- package/dist/cjs/hashing/hash.d.cts +7 -0
- package/dist/cjs/hashing/murmur.cjs +32 -9
- package/dist/cjs/hashing/murmur.cjs.map +1 -1
- package/dist/cjs/hashing/murmur.d.cts +1 -0
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/operators/distinct.cjs.map +1 -1
- package/dist/cjs/operators/distinct.d.cts +1 -1
- package/dist/cjs/operators/groupBy.cjs +1 -1
- package/dist/cjs/operators/groupBy.cjs.map +1 -1
- package/dist/cjs/operators/groupedTopKWithFractionalIndex.cjs +4 -5
- package/dist/cjs/operators/groupedTopKWithFractionalIndex.cjs.map +1 -1
- package/dist/cjs/operators/topKArray.cjs +2 -0
- package/dist/cjs/operators/topKArray.cjs.map +1 -1
- package/dist/cjs/operators/topKState.cjs +30 -0
- package/dist/cjs/operators/topKState.cjs.map +1 -1
- package/dist/cjs/operators/topKState.d.cts +9 -0
- package/dist/cjs/operators/topKWithFractionalIndex.cjs +4 -5
- package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -1
- package/dist/cjs/utils.cjs +8 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/esm/hashing/hash.d.ts +7 -0
- package/dist/esm/hashing/hash.js +116 -47
- package/dist/esm/hashing/hash.js.map +1 -1
- package/dist/esm/hashing/murmur.d.ts +1 -0
- package/dist/esm/hashing/murmur.js +32 -9
- package/dist/esm/hashing/murmur.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/operators/distinct.d.ts +1 -1
- package/dist/esm/operators/distinct.js.map +1 -1
- package/dist/esm/operators/groupBy.js +1 -1
- package/dist/esm/operators/groupBy.js.map +1 -1
- package/dist/esm/operators/groupedTopKWithFractionalIndex.js +5 -6
- package/dist/esm/operators/groupedTopKWithFractionalIndex.js.map +1 -1
- package/dist/esm/operators/topKArray.js +2 -0
- package/dist/esm/operators/topKArray.js.map +1 -1
- package/dist/esm/operators/topKState.d.ts +9 -0
- package/dist/esm/operators/topKState.js +31 -1
- package/dist/esm/operators/topKState.js.map +1 -1
- package/dist/esm/operators/topKWithFractionalIndex.js +5 -6
- package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -1
- package/dist/esm/utils.js +8 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +5 -2
- package/src/hashing/hash.ts +189 -57
- package/src/hashing/murmur.ts +44 -10
- package/src/index.ts +1 -0
- package/src/operators/distinct.ts +5 -3
- package/src/operators/groupBy.ts +7 -4
- package/src/operators/groupedTopKWithFractionalIndex.ts +10 -6
- package/src/operators/topKArray.ts +4 -0
- package/src/operators/topKState.ts +42 -0
- package/src/operators/topKWithFractionalIndex.ts +10 -6
- package/src/operators/topKWithFractionalIndexBTree.ts +7 -8
- package/src/utils.ts +8 -0
- package/dist/cjs/operators/orderByBTree.d.cts +0 -3
- package/dist/esm/operators/orderByBTree.d.ts +0 -3
- package/src/operators/orderByBTree.ts +0 -20
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { equalHashValues } from '../hashing/hash.js'
|
|
1
2
|
import { TopKArray } from './topKArray.js'
|
|
3
|
+
import type { MultiSet } from '../multiset.js'
|
|
2
4
|
import type {
|
|
3
5
|
IndexedValue,
|
|
4
6
|
TopK,
|
|
@@ -6,6 +8,46 @@ import type {
|
|
|
6
8
|
TopKMoveChanges,
|
|
7
9
|
} from './topKArray.js'
|
|
8
10
|
|
|
11
|
+
/** Apply a keyed batch's retractions before additions. An outer join can emit
|
|
12
|
+
* a replacement in the opposite order; key multiplicity alone would hide it.
|
|
13
|
+
* Consolidate first so a transient value added and removed in this same turn
|
|
14
|
+
* cannot be mistaken for the final replacement. Use structural relation
|
|
15
|
+
* identity: map can allocate a fresh value for each side of a cancelling pair.
|
|
16
|
+
* No state survives the run.
|
|
17
|
+
*/
|
|
18
|
+
export function* topKBatch<K, T>(messages: Array<MultiSet<[K, T]>>) {
|
|
19
|
+
const keyed = new Map<K, Array<[[K, T], number]>>()
|
|
20
|
+
for (const message of messages) {
|
|
21
|
+
for (const [value, weight] of message.getInner()) {
|
|
22
|
+
const entries = keyed.get(value[0])
|
|
23
|
+
if (entries) entries.push([value, weight])
|
|
24
|
+
else keyed.set(value[0], [[value, weight]])
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const batch: Array<[[K, T], number]> = []
|
|
28
|
+
for (const entries of keyed.values()) {
|
|
29
|
+
// Ordering distinct keys needs only the caller's comparator. In particular,
|
|
30
|
+
// do not traverse irrelevant payloads or merge keys on a hash collision.
|
|
31
|
+
if (entries.length === 1) {
|
|
32
|
+
batch.push(entries[0]!)
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
// A per-key scan keeps normal two-version replacements cheap and permits
|
|
36
|
+
// cycles, at the cost of quadratic comparisons for long same-key histories.
|
|
37
|
+
const consolidated: Array<[[K, T], number]> = []
|
|
38
|
+
for (const [value, weight] of entries) {
|
|
39
|
+
const previous = consolidated.find(([candidate]) =>
|
|
40
|
+
equalHashValues(candidate[1], value[1]),
|
|
41
|
+
)
|
|
42
|
+
if (previous) previous[1] += weight
|
|
43
|
+
else consolidated.push([value, weight])
|
|
44
|
+
}
|
|
45
|
+
batch.push(...consolidated)
|
|
46
|
+
}
|
|
47
|
+
for (const entry of batch) if (entry[1] < 0) yield entry
|
|
48
|
+
for (const entry of batch) if (entry[1] > 0) yield entry
|
|
49
|
+
}
|
|
50
|
+
|
|
9
51
|
/**
|
|
10
52
|
* Helper class that manages the state for a single topK window.
|
|
11
53
|
* Encapsulates the multiplicity tracking and topK data structure,
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { DifferenceStreamWriter, UnaryOperator } from '../graph.js'
|
|
2
2
|
import { StreamBuilder } from '../d2.js'
|
|
3
3
|
import { MultiSet } from '../multiset.js'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
TopKState,
|
|
6
|
+
handleMoveIn,
|
|
7
|
+
handleMoveOut,
|
|
8
|
+
topKBatch,
|
|
9
|
+
} from './topKState.js'
|
|
5
10
|
import { TopKArray, createKeyedComparator } from './topKArray.js'
|
|
6
11
|
import type { IndexedValue, TopK } from './topKArray.js'
|
|
7
12
|
import type { DifferenceStreamReader } from '../graph.js'
|
|
@@ -76,11 +81,10 @@ export class TopKWithFractionalIndexOperator<
|
|
|
76
81
|
|
|
77
82
|
run(): void {
|
|
78
83
|
const result: Array<[[K, IndexedValue<T>], number]> = []
|
|
79
|
-
for (const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
+
for (const [[key, value], multiplicity] of topKBatch(
|
|
85
|
+
this.inputMessages(),
|
|
86
|
+
)) {
|
|
87
|
+
this.processElement(key, value, multiplicity, result)
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
if (result.length > 0) {
|
|
@@ -106,9 +106,11 @@ class TopKTree<V> implements TopK<V> {
|
|
|
106
106
|
return result
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
if (
|
|
110
|
+
this.#topKStart === this.#topKEnd ||
|
|
111
|
+
this.#tree.size - 1 < this.#topKStart
|
|
112
|
+
) {
|
|
113
|
+
// The window is empty, or there aren't enough rows to reach its offset.
|
|
112
114
|
return result
|
|
113
115
|
}
|
|
114
116
|
|
|
@@ -178,11 +180,8 @@ class TopKTree<V> implements TopK<V> {
|
|
|
178
180
|
return result
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
if (this.#comparator(value, getValue(this.#topKFirstElem))
|
|
182
|
-
//
|
|
183
|
-
// so the topK has shifted one position to the left
|
|
184
|
-
|
|
185
|
-
// the old first element moves out of the topK
|
|
183
|
+
if (this.#comparator(value, getValue(this.#topKFirstElem)) <= 0) {
|
|
184
|
+
// Deleting at or before the first selected value advances that boundary.
|
|
186
185
|
result.moveOut = this.#topKFirstElem
|
|
187
186
|
// the element that was right after the first element of the topK
|
|
188
187
|
// is now the new first element of the topK
|
package/src/utils.ts
CHANGED
|
@@ -185,6 +185,14 @@ function range(start: number, end: number): Array<number> {
|
|
|
185
185
|
export function compareKeys(a: string | number, b: string | number): number {
|
|
186
186
|
// Same type: compare directly
|
|
187
187
|
if (typeof a === typeof b) {
|
|
188
|
+
if (typeof a === `number` && typeof b === `number`) {
|
|
189
|
+
const aIsNaN = Number.isNaN(a)
|
|
190
|
+
const bIsNaN = Number.isNaN(b)
|
|
191
|
+
if (aIsNaN || bIsNaN) {
|
|
192
|
+
if (aIsNaN && bIsNaN) return 0
|
|
193
|
+
return aIsNaN ? 1 : -1
|
|
194
|
+
}
|
|
195
|
+
}
|
|
188
196
|
if (a < b) return -1
|
|
189
197
|
if (a > b) return 1
|
|
190
198
|
return 0
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { KeyValue } from '../types.js';
|
|
2
|
-
import { OrderByOptions } from './orderBy.js';
|
|
3
|
-
export declare function orderByWithFractionalIndexBTree<T extends KeyValue<unknown, unknown>, Ve = unknown>(valueExtractor: (value: T extends KeyValue<unknown, infer V> ? V : never) => Ve, options?: OrderByOptions<Ve>): (stream: import('../types.js').IStreamBuilder<T>) => import('../types.js').IStreamBuilder<[T extends KeyValue<infer K, unknown> ? K : never, [T extends KeyValue<unknown, infer V> ? V : never, string]]>;
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { KeyValue } from '../types.js';
|
|
2
|
-
import { OrderByOptions } from './orderBy.js';
|
|
3
|
-
export declare function orderByWithFractionalIndexBTree<T extends KeyValue<unknown, unknown>, Ve = unknown>(valueExtractor: (value: T extends KeyValue<unknown, infer V> ? V : never) => Ve, options?: OrderByOptions<Ve>): (stream: import('../types.js').IStreamBuilder<T>) => import('../types.js').IStreamBuilder<[T extends KeyValue<infer K, unknown> ? K : never, [T extends KeyValue<unknown, infer V> ? V : never, string]]>;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { orderByWithFractionalIndexBase } from './orderBy.js'
|
|
2
|
-
import { topKWithFractionalIndexBTree } from './topKWithFractionalIndexBTree.js'
|
|
3
|
-
import type { KeyValue } from '../types.js'
|
|
4
|
-
import type { OrderByOptions } from './orderBy.js'
|
|
5
|
-
|
|
6
|
-
export function orderByWithFractionalIndexBTree<
|
|
7
|
-
T extends KeyValue<unknown, unknown>,
|
|
8
|
-
Ve = unknown,
|
|
9
|
-
>(
|
|
10
|
-
valueExtractor: (
|
|
11
|
-
value: T extends KeyValue<unknown, infer V> ? V : never,
|
|
12
|
-
) => Ve,
|
|
13
|
-
options?: OrderByOptions<Ve>,
|
|
14
|
-
) {
|
|
15
|
-
return orderByWithFractionalIndexBase(
|
|
16
|
-
topKWithFractionalIndexBTree,
|
|
17
|
-
valueExtractor,
|
|
18
|
-
options,
|
|
19
|
-
)
|
|
20
|
-
}
|