@tanstack/db-ivm 0.1.12 → 0.1.14
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/README.md +3 -3
- package/dist/cjs/d2.cjs.map +1 -1
- package/dist/cjs/graph.cjs.map +1 -1
- package/dist/cjs/hashing/hash.cjs +22 -3
- package/dist/cjs/hashing/hash.cjs.map +1 -1
- package/dist/cjs/hashing/murmur.cjs +15 -15
- package/dist/cjs/hashing/murmur.cjs.map +1 -1
- package/dist/cjs/hashing/murmur.d.cts +1 -1
- 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/indexes.cjs.map +1 -1
- package/dist/cjs/multiset.cjs.map +1 -1
- package/dist/cjs/operators/concat.cjs.map +1 -1
- package/dist/cjs/operators/consolidate.cjs.map +1 -1
- package/dist/cjs/operators/count.cjs.map +1 -1
- package/dist/cjs/operators/debug.cjs.map +1 -1
- package/dist/cjs/operators/distinct.cjs.map +1 -1
- package/dist/cjs/operators/filter.cjs.map +1 -1
- package/dist/cjs/operators/filterBy.cjs.map +1 -1
- package/dist/cjs/operators/groupBy.cjs.map +1 -1
- package/dist/cjs/operators/join.cjs.map +1 -1
- package/dist/cjs/operators/keying.cjs.map +1 -1
- package/dist/cjs/operators/map.cjs.map +1 -1
- package/dist/cjs/operators/negate.cjs.map +1 -1
- package/dist/cjs/operators/orderBy.cjs.map +1 -1
- package/dist/cjs/operators/output.cjs.map +1 -1
- package/dist/cjs/operators/pipe.cjs.map +1 -1
- package/dist/cjs/operators/reduce.cjs.map +1 -1
- package/dist/cjs/operators/tap.cjs.map +1 -1
- package/dist/cjs/operators/topK.cjs.map +1 -1
- package/dist/cjs/operators/topKWithFractionalIndex.cjs +20 -35
- package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -1
- package/dist/cjs/operators/topKWithFractionalIndex.d.cts +3 -11
- package/dist/cjs/operators/topKWithFractionalIndexBTree.d.cts +4 -4
- package/dist/cjs/utils.cjs +9 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +5 -0
- package/dist/esm/d2.js.map +1 -1
- package/dist/esm/graph.js.map +1 -1
- package/dist/esm/hashing/hash.js +22 -3
- package/dist/esm/hashing/hash.js.map +1 -1
- package/dist/esm/hashing/murmur.d.ts +1 -1
- package/dist/esm/hashing/murmur.js +15 -15
- 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/indexes.js.map +1 -1
- package/dist/esm/multiset.js.map +1 -1
- package/dist/esm/operators/concat.js.map +1 -1
- package/dist/esm/operators/consolidate.js.map +1 -1
- package/dist/esm/operators/count.js.map +1 -1
- package/dist/esm/operators/debug.js.map +1 -1
- package/dist/esm/operators/distinct.js.map +1 -1
- package/dist/esm/operators/filter.js.map +1 -1
- package/dist/esm/operators/filterBy.js.map +1 -1
- package/dist/esm/operators/groupBy.js.map +1 -1
- package/dist/esm/operators/join.js.map +1 -1
- package/dist/esm/operators/keying.js.map +1 -1
- package/dist/esm/operators/map.js.map +1 -1
- package/dist/esm/operators/negate.js.map +1 -1
- package/dist/esm/operators/orderBy.js.map +1 -1
- package/dist/esm/operators/output.js.map +1 -1
- package/dist/esm/operators/pipe.js.map +1 -1
- package/dist/esm/operators/reduce.js.map +1 -1
- package/dist/esm/operators/tap.js.map +1 -1
- package/dist/esm/operators/topK.js.map +1 -1
- package/dist/esm/operators/topKWithFractionalIndex.d.ts +3 -11
- package/dist/esm/operators/topKWithFractionalIndex.js +21 -36
- package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -1
- package/dist/esm/operators/topKWithFractionalIndexBTree.d.ts +4 -4
- package/dist/esm/utils.d.ts +5 -0
- package/dist/esm/utils.js +9 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +29 -29
- package/src/d2.ts +4 -4
- package/src/graph.ts +6 -6
- package/src/hashing/hash.ts +39 -14
- package/src/hashing/index.ts +2 -2
- package/src/hashing/murmur.ts +15 -15
- package/src/index.ts +5 -4
- package/src/indexes.ts +8 -8
- package/src/multiset.ts +5 -5
- package/src/operators/concat.ts +6 -6
- package/src/operators/consolidate.ts +6 -6
- package/src/operators/count.ts +9 -9
- package/src/operators/debug.ts +8 -8
- package/src/operators/distinct.ts +11 -11
- package/src/operators/filter.ts +8 -8
- package/src/operators/filterBy.ts +7 -7
- package/src/operators/groupBy.ts +22 -22
- package/src/operators/index.ts +19 -19
- package/src/operators/join.ts +23 -23
- package/src/operators/keying.ts +4 -4
- package/src/operators/map.ts +8 -8
- package/src/operators/negate.ts +6 -6
- package/src/operators/orderBy.ts +26 -26
- package/src/operators/orderByBTree.ts +7 -7
- package/src/operators/output.ts +9 -9
- package/src/operators/pipe.ts +1 -1
- package/src/operators/reduce.ts +9 -9
- package/src/operators/tap.ts +8 -8
- package/src/operators/topK.ts +8 -8
- package/src/operators/topKWithFractionalIndex.ts +62 -83
- package/src/operators/topKWithFractionalIndexBTree.ts +19 -20
- package/src/types.ts +22 -22
- package/src/utils.ts +19 -4
package/src/hashing/hash.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MurmurHashStream, randomHash } from
|
|
2
|
-
import type { Hasher } from
|
|
1
|
+
import { MurmurHashStream, randomHash } from './murmur.js'
|
|
2
|
+
import type { Hasher } from './murmur.js'
|
|
3
3
|
|
|
4
4
|
/*
|
|
5
5
|
* Implementation of structural hashing based on the Composites polyfill implementation:
|
|
@@ -17,6 +17,12 @@ const OBJECT_MARKER = randomHash()
|
|
|
17
17
|
const ARRAY_MARKER = randomHash()
|
|
18
18
|
const MAP_MARKER = randomHash()
|
|
19
19
|
const SET_MARKER = randomHash()
|
|
20
|
+
const UINT8ARRAY_MARKER = randomHash()
|
|
21
|
+
|
|
22
|
+
// Maximum byte length for Uint8Arrays to hash by content instead of reference
|
|
23
|
+
// Arrays smaller than this will be hashed by content, allowing proper equality comparisons
|
|
24
|
+
// for small arrays like ULIDs (16 bytes) while still avoiding performance costs for large arrays
|
|
25
|
+
const UINT8ARRAY_CONTENT_HASH_THRESHOLD = 128
|
|
20
26
|
|
|
21
27
|
const hashCache = new WeakMap<object, number>()
|
|
22
28
|
|
|
@@ -35,6 +41,24 @@ function hashObject(input: object): number {
|
|
|
35
41
|
let valueHash: number | undefined
|
|
36
42
|
if (input instanceof Date) {
|
|
37
43
|
valueHash = hashDate(input)
|
|
44
|
+
} else if (
|
|
45
|
+
// Check if input is a Uint8Array or Buffer
|
|
46
|
+
(typeof Buffer !== `undefined` && input instanceof Buffer) ||
|
|
47
|
+
input instanceof Uint8Array
|
|
48
|
+
) {
|
|
49
|
+
// For small Uint8Arrays/Buffers (e.g., ULIDs, UUIDs), hash by content
|
|
50
|
+
// to enable proper equality comparisons. For large arrays, hash by reference
|
|
51
|
+
// to avoid performance costs.
|
|
52
|
+
if (input.byteLength <= UINT8ARRAY_CONTENT_HASH_THRESHOLD) {
|
|
53
|
+
valueHash = hashUint8Array(input)
|
|
54
|
+
} else {
|
|
55
|
+
// Deeply hashing large arrays would be too costly
|
|
56
|
+
// so we track them by reference and cache them in a weak map
|
|
57
|
+
return cachedReferenceHash(input)
|
|
58
|
+
}
|
|
59
|
+
} else if (input instanceof File) {
|
|
60
|
+
// Files are always hashed by reference due to their potentially large size
|
|
61
|
+
return cachedReferenceHash(input)
|
|
38
62
|
} else {
|
|
39
63
|
let plainObjectInput = input
|
|
40
64
|
let marker = OBJECT_MARKER
|
|
@@ -53,17 +77,6 @@ function hashObject(input: object): number {
|
|
|
53
77
|
plainObjectInput = [...input.entries()]
|
|
54
78
|
}
|
|
55
79
|
|
|
56
|
-
if (
|
|
57
|
-
(typeof Buffer !== `undefined` && input instanceof Buffer) ||
|
|
58
|
-
input instanceof Uint8Array ||
|
|
59
|
-
input instanceof File
|
|
60
|
-
) {
|
|
61
|
-
// Deeply hashing these objects would be too costly
|
|
62
|
-
// but we also don't want to ignore them
|
|
63
|
-
// so we track them by reference and cache them in a weak map
|
|
64
|
-
return cachedReferenceHash(input)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
80
|
valueHash = hashPlainObject(plainObjectInput, marker)
|
|
68
81
|
}
|
|
69
82
|
|
|
@@ -78,6 +91,18 @@ function hashDate(input: Date): number {
|
|
|
78
91
|
return hasher.digest()
|
|
79
92
|
}
|
|
80
93
|
|
|
94
|
+
function hashUint8Array(input: Uint8Array): number {
|
|
95
|
+
const hasher = new MurmurHashStream()
|
|
96
|
+
hasher.update(UINT8ARRAY_MARKER)
|
|
97
|
+
// Hash the byte length first to differentiate arrays of different sizes
|
|
98
|
+
hasher.update(input.byteLength)
|
|
99
|
+
// Hash each byte in the array
|
|
100
|
+
for (let i = 0; i < input.byteLength; i++) {
|
|
101
|
+
hasher.writeByte(input[i]!)
|
|
102
|
+
}
|
|
103
|
+
return hasher.digest()
|
|
104
|
+
}
|
|
105
|
+
|
|
81
106
|
function hashPlainObject(input: object, marker: number): number {
|
|
82
107
|
const hasher = new MurmurHashStream()
|
|
83
108
|
|
|
@@ -125,7 +150,7 @@ function updateHasher(hasher: Hasher, input: unknown): void {
|
|
|
125
150
|
return
|
|
126
151
|
default:
|
|
127
152
|
console.warn(
|
|
128
|
-
`Ignored input during hashing because it is of type ${typeof input} which is not supported
|
|
153
|
+
`Ignored input during hashing because it is of type ${typeof input} which is not supported`,
|
|
129
154
|
)
|
|
130
155
|
}
|
|
131
156
|
}
|
package/src/hashing/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { hash } from
|
|
2
|
-
export type { Hash, Hasher } from
|
|
1
|
+
export { hash } from './hash.js'
|
|
2
|
+
export type { Hash, Hasher } from './murmur.js'
|
package/src/hashing/murmur.ts
CHANGED
|
@@ -51,7 +51,7 @@ export class MurmurHashStream implements Hasher {
|
|
|
51
51
|
this.hash = Math.imul(this.hash, 5) + 0xe6546b64
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
writeByte(byte: number): void {
|
|
55
55
|
this.carry |= (byte & 0xff) << (8 * this.carryBytes)
|
|
56
56
|
this.carryBytes++
|
|
57
57
|
this.length++
|
|
@@ -74,8 +74,8 @@ export class MurmurHashStream implements Hasher {
|
|
|
74
74
|
|
|
75
75
|
for (let i = 0; i < description.length; i++) {
|
|
76
76
|
const code = description.charCodeAt(i)
|
|
77
|
-
this.
|
|
78
|
-
this.
|
|
77
|
+
this.writeByte(code & 0xff)
|
|
78
|
+
this.writeByte((code >>> 8) & 0xff)
|
|
79
79
|
}
|
|
80
80
|
return
|
|
81
81
|
}
|
|
@@ -83,20 +83,20 @@ export class MurmurHashStream implements Hasher {
|
|
|
83
83
|
this.update(STRING_MARKER)
|
|
84
84
|
for (let i = 0; i < chunk.length; i++) {
|
|
85
85
|
const code = chunk.charCodeAt(i)
|
|
86
|
-
this.
|
|
87
|
-
this.
|
|
86
|
+
this.writeByte(code & 0xff)
|
|
87
|
+
this.writeByte((code >>> 8) & 0xff)
|
|
88
88
|
}
|
|
89
89
|
return
|
|
90
90
|
case `number`:
|
|
91
91
|
dv.setFloat64(0, chunk, true) // fixed little-endian
|
|
92
|
-
this.
|
|
93
|
-
this.
|
|
94
|
-
this.
|
|
95
|
-
this.
|
|
96
|
-
this.
|
|
97
|
-
this.
|
|
98
|
-
this.
|
|
99
|
-
this.
|
|
92
|
+
this.writeByte(u8[0]!)
|
|
93
|
+
this.writeByte(u8[1]!)
|
|
94
|
+
this.writeByte(u8[2]!)
|
|
95
|
+
this.writeByte(u8[3]!)
|
|
96
|
+
this.writeByte(u8[4]!)
|
|
97
|
+
this.writeByte(u8[5]!)
|
|
98
|
+
this.writeByte(u8[6]!)
|
|
99
|
+
this.writeByte(u8[7]!)
|
|
100
100
|
return
|
|
101
101
|
case `bigint`: {
|
|
102
102
|
let value = chunk
|
|
@@ -107,10 +107,10 @@ export class MurmurHashStream implements Hasher {
|
|
|
107
107
|
this.update(BIG_INT_MARKER)
|
|
108
108
|
}
|
|
109
109
|
while (value > 0n) {
|
|
110
|
-
this.
|
|
110
|
+
this.writeByte(Number(value & 0xffn))
|
|
111
111
|
value >>= 8n
|
|
112
112
|
}
|
|
113
|
-
if (chunk === 0n) this.
|
|
113
|
+
if (chunk === 0n) this.writeByte(0)
|
|
114
114
|
return
|
|
115
115
|
}
|
|
116
116
|
default:
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
1
|
+
export * from './d2.js'
|
|
2
|
+
export * from './multiset.js'
|
|
3
|
+
export * from './operators/index.js'
|
|
4
|
+
export * from './types.js'
|
|
5
|
+
export { compareKeys } from './utils.js'
|
package/src/indexes.ts
CHANGED
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
* Prefixes extracted from array values: `['prefix', 'suffix']` → prefix='prefix'
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
|
-
import { MultiSet } from
|
|
37
|
-
import { hash } from
|
|
38
|
-
import type { Hash } from
|
|
36
|
+
import { MultiSet } from './multiset.js'
|
|
37
|
+
import { hash } from './hashing/index.js'
|
|
38
|
+
import type { Hash } from './hashing/index.js'
|
|
39
39
|
|
|
40
40
|
// We use a symbol to represent the absence of a prefix, unprefixed values a stored
|
|
41
41
|
// against this key.
|
|
@@ -183,7 +183,7 @@ export class Index<TKey, TValue, TPrefix = any> {
|
|
|
183
183
|
return `Index(${JSON.stringify(
|
|
184
184
|
[...this.entries()],
|
|
185
185
|
undefined,
|
|
186
|
-
indent ? 2 : undefined
|
|
186
|
+
indent ? 2 : undefined,
|
|
187
187
|
)})`
|
|
188
188
|
}
|
|
189
189
|
|
|
@@ -325,7 +325,7 @@ export class Index<TKey, TValue, TPrefix = any> {
|
|
|
325
325
|
key,
|
|
326
326
|
mapOrSingleValue,
|
|
327
327
|
value,
|
|
328
|
-
multiplicity
|
|
328
|
+
multiplicity,
|
|
329
329
|
)
|
|
330
330
|
return
|
|
331
331
|
}
|
|
@@ -362,7 +362,7 @@ export class Index<TKey, TValue, TPrefix = any> {
|
|
|
362
362
|
key: TKey,
|
|
363
363
|
currentSingleValue: SingleValue<TValue>,
|
|
364
364
|
newValue: TValue,
|
|
365
|
-
multiplicity: number
|
|
365
|
+
multiplicity: number,
|
|
366
366
|
) {
|
|
367
367
|
const [currentValue, currentMultiplicity] = currentSingleValue
|
|
368
368
|
|
|
@@ -438,7 +438,7 @@ export class Index<TKey, TValue, TPrefix = any> {
|
|
|
438
438
|
* @returns A multiset of the joined values.
|
|
439
439
|
*/
|
|
440
440
|
join<TValue2>(
|
|
441
|
-
other: Index<TKey, TValue2
|
|
441
|
+
other: Index<TKey, TValue2>,
|
|
442
442
|
): MultiSet<[TKey, [TValue, TValue2]]> {
|
|
443
443
|
const result: Array<[[TKey, [TValue, TValue2]], number]> = []
|
|
444
444
|
// We want to iterate over the smaller of the two indexes to reduce the
|
|
@@ -499,7 +499,7 @@ function getPrefix<TValue, TPrefix>(value: TValue): TPrefix | NO_PREFIX {
|
|
|
499
499
|
* @returns True if the value is a single value, false otherwise.
|
|
500
500
|
*/
|
|
501
501
|
function isSingleValue<TValue>(
|
|
502
|
-
value: SingleValue<TValue> | unknown
|
|
502
|
+
value: SingleValue<TValue> | unknown,
|
|
503
503
|
): value is SingleValue<TValue> {
|
|
504
504
|
return Array.isArray(value)
|
|
505
505
|
}
|
package/src/multiset.ts
CHANGED
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
DefaultMap,
|
|
3
3
|
chunkedArrayPush,
|
|
4
4
|
globalObjectIdGenerator,
|
|
5
|
-
} from
|
|
6
|
-
import { hash } from
|
|
5
|
+
} from './utils.js'
|
|
6
|
+
import { hash } from './hashing/index.js'
|
|
7
7
|
|
|
8
8
|
export type MultiSetArray<T> = Array<[T, number]>
|
|
9
9
|
export type KeyedData<T> = [key: string, value: T]
|
|
@@ -35,7 +35,7 @@ export class MultiSet<T> {
|
|
|
35
35
|
*/
|
|
36
36
|
map<U>(f: (data: T) => U): MultiSet<U> {
|
|
37
37
|
return new MultiSet(
|
|
38
|
-
this.#inner.map(([data, multiplicity]) => [f(data), multiplicity])
|
|
38
|
+
this.#inner.map(([data, multiplicity]) => [f(data), multiplicity]),
|
|
39
39
|
)
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -51,7 +51,7 @@ export class MultiSet<T> {
|
|
|
51
51
|
*/
|
|
52
52
|
negate(): MultiSet<T> {
|
|
53
53
|
return new MultiSet(
|
|
54
|
-
this.#inner.map(([data, multiplicity]) => [data, -multiplicity])
|
|
54
|
+
this.#inner.map(([data, multiplicity]) => [data, -multiplicity]),
|
|
55
55
|
)
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -142,7 +142,7 @@ export class MultiSet<T> {
|
|
|
142
142
|
const compositeKey = key + `|` + valueId
|
|
143
143
|
consolidated.set(
|
|
144
144
|
compositeKey,
|
|
145
|
-
(consolidated.get(compositeKey) || 0) + multiplicity
|
|
145
|
+
(consolidated.get(compositeKey) || 0) + multiplicity,
|
|
146
146
|
)
|
|
147
147
|
|
|
148
148
|
// Store the original data for the first occurrence
|
package/src/operators/concat.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BinaryOperator, DifferenceStreamWriter } from
|
|
2
|
-
import { StreamBuilder } from
|
|
3
|
-
import type { IStreamBuilder, PipedOperator } from
|
|
1
|
+
import { BinaryOperator, DifferenceStreamWriter } from '../graph.js'
|
|
2
|
+
import { StreamBuilder } from '../d2.js'
|
|
3
|
+
import type { IStreamBuilder, PipedOperator } from '../types.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Operator that concatenates two input streams
|
|
@@ -22,7 +22,7 @@ export class ConcatOperator<T, T2> extends BinaryOperator<T | T2> {
|
|
|
22
22
|
* @param other - The other stream to concatenate
|
|
23
23
|
*/
|
|
24
24
|
export function concat<T, T2>(
|
|
25
|
-
other: IStreamBuilder<T2
|
|
25
|
+
other: IStreamBuilder<T2>,
|
|
26
26
|
): PipedOperator<T, T | T2> {
|
|
27
27
|
return (stream: IStreamBuilder<T | T2>): IStreamBuilder<T | T2> => {
|
|
28
28
|
if (stream.graph !== other.graph) {
|
|
@@ -30,13 +30,13 @@ export function concat<T, T2>(
|
|
|
30
30
|
}
|
|
31
31
|
const output = new StreamBuilder<T | T2>(
|
|
32
32
|
stream.graph,
|
|
33
|
-
new DifferenceStreamWriter<T | T2>()
|
|
33
|
+
new DifferenceStreamWriter<T | T2>(),
|
|
34
34
|
)
|
|
35
35
|
const operator = new ConcatOperator<T, T2>(
|
|
36
36
|
stream.graph.getNextOperatorId(),
|
|
37
37
|
stream.connectReader(),
|
|
38
38
|
other.connectReader(),
|
|
39
|
-
output.writer
|
|
39
|
+
output.writer,
|
|
40
40
|
)
|
|
41
41
|
stream.graph.addOperator(operator)
|
|
42
42
|
return output
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { DifferenceStreamWriter, UnaryOperator } from
|
|
2
|
-
import { StreamBuilder } from
|
|
3
|
-
import { MultiSet } from
|
|
4
|
-
import type { IStreamBuilder, PipedOperator } from
|
|
1
|
+
import { DifferenceStreamWriter, UnaryOperator } from '../graph.js'
|
|
2
|
+
import { StreamBuilder } from '../d2.js'
|
|
3
|
+
import { MultiSet } from '../multiset.js'
|
|
4
|
+
import type { IStreamBuilder, PipedOperator } from '../types.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Operator that consolidates collections
|
|
@@ -36,12 +36,12 @@ export function consolidate<T>(): PipedOperator<T, T> {
|
|
|
36
36
|
return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {
|
|
37
37
|
const output = new StreamBuilder<T>(
|
|
38
38
|
stream.graph,
|
|
39
|
-
new DifferenceStreamWriter<T>()
|
|
39
|
+
new DifferenceStreamWriter<T>(),
|
|
40
40
|
)
|
|
41
41
|
const operator = new ConsolidateOperator<T>(
|
|
42
42
|
stream.graph.getNextOperatorId(),
|
|
43
43
|
stream.connectReader(),
|
|
44
|
-
output.writer
|
|
44
|
+
output.writer,
|
|
45
45
|
)
|
|
46
46
|
stream.graph.addOperator(operator)
|
|
47
47
|
return output
|
package/src/operators/count.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { DifferenceStreamWriter } from
|
|
2
|
-
import { StreamBuilder } from
|
|
3
|
-
import { ReduceOperator } from
|
|
4
|
-
import type { DifferenceStreamReader } from
|
|
5
|
-
import type { IStreamBuilder, KeyValue } from
|
|
1
|
+
import { DifferenceStreamWriter } from '../graph.js'
|
|
2
|
+
import { StreamBuilder } from '../d2.js'
|
|
3
|
+
import { ReduceOperator } from './reduce.js'
|
|
4
|
+
import type { DifferenceStreamReader } from '../graph.js'
|
|
5
|
+
import type { IStreamBuilder, KeyValue } from '../types.js'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Operator that counts elements by key (version-free)
|
|
@@ -11,7 +11,7 @@ export class CountOperator<K, V> extends ReduceOperator<K, V, number> {
|
|
|
11
11
|
constructor(
|
|
12
12
|
id: number,
|
|
13
13
|
inputA: DifferenceStreamReader<[K, V]>,
|
|
14
|
-
output: DifferenceStreamWriter<[K, number]
|
|
14
|
+
output: DifferenceStreamWriter<[K, number]>,
|
|
15
15
|
) {
|
|
16
16
|
const countInner = (vals: Array<[V, number]>): Array<[number, number]> => {
|
|
17
17
|
let totalCount = 0
|
|
@@ -34,16 +34,16 @@ export function count<
|
|
|
34
34
|
T,
|
|
35
35
|
>() {
|
|
36
36
|
return (
|
|
37
|
-
stream: IStreamBuilder<T
|
|
37
|
+
stream: IStreamBuilder<T>,
|
|
38
38
|
): IStreamBuilder<KeyValue<KType, number>> => {
|
|
39
39
|
const output = new StreamBuilder<KeyValue<KType, number>>(
|
|
40
40
|
stream.graph,
|
|
41
|
-
new DifferenceStreamWriter<KeyValue<KType, number>>()
|
|
41
|
+
new DifferenceStreamWriter<KeyValue<KType, number>>(),
|
|
42
42
|
)
|
|
43
43
|
const operator = new CountOperator<KType, VType>(
|
|
44
44
|
stream.graph.getNextOperatorId(),
|
|
45
45
|
stream.connectReader() as DifferenceStreamReader<KeyValue<KType, VType>>,
|
|
46
|
-
output.writer
|
|
46
|
+
output.writer,
|
|
47
47
|
)
|
|
48
48
|
stream.graph.addOperator(operator)
|
|
49
49
|
return output
|
package/src/operators/debug.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { DifferenceStreamWriter, UnaryOperator } from
|
|
2
|
-
import { StreamBuilder } from
|
|
3
|
-
import type { IStreamBuilder, PipedOperator } from
|
|
4
|
-
import type { DifferenceStreamReader } from
|
|
1
|
+
import { DifferenceStreamWriter, UnaryOperator } from '../graph.js'
|
|
2
|
+
import { StreamBuilder } from '../d2.js'
|
|
3
|
+
import type { IStreamBuilder, PipedOperator } from '../types.js'
|
|
4
|
+
import type { DifferenceStreamReader } from '../graph.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Operator that logs debug information about the stream
|
|
@@ -15,7 +15,7 @@ export class DebugOperator<T> extends UnaryOperator<T> {
|
|
|
15
15
|
inputA: DifferenceStreamReader<T>,
|
|
16
16
|
output: DifferenceStreamWriter<T>,
|
|
17
17
|
name: string,
|
|
18
|
-
indent: boolean = false
|
|
18
|
+
indent: boolean = false,
|
|
19
19
|
) {
|
|
20
20
|
super(id, inputA, output)
|
|
21
21
|
this.#name = name
|
|
@@ -37,19 +37,19 @@ export class DebugOperator<T> extends UnaryOperator<T> {
|
|
|
37
37
|
*/
|
|
38
38
|
export function debug<T>(
|
|
39
39
|
name: string,
|
|
40
|
-
indent: boolean = false
|
|
40
|
+
indent: boolean = false,
|
|
41
41
|
): PipedOperator<T, T> {
|
|
42
42
|
return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {
|
|
43
43
|
const output = new StreamBuilder<T>(
|
|
44
44
|
stream.graph,
|
|
45
|
-
new DifferenceStreamWriter<T>()
|
|
45
|
+
new DifferenceStreamWriter<T>(),
|
|
46
46
|
)
|
|
47
47
|
const operator = new DebugOperator<T>(
|
|
48
48
|
stream.graph.getNextOperatorId(),
|
|
49
49
|
stream.connectReader(),
|
|
50
50
|
output.writer,
|
|
51
51
|
name,
|
|
52
|
-
indent
|
|
52
|
+
indent,
|
|
53
53
|
)
|
|
54
54
|
stream.graph.addOperator(operator)
|
|
55
55
|
return output
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { DifferenceStreamWriter, UnaryOperator } from
|
|
2
|
-
import { StreamBuilder } from
|
|
3
|
-
import { hash } from
|
|
4
|
-
import { MultiSet } from
|
|
5
|
-
import type { Hash } from
|
|
6
|
-
import type { DifferenceStreamReader } from
|
|
7
|
-
import type { IStreamBuilder, KeyValue } from
|
|
1
|
+
import { DifferenceStreamWriter, UnaryOperator } from '../graph.js'
|
|
2
|
+
import { StreamBuilder } from '../d2.js'
|
|
3
|
+
import { hash } from '../hashing/index.js'
|
|
4
|
+
import { MultiSet } from '../multiset.js'
|
|
5
|
+
import type { Hash } from '../hashing/index.js'
|
|
6
|
+
import type { DifferenceStreamReader } from '../graph.js'
|
|
7
|
+
import type { IStreamBuilder, KeyValue } from '../types.js'
|
|
8
8
|
|
|
9
9
|
type Multiplicity = number
|
|
10
10
|
|
|
@@ -23,7 +23,7 @@ export class DistinctOperator<
|
|
|
23
23
|
id: number,
|
|
24
24
|
input: DifferenceStreamReader<T>,
|
|
25
25
|
output: DifferenceStreamWriter<KeyValue<number, GetValue<T>>>,
|
|
26
|
-
by: (value: T) => any = (value: T) => value
|
|
26
|
+
by: (value: T) => any = (value: T) => value,
|
|
27
27
|
) {
|
|
28
28
|
super(id, input, output)
|
|
29
29
|
this.#by = by
|
|
@@ -83,18 +83,18 @@ export class DistinctOperator<
|
|
|
83
83
|
* Removes duplicate values
|
|
84
84
|
*/
|
|
85
85
|
export function distinct<T extends KeyValue<any, any>>(
|
|
86
|
-
by: (value: T) => any = (value: T) => value
|
|
86
|
+
by: (value: T) => any = (value: T) => value,
|
|
87
87
|
) {
|
|
88
88
|
return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {
|
|
89
89
|
const output = new StreamBuilder<T>(
|
|
90
90
|
stream.graph,
|
|
91
|
-
new DifferenceStreamWriter<T>()
|
|
91
|
+
new DifferenceStreamWriter<T>(),
|
|
92
92
|
)
|
|
93
93
|
const operator = new DistinctOperator<T>(
|
|
94
94
|
stream.graph.getNextOperatorId(),
|
|
95
95
|
stream.connectReader(),
|
|
96
96
|
output.writer,
|
|
97
|
-
by
|
|
97
|
+
by,
|
|
98
98
|
)
|
|
99
99
|
stream.graph.addOperator(operator)
|
|
100
100
|
return output
|
package/src/operators/filter.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { DifferenceStreamWriter, LinearUnaryOperator } from
|
|
2
|
-
import { StreamBuilder } from
|
|
3
|
-
import type { IStreamBuilder, PipedOperator } from
|
|
4
|
-
import type { DifferenceStreamReader } from
|
|
5
|
-
import type { MultiSet } from
|
|
1
|
+
import { DifferenceStreamWriter, LinearUnaryOperator } from '../graph.js'
|
|
2
|
+
import { StreamBuilder } from '../d2.js'
|
|
3
|
+
import type { IStreamBuilder, PipedOperator } from '../types.js'
|
|
4
|
+
import type { DifferenceStreamReader } from '../graph.js'
|
|
5
|
+
import type { MultiSet } from '../multiset.js'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Operator that filters elements from the input stream
|
|
@@ -14,7 +14,7 @@ export class FilterOperator<T> extends LinearUnaryOperator<T, T> {
|
|
|
14
14
|
id: number,
|
|
15
15
|
inputA: DifferenceStreamReader<T>,
|
|
16
16
|
output: DifferenceStreamWriter<T>,
|
|
17
|
-
f: (data: T) => boolean
|
|
17
|
+
f: (data: T) => boolean,
|
|
18
18
|
) {
|
|
19
19
|
super(id, inputA, output)
|
|
20
20
|
this.#f = f
|
|
@@ -33,13 +33,13 @@ export function filter<T>(f: (data: T) => boolean): PipedOperator<T, T> {
|
|
|
33
33
|
return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {
|
|
34
34
|
const output = new StreamBuilder<T>(
|
|
35
35
|
stream.graph,
|
|
36
|
-
new DifferenceStreamWriter<T>()
|
|
36
|
+
new DifferenceStreamWriter<T>(),
|
|
37
37
|
)
|
|
38
38
|
const operator = new FilterOperator<T>(
|
|
39
39
|
stream.graph.getNextOperatorId(),
|
|
40
40
|
stream.connectReader(),
|
|
41
41
|
output.writer,
|
|
42
|
-
f
|
|
42
|
+
f,
|
|
43
43
|
)
|
|
44
44
|
stream.graph.addOperator(operator)
|
|
45
45
|
return output
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { map } from
|
|
2
|
-
import { innerJoin } from
|
|
3
|
-
import { consolidate } from
|
|
4
|
-
import type { IStreamBuilder, KeyValue, PipedOperator } from
|
|
1
|
+
import { map } from './map.js'
|
|
2
|
+
import { innerJoin } from './join.js'
|
|
3
|
+
import { consolidate } from './consolidate.js'
|
|
4
|
+
import type { IStreamBuilder, KeyValue, PipedOperator } from '../types.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Filters the elements of a keyed stream, by keys of another stream.
|
|
@@ -15,16 +15,16 @@ export function filterBy<
|
|
|
15
15
|
V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never,
|
|
16
16
|
T,
|
|
17
17
|
>(
|
|
18
|
-
other: IStreamBuilder<KeyValue<K, unknown
|
|
18
|
+
other: IStreamBuilder<KeyValue<K, unknown>>,
|
|
19
19
|
): PipedOperator<T, KeyValue<K, V1>> {
|
|
20
20
|
return (stream: IStreamBuilder<T>): IStreamBuilder<KeyValue<K, V1>> => {
|
|
21
21
|
const otherKeys = other.pipe(
|
|
22
|
-
map(([key, _]) => [key, null] as KeyValue<K, null>)
|
|
22
|
+
map(([key, _]) => [key, null] as KeyValue<K, null>),
|
|
23
23
|
)
|
|
24
24
|
return stream.pipe(
|
|
25
25
|
innerJoin(otherKeys),
|
|
26
26
|
map(([key, [value, _]]) => [key, value] as KeyValue<K, V1>),
|
|
27
|
-
consolidate()
|
|
27
|
+
consolidate(),
|
|
28
28
|
)
|
|
29
29
|
}
|
|
30
30
|
}
|