@tanstack/db-ivm 0.1.9 → 0.1.11

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 (95) hide show
  1. package/dist/cjs/d2.cjs +25 -49
  2. package/dist/cjs/d2.cjs.map +1 -1
  3. package/dist/cjs/graph.cjs +8 -20
  4. package/dist/cjs/graph.cjs.map +1 -1
  5. package/dist/cjs/indexes.cjs +118 -79
  6. package/dist/cjs/indexes.cjs.map +1 -1
  7. package/dist/cjs/indexes.d.cts +23 -0
  8. package/dist/cjs/multiset.cjs +106 -115
  9. package/dist/cjs/multiset.cjs.map +1 -1
  10. package/dist/cjs/multiset.d.cts +1 -0
  11. package/dist/cjs/operators/debug.cjs +5 -15
  12. package/dist/cjs/operators/debug.cjs.map +1 -1
  13. package/dist/cjs/operators/distinct.cjs +11 -22
  14. package/dist/cjs/operators/distinct.cjs.map +1 -1
  15. package/dist/cjs/operators/filter.cjs +3 -12
  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/filterBy.d.cts +1 -2
  19. package/dist/cjs/operators/groupBy.cjs +1 -2
  20. package/dist/cjs/operators/groupBy.cjs.map +1 -1
  21. package/dist/cjs/operators/join.cjs +104 -93
  22. package/dist/cjs/operators/join.cjs.map +1 -1
  23. package/dist/cjs/operators/join.d.cts +11 -8
  24. package/dist/cjs/operators/map.cjs +3 -12
  25. package/dist/cjs/operators/map.cjs.map +1 -1
  26. package/dist/cjs/operators/orderBy.cjs +13 -11
  27. package/dist/cjs/operators/orderBy.cjs.map +1 -1
  28. package/dist/cjs/operators/orderBy.d.cts +5 -2
  29. package/dist/cjs/operators/output.cjs +3 -12
  30. package/dist/cjs/operators/output.cjs.map +1 -1
  31. package/dist/cjs/operators/reduce.cjs +11 -22
  32. package/dist/cjs/operators/reduce.cjs.map +1 -1
  33. package/dist/cjs/operators/tap.cjs +3 -12
  34. package/dist/cjs/operators/tap.cjs.map +1 -1
  35. package/dist/cjs/operators/topK.cjs +4 -4
  36. package/dist/cjs/operators/topK.cjs.map +1 -1
  37. package/dist/cjs/operators/topK.d.cts +1 -2
  38. package/dist/cjs/operators/topKWithFractionalIndex.cjs +117 -82
  39. package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -1
  40. package/dist/cjs/operators/topKWithFractionalIndex.d.cts +22 -0
  41. package/dist/cjs/utils.cjs +21 -0
  42. package/dist/cjs/utils.cjs.map +1 -1
  43. package/dist/cjs/utils.d.cts +11 -0
  44. package/dist/esm/d2.js +25 -49
  45. package/dist/esm/d2.js.map +1 -1
  46. package/dist/esm/graph.js +8 -20
  47. package/dist/esm/graph.js.map +1 -1
  48. package/dist/esm/indexes.d.ts +23 -0
  49. package/dist/esm/indexes.js +118 -79
  50. package/dist/esm/indexes.js.map +1 -1
  51. package/dist/esm/multiset.d.ts +1 -0
  52. package/dist/esm/multiset.js +106 -115
  53. package/dist/esm/multiset.js.map +1 -1
  54. package/dist/esm/operators/debug.js +5 -15
  55. package/dist/esm/operators/debug.js.map +1 -1
  56. package/dist/esm/operators/distinct.js +11 -22
  57. package/dist/esm/operators/distinct.js.map +1 -1
  58. package/dist/esm/operators/filter.js +3 -12
  59. package/dist/esm/operators/filter.js.map +1 -1
  60. package/dist/esm/operators/filterBy.d.ts +1 -2
  61. package/dist/esm/operators/filterBy.js.map +1 -1
  62. package/dist/esm/operators/groupBy.js +1 -2
  63. package/dist/esm/operators/groupBy.js.map +1 -1
  64. package/dist/esm/operators/join.d.ts +11 -8
  65. package/dist/esm/operators/join.js +104 -93
  66. package/dist/esm/operators/join.js.map +1 -1
  67. package/dist/esm/operators/map.js +3 -12
  68. package/dist/esm/operators/map.js.map +1 -1
  69. package/dist/esm/operators/orderBy.d.ts +5 -2
  70. package/dist/esm/operators/orderBy.js +13 -11
  71. package/dist/esm/operators/orderBy.js.map +1 -1
  72. package/dist/esm/operators/output.js +3 -12
  73. package/dist/esm/operators/output.js.map +1 -1
  74. package/dist/esm/operators/reduce.js +11 -22
  75. package/dist/esm/operators/reduce.js.map +1 -1
  76. package/dist/esm/operators/tap.js +3 -12
  77. package/dist/esm/operators/tap.js.map +1 -1
  78. package/dist/esm/operators/topK.d.ts +1 -2
  79. package/dist/esm/operators/topK.js +4 -4
  80. package/dist/esm/operators/topK.js.map +1 -1
  81. package/dist/esm/operators/topKWithFractionalIndex.d.ts +22 -0
  82. package/dist/esm/operators/topKWithFractionalIndex.js +118 -83
  83. package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -1
  84. package/dist/esm/utils.d.ts +11 -0
  85. package/dist/esm/utils.js +21 -0
  86. package/dist/esm/utils.js.map +1 -1
  87. package/package.json +1 -1
  88. package/src/indexes.ts +54 -0
  89. package/src/multiset.ts +6 -0
  90. package/src/operators/filterBy.ts +1 -2
  91. package/src/operators/join.ts +249 -139
  92. package/src/operators/orderBy.ts +6 -2
  93. package/src/operators/topK.ts +1 -2
  94. package/src/operators/topKWithFractionalIndex.ts +111 -13
  95. package/src/utils.ts +33 -0
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sources":["../../../src/operators/output.ts"],"sourcesContent":["import { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { MultiSet } from \"../multiset.js\"\n\n/**\n * Operator that outputs the messages in the stream\n */\nexport class OutputOperator<T> extends UnaryOperator<T> {\n #fn: (data: MultiSet<T>) => void\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<T>,\n outputWriter: DifferenceStreamWriter<T>,\n fn: (data: MultiSet<T>) => void\n ) {\n super(id, inputA, outputWriter)\n this.#fn = fn\n }\n\n run(): void {\n for (const message of this.inputMessages()) {\n this.#fn(message)\n this.output.sendData(message)\n }\n }\n}\n\n/**\n * Outputs the messages in the stream\n * @param fn - The function to call with each message\n */\nexport function output<T>(\n fn: (data: MultiSet<T>) => void\n): PipedOperator<T, T> {\n return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {\n const outputStream = new StreamBuilder<T>(\n stream.graph,\n new DifferenceStreamWriter<T>()\n )\n const operator = new OutputOperator<T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n outputStream.writer,\n fn\n )\n stream.graph.addOperator(operator)\n return outputStream\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;AASO,MAAM,uBAA0B,cAAiB;AAAA,EAGtD,YACE,IACA,QACA,cACA,IACA;AACA,UAAM,IAAI,QAAQ,YAAY;AARhC;AASE,uBAAK,KAAM;AAAA,EACb;AAAA,EAEA,MAAY;AACV,eAAW,WAAW,KAAK,iBAAiB;AAC1C,yBAAK,KAAL,WAAS;AACT,WAAK,OAAO,SAAS,OAAO;AAAA,IAC9B;AAAA,EACF;AACF;AAlBE;AAwBK,SAAS,OACd,IACqB;AACrB,SAAO,CAAC,WAAiD;AACvD,UAAM,eAAe,IAAI;AAAA,MACvB,OAAO;AAAA,MACP,IAAI,uBAAA;AAAA,IAA0B;AAEhC,UAAM,WAAW,IAAI;AAAA,MACnB,OAAO,MAAM,kBAAA;AAAA,MACb,OAAO,cAAA;AAAA,MACP,aAAa;AAAA,MACb;AAAA,IAAA;AAEF,WAAO,MAAM,YAAY,QAAQ;AACjC,WAAO;AAAA,EACT;AACF;"}
1
+ {"version":3,"file":"output.js","sources":["../../../src/operators/output.ts"],"sourcesContent":["import { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { MultiSet } from \"../multiset.js\"\n\n/**\n * Operator that outputs the messages in the stream\n */\nexport class OutputOperator<T> extends UnaryOperator<T> {\n #fn: (data: MultiSet<T>) => void\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<T>,\n outputWriter: DifferenceStreamWriter<T>,\n fn: (data: MultiSet<T>) => void\n ) {\n super(id, inputA, outputWriter)\n this.#fn = fn\n }\n\n run(): void {\n for (const message of this.inputMessages()) {\n this.#fn(message)\n this.output.sendData(message)\n }\n }\n}\n\n/**\n * Outputs the messages in the stream\n * @param fn - The function to call with each message\n */\nexport function output<T>(\n fn: (data: MultiSet<T>) => void\n): PipedOperator<T, T> {\n return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {\n const outputStream = new StreamBuilder<T>(\n stream.graph,\n new DifferenceStreamWriter<T>()\n )\n const operator = new OutputOperator<T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n outputStream.writer,\n fn\n )\n stream.graph.addOperator(operator)\n return outputStream\n }\n}\n"],"names":[],"mappings":";;AASO,MAAM,uBAA0B,cAAiB;AAAA,EACtD;AAAA,EAEA,YACE,IACA,QACA,cACA,IACA;AACA,UAAM,IAAI,QAAQ,YAAY;AAC9B,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,MAAY;AACV,eAAW,WAAW,KAAK,iBAAiB;AAC1C,WAAK,IAAI,OAAO;AAChB,WAAK,OAAO,SAAS,OAAO;AAAA,IAC9B;AAAA,EACF;AACF;AAMO,SAAS,OACd,IACqB;AACrB,SAAO,CAAC,WAAiD;AACvD,UAAM,eAAe,IAAI;AAAA,MACvB,OAAO;AAAA,MACP,IAAI,uBAAA;AAAA,IAA0B;AAEhC,UAAM,WAAW,IAAI;AAAA,MACnB,OAAO,MAAM,kBAAA;AAAA,MACb,OAAO,cAAA;AAAA,MACP,aAAa;AAAA,MACb;AAAA,IAAA;AAEF,WAAO,MAAM,YAAY,QAAQ;AACjC,WAAO;AAAA,EACT;AACF;"}
@@ -1,37 +1,29 @@
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 __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
- var _index, _indexOut, _f;
9
1
  import { UnaryOperator, DifferenceStreamWriter } from "../graph.js";
10
2
  import { StreamBuilder } from "../d2.js";
11
3
  import { MultiSet } from "../multiset.js";
12
4
  import { Index } from "../indexes.js";
13
5
  class ReduceOperator extends UnaryOperator {
6
+ #index = new Index();
7
+ #indexOut = new Index();
8
+ #f;
14
9
  constructor(id, inputA, output, f) {
15
10
  super(id, inputA, output);
16
- __privateAdd(this, _index, new Index());
17
- __privateAdd(this, _indexOut, new Index());
18
- __privateAdd(this, _f);
19
- __privateSet(this, _f, f);
11
+ this.#f = f;
20
12
  }
21
13
  run() {
22
14
  const keysTodo = /* @__PURE__ */ new Set();
23
15
  for (const message of this.inputMessages()) {
24
16
  for (const [item, multiplicity] of message.getInner()) {
25
17
  const [key, value] = item;
26
- __privateGet(this, _index).addValue(key, [value, multiplicity]);
18
+ this.#index.addValue(key, [value, multiplicity]);
27
19
  keysTodo.add(key);
28
20
  }
29
21
  }
30
22
  const result = [];
31
23
  for (const key of keysTodo) {
32
- const curr = __privateGet(this, _index).get(key);
33
- const currOut = __privateGet(this, _indexOut).get(key);
34
- const out = __privateGet(this, _f).call(this, curr);
24
+ const curr = this.#index.get(key);
25
+ const currOut = this.#indexOut.get(key);
26
+ const out = this.#f(curr);
35
27
  const newOutputMap = /* @__PURE__ */ new Map();
36
28
  const oldOutputMap = /* @__PURE__ */ new Map();
37
29
  for (const [value, multiplicity] of out) {
@@ -45,14 +37,14 @@ class ReduceOperator extends UnaryOperator {
45
37
  for (const [value, multiplicity] of oldOutputMap) {
46
38
  if (!newOutputMap.has(value)) {
47
39
  result.push([[key, value], -multiplicity]);
48
- __privateGet(this, _indexOut).addValue(key, [value, -multiplicity]);
40
+ this.#indexOut.addValue(key, [value, -multiplicity]);
49
41
  }
50
42
  }
51
43
  for (const [value, multiplicity] of newOutputMap) {
52
44
  if (!oldOutputMap.has(value)) {
53
45
  if (multiplicity !== 0) {
54
46
  result.push([[key, value], multiplicity]);
55
- __privateGet(this, _indexOut).addValue(key, [value, multiplicity]);
47
+ this.#indexOut.addValue(key, [value, multiplicity]);
56
48
  }
57
49
  }
58
50
  }
@@ -62,7 +54,7 @@ class ReduceOperator extends UnaryOperator {
62
54
  const delta = newMultiplicity - oldMultiplicity;
63
55
  if (delta !== 0) {
64
56
  result.push([[key, value], delta]);
65
- __privateGet(this, _indexOut).addValue(key, [value, delta]);
57
+ this.#indexOut.addValue(key, [value, delta]);
66
58
  }
67
59
  }
68
60
  }
@@ -72,9 +64,6 @@ class ReduceOperator extends UnaryOperator {
72
64
  }
73
65
  }
74
66
  }
75
- _index = new WeakMap();
76
- _indexOut = new WeakMap();
77
- _f = new WeakMap();
78
67
  function reduce(f) {
79
68
  return (stream) => {
80
69
  const output = new StreamBuilder(
@@ -1 +1 @@
1
- {"version":3,"file":"reduce.js","sources":["../../../src/operators/reduce.ts"],"sourcesContent":["import { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport { MultiSet } from \"../multiset.js\"\nimport { Index } from \"../indexes.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { IStreamBuilder, KeyValue } from \"../types.js\"\n\n/**\n * Base operator for reduction operations (version-free)\n */\nexport class ReduceOperator<K, V1, V2> extends UnaryOperator<[K, V1], [K, V2]> {\n #index = new Index<K, V1>()\n #indexOut = new Index<K, V2>()\n #f: (values: Array<[V1, number]>) => Array<[V2, number]>\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<[K, V1]>,\n output: DifferenceStreamWriter<[K, V2]>,\n f: (values: Array<[V1, number]>) => Array<[V2, number]>\n ) {\n super(id, inputA, output)\n this.#f = f\n }\n\n run(): void {\n // Collect all input messages and update the index\n const keysTodo = new Set<K>()\n for (const message of this.inputMessages()) {\n for (const [item, multiplicity] of message.getInner()) {\n const [key, value] = item\n this.#index.addValue(key, [value, multiplicity])\n keysTodo.add(key)\n }\n }\n\n // For each key, compute the reduction and delta\n const result: Array<[[K, V2], number]> = []\n for (const key of keysTodo) {\n const curr = this.#index.get(key)\n const currOut = this.#indexOut.get(key)\n const out = this.#f(curr)\n\n // Create maps for current and previous outputs using values directly as keys\n const newOutputMap = new Map<V2, number>()\n const oldOutputMap = new Map<V2, number>()\n\n // Process new output\n for (const [value, multiplicity] of out) {\n const existing = newOutputMap.get(value) ?? 0\n newOutputMap.set(value, existing + multiplicity)\n }\n\n // Process previous output\n for (const [value, multiplicity] of currOut) {\n const existing = oldOutputMap.get(value) ?? 0\n oldOutputMap.set(value, existing + multiplicity)\n }\n\n // First, emit removals for old values that are no longer present\n for (const [value, multiplicity] of oldOutputMap) {\n if (!newOutputMap.has(value)) {\n // Remove the old value entirely\n result.push([[key, value], -multiplicity])\n this.#indexOut.addValue(key, [value, -multiplicity])\n }\n }\n\n // Then, emit additions for new values that are not present in old\n for (const [value, multiplicity] of newOutputMap) {\n if (!oldOutputMap.has(value)) {\n // Add the new value only if it has non-zero multiplicity\n if (multiplicity !== 0) {\n result.push([[key, value], multiplicity])\n this.#indexOut.addValue(key, [value, multiplicity])\n }\n }\n }\n\n // Finally, emit multiplicity changes for values that were present and are still present\n for (const [value, newMultiplicity] of newOutputMap) {\n const oldMultiplicity = oldOutputMap.get(value)\n if (oldMultiplicity !== undefined) {\n const delta = newMultiplicity - oldMultiplicity\n // Only emit actual changes, i.e. non-zero deltas\n if (delta !== 0) {\n result.push([[key, value], delta])\n this.#indexOut.addValue(key, [value, delta])\n }\n }\n }\n }\n\n if (result.length > 0) {\n this.output.sendData(new MultiSet(result))\n }\n }\n}\n\n/**\n * Reduces the elements in the stream by key (version-free)\n */\nexport function reduce<\n KType extends T extends KeyValue<infer K, infer _V> ? K : never,\n V1Type extends T extends KeyValue<KType, infer V> ? V : never,\n R,\n T,\n>(f: (values: Array<[V1Type, number]>) => Array<[R, number]>) {\n return (stream: IStreamBuilder<T>): IStreamBuilder<KeyValue<KType, R>> => {\n const output = new StreamBuilder<KeyValue<KType, R>>(\n stream.graph,\n new DifferenceStreamWriter<KeyValue<KType, R>>()\n )\n const operator = new ReduceOperator<KType, V1Type, R>(\n stream.graph.getNextOperatorId(),\n stream.connectReader() as DifferenceStreamReader<KeyValue<KType, V1Type>>,\n output.writer,\n f\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAUO,MAAM,uBAAkC,cAAgC;AAAA,EAK7E,YACE,IACA,QACA,QACA,GACA;AACA,UAAM,IAAI,QAAQ,MAAM;AAV1B,+BAAS,IAAI,MAAA;AACb,kCAAY,IAAI,MAAA;AAChB;AASE,uBAAK,IAAK;AAAA,EACZ;AAAA,EAEA,MAAY;AAEV,UAAM,+BAAe,IAAA;AACrB,eAAW,WAAW,KAAK,iBAAiB;AAC1C,iBAAW,CAAC,MAAM,YAAY,KAAK,QAAQ,YAAY;AACrD,cAAM,CAAC,KAAK,KAAK,IAAI;AACrB,2BAAK,QAAO,SAAS,KAAK,CAAC,OAAO,YAAY,CAAC;AAC/C,iBAAS,IAAI,GAAG;AAAA,MAClB;AAAA,IACF;AAGA,UAAM,SAAmC,CAAA;AACzC,eAAW,OAAO,UAAU;AAC1B,YAAM,OAAO,mBAAK,QAAO,IAAI,GAAG;AAChC,YAAM,UAAU,mBAAK,WAAU,IAAI,GAAG;AACtC,YAAM,MAAM,mBAAK,IAAL,WAAQ;AAGpB,YAAM,mCAAmB,IAAA;AACzB,YAAM,mCAAmB,IAAA;AAGzB,iBAAW,CAAC,OAAO,YAAY,KAAK,KAAK;AACvC,cAAM,WAAW,aAAa,IAAI,KAAK,KAAK;AAC5C,qBAAa,IAAI,OAAO,WAAW,YAAY;AAAA,MACjD;AAGA,iBAAW,CAAC,OAAO,YAAY,KAAK,SAAS;AAC3C,cAAM,WAAW,aAAa,IAAI,KAAK,KAAK;AAC5C,qBAAa,IAAI,OAAO,WAAW,YAAY;AAAA,MACjD;AAGA,iBAAW,CAAC,OAAO,YAAY,KAAK,cAAc;AAChD,YAAI,CAAC,aAAa,IAAI,KAAK,GAAG;AAE5B,iBAAO,KAAK,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,YAAY,CAAC;AACzC,6BAAK,WAAU,SAAS,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;AAAA,QACrD;AAAA,MACF;AAGA,iBAAW,CAAC,OAAO,YAAY,KAAK,cAAc;AAChD,YAAI,CAAC,aAAa,IAAI,KAAK,GAAG;AAE5B,cAAI,iBAAiB,GAAG;AACtB,mBAAO,KAAK,CAAC,CAAC,KAAK,KAAK,GAAG,YAAY,CAAC;AACxC,+BAAK,WAAU,SAAS,KAAK,CAAC,OAAO,YAAY,CAAC;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AAGA,iBAAW,CAAC,OAAO,eAAe,KAAK,cAAc;AACnD,cAAM,kBAAkB,aAAa,IAAI,KAAK;AAC9C,YAAI,oBAAoB,QAAW;AACjC,gBAAM,QAAQ,kBAAkB;AAEhC,cAAI,UAAU,GAAG;AACf,mBAAO,KAAK,CAAC,CAAC,KAAK,KAAK,GAAG,KAAK,CAAC;AACjC,+BAAK,WAAU,SAAS,KAAK,CAAC,OAAO,KAAK,CAAC;AAAA,UAC7C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,WAAK,OAAO,SAAS,IAAI,SAAS,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;AAtFE;AACA;AACA;AAyFK,SAAS,OAKd,GAA4D;AAC5D,SAAO,CAAC,WAAkE;AACxE,UAAM,SAAS,IAAI;AAAA,MACjB,OAAO;AAAA,MACP,IAAI,uBAAA;AAAA,IAA2C;AAEjD,UAAM,WAAW,IAAI;AAAA,MACnB,OAAO,MAAM,kBAAA;AAAA,MACb,OAAO,cAAA;AAAA,MACP,OAAO;AAAA,MACP;AAAA,IAAA;AAEF,WAAO,MAAM,YAAY,QAAQ;AACjC,WAAO;AAAA,EACT;AACF;"}
1
+ {"version":3,"file":"reduce.js","sources":["../../../src/operators/reduce.ts"],"sourcesContent":["import { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport { MultiSet } from \"../multiset.js\"\nimport { Index } from \"../indexes.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { IStreamBuilder, KeyValue } from \"../types.js\"\n\n/**\n * Base operator for reduction operations (version-free)\n */\nexport class ReduceOperator<K, V1, V2> extends UnaryOperator<[K, V1], [K, V2]> {\n #index = new Index<K, V1>()\n #indexOut = new Index<K, V2>()\n #f: (values: Array<[V1, number]>) => Array<[V2, number]>\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<[K, V1]>,\n output: DifferenceStreamWriter<[K, V2]>,\n f: (values: Array<[V1, number]>) => Array<[V2, number]>\n ) {\n super(id, inputA, output)\n this.#f = f\n }\n\n run(): void {\n // Collect all input messages and update the index\n const keysTodo = new Set<K>()\n for (const message of this.inputMessages()) {\n for (const [item, multiplicity] of message.getInner()) {\n const [key, value] = item\n this.#index.addValue(key, [value, multiplicity])\n keysTodo.add(key)\n }\n }\n\n // For each key, compute the reduction and delta\n const result: Array<[[K, V2], number]> = []\n for (const key of keysTodo) {\n const curr = this.#index.get(key)\n const currOut = this.#indexOut.get(key)\n const out = this.#f(curr)\n\n // Create maps for current and previous outputs using values directly as keys\n const newOutputMap = new Map<V2, number>()\n const oldOutputMap = new Map<V2, number>()\n\n // Process new output\n for (const [value, multiplicity] of out) {\n const existing = newOutputMap.get(value) ?? 0\n newOutputMap.set(value, existing + multiplicity)\n }\n\n // Process previous output\n for (const [value, multiplicity] of currOut) {\n const existing = oldOutputMap.get(value) ?? 0\n oldOutputMap.set(value, existing + multiplicity)\n }\n\n // First, emit removals for old values that are no longer present\n for (const [value, multiplicity] of oldOutputMap) {\n if (!newOutputMap.has(value)) {\n // Remove the old value entirely\n result.push([[key, value], -multiplicity])\n this.#indexOut.addValue(key, [value, -multiplicity])\n }\n }\n\n // Then, emit additions for new values that are not present in old\n for (const [value, multiplicity] of newOutputMap) {\n if (!oldOutputMap.has(value)) {\n // Add the new value only if it has non-zero multiplicity\n if (multiplicity !== 0) {\n result.push([[key, value], multiplicity])\n this.#indexOut.addValue(key, [value, multiplicity])\n }\n }\n }\n\n // Finally, emit multiplicity changes for values that were present and are still present\n for (const [value, newMultiplicity] of newOutputMap) {\n const oldMultiplicity = oldOutputMap.get(value)\n if (oldMultiplicity !== undefined) {\n const delta = newMultiplicity - oldMultiplicity\n // Only emit actual changes, i.e. non-zero deltas\n if (delta !== 0) {\n result.push([[key, value], delta])\n this.#indexOut.addValue(key, [value, delta])\n }\n }\n }\n }\n\n if (result.length > 0) {\n this.output.sendData(new MultiSet(result))\n }\n }\n}\n\n/**\n * Reduces the elements in the stream by key (version-free)\n */\nexport function reduce<\n KType extends T extends KeyValue<infer K, infer _V> ? K : never,\n V1Type extends T extends KeyValue<KType, infer V> ? V : never,\n R,\n T,\n>(f: (values: Array<[V1Type, number]>) => Array<[R, number]>) {\n return (stream: IStreamBuilder<T>): IStreamBuilder<KeyValue<KType, R>> => {\n const output = new StreamBuilder<KeyValue<KType, R>>(\n stream.graph,\n new DifferenceStreamWriter<KeyValue<KType, R>>()\n )\n const operator = new ReduceOperator<KType, V1Type, R>(\n stream.graph.getNextOperatorId(),\n stream.connectReader() as DifferenceStreamReader<KeyValue<KType, V1Type>>,\n output.writer,\n f\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n"],"names":[],"mappings":";;;;AAUO,MAAM,uBAAkC,cAAgC;AAAA,EAC7E,SAAS,IAAI,MAAA;AAAA,EACb,YAAY,IAAI,MAAA;AAAA,EAChB;AAAA,EAEA,YACE,IACA,QACA,QACA,GACA;AACA,UAAM,IAAI,QAAQ,MAAM;AACxB,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,MAAY;AAEV,UAAM,+BAAe,IAAA;AACrB,eAAW,WAAW,KAAK,iBAAiB;AAC1C,iBAAW,CAAC,MAAM,YAAY,KAAK,QAAQ,YAAY;AACrD,cAAM,CAAC,KAAK,KAAK,IAAI;AACrB,aAAK,OAAO,SAAS,KAAK,CAAC,OAAO,YAAY,CAAC;AAC/C,iBAAS,IAAI,GAAG;AAAA,MAClB;AAAA,IACF;AAGA,UAAM,SAAmC,CAAA;AACzC,eAAW,OAAO,UAAU;AAC1B,YAAM,OAAO,KAAK,OAAO,IAAI,GAAG;AAChC,YAAM,UAAU,KAAK,UAAU,IAAI,GAAG;AACtC,YAAM,MAAM,KAAK,GAAG,IAAI;AAGxB,YAAM,mCAAmB,IAAA;AACzB,YAAM,mCAAmB,IAAA;AAGzB,iBAAW,CAAC,OAAO,YAAY,KAAK,KAAK;AACvC,cAAM,WAAW,aAAa,IAAI,KAAK,KAAK;AAC5C,qBAAa,IAAI,OAAO,WAAW,YAAY;AAAA,MACjD;AAGA,iBAAW,CAAC,OAAO,YAAY,KAAK,SAAS;AAC3C,cAAM,WAAW,aAAa,IAAI,KAAK,KAAK;AAC5C,qBAAa,IAAI,OAAO,WAAW,YAAY;AAAA,MACjD;AAGA,iBAAW,CAAC,OAAO,YAAY,KAAK,cAAc;AAChD,YAAI,CAAC,aAAa,IAAI,KAAK,GAAG;AAE5B,iBAAO,KAAK,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,YAAY,CAAC;AACzC,eAAK,UAAU,SAAS,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;AAAA,QACrD;AAAA,MACF;AAGA,iBAAW,CAAC,OAAO,YAAY,KAAK,cAAc;AAChD,YAAI,CAAC,aAAa,IAAI,KAAK,GAAG;AAE5B,cAAI,iBAAiB,GAAG;AACtB,mBAAO,KAAK,CAAC,CAAC,KAAK,KAAK,GAAG,YAAY,CAAC;AACxC,iBAAK,UAAU,SAAS,KAAK,CAAC,OAAO,YAAY,CAAC;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AAGA,iBAAW,CAAC,OAAO,eAAe,KAAK,cAAc;AACnD,cAAM,kBAAkB,aAAa,IAAI,KAAK;AAC9C,YAAI,oBAAoB,QAAW;AACjC,gBAAM,QAAQ,kBAAkB;AAEhC,cAAI,UAAU,GAAG;AACf,mBAAO,KAAK,CAAC,CAAC,KAAK,KAAK,GAAG,KAAK,CAAC;AACjC,iBAAK,UAAU,SAAS,KAAK,CAAC,OAAO,KAAK,CAAC;AAAA,UAC7C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,WAAK,OAAO,SAAS,IAAI,SAAS,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;AAKO,SAAS,OAKd,GAA4D;AAC5D,SAAO,CAAC,WAAkE;AACxE,UAAM,SAAS,IAAI;AAAA,MACjB,OAAO;AAAA,MACP,IAAI,uBAAA;AAAA,IAA2C;AAEjD,UAAM,WAAW,IAAI;AAAA,MACnB,OAAO,MAAM,kBAAA;AAAA,MACb,OAAO,cAAA;AAAA,MACP,OAAO;AAAA,MACP;AAAA,IAAA;AAEF,WAAO,MAAM,YAAY,QAAQ;AACjC,WAAO;AAAA,EACT;AACF;"}
@@ -1,25 +1,16 @@
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 __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
- var _f;
9
1
  import { LinearUnaryOperator, DifferenceStreamWriter } from "../graph.js";
10
2
  import { StreamBuilder } from "../d2.js";
11
3
  class TapOperator extends LinearUnaryOperator {
4
+ #f;
12
5
  constructor(id, inputA, output, f) {
13
6
  super(id, inputA, output);
14
- __privateAdd(this, _f);
15
- __privateSet(this, _f, f);
7
+ this.#f = f;
16
8
  }
17
9
  inner(collection) {
18
- __privateGet(this, _f).call(this, collection);
10
+ this.#f(collection);
19
11
  return collection;
20
12
  }
21
13
  }
22
- _f = new WeakMap();
23
14
  function tap(f) {
24
15
  return (stream) => {
25
16
  const output = new StreamBuilder(
@@ -1 +1 @@
1
- {"version":3,"file":"tap.js","sources":["../../../src/operators/tap.ts"],"sourcesContent":["import { DifferenceStreamWriter, LinearUnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { MultiSet } from \"../multiset.js\"\n\n/**\n * Operator that applies a function to each multi-set in the input stream\n */\nexport class TapOperator<T> extends LinearUnaryOperator<T, T> {\n #f: (data: MultiSet<T>) => void\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<T>,\n f: (data: MultiSet<T>) => void\n ) {\n super(id, inputA, output)\n this.#f = f\n }\n\n inner(collection: MultiSet<T>): MultiSet<T> {\n this.#f(collection)\n return collection\n }\n}\n\n/**\n * Invokes a function for each multi-set in the input stream.\n * This operator doesn't modify the stream and is used to perform side effects.\n * @param f - The function to invoke on each multi-set\n * @returns The input stream\n */\nexport function tap<T>(f: (data: MultiSet<T>) => void): PipedOperator<T, T> {\n return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {\n const output = new StreamBuilder<T>(\n stream.graph,\n new DifferenceStreamWriter<T>()\n )\n const operator = new TapOperator<T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n f\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;AASO,MAAM,oBAAuB,oBAA0B;AAAA,EAG5D,YACE,IACA,QACA,QACA,GACA;AACA,UAAM,IAAI,QAAQ,MAAM;AAR1B;AASE,uBAAK,IAAK;AAAA,EACZ;AAAA,EAEA,MAAM,YAAsC;AAC1C,uBAAK,IAAL,WAAQ;AACR,WAAO;AAAA,EACT;AACF;AAhBE;AAwBK,SAAS,IAAO,GAAqD;AAC1E,SAAO,CAAC,WAAiD;AACvD,UAAM,SAAS,IAAI;AAAA,MACjB,OAAO;AAAA,MACP,IAAI,uBAAA;AAAA,IAA0B;AAEhC,UAAM,WAAW,IAAI;AAAA,MACnB,OAAO,MAAM,kBAAA;AAAA,MACb,OAAO,cAAA;AAAA,MACP,OAAO;AAAA,MACP;AAAA,IAAA;AAEF,WAAO,MAAM,YAAY,QAAQ;AACjC,WAAO;AAAA,EACT;AACF;"}
1
+ {"version":3,"file":"tap.js","sources":["../../../src/operators/tap.ts"],"sourcesContent":["import { DifferenceStreamWriter, LinearUnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { MultiSet } from \"../multiset.js\"\n\n/**\n * Operator that applies a function to each multi-set in the input stream\n */\nexport class TapOperator<T> extends LinearUnaryOperator<T, T> {\n #f: (data: MultiSet<T>) => void\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<T>,\n f: (data: MultiSet<T>) => void\n ) {\n super(id, inputA, output)\n this.#f = f\n }\n\n inner(collection: MultiSet<T>): MultiSet<T> {\n this.#f(collection)\n return collection\n }\n}\n\n/**\n * Invokes a function for each multi-set in the input stream.\n * This operator doesn't modify the stream and is used to perform side effects.\n * @param f - The function to invoke on each multi-set\n * @returns The input stream\n */\nexport function tap<T>(f: (data: MultiSet<T>) => void): PipedOperator<T, T> {\n return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {\n const output = new StreamBuilder<T>(\n stream.graph,\n new DifferenceStreamWriter<T>()\n )\n const operator = new TapOperator<T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n f\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n"],"names":[],"mappings":";;AASO,MAAM,oBAAuB,oBAA0B;AAAA,EAC5D;AAAA,EAEA,YACE,IACA,QACA,QACA,GACA;AACA,UAAM,IAAI,QAAQ,MAAM;AACxB,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,MAAM,YAAsC;AAC1C,SAAK,GAAG,UAAU;AAClB,WAAO;AAAA,EACT;AACF;AAQO,SAAS,IAAO,GAAqD;AAC1E,SAAO,CAAC,WAAiD;AACvD,UAAM,SAAS,IAAI;AAAA,MACjB,OAAO;AAAA,MACP,IAAI,uBAAA;AAAA,IAA0B;AAEhC,UAAM,WAAW,IAAI;AAAA,MACnB,OAAO,MAAM,kBAAA;AAAA,MACb,OAAO,cAAA;AAAA,MACP,OAAO;AAAA,MACP;AAAA,IAAA;AAEF,WAAO,MAAM,YAAY,QAAQ;AACjC,WAAO;AAAA,EACT;AACF;"}
@@ -1,5 +1,4 @@
1
- import { PipedOperator } from '../types.js';
2
- import { KeyValue } from '../types.js';
1
+ import { KeyValue, PipedOperator } from '../types.js';
3
2
  interface TopKOptions {
4
3
  limit?: number;
5
4
  offset?: number;
@@ -1,8 +1,8 @@
1
1
  import { MultiSet } from "../multiset.js";
2
2
  import { reduce } from "./reduce.js";
3
3
  function topK(comparator, options) {
4
- const limit = (options == null ? void 0 : options.limit) ?? Infinity;
5
- const offset = (options == null ? void 0 : options.offset) ?? 0;
4
+ const limit = options?.limit ?? Infinity;
5
+ const offset = options?.offset ?? 0;
6
6
  return (stream) => {
7
7
  const reduced = stream.pipe(
8
8
  reduce((values) => {
@@ -15,8 +15,8 @@ function topK(comparator, options) {
15
15
  };
16
16
  }
17
17
  function topKWithIndex(comparator, options) {
18
- const limit = (options == null ? void 0 : options.limit) ?? Infinity;
19
- const offset = (options == null ? void 0 : options.offset) ?? 0;
18
+ const limit = options?.limit ?? Infinity;
19
+ const offset = options?.offset ?? 0;
20
20
  return (stream) => {
21
21
  const reduced = stream.pipe(
22
22
  reduce((values) => {
@@ -1 +1 @@
1
- {"version":3,"file":"topK.js","sources":["../../../src/operators/topK.ts"],"sourcesContent":["import { MultiSet } from \"../multiset.js\"\nimport { reduce } from \"./reduce.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types\"\nimport type { KeyValue } from \"../types.js\"\n\ninterface TopKOptions {\n limit?: number\n offset?: number\n}\n\n/**\n * Limits the number of results based on a comparator, with optional offset.\n * This works on a keyed stream, where the key is the first element of the tuple\n * The ordering is withing a key group, i.e. elements are sorted within a key group\n * and the limit + offset is applied to that sorted group.\n * To order the entire stream, key by the same value for all elements such as null.\n *\n * @param comparator - A function that compares two elements\n * @param options - An optional object containing limit and offset properties\n * @returns A piped operator that limits the number of results\n */\nexport function topK<\n KType extends T extends KeyValue<infer K, infer _V> ? K : never,\n V1Type extends T extends KeyValue<KType, infer V> ? V : never,\n T,\n>(\n comparator: (a: V1Type, b: V1Type) => number,\n options?: TopKOptions\n): PipedOperator<T, T> {\n const limit = options?.limit ?? Infinity\n const offset = options?.offset ?? 0\n\n return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {\n const reduced = stream.pipe(\n reduce((values) => {\n // `values` is a list of tuples, first element is the value, second is the multiplicity\n const consolidated = new MultiSet(values).consolidate()\n const sortedValues = consolidated\n .getInner()\n .sort((a, b) => comparator(a[0] as V1Type, b[0] as V1Type))\n return sortedValues.slice(offset, offset + limit)\n })\n )\n return reduced as IStreamBuilder<T>\n }\n}\n\n/**\n * Limits the number of results based on a comparator, with optional offset.\n * This works on a keyed stream, where the key is the first element of the tuple\n * The ordering is withing a key group, i.e. elements are sorted within a key group\n * and the limit + offset is applied to that sorted group.\n * To order the entire stream, key by the same value for all elements such as null.\n * Adds the index of the element to the result as [key, [value, index]]\n *\n * @param comparator - A function that compares two elements\n * @param options - An optional object containing limit and offset properties\n * @returns A piped operator that orders the elements and limits the number of results\n */\nexport function topKWithIndex<\n KType extends T extends KeyValue<infer K, infer _V> ? K : never,\n V1Type extends T extends KeyValue<KType, infer V> ? V : never,\n T,\n>(\n comparator: (a: V1Type, b: V1Type) => number,\n options?: TopKOptions\n): PipedOperator<T, KeyValue<KType, [V1Type, number]>> {\n const limit = options?.limit ?? Infinity\n const offset = options?.offset ?? 0\n\n return (\n stream: IStreamBuilder<T>\n ): IStreamBuilder<KeyValue<KType, [V1Type, number]>> => {\n const reduced = stream.pipe(\n reduce<KType, V1Type, [V1Type, number], T>((values) => {\n // `values` is a list of tuples, first element is the value, second is the multiplicity\n const consolidated = new MultiSet(values).consolidate()\n let i = offset\n const sortedValues = consolidated\n .getInner()\n .sort((a, b) => comparator(a[0], b[0]))\n .slice(offset, offset + limit)\n .map(([value, multiplicity]): [[V1Type, number], number] => [\n [value, i++],\n multiplicity,\n ])\n return sortedValues\n })\n )\n return reduced\n }\n}\n"],"names":[],"mappings":";;AAqBO,SAAS,KAKd,YACA,SACqB;AACrB,QAAM,SAAQ,mCAAS,UAAS;AAChC,QAAM,UAAS,mCAAS,WAAU;AAElC,SAAO,CAAC,WAAiD;AACvD,UAAM,UAAU,OAAO;AAAA,MACrB,OAAO,CAAC,WAAW;AAEjB,cAAM,eAAe,IAAI,SAAS,MAAM,EAAE,YAAA;AAC1C,cAAM,eAAe,aAClB,SAAA,EACA,KAAK,CAAC,GAAG,MAAM,WAAW,EAAE,CAAC,GAAa,EAAE,CAAC,CAAW,CAAC;AAC5D,eAAO,aAAa,MAAM,QAAQ,SAAS,KAAK;AAAA,MAClD,CAAC;AAAA,IAAA;AAEH,WAAO;AAAA,EACT;AACF;AAcO,SAAS,cAKd,YACA,SACqD;AACrD,QAAM,SAAQ,mCAAS,UAAS;AAChC,QAAM,UAAS,mCAAS,WAAU;AAElC,SAAO,CACL,WACsD;AACtD,UAAM,UAAU,OAAO;AAAA,MACrB,OAA2C,CAAC,WAAW;AAErD,cAAM,eAAe,IAAI,SAAS,MAAM,EAAE,YAAA;AAC1C,YAAI,IAAI;AACR,cAAM,eAAe,aAClB,SAAA,EACA,KAAK,CAAC,GAAG,MAAM,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EACrC,MAAM,QAAQ,SAAS,KAAK,EAC5B,IAAI,CAAC,CAAC,OAAO,YAAY,MAAkC;AAAA,UAC1D,CAAC,OAAO,GAAG;AAAA,UACX;AAAA,QAAA,CACD;AACH,eAAO;AAAA,MACT,CAAC;AAAA,IAAA;AAEH,WAAO;AAAA,EACT;AACF;"}
1
+ {"version":3,"file":"topK.js","sources":["../../../src/operators/topK.ts"],"sourcesContent":["import { MultiSet } from \"../multiset.js\"\nimport { reduce } from \"./reduce.js\"\nimport type { IStreamBuilder, KeyValue, PipedOperator } from \"../types\"\n\ninterface TopKOptions {\n limit?: number\n offset?: number\n}\n\n/**\n * Limits the number of results based on a comparator, with optional offset.\n * This works on a keyed stream, where the key is the first element of the tuple\n * The ordering is withing a key group, i.e. elements are sorted within a key group\n * and the limit + offset is applied to that sorted group.\n * To order the entire stream, key by the same value for all elements such as null.\n *\n * @param comparator - A function that compares two elements\n * @param options - An optional object containing limit and offset properties\n * @returns A piped operator that limits the number of results\n */\nexport function topK<\n KType extends T extends KeyValue<infer K, infer _V> ? K : never,\n V1Type extends T extends KeyValue<KType, infer V> ? V : never,\n T,\n>(\n comparator: (a: V1Type, b: V1Type) => number,\n options?: TopKOptions\n): PipedOperator<T, T> {\n const limit = options?.limit ?? Infinity\n const offset = options?.offset ?? 0\n\n return (stream: IStreamBuilder<T>): IStreamBuilder<T> => {\n const reduced = stream.pipe(\n reduce((values) => {\n // `values` is a list of tuples, first element is the value, second is the multiplicity\n const consolidated = new MultiSet(values).consolidate()\n const sortedValues = consolidated\n .getInner()\n .sort((a, b) => comparator(a[0] as V1Type, b[0] as V1Type))\n return sortedValues.slice(offset, offset + limit)\n })\n )\n return reduced as IStreamBuilder<T>\n }\n}\n\n/**\n * Limits the number of results based on a comparator, with optional offset.\n * This works on a keyed stream, where the key is the first element of the tuple\n * The ordering is withing a key group, i.e. elements are sorted within a key group\n * and the limit + offset is applied to that sorted group.\n * To order the entire stream, key by the same value for all elements such as null.\n * Adds the index of the element to the result as [key, [value, index]]\n *\n * @param comparator - A function that compares two elements\n * @param options - An optional object containing limit and offset properties\n * @returns A piped operator that orders the elements and limits the number of results\n */\nexport function topKWithIndex<\n KType extends T extends KeyValue<infer K, infer _V> ? K : never,\n V1Type extends T extends KeyValue<KType, infer V> ? V : never,\n T,\n>(\n comparator: (a: V1Type, b: V1Type) => number,\n options?: TopKOptions\n): PipedOperator<T, KeyValue<KType, [V1Type, number]>> {\n const limit = options?.limit ?? Infinity\n const offset = options?.offset ?? 0\n\n return (\n stream: IStreamBuilder<T>\n ): IStreamBuilder<KeyValue<KType, [V1Type, number]>> => {\n const reduced = stream.pipe(\n reduce<KType, V1Type, [V1Type, number], T>((values) => {\n // `values` is a list of tuples, first element is the value, second is the multiplicity\n const consolidated = new MultiSet(values).consolidate()\n let i = offset\n const sortedValues = consolidated\n .getInner()\n .sort((a, b) => comparator(a[0], b[0]))\n .slice(offset, offset + limit)\n .map(([value, multiplicity]): [[V1Type, number], number] => [\n [value, i++],\n multiplicity,\n ])\n return sortedValues\n })\n )\n return reduced\n }\n}\n"],"names":[],"mappings":";;AAoBO,SAAS,KAKd,YACA,SACqB;AACrB,QAAM,QAAQ,SAAS,SAAS;AAChC,QAAM,SAAS,SAAS,UAAU;AAElC,SAAO,CAAC,WAAiD;AACvD,UAAM,UAAU,OAAO;AAAA,MACrB,OAAO,CAAC,WAAW;AAEjB,cAAM,eAAe,IAAI,SAAS,MAAM,EAAE,YAAA;AAC1C,cAAM,eAAe,aAClB,SAAA,EACA,KAAK,CAAC,GAAG,MAAM,WAAW,EAAE,CAAC,GAAa,EAAE,CAAC,CAAW,CAAC;AAC5D,eAAO,aAAa,MAAM,QAAQ,SAAS,KAAK;AAAA,MAClD,CAAC;AAAA,IAAA;AAEH,WAAO;AAAA,EACT;AACF;AAcO,SAAS,cAKd,YACA,SACqD;AACrD,QAAM,QAAQ,SAAS,SAAS;AAChC,QAAM,SAAS,SAAS,UAAU;AAElC,SAAO,CACL,WACsD;AACtD,UAAM,UAAU,OAAO;AAAA,MACrB,OAA2C,CAAC,WAAW;AAErD,cAAM,eAAe,IAAI,SAAS,MAAM,EAAE,YAAA;AAC1C,YAAI,IAAI;AACR,cAAM,eAAe,aAClB,SAAA,EACA,KAAK,CAAC,GAAG,MAAM,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EACrC,MAAM,QAAQ,SAAS,KAAK,EAC5B,IAAI,CAAC,CAAC,OAAO,YAAY,MAAkC;AAAA,UAC1D,CAAC,OAAO,GAAG;AAAA,UACX;AAAA,QAAA,CACD;AACH,eAAO;AAAA,MACT,CAAC;AAAA,IAAA;AAEH,WAAO;AAAA,EACT;AACF;"}
@@ -4,6 +4,10 @@ export interface TopKWithFractionalIndexOptions {
4
4
  limit?: number;
5
5
  offset?: number;
6
6
  setSizeCallback?: (getSize: () => number) => void;
7
+ setWindowFn?: (windowFn: (options: {
8
+ offset?: number;
9
+ limit?: number;
10
+ }) => void) => void;
7
11
  }
8
12
  export type TopKChanges<V> = {
9
13
  /** Indicates which element moves into the topK (if any) */
@@ -11,6 +15,14 @@ export type TopKChanges<V> = {
11
15
  /** Indicates which element moves out of the topK (if any) */
12
16
  moveOut: IndexedValue<V> | null;
13
17
  };
18
+ export type TopKMoveChanges<V> = {
19
+ /** Flag that marks whether there were any changes to the topK */
20
+ changes: boolean;
21
+ /** Indicates which elements move into the topK (if any) */
22
+ moveIns: Array<IndexedValue<V>>;
23
+ /** Indicates which elements move out of the topK (if any) */
24
+ moveOuts: Array<IndexedValue<V>>;
25
+ };
14
26
  /**
15
27
  * A topK data structure that supports insertions and deletions
16
28
  * and returns changes to the topK.
@@ -35,8 +47,18 @@ export declare class TopKWithFractionalIndexOperator<K, T> extends UnaryOperator
35
47
  #private;
36
48
  constructor(id: number, inputA: DifferenceStreamReader<[K, T]>, output: DifferenceStreamWriter<[K, IndexedValue<T>]>, comparator: (a: T, b: T) => number, options: TopKWithFractionalIndexOptions);
37
49
  protected createTopK(offset: number, limit: number, comparator: (a: TaggedValue<K, T>, b: TaggedValue<K, T>) => number): TopK<TaggedValue<K, T>>;
50
+ /**
51
+ * Moves the topK window based on the provided offset and limit.
52
+ * Any changes to the topK are sent to the output.
53
+ */
54
+ moveTopK({ offset, limit }: {
55
+ offset?: number;
56
+ limit?: number;
57
+ }): void;
38
58
  run(): void;
39
59
  processElement(key: K, value: T, multiplicity: number, result: Array<[[K, IndexedValue<T>], number]>): void;
60
+ private handleMoveIn;
61
+ private handleMoveOut;
40
62
  private getMultiplicity;
41
63
  private addKey;
42
64
  }
@@ -1,48 +1,68 @@
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 __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
- var _sortedValues, _comparator, _topKStart, _topKEnd, _TopKArray_instances, findIndex_fn, _index, _topK, _limit;
10
1
  import { generateKeyBetween } from "fractional-indexing";
11
2
  import { UnaryOperator, DifferenceStreamWriter } from "../graph.js";
12
3
  import { StreamBuilder } from "../d2.js";
13
4
  import { MultiSet } from "../multiset.js";
14
- import { binarySearch, globalObjectIdGenerator } from "../utils.js";
5
+ import { diffHalfOpen, binarySearch, globalObjectIdGenerator } from "../utils.js";
15
6
  class TopKArray {
7
+ #sortedValues = [];
8
+ #comparator;
9
+ #topKStart;
10
+ #topKEnd;
16
11
  constructor(offset, limit, comparator) {
17
- __privateAdd(this, _TopKArray_instances);
18
- __privateAdd(this, _sortedValues, []);
19
- __privateAdd(this, _comparator);
20
- __privateAdd(this, _topKStart);
21
- __privateAdd(this, _topKEnd);
22
- __privateSet(this, _topKStart, offset);
23
- __privateSet(this, _topKEnd, offset + limit);
24
- __privateSet(this, _comparator, comparator);
12
+ this.#topKStart = offset;
13
+ this.#topKEnd = offset + limit;
14
+ this.#comparator = comparator;
25
15
  }
26
16
  get size() {
27
- const offset = __privateGet(this, _topKStart);
28
- const limit = __privateGet(this, _topKEnd) - __privateGet(this, _topKStart);
29
- const available = __privateGet(this, _sortedValues).length - offset;
17
+ const offset = this.#topKStart;
18
+ const limit = this.#topKEnd - this.#topKStart;
19
+ const available = this.#sortedValues.length - offset;
30
20
  return Math.max(0, Math.min(limit, available));
31
21
  }
22
+ /**
23
+ * Moves the topK window
24
+ */
25
+ move({
26
+ offset,
27
+ limit
28
+ }) {
29
+ const oldOffset = this.#topKStart;
30
+ const oldLimit = this.#topKEnd - this.#topKStart;
31
+ const oldRange = [this.#topKStart, this.#topKEnd];
32
+ this.#topKStart = offset ?? oldOffset;
33
+ this.#topKEnd = this.#topKStart + (limit ?? oldLimit);
34
+ const newRange = [this.#topKStart, this.#topKEnd];
35
+ const { onlyInA, onlyInB } = diffHalfOpen(oldRange, newRange);
36
+ const moveIns = [];
37
+ onlyInB.forEach((index) => {
38
+ const value = this.#sortedValues[index];
39
+ if (value) {
40
+ moveIns.push(value);
41
+ }
42
+ });
43
+ const moveOuts = [];
44
+ onlyInA.forEach((index) => {
45
+ const value = this.#sortedValues[index];
46
+ if (value) {
47
+ moveOuts.push(value);
48
+ }
49
+ });
50
+ return { moveIns, moveOuts, changes: onlyInA.length + onlyInB.length > 0 };
51
+ }
32
52
  insert(value) {
33
53
  const result = { moveIn: null, moveOut: null };
34
- const index = __privateMethod(this, _TopKArray_instances, findIndex_fn).call(this, value);
35
- const indexBefore = index === 0 ? null : getIndex(__privateGet(this, _sortedValues)[index - 1]);
36
- const indexAfter = index === __privateGet(this, _sortedValues).length ? null : getIndex(__privateGet(this, _sortedValues)[index]);
54
+ const index = this.#findIndex(value);
55
+ const indexBefore = index === 0 ? null : getIndex(this.#sortedValues[index - 1]);
56
+ const indexAfter = index === this.#sortedValues.length ? null : getIndex(this.#sortedValues[index]);
37
57
  const fractionalIndex = generateKeyBetween(indexBefore, indexAfter);
38
58
  const val = indexedValue(value, fractionalIndex);
39
- __privateGet(this, _sortedValues).splice(index, 0, val);
40
- if (index < __privateGet(this, _topKEnd)) {
41
- const moveInIndex = Math.max(index, __privateGet(this, _topKStart));
42
- if (moveInIndex < __privateGet(this, _sortedValues).length) {
43
- result.moveIn = __privateGet(this, _sortedValues)[moveInIndex];
44
- if (__privateGet(this, _topKEnd) < __privateGet(this, _sortedValues).length) {
45
- result.moveOut = __privateGet(this, _sortedValues)[__privateGet(this, _topKEnd)];
59
+ this.#sortedValues.splice(index, 0, val);
60
+ if (index < this.#topKEnd) {
61
+ const moveInIndex = Math.max(index, this.#topKStart);
62
+ if (moveInIndex < this.#sortedValues.length) {
63
+ result.moveIn = this.#sortedValues[moveInIndex];
64
+ if (this.#topKEnd < this.#sortedValues.length) {
65
+ result.moveOut = this.#sortedValues[this.#topKEnd];
46
66
  }
47
67
  }
48
68
  }
@@ -56,54 +76,47 @@ class TopKArray {
56
76
  */
57
77
  delete(value) {
58
78
  const result = { moveIn: null, moveOut: null };
59
- const index = __privateMethod(this, _TopKArray_instances, findIndex_fn).call(this, value);
60
- const [removedElem] = __privateGet(this, _sortedValues).splice(index, 1);
61
- if (index < __privateGet(this, _topKEnd)) {
79
+ const index = this.#findIndex(value);
80
+ const [removedElem] = this.#sortedValues.splice(index, 1);
81
+ if (index < this.#topKEnd) {
62
82
  result.moveOut = removedElem;
63
- if (index < __privateGet(this, _topKStart)) {
64
- const moveOutIndex = __privateGet(this, _topKStart) - 1;
65
- if (moveOutIndex < __privateGet(this, _sortedValues).length) {
66
- result.moveOut = __privateGet(this, _sortedValues)[moveOutIndex];
83
+ if (index < this.#topKStart) {
84
+ const moveOutIndex = this.#topKStart - 1;
85
+ if (moveOutIndex < this.#sortedValues.length) {
86
+ result.moveOut = this.#sortedValues[moveOutIndex];
67
87
  } else {
68
88
  result.moveOut = null;
69
89
  }
70
90
  }
71
- const moveInIndex = __privateGet(this, _topKEnd) - 1;
72
- if (moveInIndex < __privateGet(this, _sortedValues).length) {
73
- result.moveIn = __privateGet(this, _sortedValues)[moveInIndex];
91
+ const moveInIndex = this.#topKEnd - 1;
92
+ if (moveInIndex < this.#sortedValues.length) {
93
+ result.moveIn = this.#sortedValues[moveInIndex];
74
94
  }
75
95
  }
76
96
  return result;
77
97
  }
98
+ // TODO: see if there is a way to refactor the code for insert and delete in the topK above
99
+ // because they are very similar, one is shifting the topK window to the left and the other is shifting it to the right
100
+ // so i have the feeling there is a common pattern here and we can implement both cases using that pattern
101
+ #findIndex(value) {
102
+ return binarySearch(
103
+ this.#sortedValues,
104
+ indexedValue(value, ``),
105
+ (a, b) => this.#comparator(getValue(a), getValue(b))
106
+ );
107
+ }
78
108
  }
79
- _sortedValues = new WeakMap();
80
- _comparator = new WeakMap();
81
- _topKStart = new WeakMap();
82
- _topKEnd = new WeakMap();
83
- _TopKArray_instances = new WeakSet();
84
- // TODO: see if there is a way to refactor the code for insert and delete in the topK above
85
- // because they are very similar, one is shifting the topK window to the left and the other is shifting it to the right
86
- // so i have the feeling there is a common pattern here and we can implement both cases using that pattern
87
- findIndex_fn = function(value) {
88
- return binarySearch(
89
- __privateGet(this, _sortedValues),
90
- indexedValue(value, ``),
91
- (a, b) => __privateGet(this, _comparator).call(this, getValue(a), getValue(b))
92
- );
93
- };
94
109
  class TopKWithFractionalIndexOperator extends UnaryOperator {
110
+ #index = /* @__PURE__ */ new Map();
111
+ // maps keys to their multiplicity
112
+ /**
113
+ * topK data structure that supports insertions and deletions
114
+ * and returns changes to the topK.
115
+ */
116
+ #topK;
95
117
  constructor(id, inputA, output, comparator, options) {
96
- var _a;
97
118
  super(id, inputA, output);
98
- __privateAdd(this, _index, /* @__PURE__ */ new Map());
99
- // maps keys to their multiplicity
100
- /**
101
- * topK data structure that supports insertions and deletions
102
- * and returns changes to the topK.
103
- */
104
- __privateAdd(this, _topK);
105
- __privateAdd(this, _limit);
106
- __privateSet(this, _limit, options.limit ?? Infinity);
119
+ const limit = options.limit ?? Infinity;
107
120
  const offset = options.offset ?? 0;
108
121
  const compareTaggedValues = (a, b) => {
109
122
  const valueComparison = comparator(getVal(a), getVal(b));
@@ -114,12 +127,31 @@ class TopKWithFractionalIndexOperator extends UnaryOperator {
114
127
  const tieBreakerB = getTag(b);
115
128
  return tieBreakerA - tieBreakerB;
116
129
  };
117
- __privateSet(this, _topK, this.createTopK(offset, __privateGet(this, _limit), compareTaggedValues));
118
- (_a = options.setSizeCallback) == null ? void 0 : _a.call(options, () => __privateGet(this, _topK).size);
130
+ this.#topK = this.createTopK(offset, limit, compareTaggedValues);
131
+ options.setSizeCallback?.(() => this.#topK.size);
132
+ options.setWindowFn?.(this.moveTopK.bind(this));
119
133
  }
120
134
  createTopK(offset, limit, comparator) {
121
135
  return new TopKArray(offset, limit, comparator);
122
136
  }
137
+ /**
138
+ * Moves the topK window based on the provided offset and limit.
139
+ * Any changes to the topK are sent to the output.
140
+ */
141
+ moveTopK({ offset, limit }) {
142
+ if (!(this.#topK instanceof TopKArray)) {
143
+ throw new Error(
144
+ `Cannot move B+-tree implementation of TopK with fractional index`
145
+ );
146
+ }
147
+ const result = [];
148
+ const diff = this.#topK.move({ offset, limit });
149
+ diff.moveIns.forEach((moveIn) => this.handleMoveIn(moveIn, result));
150
+ diff.moveOuts.forEach((moveOut) => this.handleMoveOut(moveOut, result));
151
+ if (diff.changes) {
152
+ this.output.sendData(new MultiSet(result));
153
+ }
154
+ }
123
155
  run() {
124
156
  const result = [];
125
157
  for (const message of this.inputMessages()) {
@@ -140,44 +172,47 @@ class TopKWithFractionalIndexOperator extends UnaryOperator {
140
172
  };
141
173
  if (oldMultiplicity <= 0 && newMultiplicity > 0) {
142
174
  const taggedValue = tagValue(key, value);
143
- res = __privateGet(this, _topK).insert(taggedValue);
175
+ res = this.#topK.insert(taggedValue);
144
176
  } else if (oldMultiplicity > 0 && newMultiplicity <= 0) {
145
177
  const taggedValue = tagValue(key, value);
146
- res = __privateGet(this, _topK).delete(taggedValue);
178
+ res = this.#topK.delete(taggedValue);
147
179
  } else ;
148
- if (res.moveIn) {
149
- const index = getIndex(res.moveIn);
150
- const taggedValue = getValue(res.moveIn);
180
+ this.handleMoveIn(res.moveIn, result);
181
+ this.handleMoveOut(res.moveOut, result);
182
+ return;
183
+ }
184
+ handleMoveIn(moveIn, result) {
185
+ if (moveIn) {
186
+ const index = getIndex(moveIn);
187
+ const taggedValue = getValue(moveIn);
151
188
  const k = getKey(taggedValue);
152
189
  const val = getVal(taggedValue);
153
190
  result.push([[k, [val, index]], 1]);
154
191
  }
155
- if (res.moveOut) {
156
- const index = getIndex(res.moveOut);
157
- const taggedValue = getValue(res.moveOut);
192
+ }
193
+ handleMoveOut(moveOut, result) {
194
+ if (moveOut) {
195
+ const index = getIndex(moveOut);
196
+ const taggedValue = getValue(moveOut);
158
197
  const k = getKey(taggedValue);
159
198
  const val = getVal(taggedValue);
160
199
  result.push([[k, [val, index]], -1]);
161
200
  }
162
- return;
163
201
  }
164
202
  getMultiplicity(key) {
165
- return __privateGet(this, _index).get(key) ?? 0;
203
+ return this.#index.get(key) ?? 0;
166
204
  }
167
205
  addKey(key, multiplicity) {
168
206
  const oldMultiplicity = this.getMultiplicity(key);
169
207
  const newMultiplicity = oldMultiplicity + multiplicity;
170
208
  if (newMultiplicity === 0) {
171
- __privateGet(this, _index).delete(key);
209
+ this.#index.delete(key);
172
210
  } else {
173
- __privateGet(this, _index).set(key, newMultiplicity);
211
+ this.#index.set(key, newMultiplicity);
174
212
  }
175
213
  return { oldMultiplicity, newMultiplicity };
176
214
  }
177
215
  }
178
- _index = new WeakMap();
179
- _topK = new WeakMap();
180
- _limit = new WeakMap();
181
216
  function topKWithFractionalIndex(comparator, options) {
182
217
  const opts = options || {};
183
218
  return (stream) => {