@tanstack/db-ivm 0.1.13 → 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.map +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.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 +3 -3
- package/src/hashing/index.ts +2 -2
- 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/dist/esm/utils.js
CHANGED
|
@@ -103,11 +103,20 @@ function range(start, end) {
|
|
|
103
103
|
for (let i = start; i < end; i++) out.push(i);
|
|
104
104
|
return out;
|
|
105
105
|
}
|
|
106
|
+
function compareKeys(a, b) {
|
|
107
|
+
if (typeof a === typeof b) {
|
|
108
|
+
if (a < b) return -1;
|
|
109
|
+
if (a > b) return 1;
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
return typeof a === `string` ? -1 : 1;
|
|
113
|
+
}
|
|
106
114
|
export {
|
|
107
115
|
DefaultMap,
|
|
108
116
|
ObjectIdGenerator,
|
|
109
117
|
binarySearch,
|
|
110
118
|
chunkedArrayPush,
|
|
119
|
+
compareKeys,
|
|
111
120
|
diffHalfOpen,
|
|
112
121
|
globalObjectIdGenerator
|
|
113
122
|
};
|
package/dist/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["/**\n * Simple assertion function for runtime checks.\n * Throws an error if the condition is false.\n */\nexport function assert(\n condition: unknown,\n message?: string
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["/**\n * Simple assertion function for runtime checks.\n * Throws an error if the condition is false.\n */\nexport function assert(\n condition: unknown,\n message?: string,\n): asserts condition {\n if (!condition) {\n throw new Error(message || `Assertion failed`)\n }\n}\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 return 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\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\nexport function* concatIterable<T>(\n ...iterables: Array<Iterable<T>>\n): Iterable<T> {\n for (const iterable of iterables) {\n yield* iterable\n }\n}\n\nexport function* mapIterable<T, U>(\n it: Iterable<T>,\n fn: (t: T) => U,\n): Iterable<U> {\n for (const t of it) {\n yield fn(t)\n }\n}\n\nexport type HRange = [number, number] // half-open [start, end[ i.e. end is exclusive\n\n/**\n * Computes the difference between two half-open ranges.\n * @param a - The first half-open range\n * @param b - The second half-open range\n * @returns The difference between the two ranges\n */\nexport function diffHalfOpen(a: HRange, b: HRange) {\n const [a1, a2] = a\n const [b1, b2] = b\n\n // A \\ B can be up to two segments (left and right of the overlap)\n const onlyInA: Array<number> = [\n ...range(a1, Math.min(a2, b1)), // left side of A outside B\n ...range(Math.max(a1, b2), a2), // right side of A outside B\n ]\n\n // B \\ A similarly\n const onlyInB: Array<number> = [\n ...range(b1, Math.min(b2, a1)),\n ...range(Math.max(b1, a2), b2),\n ]\n\n return { onlyInA, onlyInB }\n}\n\nfunction range(start: number, end: number): Array<number> {\n const out: Array<number> = []\n for (let i = start; i < end; i++) out.push(i)\n return out\n}\n\n/**\n * Compares two keys (string | number) in a consistent, deterministic way.\n * Handles mixed types by ordering strings before numbers.\n */\nexport function compareKeys(a: string | number, b: string | number): number {\n // Same type: compare directly\n if (typeof a === typeof b) {\n if (a < b) return -1\n if (a > b) return 1\n return 0\n }\n // Different types: strings come before numbers\n return typeof a === `string` ? -1 : 1\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/db-ivm",
|
|
3
|
+
"version": "0.1.14",
|
|
3
4
|
"description": "Incremental View Maintenance for TanStack DB based on Differential Dataflow",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"@types/debug": "^4.1.12",
|
|
11
|
-
"@vitest/coverage-istanbul": "^3.2.4"
|
|
5
|
+
"author": "Sam Willis",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/TanStack/db.git",
|
|
10
|
+
"directory": "packages/db-ivm"
|
|
12
11
|
},
|
|
12
|
+
"homepage": "https://tanstack.com/db",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"electric",
|
|
15
|
+
"sql",
|
|
16
|
+
"optimistic",
|
|
17
|
+
"typescript",
|
|
18
|
+
"ivm",
|
|
19
|
+
"differential-dataflow"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "dist/cjs/index.cjs",
|
|
23
|
+
"module": "dist/esm/index.js",
|
|
24
|
+
"types": "dist/esm/index.d.ts",
|
|
13
25
|
"exports": {
|
|
14
26
|
".": {
|
|
15
27
|
"import": {
|
|
@@ -23,38 +35,26 @@
|
|
|
23
35
|
},
|
|
24
36
|
"./package.json": "./package.json"
|
|
25
37
|
},
|
|
38
|
+
"sideEffects": false,
|
|
26
39
|
"files": [
|
|
27
40
|
"dist",
|
|
28
41
|
"src"
|
|
29
42
|
],
|
|
30
|
-
"
|
|
31
|
-
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"fractional-indexing": "^3.2.0",
|
|
45
|
+
"sorted-btree": "^1.8.1"
|
|
46
|
+
},
|
|
32
47
|
"peerDependencies": {
|
|
33
48
|
"typescript": ">=4.7"
|
|
34
49
|
},
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"type": "git",
|
|
39
|
-
"url": "https://github.com/TanStack/db.git",
|
|
40
|
-
"directory": "packages/db-ivm"
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/debug": "^4.1.12",
|
|
52
|
+
"@vitest/coverage-istanbul": "^3.2.4"
|
|
41
53
|
},
|
|
42
|
-
"homepage": "https://tanstack.com/db",
|
|
43
|
-
"keywords": [
|
|
44
|
-
"electric",
|
|
45
|
-
"sql",
|
|
46
|
-
"optimistic",
|
|
47
|
-
"typescript",
|
|
48
|
-
"ivm",
|
|
49
|
-
"differential-dataflow"
|
|
50
|
-
],
|
|
51
|
-
"sideEffects": false,
|
|
52
|
-
"type": "module",
|
|
53
|
-
"types": "dist/esm/index.d.ts",
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build": "vite build",
|
|
56
56
|
"dev": "vite build --watch",
|
|
57
57
|
"lint": "eslint . --fix",
|
|
58
|
-
"test": "
|
|
58
|
+
"test": "vitest --run"
|
|
59
59
|
}
|
|
60
60
|
}
|
package/src/d2.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { DifferenceStreamWriter } from
|
|
1
|
+
import { DifferenceStreamWriter } from './graph.js'
|
|
2
2
|
import type {
|
|
3
3
|
BinaryOperator,
|
|
4
4
|
DifferenceStreamReader,
|
|
5
5
|
UnaryOperator,
|
|
6
|
-
} from
|
|
7
|
-
import type { MultiSet, MultiSetArray } from
|
|
8
|
-
import type { ID2, IStreamBuilder, PipedOperator } from
|
|
6
|
+
} from './graph.js'
|
|
7
|
+
import type { MultiSet, MultiSetArray } from './multiset.js'
|
|
8
|
+
import type { ID2, IStreamBuilder, PipedOperator } from './types.js'
|
|
9
9
|
|
|
10
10
|
export class D2 implements ID2 {
|
|
11
11
|
#operators: Array<UnaryOperator<any> | BinaryOperator<any>> = []
|
package/src/graph.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { MultiSet } from
|
|
2
|
-
import type { MultiSetArray } from
|
|
1
|
+
import { MultiSet } from './multiset.js'
|
|
2
|
+
import type { MultiSetArray } from './multiset.js'
|
|
3
3
|
import type {
|
|
4
4
|
IDifferenceStreamReader,
|
|
5
5
|
IDifferenceStreamWriter,
|
|
6
6
|
IOperator,
|
|
7
|
-
} from
|
|
7
|
+
} from './types.js'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* A read handle to a dataflow edge that receives data from a writer.
|
|
@@ -61,7 +61,7 @@ export abstract class Operator<T> implements IOperator<T> {
|
|
|
61
61
|
constructor(
|
|
62
62
|
public id: number,
|
|
63
63
|
inputs: Array<DifferenceStreamReader<T>>,
|
|
64
|
-
output: DifferenceStreamWriter<T
|
|
64
|
+
output: DifferenceStreamWriter<T>,
|
|
65
65
|
) {
|
|
66
66
|
this.inputs = inputs
|
|
67
67
|
this.output = output
|
|
@@ -84,7 +84,7 @@ export abstract class UnaryOperator<Tin, Tout = Tin> extends Operator<
|
|
|
84
84
|
constructor(
|
|
85
85
|
public id: number,
|
|
86
86
|
inputA: DifferenceStreamReader<Tin>,
|
|
87
|
-
output: DifferenceStreamWriter<Tout
|
|
87
|
+
output: DifferenceStreamWriter<Tout>,
|
|
88
88
|
) {
|
|
89
89
|
super(id, [inputA], output)
|
|
90
90
|
}
|
|
@@ -103,7 +103,7 @@ export abstract class BinaryOperator<T> extends Operator<T> {
|
|
|
103
103
|
public id: number,
|
|
104
104
|
inputA: DifferenceStreamReader<T>,
|
|
105
105
|
inputB: DifferenceStreamReader<T>,
|
|
106
|
-
output: DifferenceStreamWriter<T
|
|
106
|
+
output: DifferenceStreamWriter<T>,
|
|
107
107
|
) {
|
|
108
108
|
super(id, [inputA, inputB], output)
|
|
109
109
|
}
|
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:
|
|
@@ -150,7 +150,7 @@ function updateHasher(hasher: Hasher, input: unknown): void {
|
|
|
150
150
|
return
|
|
151
151
|
default:
|
|
152
152
|
console.warn(
|
|
153
|
-
`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`,
|
|
154
154
|
)
|
|
155
155
|
}
|
|
156
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/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
|
}
|