@tanstack/db-ivm 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/d2.cjs.map +1 -1
  3. package/dist/cjs/graph.cjs.map +1 -1
  4. package/dist/cjs/hashing/hash.cjs.map +1 -1
  5. package/dist/cjs/index.cjs +6 -3
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/index.d.cts +1 -0
  8. package/dist/cjs/indexes.cjs +1 -1
  9. package/dist/cjs/indexes.cjs.map +1 -1
  10. package/dist/cjs/multiset.cjs.map +1 -1
  11. package/dist/cjs/operators/concat.cjs.map +1 -1
  12. package/dist/cjs/operators/consolidate.cjs.map +1 -1
  13. package/dist/cjs/operators/count.cjs.map +1 -1
  14. package/dist/cjs/operators/debug.cjs.map +1 -1
  15. package/dist/cjs/operators/distinct.cjs.map +1 -1
  16. package/dist/cjs/operators/filter.cjs.map +1 -1
  17. package/dist/cjs/operators/filterBy.cjs.map +1 -1
  18. package/dist/cjs/operators/groupBy.cjs +2 -1
  19. package/dist/cjs/operators/groupBy.cjs.map +1 -1
  20. package/dist/cjs/operators/groupedTopKWithFractionalIndex.cjs +116 -0
  21. package/dist/cjs/operators/groupedTopKWithFractionalIndex.cjs.map +1 -0
  22. package/dist/cjs/operators/groupedTopKWithFractionalIndex.d.cts +50 -0
  23. package/dist/cjs/operators/index.d.cts +1 -0
  24. package/dist/cjs/operators/join.cjs.map +1 -1
  25. package/dist/cjs/operators/keying.cjs.map +1 -1
  26. package/dist/cjs/operators/map.cjs.map +1 -1
  27. package/dist/cjs/operators/negate.cjs.map +1 -1
  28. package/dist/cjs/operators/orderBy.cjs.map +1 -1
  29. package/dist/cjs/operators/output.cjs.map +1 -1
  30. package/dist/cjs/operators/pipe.cjs.map +1 -1
  31. package/dist/cjs/operators/reduce.cjs.map +1 -1
  32. package/dist/cjs/operators/tap.cjs.map +1 -1
  33. package/dist/cjs/operators/topK.cjs.map +1 -1
  34. package/dist/cjs/operators/topKArray.cjs +137 -0
  35. package/dist/cjs/operators/topKArray.cjs.map +1 -0
  36. package/dist/cjs/operators/topKArray.d.cts +59 -0
  37. package/dist/cjs/operators/topKState.cjs +73 -0
  38. package/dist/cjs/operators/topKState.cjs.map +1 -0
  39. package/dist/cjs/operators/topKState.d.cts +35 -0
  40. package/dist/cjs/operators/topKWithFractionalIndex.cjs +17 -208
  41. package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -1
  42. package/dist/cjs/operators/topKWithFractionalIndex.d.cts +4 -43
  43. package/dist/cjs/operators/topKWithFractionalIndexBTree.d.cts +5 -4
  44. package/dist/cjs/utils.cjs +21 -0
  45. package/dist/cjs/utils.cjs.map +1 -1
  46. package/dist/cjs/utils.d.cts +11 -0
  47. package/dist/esm/d2.js.map +1 -1
  48. package/dist/esm/graph.js.map +1 -1
  49. package/dist/esm/hashing/hash.js.map +1 -1
  50. package/dist/esm/index.d.ts +1 -0
  51. package/dist/esm/index.js +7 -4
  52. package/dist/esm/index.js.map +1 -1
  53. package/dist/esm/indexes.js +1 -1
  54. package/dist/esm/indexes.js.map +1 -1
  55. package/dist/esm/multiset.js.map +1 -1
  56. package/dist/esm/operators/concat.js.map +1 -1
  57. package/dist/esm/operators/consolidate.js.map +1 -1
  58. package/dist/esm/operators/count.js.map +1 -1
  59. package/dist/esm/operators/debug.js.map +1 -1
  60. package/dist/esm/operators/distinct.js.map +1 -1
  61. package/dist/esm/operators/filter.js.map +1 -1
  62. package/dist/esm/operators/filterBy.js.map +1 -1
  63. package/dist/esm/operators/groupBy.js +2 -1
  64. package/dist/esm/operators/groupBy.js.map +1 -1
  65. package/dist/esm/operators/groupedTopKWithFractionalIndex.d.ts +50 -0
  66. package/dist/esm/operators/groupedTopKWithFractionalIndex.js +116 -0
  67. package/dist/esm/operators/groupedTopKWithFractionalIndex.js.map +1 -0
  68. package/dist/esm/operators/index.d.ts +1 -0
  69. package/dist/esm/operators/join.js.map +1 -1
  70. package/dist/esm/operators/keying.js.map +1 -1
  71. package/dist/esm/operators/map.js.map +1 -1
  72. package/dist/esm/operators/negate.js.map +1 -1
  73. package/dist/esm/operators/orderBy.js.map +1 -1
  74. package/dist/esm/operators/output.js.map +1 -1
  75. package/dist/esm/operators/pipe.js.map +1 -1
  76. package/dist/esm/operators/reduce.js.map +1 -1
  77. package/dist/esm/operators/tap.js.map +1 -1
  78. package/dist/esm/operators/topK.js.map +1 -1
  79. package/dist/esm/operators/topKArray.d.ts +59 -0
  80. package/dist/esm/operators/topKArray.js +137 -0
  81. package/dist/esm/operators/topKArray.js.map +1 -0
  82. package/dist/esm/operators/topKState.d.ts +35 -0
  83. package/dist/esm/operators/topKState.js +73 -0
  84. package/dist/esm/operators/topKState.js.map +1 -0
  85. package/dist/esm/operators/topKWithFractionalIndex.d.ts +4 -43
  86. package/dist/esm/operators/topKWithFractionalIndex.js +16 -207
  87. package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -1
  88. package/dist/esm/operators/topKWithFractionalIndexBTree.d.ts +5 -4
  89. package/dist/esm/utils.d.ts +11 -0
  90. package/dist/esm/utils.js +22 -1
  91. package/dist/esm/utils.js.map +1 -1
  92. package/package.json +29 -29
  93. package/src/d2.ts +4 -4
  94. package/src/graph.ts +6 -6
  95. package/src/hashing/hash.ts +3 -3
  96. package/src/hashing/index.ts +2 -2
  97. package/src/index.ts +5 -4
  98. package/src/indexes.ts +8 -8
  99. package/src/multiset.ts +5 -5
  100. package/src/operators/concat.ts +6 -6
  101. package/src/operators/consolidate.ts +6 -6
  102. package/src/operators/count.ts +9 -9
  103. package/src/operators/debug.ts +8 -8
  104. package/src/operators/distinct.ts +11 -11
  105. package/src/operators/filter.ts +8 -8
  106. package/src/operators/filterBy.ts +7 -7
  107. package/src/operators/groupBy.ts +24 -23
  108. package/src/operators/groupedTopKWithFractionalIndex.ts +192 -0
  109. package/src/operators/index.ts +20 -19
  110. package/src/operators/join.ts +23 -23
  111. package/src/operators/keying.ts +4 -4
  112. package/src/operators/map.ts +8 -8
  113. package/src/operators/negate.ts +6 -6
  114. package/src/operators/orderBy.ts +26 -26
  115. package/src/operators/orderByBTree.ts +7 -7
  116. package/src/operators/output.ts +9 -9
  117. package/src/operators/pipe.ts +1 -1
  118. package/src/operators/reduce.ts +9 -9
  119. package/src/operators/tap.ts +8 -8
  120. package/src/operators/topK.ts +8 -8
  121. package/src/operators/topKArray.ts +255 -0
  122. package/src/operators/topKState.ts +111 -0
  123. package/src/operators/topKWithFractionalIndex.ts +36 -381
  124. package/src/operators/topKWithFractionalIndexBTree.ts +21 -30
  125. package/src/types.ts +22 -22
  126. package/src/utils.ts +36 -4
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 "./multiset.js"
37
- import { hash } from "./hashing/index.js"
38
- import type { Hash } from "./hashing/index.js"
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 "./utils.js"
6
- import { hash } from "./hashing/index.js"
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
@@ -1,6 +1,6 @@
1
- import { BinaryOperator, DifferenceStreamWriter } from "../graph.js"
2
- import { StreamBuilder } from "../d2.js"
3
- import type { IStreamBuilder, PipedOperator } from "../types.js"
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 "../graph.js"
2
- import { StreamBuilder } from "../d2.js"
3
- import { MultiSet } from "../multiset.js"
4
- import type { IStreamBuilder, PipedOperator } from "../types.js"
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
@@ -1,8 +1,8 @@
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"
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
@@ -1,7 +1,7 @@
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"
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 "../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"
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
@@ -1,8 +1,8 @@
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"
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 "./map.js"
2
- import { innerJoin } from "./join.js"
3
- import { consolidate } from "./consolidate.js"
4
- import type { IStreamBuilder, KeyValue, PipedOperator } from "../types.js"
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
  }
@@ -1,6 +1,7 @@
1
- import { map } from "./map.js"
2
- import { reduce } from "./reduce.js"
3
- import type { IStreamBuilder, KeyValue } from "../types.js"
1
+ import { serializeValue } from '../utils.js'
2
+ import { map } from './map.js'
3
+ import { reduce } from './reduce.js'
4
+ import type { IStreamBuilder, KeyValue } from '../types.js'
4
5
 
5
6
  type GroupKey = Record<string, unknown>
6
7
 
@@ -26,7 +27,7 @@ type AggregatesReturnType<T, A> = {
26
27
  }
27
28
 
28
29
  function isPipedAggregateFunction<T, R>(
29
- aggregate: AggregateFunction<T, R>
30
+ aggregate: AggregateFunction<T, R>,
30
31
  ): aggregate is PipedAggregateFunction<T, R> {
31
32
  return `pipe` in aggregate
32
33
  }
@@ -45,20 +46,20 @@ export function groupBy<
45
46
 
46
47
  const basicAggregates = Object.fromEntries(
47
48
  Object.entries(aggregates).filter(
48
- ([_, aggregate]) => !isPipedAggregateFunction(aggregate)
49
- )
49
+ ([_, aggregate]) => !isPipedAggregateFunction(aggregate),
50
+ ),
50
51
  ) as Record<string, BasicAggregateFunction<T, any, any>>
51
52
 
52
53
  // @ts-expect-error - TODO: we don't use this yet, but we will
53
54
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
54
55
  const pipedAggregates = Object.fromEntries(
55
56
  Object.entries(aggregates).filter(([_, aggregate]) =>
56
- isPipedAggregateFunction(aggregate)
57
- )
57
+ isPipedAggregateFunction(aggregate),
58
+ ),
58
59
  ) as Record<string, PipedAggregateFunction<T, any>>
59
60
 
60
61
  return (
61
- stream: IStreamBuilder<T>
62
+ stream: IStreamBuilder<T>,
62
63
  ): IStreamBuilder<KeyValue<string, ResultType>> => {
63
64
  // Special key to store the original key object
64
65
  const KEY_SENTINEL = `__original_key__`
@@ -67,7 +68,7 @@ export function groupBy<
67
68
  const withKeysAndValues = stream.pipe(
68
69
  map((data) => {
69
70
  const key = keyExtractor(data)
70
- const keyString = JSON.stringify(key)
71
+ const keyString = serializeValue(key)
71
72
 
72
73
  // Create values object with pre-aggregated values
73
74
  const values: Record<string, unknown> = {}
@@ -81,7 +82,7 @@ export function groupBy<
81
82
  }
82
83
 
83
84
  return [keyString, values] as KeyValue<string, Record<string, unknown>>
84
- })
85
+ }),
85
86
  )
86
87
 
87
88
  // Then reduce to compute aggregates
@@ -107,13 +108,13 @@ export function groupBy<
107
108
  // Apply each aggregate function
108
109
  for (const [name, aggregate] of Object.entries(basicAggregates)) {
109
110
  const preValues = values.map(
110
- ([v, m]) => [v[name], m] as [any, number]
111
+ ([v, m]) => [v[name], m] as [any, number],
111
112
  )
112
113
  result[name] = aggregate.reduce(preValues)
113
114
  }
114
115
 
115
116
  return [[result, 1]]
116
- })
117
+ }),
117
118
  )
118
119
 
119
120
  // Finally map to extract the key and include all values
@@ -139,7 +140,7 @@ export function groupBy<
139
140
 
140
141
  // Return with the string key instead of the object
141
142
  return [keyString, result] as KeyValue<string, ResultType>
142
- })
143
+ }),
143
144
  )
144
145
  }
145
146
  }
@@ -148,7 +149,7 @@ export function groupBy<
148
149
  * Creates a sum aggregate function
149
150
  */
150
151
  export function sum<T>(
151
- valueExtractor: (value: T) => number = (v) => v as unknown as number
152
+ valueExtractor: (value: T) => number = (v) => v as unknown as number,
152
153
  ): AggregateFunction<T, number, number> {
153
154
  return {
154
155
  preMap: (data: T) => valueExtractor(data),
@@ -166,7 +167,7 @@ export function sum<T>(
166
167
  * Creates a count aggregate function
167
168
  */
168
169
  export function count<T>(
169
- valueExtractor: (value: T) => any = (v) => v
170
+ valueExtractor: (value: T) => any = (v) => v,
170
171
  ): AggregateFunction<T, number, number> {
171
172
  return {
172
173
  // Count only not-null values (the `== null` comparison gives true for both null and undefined)
@@ -185,7 +186,7 @@ export function count<T>(
185
186
  * Creates an average aggregate function
186
187
  */
187
188
  export function avg<T>(
188
- valueExtractor: (value: T) => number = (v) => v as unknown as number
189
+ valueExtractor: (value: T) => number = (v) => v as unknown as number,
189
190
  ): AggregateFunction<T, number, { sum: number; count: number }> {
190
191
  return {
191
192
  preMap: (data: T) => ({
@@ -222,10 +223,10 @@ export function min<T extends CanMinMax>(): AggregateFunction<
222
223
  T | undefined
223
224
  >
224
225
  export function min<T, V extends CanMinMax>(
225
- valueExtractor: (value: T) => V
226
+ valueExtractor: (value: T) => V,
226
227
  ): AggregateFunction<T, V | undefined, V | undefined>
227
228
  export function min<T, V extends CanMinMax>(
228
- valueExtractor?: (value: T) => V
229
+ valueExtractor?: (value: T) => V,
229
230
  ): AggregateFunction<T, V | undefined, V | undefined> {
230
231
  const extractor = valueExtractor ?? ((v: T) => v as unknown as V)
231
232
  return {
@@ -252,10 +253,10 @@ export function max<T extends CanMinMax>(): AggregateFunction<
252
253
  T | undefined
253
254
  >
254
255
  export function max<T, V extends CanMinMax>(
255
- valueExtractor: (value: T) => V
256
+ valueExtractor: (value: T) => V,
256
257
  ): AggregateFunction<T, V | undefined, V | undefined>
257
258
  export function max<T, V extends CanMinMax>(
258
- valueExtractor?: (value: T) => V
259
+ valueExtractor?: (value: T) => V,
259
260
  ): AggregateFunction<T, V | undefined, V | undefined> {
260
261
  const extractor = valueExtractor ?? ((v: T) => v as unknown as V)
261
262
  return {
@@ -278,7 +279,7 @@ export function max<T, V extends CanMinMax>(
278
279
  * @param valueExtractor Function to extract a numeric value from each data entry
279
280
  */
280
281
  export function median<T>(
281
- valueExtractor: (value: T) => number = (v) => v as unknown as number
282
+ valueExtractor: (value: T) => number = (v) => v as unknown as number,
282
283
  ): AggregateFunction<T, number, Array<number>> {
283
284
  return {
284
285
  preMap: (data: T) => [valueExtractor(data)],
@@ -326,7 +327,7 @@ export function median<T>(
326
327
  * @param valueExtractor Function to extract a value from each data entry
327
328
  */
328
329
  export function mode<T>(
329
- valueExtractor: (value: T) => number = (v) => v as unknown as number
330
+ valueExtractor: (value: T) => number = (v) => v as unknown as number,
330
331
  ): AggregateFunction<T, number, Map<number, number>> {
331
332
  return {
332
333
  preMap: (data: T) => {