@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.
- package/LICENSE +21 -0
- package/dist/cjs/d2.cjs +111 -0
- package/dist/cjs/d2.cjs.map +1 -0
- package/dist/cjs/d2.d.cts +45 -0
- package/dist/cjs/graph.cjs +90 -0
- package/dist/cjs/graph.cjs.map +1 -0
- package/dist/cjs/graph.d.cts +57 -0
- package/dist/cjs/index.cjs +72 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +4 -0
- package/dist/cjs/indexes.cjs +104 -0
- package/dist/cjs/indexes.cjs.map +1 -0
- package/dist/cjs/indexes.d.cts +20 -0
- package/dist/cjs/multiset.cjs +173 -0
- package/dist/cjs/multiset.cjs.map +1 -0
- package/dist/cjs/multiset.d.cts +36 -0
- package/dist/cjs/operators/concat.cjs +37 -0
- package/dist/cjs/operators/concat.cjs.map +1 -0
- package/dist/cjs/operators/concat.d.cts +13 -0
- package/dist/cjs/operators/consolidate.cjs +40 -0
- package/dist/cjs/operators/consolidate.cjs.map +1 -0
- package/dist/cjs/operators/consolidate.d.cts +12 -0
- package/dist/cjs/operators/count.cjs +36 -0
- package/dist/cjs/operators/count.cjs.map +1 -0
- package/dist/cjs/operators/count.d.cts +13 -0
- package/dist/cjs/operators/debug.cjs +50 -0
- package/dist/cjs/operators/debug.cjs.map +1 -0
- package/dist/cjs/operators/debug.d.cts +16 -0
- package/dist/cjs/operators/distinct.cjs +78 -0
- package/dist/cjs/operators/distinct.cjs.map +1 -0
- package/dist/cjs/operators/distinct.d.cts +14 -0
- package/dist/cjs/operators/filter.cjs +43 -0
- package/dist/cjs/operators/filter.cjs.map +1 -0
- package/dist/cjs/operators/filter.d.cts +16 -0
- package/dist/cjs/operators/filterBy.cjs +19 -0
- package/dist/cjs/operators/filterBy.cjs.map +1 -0
- package/dist/cjs/operators/filterBy.d.cts +10 -0
- package/dist/cjs/operators/groupBy.cjs +225 -0
- package/dist/cjs/operators/groupBy.cjs.map +1 -0
- package/dist/cjs/operators/groupBy.d.cts +68 -0
- package/dist/cjs/operators/index.d.cts +18 -0
- package/dist/cjs/operators/join.cjs +145 -0
- package/dist/cjs/operators/join.cjs.map +1 -0
- package/dist/cjs/operators/join.d.cts +48 -0
- package/dist/cjs/operators/keying.cjs +16 -0
- package/dist/cjs/operators/keying.cjs.map +1 -0
- package/dist/cjs/operators/keying.d.cts +19 -0
- package/dist/cjs/operators/map.cjs +43 -0
- package/dist/cjs/operators/map.cjs.map +1 -0
- package/dist/cjs/operators/map.d.cts +16 -0
- package/dist/cjs/operators/negate.cjs +28 -0
- package/dist/cjs/operators/negate.cjs.map +1 -0
- package/dist/cjs/operators/negate.d.cts +13 -0
- package/dist/cjs/operators/orderBy.cjs +102 -0
- package/dist/cjs/operators/orderBy.cjs.map +1 -0
- package/dist/cjs/operators/orderBy.d.cts +38 -0
- package/dist/cjs/operators/orderByBTree.d.cts +3 -0
- package/dist/cjs/operators/output.cjs +46 -0
- package/dist/cjs/operators/output.cjs.map +1 -0
- package/dist/cjs/operators/output.d.cts +16 -0
- package/dist/cjs/operators/pipe.cjs +9 -0
- package/dist/cjs/operators/pipe.cjs.map +1 -0
- package/dist/cjs/operators/pipe.d.cts +21 -0
- package/dist/cjs/operators/reduce.cjs +99 -0
- package/dist/cjs/operators/reduce.cjs.map +1 -0
- package/dist/cjs/operators/reduce.d.cts +14 -0
- package/dist/cjs/operators/topK.cjs +39 -0
- package/dist/cjs/operators/topK.cjs.map +1 -0
- package/dist/cjs/operators/topK.d.cts +32 -0
- package/dist/cjs/operators/topKWithFractionalIndex.cjs +218 -0
- package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -0
- package/dist/cjs/operators/topKWithFractionalIndex.d.cts +58 -0
- package/dist/cjs/operators/topKWithFractionalIndexBTree.d.cts +27 -0
- package/dist/cjs/types.d.cts +30 -0
- package/dist/cjs/utils.cjs +125 -0
- package/dist/cjs/utils.cjs.map +1 -0
- package/dist/cjs/utils.d.cts +40 -0
- package/dist/esm/d2.d.ts +45 -0
- package/dist/esm/d2.js +111 -0
- package/dist/esm/d2.js.map +1 -0
- package/dist/esm/graph.d.ts +57 -0
- package/dist/esm/graph.js +90 -0
- package/dist/esm/graph.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +72 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/indexes.d.ts +20 -0
- package/dist/esm/indexes.js +104 -0
- package/dist/esm/indexes.js.map +1 -0
- package/dist/esm/multiset.d.ts +36 -0
- package/dist/esm/multiset.js +173 -0
- package/dist/esm/multiset.js.map +1 -0
- package/dist/esm/operators/concat.d.ts +13 -0
- package/dist/esm/operators/concat.js +37 -0
- package/dist/esm/operators/concat.js.map +1 -0
- package/dist/esm/operators/consolidate.d.ts +12 -0
- package/dist/esm/operators/consolidate.js +40 -0
- package/dist/esm/operators/consolidate.js.map +1 -0
- package/dist/esm/operators/count.d.ts +13 -0
- package/dist/esm/operators/count.js +36 -0
- package/dist/esm/operators/count.js.map +1 -0
- package/dist/esm/operators/debug.d.ts +16 -0
- package/dist/esm/operators/debug.js +50 -0
- package/dist/esm/operators/debug.js.map +1 -0
- package/dist/esm/operators/distinct.d.ts +14 -0
- package/dist/esm/operators/distinct.js +78 -0
- package/dist/esm/operators/distinct.js.map +1 -0
- package/dist/esm/operators/filter.d.ts +16 -0
- package/dist/esm/operators/filter.js +43 -0
- package/dist/esm/operators/filter.js.map +1 -0
- package/dist/esm/operators/filterBy.d.ts +10 -0
- package/dist/esm/operators/filterBy.js +19 -0
- package/dist/esm/operators/filterBy.js.map +1 -0
- package/dist/esm/operators/groupBy.d.ts +68 -0
- package/dist/esm/operators/groupBy.js +225 -0
- package/dist/esm/operators/groupBy.js.map +1 -0
- package/dist/esm/operators/index.d.ts +18 -0
- package/dist/esm/operators/join.d.ts +48 -0
- package/dist/esm/operators/join.js +145 -0
- package/dist/esm/operators/join.js.map +1 -0
- package/dist/esm/operators/keying.d.ts +19 -0
- package/dist/esm/operators/keying.js +16 -0
- package/dist/esm/operators/keying.js.map +1 -0
- package/dist/esm/operators/map.d.ts +16 -0
- package/dist/esm/operators/map.js +43 -0
- package/dist/esm/operators/map.js.map +1 -0
- package/dist/esm/operators/negate.d.ts +13 -0
- package/dist/esm/operators/negate.js +28 -0
- package/dist/esm/operators/negate.js.map +1 -0
- package/dist/esm/operators/orderBy.d.ts +38 -0
- package/dist/esm/operators/orderBy.js +102 -0
- package/dist/esm/operators/orderBy.js.map +1 -0
- package/dist/esm/operators/orderByBTree.d.ts +3 -0
- package/dist/esm/operators/output.d.ts +16 -0
- package/dist/esm/operators/output.js +46 -0
- package/dist/esm/operators/output.js.map +1 -0
- package/dist/esm/operators/pipe.d.ts +21 -0
- package/dist/esm/operators/pipe.js +9 -0
- package/dist/esm/operators/pipe.js.map +1 -0
- package/dist/esm/operators/reduce.d.ts +14 -0
- package/dist/esm/operators/reduce.js +99 -0
- package/dist/esm/operators/reduce.js.map +1 -0
- package/dist/esm/operators/topK.d.ts +32 -0
- package/dist/esm/operators/topK.js +39 -0
- package/dist/esm/operators/topK.js.map +1 -0
- package/dist/esm/operators/topKWithFractionalIndex.d.ts +58 -0
- package/dist/esm/operators/topKWithFractionalIndex.js +218 -0
- package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -0
- package/dist/esm/operators/topKWithFractionalIndexBTree.d.ts +27 -0
- package/dist/esm/types.d.ts +30 -0
- package/dist/esm/utils.d.ts +40 -0
- package/dist/esm/utils.js +125 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +6 -7
- package/src/operators/orderBy.ts +11 -29
- package/src/operators/topKWithFractionalIndex.ts +69 -57
- package/src/operators/topKWithFractionalIndexBTree.ts +14 -19
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { map } from "./map.js";
|
|
2
|
+
import { innerJoin } from "./join.js";
|
|
3
|
+
import { consolidate } from "./consolidate.js";
|
|
4
|
+
function filterBy(other) {
|
|
5
|
+
return (stream) => {
|
|
6
|
+
const otherKeys = other.pipe(
|
|
7
|
+
map(([key, _]) => [key, null])
|
|
8
|
+
);
|
|
9
|
+
return stream.pipe(
|
|
10
|
+
innerJoin(otherKeys),
|
|
11
|
+
map(([key, [value, _]]) => [key, value]),
|
|
12
|
+
consolidate()
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
filterBy
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=filterBy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filterBy.js","sources":["../../../src/operators/filterBy.ts"],"sourcesContent":["import { map } from \"./map.js\"\nimport { innerJoin } from \"./join.js\"\nimport { consolidate } from \"./consolidate.js\"\nimport type { KeyValue } from \"../types.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types\"\n\n/**\n * Filters the elements of a keyed stream, by keys of another stream.\n * This allows you to build pipelies where you have multiple outputs that are related,\n * such as a streams of issues and comments for a project.\n *\n * @param other - The other stream to filter by, which must have the same key type as the input stream\n */\nexport function filterBy<\n K,\n V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never,\n T,\n>(\n other: IStreamBuilder<KeyValue<K, unknown>>\n): PipedOperator<T, KeyValue<K, V1>> {\n return (stream: IStreamBuilder<T>): IStreamBuilder<KeyValue<K, V1>> => {\n const otherKeys = other.pipe(\n map(([key, _]) => [key, null] as KeyValue<K, null>)\n )\n return stream.pipe(\n innerJoin(otherKeys),\n map(([key, [value, _]]) => [key, value] as KeyValue<K, V1>),\n consolidate()\n )\n }\n}\n"],"names":[],"mappings":";;;AAaO,SAAS,SAKd,OACmC;AACnC,SAAO,CAAC,WAA+D;AACrE,UAAM,YAAY,MAAM;AAAA,MACtB,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,CAAsB;AAAA,IAAA;AAEpD,WAAO,OAAO;AAAA,MACZ,UAAU,SAAS;AAAA,MACnB,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,CAAoB;AAAA,MAC1D,YAAA;AAAA,IAAY;AAAA,EAEhB;AACF;"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { IStreamBuilder, KeyValue } from '../types.js';
|
|
2
|
+
type GroupKey = Record<string, unknown>;
|
|
3
|
+
type BasicAggregateFunction<T, R, V = unknown> = {
|
|
4
|
+
preMap: (data: T) => V;
|
|
5
|
+
reduce: (values: Array<[V, number]>) => V;
|
|
6
|
+
postMap?: (result: V) => R;
|
|
7
|
+
};
|
|
8
|
+
type PipedAggregateFunction<T, R> = {
|
|
9
|
+
pipe: (stream: IStreamBuilder<T>) => IStreamBuilder<KeyValue<string, R>>;
|
|
10
|
+
};
|
|
11
|
+
type AggregateFunction<T, R, V = unknown> = BasicAggregateFunction<T, R, V> | PipedAggregateFunction<T, R>;
|
|
12
|
+
type ExtractAggregateReturnType<T, A> = A extends AggregateFunction<T, infer R, any> ? R : never;
|
|
13
|
+
type AggregatesReturnType<T, A> = {
|
|
14
|
+
[K in keyof A]: ExtractAggregateReturnType<T, A[K]>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Groups data by key and applies multiple aggregate operations
|
|
18
|
+
* @param keyExtractor Function to extract grouping key from data
|
|
19
|
+
* @param aggregates Object mapping aggregate names to aggregate functions
|
|
20
|
+
*/
|
|
21
|
+
export declare function groupBy<T, K extends GroupKey, A extends Record<string, AggregateFunction<T, any, any>>>(keyExtractor: (data: T) => K, aggregates?: A): (stream: IStreamBuilder<T>) => IStreamBuilder<KeyValue<string, K & AggregatesReturnType<T, A>>>;
|
|
22
|
+
/**
|
|
23
|
+
* Creates a sum aggregate function
|
|
24
|
+
*/
|
|
25
|
+
export declare function sum<T>(valueExtractor?: (value: T) => number): AggregateFunction<T, number, number>;
|
|
26
|
+
/**
|
|
27
|
+
* Creates a count aggregate function
|
|
28
|
+
*/
|
|
29
|
+
export declare function count<T>(): AggregateFunction<T, number, number>;
|
|
30
|
+
/**
|
|
31
|
+
* Creates an average aggregate function
|
|
32
|
+
*/
|
|
33
|
+
export declare function avg<T>(valueExtractor?: (value: T) => number): AggregateFunction<T, number, {
|
|
34
|
+
sum: number;
|
|
35
|
+
count: number;
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
* Creates a min aggregate function that computes the minimum value in a group
|
|
39
|
+
* @param valueExtractor Function to extract a numeric value from each data entry
|
|
40
|
+
*/
|
|
41
|
+
export declare function min<T>(valueExtractor?: (value: T) => number): AggregateFunction<T, number, number>;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a max aggregate function that computes the maximum value in a group
|
|
44
|
+
* @param valueExtractor Function to extract a numeric value from each data entry
|
|
45
|
+
*/
|
|
46
|
+
export declare function max<T>(valueExtractor?: (value: T) => number): AggregateFunction<T, number, number>;
|
|
47
|
+
/**
|
|
48
|
+
* Creates a median aggregate function that computes the middle value in a sorted group
|
|
49
|
+
* If there's an even number of values, returns the average of the two middle values
|
|
50
|
+
* @param valueExtractor Function to extract a numeric value from each data entry
|
|
51
|
+
*/
|
|
52
|
+
export declare function median<T>(valueExtractor?: (value: T) => number): AggregateFunction<T, number, Array<number>>;
|
|
53
|
+
/**
|
|
54
|
+
* Creates a mode aggregate function that computes the most frequent value in a group
|
|
55
|
+
* If multiple values have the same highest frequency, returns the first one encountered
|
|
56
|
+
* @param valueExtractor Function to extract a value from each data entry
|
|
57
|
+
*/
|
|
58
|
+
export declare function mode<T>(valueExtractor?: (value: T) => number): AggregateFunction<T, number, Map<number, number>>;
|
|
59
|
+
export declare const groupByOperators: {
|
|
60
|
+
sum: typeof sum;
|
|
61
|
+
count: typeof count;
|
|
62
|
+
avg: typeof avg;
|
|
63
|
+
min: typeof min;
|
|
64
|
+
max: typeof max;
|
|
65
|
+
median: typeof median;
|
|
66
|
+
mode: typeof mode;
|
|
67
|
+
};
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { map } from "./map.js";
|
|
2
|
+
import { reduce } from "./reduce.js";
|
|
3
|
+
function isPipedAggregateFunction(aggregate) {
|
|
4
|
+
return `pipe` in aggregate;
|
|
5
|
+
}
|
|
6
|
+
function groupBy(keyExtractor, aggregates = {}) {
|
|
7
|
+
const basicAggregates = Object.fromEntries(
|
|
8
|
+
Object.entries(aggregates).filter(
|
|
9
|
+
([_, aggregate]) => !isPipedAggregateFunction(aggregate)
|
|
10
|
+
)
|
|
11
|
+
);
|
|
12
|
+
Object.fromEntries(
|
|
13
|
+
Object.entries(aggregates).filter(
|
|
14
|
+
([_, aggregate]) => isPipedAggregateFunction(aggregate)
|
|
15
|
+
)
|
|
16
|
+
);
|
|
17
|
+
return (stream) => {
|
|
18
|
+
const KEY_SENTINEL = `__original_key__`;
|
|
19
|
+
const withKeysAndValues = stream.pipe(
|
|
20
|
+
map((data) => {
|
|
21
|
+
const key = keyExtractor(data);
|
|
22
|
+
const keyString = JSON.stringify(key);
|
|
23
|
+
const values = {};
|
|
24
|
+
values[KEY_SENTINEL] = key;
|
|
25
|
+
for (const [name, aggregate] of Object.entries(basicAggregates)) {
|
|
26
|
+
values[name] = aggregate.preMap(data);
|
|
27
|
+
}
|
|
28
|
+
return [keyString, values];
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
const reduced = withKeysAndValues.pipe(
|
|
32
|
+
reduce((values) => {
|
|
33
|
+
var _a, _b;
|
|
34
|
+
let totalMultiplicity = 0;
|
|
35
|
+
for (const [_, multiplicity] of values) {
|
|
36
|
+
totalMultiplicity += multiplicity;
|
|
37
|
+
}
|
|
38
|
+
if (totalMultiplicity <= 0) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const result = {};
|
|
42
|
+
const originalKey = (_b = (_a = values[0]) == null ? void 0 : _a[0]) == null ? void 0 : _b[KEY_SENTINEL];
|
|
43
|
+
result[KEY_SENTINEL] = originalKey;
|
|
44
|
+
for (const [name, aggregate] of Object.entries(basicAggregates)) {
|
|
45
|
+
const preValues = values.map(
|
|
46
|
+
([v, m]) => [v[name], m]
|
|
47
|
+
);
|
|
48
|
+
result[name] = aggregate.reduce(preValues);
|
|
49
|
+
}
|
|
50
|
+
return [[result, 1]];
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
return reduced.pipe(
|
|
54
|
+
map(([keyString, values]) => {
|
|
55
|
+
const key = values[KEY_SENTINEL];
|
|
56
|
+
const result = {};
|
|
57
|
+
Object.assign(result, key);
|
|
58
|
+
for (const [name, aggregate] of Object.entries(basicAggregates)) {
|
|
59
|
+
if (aggregate.postMap) {
|
|
60
|
+
result[name] = aggregate.postMap(values[name]);
|
|
61
|
+
} else {
|
|
62
|
+
result[name] = values[name];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return [keyString, result];
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function sum(valueExtractor = (v) => v) {
|
|
71
|
+
return {
|
|
72
|
+
preMap: (data) => valueExtractor(data),
|
|
73
|
+
reduce: (values) => {
|
|
74
|
+
let total = 0;
|
|
75
|
+
for (const [value, multiplicity] of values) {
|
|
76
|
+
total += value * multiplicity;
|
|
77
|
+
}
|
|
78
|
+
return total;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function count() {
|
|
83
|
+
return {
|
|
84
|
+
preMap: () => 1,
|
|
85
|
+
reduce: (values) => {
|
|
86
|
+
let totalCount = 0;
|
|
87
|
+
for (const [_, multiplicity] of values) {
|
|
88
|
+
totalCount += multiplicity;
|
|
89
|
+
}
|
|
90
|
+
return totalCount;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function avg(valueExtractor = (v) => v) {
|
|
95
|
+
return {
|
|
96
|
+
preMap: (data) => ({
|
|
97
|
+
sum: valueExtractor(data),
|
|
98
|
+
count: 0
|
|
99
|
+
}),
|
|
100
|
+
reduce: (values) => {
|
|
101
|
+
let totalSum = 0;
|
|
102
|
+
let totalCount = 0;
|
|
103
|
+
for (const [value, multiplicity] of values) {
|
|
104
|
+
totalSum += value.sum * multiplicity;
|
|
105
|
+
totalCount += multiplicity;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
sum: totalSum,
|
|
109
|
+
count: totalCount
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
postMap: (result) => {
|
|
113
|
+
return result.sum / result.count;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function min(valueExtractor = (v) => v) {
|
|
118
|
+
return {
|
|
119
|
+
preMap: (data) => valueExtractor(data),
|
|
120
|
+
reduce: (values) => {
|
|
121
|
+
let minValue = Number.POSITIVE_INFINITY;
|
|
122
|
+
for (const [value, _multiplicity] of values) {
|
|
123
|
+
if (value < minValue) {
|
|
124
|
+
minValue = value;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return minValue === Number.POSITIVE_INFINITY ? 0 : minValue;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function max(valueExtractor = (v) => v) {
|
|
132
|
+
return {
|
|
133
|
+
preMap: (data) => valueExtractor(data),
|
|
134
|
+
reduce: (values) => {
|
|
135
|
+
let maxValue = Number.NEGATIVE_INFINITY;
|
|
136
|
+
for (const [value, _multiplicity] of values) {
|
|
137
|
+
if (value > maxValue) {
|
|
138
|
+
maxValue = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return maxValue === Number.NEGATIVE_INFINITY ? 0 : maxValue;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function median(valueExtractor = (v) => v) {
|
|
146
|
+
return {
|
|
147
|
+
preMap: (data) => [valueExtractor(data)],
|
|
148
|
+
reduce: (values) => {
|
|
149
|
+
const allValues = [];
|
|
150
|
+
for (const [valueArray, multiplicity] of values) {
|
|
151
|
+
for (const value of valueArray) {
|
|
152
|
+
for (let i = 0; i < multiplicity; i++) {
|
|
153
|
+
allValues.push(value);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (allValues.length === 0) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
allValues.sort((a, b) => a - b);
|
|
161
|
+
return allValues;
|
|
162
|
+
},
|
|
163
|
+
postMap: (result) => {
|
|
164
|
+
if (result.length === 0) return 0;
|
|
165
|
+
const mid = Math.floor(result.length / 2);
|
|
166
|
+
if (result.length % 2 === 0) {
|
|
167
|
+
return (result[mid - 1] + result[mid]) / 2;
|
|
168
|
+
}
|
|
169
|
+
return result[mid];
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function mode(valueExtractor = (v) => v) {
|
|
174
|
+
return {
|
|
175
|
+
preMap: (data) => {
|
|
176
|
+
const value = valueExtractor(data);
|
|
177
|
+
const frequencyMap = /* @__PURE__ */ new Map();
|
|
178
|
+
frequencyMap.set(value, 1);
|
|
179
|
+
return frequencyMap;
|
|
180
|
+
},
|
|
181
|
+
reduce: (values) => {
|
|
182
|
+
const combinedMap = /* @__PURE__ */ new Map();
|
|
183
|
+
for (const [frequencyMap, multiplicity] of values) {
|
|
184
|
+
for (const [value, frequencyCount] of frequencyMap.entries()) {
|
|
185
|
+
const currentCount = combinedMap.get(value) || 0;
|
|
186
|
+
combinedMap.set(value, currentCount + frequencyCount * multiplicity);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return combinedMap;
|
|
190
|
+
},
|
|
191
|
+
postMap: (result) => {
|
|
192
|
+
if (result.size === 0) return 0;
|
|
193
|
+
let modeValue = 0;
|
|
194
|
+
let maxFrequency = 0;
|
|
195
|
+
for (const [value, frequency] of result.entries()) {
|
|
196
|
+
if (frequency > maxFrequency) {
|
|
197
|
+
maxFrequency = frequency;
|
|
198
|
+
modeValue = value;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return modeValue;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
const groupByOperators = {
|
|
206
|
+
sum,
|
|
207
|
+
count,
|
|
208
|
+
avg,
|
|
209
|
+
min,
|
|
210
|
+
max,
|
|
211
|
+
median,
|
|
212
|
+
mode
|
|
213
|
+
};
|
|
214
|
+
export {
|
|
215
|
+
avg,
|
|
216
|
+
count,
|
|
217
|
+
groupBy,
|
|
218
|
+
groupByOperators,
|
|
219
|
+
max,
|
|
220
|
+
median,
|
|
221
|
+
min,
|
|
222
|
+
mode,
|
|
223
|
+
sum
|
|
224
|
+
};
|
|
225
|
+
//# sourceMappingURL=groupBy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groupBy.js","sources":["../../../src/operators/groupBy.ts"],"sourcesContent":["import { map } from \"./map.js\"\nimport { reduce } from \"./reduce.js\"\nimport type { IStreamBuilder, KeyValue } from \"../types.js\"\n\ntype GroupKey = Record<string, unknown>\n\ntype BasicAggregateFunction<T, R, V = unknown> = {\n preMap: (data: T) => V\n reduce: (values: Array<[V, number]>) => V\n postMap?: (result: V) => R\n}\n\ntype PipedAggregateFunction<T, R> = {\n pipe: (stream: IStreamBuilder<T>) => IStreamBuilder<KeyValue<string, R>>\n}\n\ntype AggregateFunction<T, R, V = unknown> =\n | BasicAggregateFunction<T, R, V>\n | PipedAggregateFunction<T, R>\n\ntype ExtractAggregateReturnType<T, A> =\n A extends AggregateFunction<T, infer R, any> ? R : never\n\ntype AggregatesReturnType<T, A> = {\n [K in keyof A]: ExtractAggregateReturnType<T, A[K]>\n}\n\nfunction isPipedAggregateFunction<T, R>(\n aggregate: AggregateFunction<T, R>\n): aggregate is PipedAggregateFunction<T, R> {\n return `pipe` in aggregate\n}\n\n/**\n * Groups data by key and applies multiple aggregate operations\n * @param keyExtractor Function to extract grouping key from data\n * @param aggregates Object mapping aggregate names to aggregate functions\n */\nexport function groupBy<\n T,\n K extends GroupKey,\n A extends Record<string, AggregateFunction<T, any, any>>,\n>(keyExtractor: (data: T) => K, aggregates: A = {} as A) {\n type ResultType = K & AggregatesReturnType<T, A>\n\n const basicAggregates = Object.fromEntries(\n Object.entries(aggregates).filter(\n ([_, aggregate]) => !isPipedAggregateFunction(aggregate)\n )\n ) as Record<string, BasicAggregateFunction<T, any, any>>\n\n // @ts-expect-error - TODO: we don't use this yet, but we will\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const pipedAggregates = Object.fromEntries(\n Object.entries(aggregates).filter(([_, aggregate]) =>\n isPipedAggregateFunction(aggregate)\n )\n ) as Record<string, PipedAggregateFunction<T, any>>\n\n return (\n stream: IStreamBuilder<T>\n ): IStreamBuilder<KeyValue<string, ResultType>> => {\n // Special key to store the original key object\n const KEY_SENTINEL = `__original_key__`\n\n // First map to extract keys and pre-aggregate values\n const withKeysAndValues = stream.pipe(\n map((data) => {\n const key = keyExtractor(data)\n const keyString = JSON.stringify(key)\n\n // Create values object with pre-aggregated values\n const values: Record<string, unknown> = {}\n\n // Store the original key object\n values[KEY_SENTINEL] = key\n\n // Add pre-aggregated values\n for (const [name, aggregate] of Object.entries(basicAggregates)) {\n values[name] = aggregate.preMap(data)\n }\n\n return [keyString, values] as KeyValue<string, Record<string, unknown>>\n })\n )\n\n // Then reduce to compute aggregates\n const reduced = withKeysAndValues.pipe(\n reduce((values) => {\n // Calculate total multiplicity to check if the group should exist\n let totalMultiplicity = 0\n for (const [_, multiplicity] of values) {\n totalMultiplicity += multiplicity\n }\n\n // If total multiplicity is 0 or negative, the group should be removed completely\n if (totalMultiplicity <= 0) {\n return []\n }\n\n const result: Record<string, unknown> = {}\n\n // Get the original key from first value in group\n const originalKey = values[0]?.[0]?.[KEY_SENTINEL]\n result[KEY_SENTINEL] = originalKey\n\n // Apply each aggregate function\n for (const [name, aggregate] of Object.entries(basicAggregates)) {\n const preValues = values.map(\n ([v, m]) => [v[name], m] as [any, number]\n )\n result[name] = aggregate.reduce(preValues)\n }\n\n return [[result, 1]]\n })\n )\n\n // Finally map to extract the key and include all values\n return reduced.pipe(\n map(([keyString, values]) => {\n // Extract the original key\n const key = values[KEY_SENTINEL] as K\n\n // Create intermediate result with key values and aggregate results\n const result: Record<string, unknown> = {}\n\n // Add key properties to result\n Object.assign(result, key)\n\n // Apply postMap if provided\n for (const [name, aggregate] of Object.entries(basicAggregates)) {\n if (aggregate.postMap) {\n result[name] = aggregate.postMap(values[name])\n } else {\n result[name] = values[name]\n }\n }\n\n // Return with the string key instead of the object\n return [keyString, result] as KeyValue<string, ResultType>\n })\n )\n }\n}\n\n/**\n * Creates a sum aggregate function\n */\nexport function sum<T>(\n valueExtractor: (value: T) => number = (v) => v as unknown as number\n): AggregateFunction<T, number, number> {\n return {\n preMap: (data: T) => valueExtractor(data),\n reduce: (values: Array<[number, number]>) => {\n let total = 0\n for (const [value, multiplicity] of values) {\n total += value * multiplicity\n }\n return total\n },\n }\n}\n\n/**\n * Creates a count aggregate function\n */\nexport function count<T>(): AggregateFunction<T, number, number> {\n return {\n preMap: () => 1,\n reduce: (values: Array<[number, number]>) => {\n let totalCount = 0\n for (const [_, multiplicity] of values) {\n totalCount += multiplicity\n }\n return totalCount\n },\n }\n}\n\n/**\n * Creates an average aggregate function\n */\nexport function avg<T>(\n valueExtractor: (value: T) => number = (v) => v as unknown as number\n): AggregateFunction<T, number, { sum: number; count: number }> {\n return {\n preMap: (data: T) => ({\n sum: valueExtractor(data),\n count: 0,\n }),\n reduce: (values: Array<[{ sum: number; count: number }, number]>) => {\n let totalSum = 0\n let totalCount = 0\n for (const [value, multiplicity] of values) {\n totalSum += value.sum * multiplicity\n totalCount += multiplicity\n }\n return {\n sum: totalSum,\n count: totalCount,\n }\n },\n postMap: (result: { sum: number; count: number }) => {\n return result.sum / result.count\n },\n }\n}\n\n/**\n * Creates a min aggregate function that computes the minimum value in a group\n * @param valueExtractor Function to extract a numeric value from each data entry\n */\nexport function min<T>(\n valueExtractor: (value: T) => number = (v) => v as unknown as number\n): AggregateFunction<T, number, number> {\n return {\n preMap: (data: T) => valueExtractor(data),\n reduce: (values: Array<[number, number]>) => {\n let minValue = Number.POSITIVE_INFINITY\n for (const [value, _multiplicity] of values) {\n if (value < minValue) {\n minValue = value\n }\n }\n return minValue === Number.POSITIVE_INFINITY ? 0 : minValue\n },\n }\n}\n\n/**\n * Creates a max aggregate function that computes the maximum value in a group\n * @param valueExtractor Function to extract a numeric value from each data entry\n */\nexport function max<T>(\n valueExtractor: (value: T) => number = (v) => v as unknown as number\n): AggregateFunction<T, number, number> {\n return {\n preMap: (data: T) => valueExtractor(data),\n reduce: (values: Array<[number, number]>) => {\n let maxValue = Number.NEGATIVE_INFINITY\n for (const [value, _multiplicity] of values) {\n if (value > maxValue) {\n maxValue = value\n }\n }\n return maxValue === Number.NEGATIVE_INFINITY ? 0 : maxValue\n },\n }\n}\n\n/**\n * Creates a median aggregate function that computes the middle value in a sorted group\n * If there's an even number of values, returns the average of the two middle values\n * @param valueExtractor Function to extract a numeric value from each data entry\n */\nexport function median<T>(\n valueExtractor: (value: T) => number = (v) => v as unknown as number\n): AggregateFunction<T, number, Array<number>> {\n return {\n preMap: (data: T) => [valueExtractor(data)],\n reduce: (values: Array<[Array<number>, number]>) => {\n // Flatten all values, taking multiplicity into account\n const allValues: Array<number> = []\n for (const [valueArray, multiplicity] of values) {\n for (const value of valueArray) {\n // Add each value multiple times based on multiplicity\n for (let i = 0; i < multiplicity; i++) {\n allValues.push(value)\n }\n }\n }\n\n // Return empty array if no values\n if (allValues.length === 0) {\n return []\n }\n\n // Sort values\n allValues.sort((a, b) => a - b)\n\n return allValues\n },\n postMap: (result: Array<number>) => {\n if (result.length === 0) return 0\n\n const mid = Math.floor(result.length / 2)\n\n // If even number of values, average the two middle values\n if (result.length % 2 === 0) {\n return (result[mid - 1]! + result[mid]!) / 2\n }\n\n // If odd number of values, return the middle value\n return result[mid]!\n },\n }\n}\n\n/**\n * Creates a mode aggregate function that computes the most frequent value in a group\n * If multiple values have the same highest frequency, returns the first one encountered\n * @param valueExtractor Function to extract a value from each data entry\n */\nexport function mode<T>(\n valueExtractor: (value: T) => number = (v) => v as unknown as number\n): AggregateFunction<T, number, Map<number, number>> {\n return {\n preMap: (data: T) => {\n const value = valueExtractor(data)\n const frequencyMap = new Map<number, number>()\n frequencyMap.set(value, 1)\n return frequencyMap\n },\n reduce: (values: Array<[Map<number, number>, number]>) => {\n // Combine all frequency maps\n const combinedMap = new Map<number, number>()\n\n for (const [frequencyMap, multiplicity] of values) {\n for (const [value, frequencyCount] of frequencyMap.entries()) {\n const currentCount = combinedMap.get(value) || 0\n combinedMap.set(value, currentCount + frequencyCount * multiplicity)\n }\n }\n\n return combinedMap\n },\n postMap: (result: Map<number, number>) => {\n if (result.size === 0) return 0\n\n let modeValue = 0\n let maxFrequency = 0\n\n for (const [value, frequency] of result.entries()) {\n if (frequency > maxFrequency) {\n maxFrequency = frequency\n modeValue = value\n }\n }\n\n return modeValue\n },\n }\n}\n\nexport const groupByOperators = {\n sum,\n count,\n avg,\n min,\n max,\n median,\n mode,\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export * from './pipe.js';
|
|
2
|
+
export * from './map.js';
|
|
3
|
+
export * from './filter.js';
|
|
4
|
+
export * from './negate.js';
|
|
5
|
+
export * from './concat.js';
|
|
6
|
+
export * from './debug.js';
|
|
7
|
+
export * from './output.js';
|
|
8
|
+
export * from './consolidate.js';
|
|
9
|
+
export * from './join.js';
|
|
10
|
+
export * from './reduce.js';
|
|
11
|
+
export * from './count.js';
|
|
12
|
+
export * from './distinct.js';
|
|
13
|
+
export * from './keying.js';
|
|
14
|
+
export * from './topK.js';
|
|
15
|
+
export * from './topKWithFractionalIndex.js';
|
|
16
|
+
export * from './orderBy.js';
|
|
17
|
+
export * from './filterBy.js';
|
|
18
|
+
export { groupBy, groupByOperators } from './groupBy.js';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BinaryOperator, DifferenceStreamWriter, DifferenceStreamReader } from '../graph.js';
|
|
2
|
+
import { IStreamBuilder, KeyValue, PipedOperator } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Type of join to perform
|
|
5
|
+
*/
|
|
6
|
+
export type JoinType = `inner` | `left` | `right` | `full` | `anti`;
|
|
7
|
+
/**
|
|
8
|
+
* Operator that joins two input streams
|
|
9
|
+
*/
|
|
10
|
+
export declare class JoinOperator<K, V1, V2> extends BinaryOperator<[
|
|
11
|
+
K,
|
|
12
|
+
V1
|
|
13
|
+
] | [K, V2] | [K, [V1, V2]]> {
|
|
14
|
+
#private;
|
|
15
|
+
constructor(id: number, inputA: DifferenceStreamReader<[K, V1]>, inputB: DifferenceStreamReader<[K, V2]>, output: DifferenceStreamWriter<[K, [V1, V2]]>);
|
|
16
|
+
run(): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Joins two input streams
|
|
20
|
+
* @param other - The other stream to join with
|
|
21
|
+
* @param type - The type of join to perform
|
|
22
|
+
*/
|
|
23
|
+
export declare function join<K, V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never, V2, T>(other: IStreamBuilder<KeyValue<K, V2>>, type?: JoinType): PipedOperator<T, KeyValue<K, [V1 | null, V2 | null]>>;
|
|
24
|
+
/**
|
|
25
|
+
* Joins two input streams
|
|
26
|
+
* @param other - The other stream to join with
|
|
27
|
+
*/
|
|
28
|
+
export declare function innerJoin<K, V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never, V2, T>(other: IStreamBuilder<KeyValue<K, V2>>): PipedOperator<T, KeyValue<K, [V1, V2]>>;
|
|
29
|
+
/**
|
|
30
|
+
* Joins two input streams
|
|
31
|
+
* @param other - The other stream to join with
|
|
32
|
+
*/
|
|
33
|
+
export declare function antiJoin<K, V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never, V2, T>(other: IStreamBuilder<KeyValue<K, V2>>): PipedOperator<T, KeyValue<K, [V1, null]>>;
|
|
34
|
+
/**
|
|
35
|
+
* Joins two input streams
|
|
36
|
+
* @param other - The other stream to join with
|
|
37
|
+
*/
|
|
38
|
+
export declare function leftJoin<K, V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never, V2, T>(other: IStreamBuilder<KeyValue<K, V2>>): PipedOperator<T, KeyValue<K, [V1, V2 | null]>>;
|
|
39
|
+
/**
|
|
40
|
+
* Joins two input streams
|
|
41
|
+
* @param other - The other stream to join with
|
|
42
|
+
*/
|
|
43
|
+
export declare function rightJoin<K, V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never, V2, T>(other: IStreamBuilder<KeyValue<K, V2>>): PipedOperator<T, KeyValue<K, [V1 | null, V2]>>;
|
|
44
|
+
/**
|
|
45
|
+
* Joins two input streams
|
|
46
|
+
* @param other - The other stream to join with
|
|
47
|
+
*/
|
|
48
|
+
export declare function fullJoin<K, V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never, V2, T>(other: IStreamBuilder<KeyValue<K, V2>>): PipedOperator<T, KeyValue<K, [V1 | null, V2 | null]>>;
|
|
@@ -0,0 +1,145 @@
|
|
|
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 _indexA, _indexB;
|
|
8
|
+
import { BinaryOperator, DifferenceStreamWriter } from "../graph.js";
|
|
9
|
+
import { StreamBuilder } from "../d2.js";
|
|
10
|
+
import { MultiSet } from "../multiset.js";
|
|
11
|
+
import { Index } from "../indexes.js";
|
|
12
|
+
import { negate } from "./negate.js";
|
|
13
|
+
import { map } from "./map.js";
|
|
14
|
+
import { concat } from "./concat.js";
|
|
15
|
+
class JoinOperator extends BinaryOperator {
|
|
16
|
+
constructor(id, inputA, inputB, output) {
|
|
17
|
+
super(id, inputA, inputB, output);
|
|
18
|
+
__privateAdd(this, _indexA, new Index());
|
|
19
|
+
__privateAdd(this, _indexB, new Index());
|
|
20
|
+
}
|
|
21
|
+
run() {
|
|
22
|
+
const deltaA = new Index();
|
|
23
|
+
const deltaB = new Index();
|
|
24
|
+
const messagesA = this.inputAMessages();
|
|
25
|
+
for (const message of messagesA) {
|
|
26
|
+
const multiSetMessage = message;
|
|
27
|
+
for (const [item, multiplicity] of multiSetMessage.getInner()) {
|
|
28
|
+
const [key, value] = item;
|
|
29
|
+
deltaA.addValue(key, [value, multiplicity]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const messagesB = this.inputBMessages();
|
|
33
|
+
for (const message of messagesB) {
|
|
34
|
+
const multiSetMessage = message;
|
|
35
|
+
for (const [item, multiplicity] of multiSetMessage.getInner()) {
|
|
36
|
+
const [key, value] = item;
|
|
37
|
+
deltaB.addValue(key, [value, multiplicity]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const results = new MultiSet();
|
|
41
|
+
results.extend(deltaA.join(__privateGet(this, _indexB)));
|
|
42
|
+
__privateGet(this, _indexA).append(deltaA);
|
|
43
|
+
results.extend(__privateGet(this, _indexA).join(deltaB));
|
|
44
|
+
if (results.getInner().length > 0) {
|
|
45
|
+
this.output.sendData(results);
|
|
46
|
+
}
|
|
47
|
+
__privateGet(this, _indexB).append(deltaB);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
_indexA = new WeakMap();
|
|
51
|
+
_indexB = new WeakMap();
|
|
52
|
+
function join(other, type = `inner`) {
|
|
53
|
+
switch (type) {
|
|
54
|
+
case `inner`:
|
|
55
|
+
return innerJoin(other);
|
|
56
|
+
case `anti`:
|
|
57
|
+
return antiJoin(other);
|
|
58
|
+
case `left`:
|
|
59
|
+
return leftJoin(other);
|
|
60
|
+
case `right`:
|
|
61
|
+
return rightJoin(other);
|
|
62
|
+
case `full`:
|
|
63
|
+
return fullJoin(other);
|
|
64
|
+
default:
|
|
65
|
+
throw new Error(`Join type ${type} is invalid`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function innerJoin(other) {
|
|
69
|
+
return (stream) => {
|
|
70
|
+
if (stream.graph !== other.graph) {
|
|
71
|
+
throw new Error(`Cannot join streams from different graphs`);
|
|
72
|
+
}
|
|
73
|
+
const output = new StreamBuilder(
|
|
74
|
+
stream.graph,
|
|
75
|
+
new DifferenceStreamWriter()
|
|
76
|
+
);
|
|
77
|
+
const operator = new JoinOperator(
|
|
78
|
+
stream.graph.getNextOperatorId(),
|
|
79
|
+
stream.connectReader(),
|
|
80
|
+
other.connectReader(),
|
|
81
|
+
output.writer
|
|
82
|
+
);
|
|
83
|
+
stream.graph.addOperator(operator);
|
|
84
|
+
stream.graph.addStream(output.connectReader());
|
|
85
|
+
return output;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function antiJoin(other) {
|
|
89
|
+
return (stream) => {
|
|
90
|
+
const matchedLeft = stream.pipe(
|
|
91
|
+
innerJoin(other),
|
|
92
|
+
map(([key, [valueLeft, _valueRight]]) => [key, valueLeft])
|
|
93
|
+
);
|
|
94
|
+
const anti = stream.pipe(
|
|
95
|
+
concat(matchedLeft.pipe(negate())),
|
|
96
|
+
// @ts-ignore TODO: fix this
|
|
97
|
+
map(([key, value]) => [key, [value, null]])
|
|
98
|
+
);
|
|
99
|
+
return anti;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function leftJoin(other) {
|
|
103
|
+
return (stream) => {
|
|
104
|
+
const left = stream;
|
|
105
|
+
const right = other;
|
|
106
|
+
const inner = left.pipe(innerJoin(right));
|
|
107
|
+
const anti = left.pipe(antiJoin(right));
|
|
108
|
+
return inner.pipe(concat(anti));
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function rightJoin(other) {
|
|
112
|
+
return (stream) => {
|
|
113
|
+
const left = stream;
|
|
114
|
+
const right = other;
|
|
115
|
+
const inner = left.pipe(innerJoin(right));
|
|
116
|
+
const anti = right.pipe(
|
|
117
|
+
antiJoin(left),
|
|
118
|
+
map(([key, [a, b]]) => [key, [b, a]])
|
|
119
|
+
);
|
|
120
|
+
return inner.pipe(concat(anti));
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function fullJoin(other) {
|
|
124
|
+
return (stream) => {
|
|
125
|
+
const left = stream;
|
|
126
|
+
const right = other;
|
|
127
|
+
const inner = left.pipe(innerJoin(right));
|
|
128
|
+
const antiLeft = left.pipe(antiJoin(right));
|
|
129
|
+
const antiRight = right.pipe(
|
|
130
|
+
antiJoin(left),
|
|
131
|
+
map(([key, [a, b]]) => [key, [b, a]])
|
|
132
|
+
);
|
|
133
|
+
return inner.pipe(concat(antiLeft), concat(antiRight));
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
export {
|
|
137
|
+
JoinOperator,
|
|
138
|
+
antiJoin,
|
|
139
|
+
fullJoin,
|
|
140
|
+
innerJoin,
|
|
141
|
+
join,
|
|
142
|
+
leftJoin,
|
|
143
|
+
rightJoin
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=join.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"join.js","sources":["../../../src/operators/join.ts"],"sourcesContent":["import { BinaryOperator, DifferenceStreamWriter } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport { MultiSet } from \"../multiset.js\"\nimport { Index } from \"../indexes.js\"\nimport { negate } from \"./negate.js\"\nimport { map } from \"./map.js\"\nimport { concat } from \"./concat.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { IStreamBuilder, KeyValue, PipedOperator } from \"../types.js\"\n\n/**\n * Type of join to perform\n */\nexport type JoinType = `inner` | `left` | `right` | `full` | `anti`\n\n/**\n * Operator that joins two input streams\n */\nexport class JoinOperator<K, V1, V2> extends BinaryOperator<\n [K, V1] | [K, V2] | [K, [V1, V2]]\n> {\n #indexA = new Index<K, V1>()\n #indexB = new Index<K, V2>()\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<[K, V1]>,\n inputB: DifferenceStreamReader<[K, V2]>,\n output: DifferenceStreamWriter<[K, [V1, V2]]>\n ) {\n super(id, inputA, inputB, output)\n }\n\n run(): void {\n const deltaA = new Index<K, V1>()\n const deltaB = new Index<K, V2>()\n\n // Process input A - process ALL messages, not just the first one\n const messagesA = this.inputAMessages()\n for (const message of messagesA) {\n const multiSetMessage = message as unknown as MultiSet<[K, V1]>\n for (const [item, multiplicity] of multiSetMessage.getInner()) {\n const [key, value] = item\n deltaA.addValue(key, [value, multiplicity])\n }\n }\n\n // Process input B - process ALL messages, not just the first one\n const messagesB = this.inputBMessages()\n for (const message of messagesB) {\n const multiSetMessage = message as unknown as MultiSet<[K, V2]>\n for (const [item, multiplicity] of multiSetMessage.getInner()) {\n const [key, value] = item\n deltaB.addValue(key, [value, multiplicity])\n }\n }\n\n // Process results\n const results = new MultiSet<[K, [V1, V2]]>()\n\n // Join deltaA with existing indexB\n results.extend(deltaA.join(this.#indexB))\n\n // Append deltaA to indexA\n this.#indexA.append(deltaA)\n\n // Join existing indexA with deltaB\n results.extend(this.#indexA.join(deltaB))\n\n // Send results\n if (results.getInner().length > 0) {\n this.output.sendData(results)\n }\n\n // Append deltaB to indexB\n this.#indexB.append(deltaB)\n }\n}\n\n/**\n * Joins two input streams\n * @param other - The other stream to join with\n * @param type - The type of join to perform\n */\nexport function join<\n K,\n V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never,\n V2,\n T,\n>(\n other: IStreamBuilder<KeyValue<K, V2>>,\n type: JoinType = `inner`\n): PipedOperator<T, KeyValue<K, [V1 | null, V2 | null]>> {\n switch (type) {\n case `inner`:\n return innerJoin(other) as unknown as PipedOperator<\n T,\n KeyValue<K, [V1, V2]>\n >\n case `anti`:\n return antiJoin(other) as unknown as PipedOperator<\n T,\n KeyValue<K, [V1, null]>\n >\n case `left`:\n return leftJoin(other) as unknown as PipedOperator<\n T,\n KeyValue<K, [V1, V2 | null]>\n >\n case `right`:\n return rightJoin(other) as unknown as PipedOperator<\n T,\n KeyValue<K, [V1 | null, V2]>\n >\n case `full`:\n return fullJoin(other) as unknown as PipedOperator<\n T,\n KeyValue<K, [V1 | null, V2 | null]>\n >\n default:\n throw new Error(`Join type ${type} is invalid`)\n }\n}\n\n/**\n * Joins two input streams\n * @param other - The other stream to join with\n */\nexport function innerJoin<\n K,\n V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never,\n V2,\n T,\n>(\n other: IStreamBuilder<KeyValue<K, V2>>\n): PipedOperator<T, KeyValue<K, [V1, V2]>> {\n return (stream: IStreamBuilder<T>): IStreamBuilder<KeyValue<K, [V1, V2]>> => {\n if (stream.graph !== other.graph) {\n throw new Error(`Cannot join streams from different graphs`)\n }\n const output = new StreamBuilder<KeyValue<K, [V1, V2]>>(\n stream.graph,\n new DifferenceStreamWriter<KeyValue<K, [V1, V2]>>()\n )\n const operator = new JoinOperator<K, V1, V2>(\n stream.graph.getNextOperatorId(),\n stream.connectReader() as DifferenceStreamReader<KeyValue<K, V1>>,\n other.connectReader(),\n output.writer\n )\n stream.graph.addOperator(operator)\n stream.graph.addStream(output.connectReader())\n return output\n }\n}\n\n/**\n * Joins two input streams\n * @param other - The other stream to join with\n */\nexport function antiJoin<\n K,\n V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never,\n V2,\n T,\n>(\n other: IStreamBuilder<KeyValue<K, V2>>\n): PipedOperator<T, KeyValue<K, [V1, null]>> {\n return (\n stream: IStreamBuilder<T>\n ): IStreamBuilder<KeyValue<K, [V1, null]>> => {\n const matchedLeft = stream.pipe(\n innerJoin(other),\n map(([key, [valueLeft, _valueRight]]) => [key, valueLeft])\n )\n const anti = stream.pipe(\n concat(matchedLeft.pipe(negate())),\n // @ts-ignore TODO: fix this\n map(([key, value]) => [key, [value, null]])\n )\n return anti as IStreamBuilder<KeyValue<K, [V1, null]>>\n }\n}\n\n/**\n * Joins two input streams\n * @param other - The other stream to join with\n */\nexport function leftJoin<\n K,\n V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never,\n V2,\n T,\n>(\n other: IStreamBuilder<KeyValue<K, V2>>\n): PipedOperator<T, KeyValue<K, [V1, V2 | null]>> {\n return (\n stream: IStreamBuilder<T>\n ): IStreamBuilder<KeyValue<K, [V1, V2 | null]>> => {\n const left = stream\n const right = other\n const inner = left.pipe(innerJoin(right))\n const anti = left.pipe(antiJoin(right))\n return inner.pipe(concat(anti)) as IStreamBuilder<\n KeyValue<K, [V1, V2 | null]>\n >\n }\n}\n\n/**\n * Joins two input streams\n * @param other - The other stream to join with\n */\nexport function rightJoin<\n K,\n V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never,\n V2,\n T,\n>(\n other: IStreamBuilder<KeyValue<K, V2>>\n): PipedOperator<T, KeyValue<K, [V1 | null, V2]>> {\n return (\n stream: IStreamBuilder<T>\n ): IStreamBuilder<KeyValue<K, [V1 | null, V2]>> => {\n const left = stream as IStreamBuilder<KeyValue<K, V1>>\n const right = other\n const inner = left.pipe(innerJoin(right))\n const anti = right.pipe(\n antiJoin(left),\n map(([key, [a, b]]) => [key, [b, a]])\n )\n return inner.pipe(concat(anti)) as IStreamBuilder<\n KeyValue<K, [V1 | null, V2]>\n >\n }\n}\n\n/**\n * Joins two input streams\n * @param other - The other stream to join with\n */\nexport function fullJoin<\n K,\n V1 extends T extends KeyValue<infer _KT, infer VT> ? VT : never,\n V2,\n T,\n>(\n other: IStreamBuilder<KeyValue<K, V2>>\n): PipedOperator<T, KeyValue<K, [V1 | null, V2 | null]>> {\n return (\n stream: IStreamBuilder<T>\n ): IStreamBuilder<KeyValue<K, [V1 | null, V2 | null]>> => {\n const left = stream as IStreamBuilder<KeyValue<K, V1>>\n const right = other\n const inner = left.pipe(innerJoin(right))\n const antiLeft = left.pipe(antiJoin(right))\n const antiRight = right.pipe(\n antiJoin(left),\n map(([key, [a, b]]) => [key, [b, a]])\n )\n return inner.pipe(concat(antiLeft), concat(antiRight)) as IStreamBuilder<\n KeyValue<K, [V1 | null, V2 | null]>\n >\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PipedOperator } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Type for a keyed value
|
|
4
|
+
*/
|
|
5
|
+
export type Keyed<K, V> = [K, V];
|
|
6
|
+
/**
|
|
7
|
+
* Takes an unkeyed input and returns a keyed result
|
|
8
|
+
* @param keyFn - Function to generate the key for each value
|
|
9
|
+
*/
|
|
10
|
+
export declare function keyBy<T, K>(keyFn: (value: T) => K): PipedOperator<T, Keyed<K, T>>;
|
|
11
|
+
/**
|
|
12
|
+
* Removes the key from a keyed stream
|
|
13
|
+
*/
|
|
14
|
+
export declare function unkey<K, V>(): PipedOperator<Keyed<K, V>, V>;
|
|
15
|
+
/**
|
|
16
|
+
* Takes a keyed input and rekeys it with a new key
|
|
17
|
+
* @param keyFn - Function to generate the new key for each value
|
|
18
|
+
*/
|
|
19
|
+
export declare function rekey<K1, K2, V>(keyFn: (value: V) => K2): PipedOperator<Keyed<K1, V>, Keyed<K2, V>>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { map } from "./map.js";
|
|
2
|
+
function keyBy(keyFn) {
|
|
3
|
+
return map((value) => [keyFn(value), value]);
|
|
4
|
+
}
|
|
5
|
+
function unkey() {
|
|
6
|
+
return map(([_, value]) => value);
|
|
7
|
+
}
|
|
8
|
+
function rekey(keyFn) {
|
|
9
|
+
return map(([_, value]) => [keyFn(value), value]);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
keyBy,
|
|
13
|
+
rekey,
|
|
14
|
+
unkey
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=keying.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keying.js","sources":["../../../src/operators/keying.ts"],"sourcesContent":["import { map } from \"./map.js\"\nimport type { PipedOperator } from \"../types.js\"\n\n/**\n * Type for a keyed value\n */\nexport type Keyed<K, V> = [K, V]\n\n/**\n * Takes an unkeyed input and returns a keyed result\n * @param keyFn - Function to generate the key for each value\n */\nexport function keyBy<T, K>(\n keyFn: (value: T) => K\n): PipedOperator<T, Keyed<K, T>> {\n return map((value: T): Keyed<K, T> => [keyFn(value), value])\n}\n\n/**\n * Removes the key from a keyed stream\n */\nexport function unkey<K, V>(): PipedOperator<Keyed<K, V>, V> {\n return map(([_, value]: Keyed<K, V>): V => value)\n}\n\n/**\n * Takes a keyed input and rekeys it with a new key\n * @param keyFn - Function to generate the new key for each value\n */\nexport function rekey<K1, K2, V>(\n keyFn: (value: V) => K2\n): PipedOperator<Keyed<K1, V>, Keyed<K2, V>> {\n return map(([_, value]: Keyed<K1, V>): Keyed<K2, V> => [keyFn(value), value])\n}\n"],"names":[],"mappings":";AAYO,SAAS,MACd,OAC+B;AAC/B,SAAO,IAAI,CAAC,UAA0B,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC;AAC7D;AAKO,SAAS,QAA6C;AAC3D,SAAO,IAAI,CAAC,CAAC,GAAG,KAAK,MAAsB,KAAK;AAClD;AAMO,SAAS,MACd,OAC2C;AAC3C,SAAO,IAAI,CAAC,CAAC,GAAG,KAAK,MAAkC,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC;AAC9E;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DifferenceStreamWriter, LinearUnaryOperator, DifferenceStreamReader } from '../graph.js';
|
|
2
|
+
import { PipedOperator } from '../types.js';
|
|
3
|
+
import { MultiSet } from '../multiset.js';
|
|
4
|
+
/**
|
|
5
|
+
* Operator that applies a function to each element in the input stream
|
|
6
|
+
*/
|
|
7
|
+
export declare class MapOperator<T, U> extends LinearUnaryOperator<T, U> {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(id: number, inputA: DifferenceStreamReader<T>, output: DifferenceStreamWriter<U>, f: (data: T) => U);
|
|
10
|
+
inner(collection: MultiSet<T>): MultiSet<U>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Applies a function to each element in the input stream
|
|
14
|
+
* @param f - The function to apply to each element
|
|
15
|
+
*/
|
|
16
|
+
export declare function map<T, O>(f: (data: T) => O): PipedOperator<T, O>;
|