@tanstack/db-ivm 0.1.9 → 0.1.10

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 (85) 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 +10 -10
  27. package/dist/cjs/operators/orderBy.cjs.map +1 -1
  28. package/dist/cjs/operators/orderBy.d.cts +1 -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 +56 -75
  39. package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -1
  40. package/dist/esm/d2.js +25 -49
  41. package/dist/esm/d2.js.map +1 -1
  42. package/dist/esm/graph.js +8 -20
  43. package/dist/esm/graph.js.map +1 -1
  44. package/dist/esm/indexes.d.ts +23 -0
  45. package/dist/esm/indexes.js +118 -79
  46. package/dist/esm/indexes.js.map +1 -1
  47. package/dist/esm/multiset.d.ts +1 -0
  48. package/dist/esm/multiset.js +106 -115
  49. package/dist/esm/multiset.js.map +1 -1
  50. package/dist/esm/operators/debug.js +5 -15
  51. package/dist/esm/operators/debug.js.map +1 -1
  52. package/dist/esm/operators/distinct.js +11 -22
  53. package/dist/esm/operators/distinct.js.map +1 -1
  54. package/dist/esm/operators/filter.js +3 -12
  55. package/dist/esm/operators/filter.js.map +1 -1
  56. package/dist/esm/operators/filterBy.d.ts +1 -2
  57. package/dist/esm/operators/filterBy.js.map +1 -1
  58. package/dist/esm/operators/groupBy.js +1 -2
  59. package/dist/esm/operators/groupBy.js.map +1 -1
  60. package/dist/esm/operators/join.d.ts +11 -8
  61. package/dist/esm/operators/join.js +104 -93
  62. package/dist/esm/operators/join.js.map +1 -1
  63. package/dist/esm/operators/map.js +3 -12
  64. package/dist/esm/operators/map.js.map +1 -1
  65. package/dist/esm/operators/orderBy.d.ts +1 -2
  66. package/dist/esm/operators/orderBy.js +10 -10
  67. package/dist/esm/operators/orderBy.js.map +1 -1
  68. package/dist/esm/operators/output.js +3 -12
  69. package/dist/esm/operators/output.js.map +1 -1
  70. package/dist/esm/operators/reduce.js +11 -22
  71. package/dist/esm/operators/reduce.js.map +1 -1
  72. package/dist/esm/operators/tap.js +3 -12
  73. package/dist/esm/operators/tap.js.map +1 -1
  74. package/dist/esm/operators/topK.d.ts +1 -2
  75. package/dist/esm/operators/topK.js +4 -4
  76. package/dist/esm/operators/topK.js.map +1 -1
  77. package/dist/esm/operators/topKWithFractionalIndex.js +56 -75
  78. package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -1
  79. package/package.json +1 -1
  80. package/src/indexes.ts +54 -0
  81. package/src/multiset.ts +6 -0
  82. package/src/operators/filterBy.ts +1 -2
  83. package/src/operators/join.ts +249 -139
  84. package/src/operators/orderBy.ts +1 -2
  85. package/src/operators/topK.ts +1 -2
@@ -1,49 +1,39 @@
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 _inner, _MultiSet_instances, consolidateKeyed_fn, consolidateUnkeyed_fn;
10
1
  import { chunkedArrayPush, globalObjectIdGenerator, DefaultMap } from "./utils.js";
11
2
  import { hash } from "./hashing/hash.js";
12
- const _MultiSet = class _MultiSet {
3
+ class MultiSet {
4
+ #inner;
13
5
  constructor(data = []) {
14
- __privateAdd(this, _MultiSet_instances);
15
- __privateAdd(this, _inner);
16
- __privateSet(this, _inner, data);
6
+ this.#inner = data;
17
7
  }
18
8
  toString(indent = false) {
19
- return `MultiSet(${JSON.stringify(__privateGet(this, _inner), null, indent ? 2 : void 0)})`;
9
+ return `MultiSet(${JSON.stringify(this.#inner, null, indent ? 2 : void 0)})`;
20
10
  }
21
11
  toJSON() {
22
12
  return JSON.stringify(Array.from(this.getInner()));
23
13
  }
24
14
  static fromJSON(json) {
25
- return new _MultiSet(JSON.parse(json));
15
+ return new MultiSet(JSON.parse(json));
26
16
  }
27
17
  /**
28
18
  * Apply a function to all records in the collection.
29
19
  */
30
20
  map(f) {
31
- return new _MultiSet(
32
- __privateGet(this, _inner).map(([data, multiplicity]) => [f(data), multiplicity])
21
+ return new MultiSet(
22
+ this.#inner.map(([data, multiplicity]) => [f(data), multiplicity])
33
23
  );
34
24
  }
35
25
  /**
36
26
  * Filter out records for which a function f(record) evaluates to False.
37
27
  */
38
28
  filter(f) {
39
- return new _MultiSet(__privateGet(this, _inner).filter(([data, _]) => f(data)));
29
+ return new MultiSet(this.#inner.filter(([data, _]) => f(data)));
40
30
  }
41
31
  /**
42
32
  * Negate all multiplicities in the collection.
43
33
  */
44
34
  negate() {
45
- return new _MultiSet(
46
- __privateGet(this, _inner).map(([data, multiplicity]) => [data, -multiplicity])
35
+ return new MultiSet(
36
+ this.#inner.map(([data, multiplicity]) => [data, -multiplicity])
47
37
  );
48
38
  }
49
39
  /**
@@ -51,9 +41,9 @@ const _MultiSet = class _MultiSet {
51
41
  */
52
42
  concat(other) {
53
43
  const out = [];
54
- chunkedArrayPush(out, __privateGet(this, _inner));
44
+ chunkedArrayPush(out, this.#inner);
55
45
  chunkedArrayPush(out, other.getInner());
56
- return new _MultiSet(out);
46
+ return new MultiSet(out);
57
47
  }
58
48
  /**
59
49
  * Produce as output a collection that is logically equivalent to the input
@@ -61,113 +51,114 @@ const _MultiSet = class _MultiSet {
61
51
  * (record, multiplicity) pair.
62
52
  */
63
53
  consolidate() {
64
- var _a;
65
- if (__privateGet(this, _inner).length > 0) {
66
- const firstItem = (_a = __privateGet(this, _inner)[0]) == null ? void 0 : _a[0];
54
+ if (this.#inner.length > 0) {
55
+ const firstItem = this.#inner[0]?.[0];
67
56
  if (Array.isArray(firstItem) && firstItem.length === 2) {
68
- return __privateMethod(this, _MultiSet_instances, consolidateKeyed_fn).call(this);
57
+ return this.#consolidateKeyed();
69
58
  }
70
59
  }
71
- return __privateMethod(this, _MultiSet_instances, consolidateUnkeyed_fn).call(this);
72
- }
73
- extend(other) {
74
- const otherArray = other instanceof _MultiSet ? other.getInner() : other;
75
- chunkedArrayPush(__privateGet(this, _inner), otherArray);
76
- }
77
- getInner() {
78
- return __privateGet(this, _inner);
60
+ return this.#consolidateUnkeyed();
79
61
  }
80
- };
81
- _inner = new WeakMap();
82
- _MultiSet_instances = new WeakSet();
83
- /**
84
- * Private method for consolidating keyed multisets where keys are strings/numbers
85
- * and values are compared by reference equality.
86
- *
87
- * This method provides significant performance improvements over the hash-based approach
88
- * by using WeakMap for object reference tracking and avoiding expensive serialization.
89
- *
90
- * Special handling for join operations: When values are tuples of length 2 (common in joins),
91
- * we unpack them and compare each element individually to maintain proper equality semantics.
92
- */
93
- consolidateKeyed_fn = function() {
94
- const consolidated = /* @__PURE__ */ new Map();
95
- const values = /* @__PURE__ */ new Map();
96
- const getTupleId = (tuple) => {
97
- if (tuple.length !== 2) {
98
- throw new Error(`Expected tuple of length 2`);
99
- }
100
- const [first, second] = tuple;
101
- return `${globalObjectIdGenerator.getStringId(first)}|${globalObjectIdGenerator.getStringId(second)}`;
102
- };
103
- for (const [data, multiplicity] of __privateGet(this, _inner)) {
104
- if (!Array.isArray(data) || data.length !== 2) {
105
- return __privateMethod(this, _MultiSet_instances, consolidateUnkeyed_fn).call(this);
106
- }
107
- const [key, value] = data;
108
- if (typeof key !== `string` && typeof key !== `number`) {
109
- return __privateMethod(this, _MultiSet_instances, consolidateUnkeyed_fn).call(this);
110
- }
111
- let valueId;
112
- if (Array.isArray(value) && value.length === 2) {
113
- valueId = getTupleId(value);
114
- } else {
115
- valueId = globalObjectIdGenerator.getStringId(value);
62
+ /**
63
+ * Private method for consolidating keyed multisets where keys are strings/numbers
64
+ * and values are compared by reference equality.
65
+ *
66
+ * This method provides significant performance improvements over the hash-based approach
67
+ * by using WeakMap for object reference tracking and avoiding expensive serialization.
68
+ *
69
+ * Special handling for join operations: When values are tuples of length 2 (common in joins),
70
+ * we unpack them and compare each element individually to maintain proper equality semantics.
71
+ */
72
+ #consolidateKeyed() {
73
+ const consolidated = /* @__PURE__ */ new Map();
74
+ const values = /* @__PURE__ */ new Map();
75
+ const getTupleId = (tuple) => {
76
+ if (tuple.length !== 2) {
77
+ throw new Error(`Expected tuple of length 2`);
78
+ }
79
+ const [first, second] = tuple;
80
+ return `${globalObjectIdGenerator.getStringId(first)}|${globalObjectIdGenerator.getStringId(second)}`;
81
+ };
82
+ for (const [data, multiplicity] of this.#inner) {
83
+ if (!Array.isArray(data) || data.length !== 2) {
84
+ return this.#consolidateUnkeyed();
85
+ }
86
+ const [key, value] = data;
87
+ if (typeof key !== `string` && typeof key !== `number`) {
88
+ return this.#consolidateUnkeyed();
89
+ }
90
+ let valueId;
91
+ if (Array.isArray(value) && value.length === 2) {
92
+ valueId = getTupleId(value);
93
+ } else {
94
+ valueId = globalObjectIdGenerator.getStringId(value);
95
+ }
96
+ const compositeKey = key + `|` + valueId;
97
+ consolidated.set(
98
+ compositeKey,
99
+ (consolidated.get(compositeKey) || 0) + multiplicity
100
+ );
101
+ if (!values.has(compositeKey)) {
102
+ values.set(compositeKey, data);
103
+ }
116
104
  }
117
- const compositeKey = key + `|` + valueId;
118
- consolidated.set(
119
- compositeKey,
120
- (consolidated.get(compositeKey) || 0) + multiplicity
121
- );
122
- if (!values.has(compositeKey)) {
123
- values.set(compositeKey, data);
105
+ const result = [];
106
+ for (const [compositeKey, multiplicity] of consolidated) {
107
+ if (multiplicity !== 0) {
108
+ result.push([values.get(compositeKey), multiplicity]);
109
+ }
124
110
  }
111
+ return new MultiSet(result);
125
112
  }
126
- const result = [];
127
- for (const [compositeKey, multiplicity] of consolidated) {
128
- if (multiplicity !== 0) {
129
- result.push([values.get(compositeKey), multiplicity]);
113
+ /**
114
+ * Private method for consolidating unkeyed multisets using the original approach.
115
+ */
116
+ #consolidateUnkeyed() {
117
+ const consolidated = new DefaultMap(() => 0);
118
+ const values = /* @__PURE__ */ new Map();
119
+ let hasString = false;
120
+ let hasNumber = false;
121
+ let hasOther = false;
122
+ for (const [data, _] of this.#inner) {
123
+ if (typeof data === `string`) {
124
+ hasString = true;
125
+ } else if (typeof data === `number`) {
126
+ hasNumber = true;
127
+ } else {
128
+ hasOther = true;
129
+ break;
130
+ }
130
131
  }
131
- }
132
- return new _MultiSet(result);
133
- };
134
- /**
135
- * Private method for consolidating unkeyed multisets using the original approach.
136
- */
137
- consolidateUnkeyed_fn = function() {
138
- const consolidated = new DefaultMap(() => 0);
139
- const values = /* @__PURE__ */ new Map();
140
- let hasString = false;
141
- let hasNumber = false;
142
- let hasOther = false;
143
- for (const [data, _] of __privateGet(this, _inner)) {
144
- if (typeof data === `string`) {
145
- hasString = true;
146
- } else if (typeof data === `number`) {
147
- hasNumber = true;
148
- } else {
149
- hasOther = true;
150
- break;
132
+ const requireJson = hasOther || hasString && hasNumber;
133
+ for (const [data, multiplicity] of this.#inner) {
134
+ const key = requireJson ? hash(data) : data;
135
+ if (requireJson && !values.has(key)) {
136
+ values.set(key, data);
137
+ }
138
+ consolidated.update(key, (count) => count + multiplicity);
151
139
  }
152
- }
153
- const requireJson = hasOther || hasString && hasNumber;
154
- for (const [data, multiplicity] of __privateGet(this, _inner)) {
155
- const key = requireJson ? hash(data) : data;
156
- if (requireJson && !values.has(key)) {
157
- values.set(key, data);
140
+ const result = [];
141
+ for (const [key, multiplicity] of consolidated.entries()) {
142
+ if (multiplicity !== 0) {
143
+ const parsedKey = requireJson ? values.get(key) : key;
144
+ result.push([parsedKey, multiplicity]);
145
+ }
158
146
  }
159
- consolidated.update(key, (count) => count + multiplicity);
147
+ return new MultiSet(result);
148
+ }
149
+ extend(other) {
150
+ const otherArray = other instanceof MultiSet ? other.getInner() : other;
151
+ chunkedArrayPush(this.#inner, otherArray);
160
152
  }
161
- const result = [];
162
- for (const [key, multiplicity] of consolidated.entries()) {
153
+ add(item, multiplicity) {
163
154
  if (multiplicity !== 0) {
164
- const parsedKey = requireJson ? values.get(key) : key;
165
- result.push([parsedKey, multiplicity]);
155
+ this.#inner.push([item, multiplicity]);
166
156
  }
167
157
  }
168
- return new _MultiSet(result);
169
- };
170
- let MultiSet = _MultiSet;
158
+ getInner() {
159
+ return this.#inner;
160
+ }
161
+ }
171
162
  export {
172
163
  MultiSet
173
164
  };
@@ -1 +1 @@
1
- {"version":3,"file":"multiset.js","sources":["../../src/multiset.ts"],"sourcesContent":["import {\n DefaultMap,\n chunkedArrayPush,\n globalObjectIdGenerator,\n} from \"./utils.js\"\nimport { hash } from \"./hashing/index.js\"\n\nexport type MultiSetArray<T> = Array<[T, number]>\nexport type KeyedData<T> = [key: string, value: T]\n\n/**\n * A multiset of data.\n */\nexport class MultiSet<T> {\n #inner: MultiSetArray<T>\n\n constructor(data: MultiSetArray<T> = []) {\n this.#inner = data\n }\n\n toString(indent = false): string {\n return `MultiSet(${JSON.stringify(this.#inner, null, indent ? 2 : undefined)})`\n }\n\n toJSON(): string {\n return JSON.stringify(Array.from(this.getInner()))\n }\n\n static fromJSON<U>(json: string): MultiSet<U> {\n return new MultiSet(JSON.parse(json))\n }\n\n /**\n * Apply a function to all records in the collection.\n */\n map<U>(f: (data: T) => U): MultiSet<U> {\n return new MultiSet(\n this.#inner.map(([data, multiplicity]) => [f(data), multiplicity])\n )\n }\n\n /**\n * Filter out records for which a function f(record) evaluates to False.\n */\n filter(f: (data: T) => boolean): MultiSet<T> {\n return new MultiSet(this.#inner.filter(([data, _]) => f(data)))\n }\n\n /**\n * Negate all multiplicities in the collection.\n */\n negate(): MultiSet<T> {\n return new MultiSet(\n this.#inner.map(([data, multiplicity]) => [data, -multiplicity])\n )\n }\n\n /**\n * Concatenate two collections together.\n */\n concat(other: MultiSet<T>): MultiSet<T> {\n const out: MultiSetArray<T> = []\n chunkedArrayPush(out, this.#inner)\n chunkedArrayPush(out, other.getInner())\n return new MultiSet(out)\n }\n\n /**\n * Produce as output a collection that is logically equivalent to the input\n * but which combines identical instances of the same record into one\n * (record, multiplicity) pair.\n */\n consolidate(): MultiSet<T> {\n // Check if this looks like a keyed multiset (first item is a tuple of length 2)\n if (this.#inner.length > 0) {\n const firstItem = this.#inner[0]?.[0]\n if (Array.isArray(firstItem) && firstItem.length === 2) {\n return this.#consolidateKeyed()\n }\n }\n\n // Fall back to original method for unkeyed data\n return this.#consolidateUnkeyed()\n }\n\n /**\n * Private method for consolidating keyed multisets where keys are strings/numbers\n * and values are compared by reference equality.\n *\n * This method provides significant performance improvements over the hash-based approach\n * by using WeakMap for object reference tracking and avoiding expensive serialization.\n *\n * Special handling for join operations: When values are tuples of length 2 (common in joins),\n * we unpack them and compare each element individually to maintain proper equality semantics.\n */\n #consolidateKeyed(): MultiSet<T> {\n const consolidated = new Map<string, number>()\n const values = new Map<string, T>()\n\n // Use global object ID generator for consistent reference equality\n\n /**\n * Special handler for tuples (arrays of length 2) commonly produced by join operations.\n * Unpacks the tuple and generates an ID based on both elements to ensure proper\n * consolidation of join results like ['A', null] and [null, 'X'].\n */\n const getTupleId = (tuple: Array<any>): string => {\n if (tuple.length !== 2) {\n throw new Error(`Expected tuple of length 2`)\n }\n const [first, second] = tuple\n return `${globalObjectIdGenerator.getStringId(first)}|${globalObjectIdGenerator.getStringId(second)}`\n }\n\n // Process each item in the multiset\n for (const [data, multiplicity] of this.#inner) {\n // Verify this is still a keyed item (should be [key, value] pair)\n if (!Array.isArray(data) || data.length !== 2) {\n // Found non-keyed item, fall back to unkeyed consolidation\n return this.#consolidateUnkeyed()\n }\n\n const [key, value] = data\n\n // Verify key is string or number as expected for keyed multisets\n if (typeof key !== `string` && typeof key !== `number`) {\n // Found non-string/number key, fall back to unkeyed consolidation\n return this.#consolidateUnkeyed()\n }\n\n // Generate value ID with special handling for join tuples\n let valueId: string\n if (Array.isArray(value) && value.length === 2) {\n // Special case: value is a tuple from join operations\n valueId = getTupleId(value)\n } else {\n // Regular case: use reference/value equality\n valueId = globalObjectIdGenerator.getStringId(value)\n }\n\n // Create composite key and consolidate\n const compositeKey = key + `|` + valueId\n consolidated.set(\n compositeKey,\n (consolidated.get(compositeKey) || 0) + multiplicity\n )\n\n // Store the original data for the first occurrence\n if (!values.has(compositeKey)) {\n values.set(compositeKey, data as T)\n }\n }\n\n // Build result array, filtering out zero multiplicities\n const result: MultiSetArray<T> = []\n for (const [compositeKey, multiplicity] of consolidated) {\n if (multiplicity !== 0) {\n result.push([values.get(compositeKey)!, multiplicity])\n }\n }\n\n return new MultiSet(result)\n }\n\n /**\n * Private method for consolidating unkeyed multisets using the original approach.\n */\n #consolidateUnkeyed(): MultiSet<T> {\n const consolidated = new DefaultMap<string | number, number>(() => 0)\n const values = new Map<string, any>()\n\n let hasString = false\n let hasNumber = false\n let hasOther = false\n for (const [data, _] of this.#inner) {\n if (typeof data === `string`) {\n hasString = true\n } else if (typeof data === `number`) {\n hasNumber = true\n } else {\n hasOther = true\n break\n }\n }\n\n const requireJson = hasOther || (hasString && hasNumber)\n\n for (const [data, multiplicity] of this.#inner) {\n const key = requireJson ? hash(data) : (data as string | number)\n if (requireJson && !values.has(key as string)) {\n values.set(key as string, data)\n }\n consolidated.update(key, (count) => count + multiplicity)\n }\n\n const result: MultiSetArray<T> = []\n for (const [key, multiplicity] of consolidated.entries()) {\n if (multiplicity !== 0) {\n const parsedKey = requireJson ? values.get(key as string) : key\n result.push([parsedKey as T, multiplicity])\n }\n }\n\n return new MultiSet(result)\n }\n\n extend(other: MultiSet<T> | MultiSetArray<T>): void {\n const otherArray = other instanceof MultiSet ? other.getInner() : other\n chunkedArrayPush(this.#inner, otherArray)\n }\n\n getInner(): MultiSetArray<T> {\n return this.#inner\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"multiset.js","sources":["../../src/multiset.ts"],"sourcesContent":["import {\n DefaultMap,\n chunkedArrayPush,\n globalObjectIdGenerator,\n} from \"./utils.js\"\nimport { hash } from \"./hashing/index.js\"\n\nexport type MultiSetArray<T> = Array<[T, number]>\nexport type KeyedData<T> = [key: string, value: T]\n\n/**\n * A multiset of data.\n */\nexport class MultiSet<T> {\n #inner: MultiSetArray<T>\n\n constructor(data: MultiSetArray<T> = []) {\n this.#inner = data\n }\n\n toString(indent = false): string {\n return `MultiSet(${JSON.stringify(this.#inner, null, indent ? 2 : undefined)})`\n }\n\n toJSON(): string {\n return JSON.stringify(Array.from(this.getInner()))\n }\n\n static fromJSON<U>(json: string): MultiSet<U> {\n return new MultiSet(JSON.parse(json))\n }\n\n /**\n * Apply a function to all records in the collection.\n */\n map<U>(f: (data: T) => U): MultiSet<U> {\n return new MultiSet(\n this.#inner.map(([data, multiplicity]) => [f(data), multiplicity])\n )\n }\n\n /**\n * Filter out records for which a function f(record) evaluates to False.\n */\n filter(f: (data: T) => boolean): MultiSet<T> {\n return new MultiSet(this.#inner.filter(([data, _]) => f(data)))\n }\n\n /**\n * Negate all multiplicities in the collection.\n */\n negate(): MultiSet<T> {\n return new MultiSet(\n this.#inner.map(([data, multiplicity]) => [data, -multiplicity])\n )\n }\n\n /**\n * Concatenate two collections together.\n */\n concat(other: MultiSet<T>): MultiSet<T> {\n const out: MultiSetArray<T> = []\n chunkedArrayPush(out, this.#inner)\n chunkedArrayPush(out, other.getInner())\n return new MultiSet(out)\n }\n\n /**\n * Produce as output a collection that is logically equivalent to the input\n * but which combines identical instances of the same record into one\n * (record, multiplicity) pair.\n */\n consolidate(): MultiSet<T> {\n // Check if this looks like a keyed multiset (first item is a tuple of length 2)\n if (this.#inner.length > 0) {\n const firstItem = this.#inner[0]?.[0]\n if (Array.isArray(firstItem) && firstItem.length === 2) {\n return this.#consolidateKeyed()\n }\n }\n\n // Fall back to original method for unkeyed data\n return this.#consolidateUnkeyed()\n }\n\n /**\n * Private method for consolidating keyed multisets where keys are strings/numbers\n * and values are compared by reference equality.\n *\n * This method provides significant performance improvements over the hash-based approach\n * by using WeakMap for object reference tracking and avoiding expensive serialization.\n *\n * Special handling for join operations: When values are tuples of length 2 (common in joins),\n * we unpack them and compare each element individually to maintain proper equality semantics.\n */\n #consolidateKeyed(): MultiSet<T> {\n const consolidated = new Map<string, number>()\n const values = new Map<string, T>()\n\n // Use global object ID generator for consistent reference equality\n\n /**\n * Special handler for tuples (arrays of length 2) commonly produced by join operations.\n * Unpacks the tuple and generates an ID based on both elements to ensure proper\n * consolidation of join results like ['A', null] and [null, 'X'].\n */\n const getTupleId = (tuple: Array<any>): string => {\n if (tuple.length !== 2) {\n throw new Error(`Expected tuple of length 2`)\n }\n const [first, second] = tuple\n return `${globalObjectIdGenerator.getStringId(first)}|${globalObjectIdGenerator.getStringId(second)}`\n }\n\n // Process each item in the multiset\n for (const [data, multiplicity] of this.#inner) {\n // Verify this is still a keyed item (should be [key, value] pair)\n if (!Array.isArray(data) || data.length !== 2) {\n // Found non-keyed item, fall back to unkeyed consolidation\n return this.#consolidateUnkeyed()\n }\n\n const [key, value] = data\n\n // Verify key is string or number as expected for keyed multisets\n if (typeof key !== `string` && typeof key !== `number`) {\n // Found non-string/number key, fall back to unkeyed consolidation\n return this.#consolidateUnkeyed()\n }\n\n // Generate value ID with special handling for join tuples\n let valueId: string\n if (Array.isArray(value) && value.length === 2) {\n // Special case: value is a tuple from join operations\n valueId = getTupleId(value)\n } else {\n // Regular case: use reference/value equality\n valueId = globalObjectIdGenerator.getStringId(value)\n }\n\n // Create composite key and consolidate\n const compositeKey = key + `|` + valueId\n consolidated.set(\n compositeKey,\n (consolidated.get(compositeKey) || 0) + multiplicity\n )\n\n // Store the original data for the first occurrence\n if (!values.has(compositeKey)) {\n values.set(compositeKey, data as T)\n }\n }\n\n // Build result array, filtering out zero multiplicities\n const result: MultiSetArray<T> = []\n for (const [compositeKey, multiplicity] of consolidated) {\n if (multiplicity !== 0) {\n result.push([values.get(compositeKey)!, multiplicity])\n }\n }\n\n return new MultiSet(result)\n }\n\n /**\n * Private method for consolidating unkeyed multisets using the original approach.\n */\n #consolidateUnkeyed(): MultiSet<T> {\n const consolidated = new DefaultMap<string | number, number>(() => 0)\n const values = new Map<string, any>()\n\n let hasString = false\n let hasNumber = false\n let hasOther = false\n for (const [data, _] of this.#inner) {\n if (typeof data === `string`) {\n hasString = true\n } else if (typeof data === `number`) {\n hasNumber = true\n } else {\n hasOther = true\n break\n }\n }\n\n const requireJson = hasOther || (hasString && hasNumber)\n\n for (const [data, multiplicity] of this.#inner) {\n const key = requireJson ? hash(data) : (data as string | number)\n if (requireJson && !values.has(key as string)) {\n values.set(key as string, data)\n }\n consolidated.update(key, (count) => count + multiplicity)\n }\n\n const result: MultiSetArray<T> = []\n for (const [key, multiplicity] of consolidated.entries()) {\n if (multiplicity !== 0) {\n const parsedKey = requireJson ? values.get(key as string) : key\n result.push([parsedKey as T, multiplicity])\n }\n }\n\n return new MultiSet(result)\n }\n\n extend(other: MultiSet<T> | MultiSetArray<T>): void {\n const otherArray = other instanceof MultiSet ? other.getInner() : other\n chunkedArrayPush(this.#inner, otherArray)\n }\n\n add(item: T, multiplicity: number): void {\n if (multiplicity !== 0) {\n this.#inner.push([item, multiplicity])\n }\n }\n\n getInner(): MultiSetArray<T> {\n return this.#inner\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,30 +1,20 @@
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 _name, _indent;
9
1
  import { UnaryOperator, DifferenceStreamWriter } from "../graph.js";
10
2
  import { StreamBuilder } from "../d2.js";
11
3
  class DebugOperator extends UnaryOperator {
4
+ #name;
5
+ #indent;
12
6
  constructor(id, inputA, output, name, indent = false) {
13
7
  super(id, inputA, output);
14
- __privateAdd(this, _name);
15
- __privateAdd(this, _indent);
16
- __privateSet(this, _name, name);
17
- __privateSet(this, _indent, indent);
8
+ this.#name = name;
9
+ this.#indent = indent;
18
10
  }
19
11
  run() {
20
12
  for (const message of this.inputMessages()) {
21
- console.log(`debug ${__privateGet(this, _name)} data: ${message.toString(__privateGet(this, _indent))}`);
13
+ console.log(`debug ${this.#name} data: ${message.toString(this.#indent)}`);
22
14
  this.output.sendData(message);
23
15
  }
24
16
  }
25
17
  }
26
- _name = new WeakMap();
27
- _indent = new WeakMap();
28
18
  function debug(name, indent = false) {
29
19
  return (stream) => {
30
20
  const output = new StreamBuilder(
@@ -1 +1 @@
1
- {"version":3,"file":"debug.js","sources":["../../../src/operators/debug.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\"\n\n/**\n * Operator that logs debug information about the stream\n */\nexport class DebugOperator<T> extends UnaryOperator<T> {\n #name: string\n #indent: boolean\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<T>,\n name: string,\n indent: boolean = false\n ) {\n super(id, inputA, output)\n this.#name = name\n this.#indent = indent\n }\n\n run(): void {\n for (const message of this.inputMessages()) {\n console.log(`debug ${this.#name} data: ${message.toString(this.#indent)}`)\n this.output.sendData(message)\n }\n }\n}\n\n/**\n * Logs debug information about the stream using console.log\n * @param name - The name to prefix debug messages with\n * @param indent - Whether to indent the debug output\n */\nexport function debug<T>(\n name: string,\n indent: boolean = false\n): 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 DebugOperator<T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n name,\n indent\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;AAQO,MAAM,sBAAyB,cAAiB;AAAA,EAIrD,YACE,IACA,QACA,QACA,MACA,SAAkB,OAClB;AACA,UAAM,IAAI,QAAQ,MAAM;AAV1B;AACA;AAUE,uBAAK,OAAQ;AACb,uBAAK,SAAU;AAAA,EACjB;AAAA,EAEA,MAAY;AACV,eAAW,WAAW,KAAK,iBAAiB;AAC1C,cAAQ,IAAI,SAAS,mBAAK,MAAK,UAAU,QAAQ,SAAS,mBAAK,QAAO,CAAC,EAAE;AACzE,WAAK,OAAO,SAAS,OAAO;AAAA,IAC9B;AAAA,EACF;AACF;AArBE;AACA;AA2BK,SAAS,MACd,MACA,SAAkB,OACG;AACrB,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,MACA;AAAA,IAAA;AAEF,WAAO,MAAM,YAAY,QAAQ;AACjC,WAAO;AAAA,EACT;AACF;"}
1
+ {"version":3,"file":"debug.js","sources":["../../../src/operators/debug.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\"\n\n/**\n * Operator that logs debug information about the stream\n */\nexport class DebugOperator<T> extends UnaryOperator<T> {\n #name: string\n #indent: boolean\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<T>,\n name: string,\n indent: boolean = false\n ) {\n super(id, inputA, output)\n this.#name = name\n this.#indent = indent\n }\n\n run(): void {\n for (const message of this.inputMessages()) {\n console.log(`debug ${this.#name} data: ${message.toString(this.#indent)}`)\n this.output.sendData(message)\n }\n }\n}\n\n/**\n * Logs debug information about the stream using console.log\n * @param name - The name to prefix debug messages with\n * @param indent - Whether to indent the debug output\n */\nexport function debug<T>(\n name: string,\n indent: boolean = false\n): 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 DebugOperator<T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n name,\n indent\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n"],"names":[],"mappings":";;AAQO,MAAM,sBAAyB,cAAiB;AAAA,EACrD;AAAA,EACA;AAAA,EAEA,YACE,IACA,QACA,QACA,MACA,SAAkB,OAClB;AACA,UAAM,IAAI,QAAQ,MAAM;AACxB,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAY;AACV,eAAW,WAAW,KAAK,iBAAiB;AAC1C,cAAQ,IAAI,SAAS,KAAK,KAAK,UAAU,QAAQ,SAAS,KAAK,OAAO,CAAC,EAAE;AACzE,WAAK,OAAO,SAAS,OAAO;AAAA,IAC9B;AAAA,EACF;AACF;AAOO,SAAS,MACd,MACA,SAAkB,OACG;AACrB,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,MACA;AAAA,IAAA;AAEF,WAAO,MAAM,YAAY,QAAQ;AACjC,WAAO;AAAA,EACT;AACF;"}
@@ -1,31 +1,22 @@
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 _by, _values;
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 { hash } from "../hashing/hash.js";
13
5
  class DistinctOperator extends UnaryOperator {
6
+ #by;
7
+ #values;
14
8
  // keeps track of the number of times each value has been seen
15
9
  constructor(id, input, output, by = (value) => value) {
16
10
  super(id, input, output);
17
- __privateAdd(this, _by);
18
- __privateAdd(this, _values);
19
- __privateSet(this, _by, by);
20
- __privateSet(this, _values, /* @__PURE__ */ new Map());
11
+ this.#by = by;
12
+ this.#values = /* @__PURE__ */ new Map();
21
13
  }
22
14
  run() {
23
- var _a;
24
15
  const updatedValues = /* @__PURE__ */ new Map();
25
16
  for (const message of this.inputMessages()) {
26
17
  for (const [value, diff] of message.getInner()) {
27
- const hashedValue = hash(__privateGet(this, _by).call(this, value));
28
- const oldMultiplicity = ((_a = updatedValues.get(hashedValue)) == null ? void 0 : _a[0]) ?? __privateGet(this, _values).get(hashedValue) ?? 0;
18
+ const hashedValue = hash(this.#by(value));
19
+ const oldMultiplicity = updatedValues.get(hashedValue)?.[0] ?? this.#values.get(hashedValue) ?? 0;
29
20
  const newMultiplicity = oldMultiplicity + diff;
30
21
  updatedValues.set(hashedValue, [newMultiplicity, value]);
31
22
  }
@@ -35,16 +26,16 @@ class DistinctOperator extends UnaryOperator {
35
26
  hashedValue,
36
27
  [newMultiplicity, value]
37
28
  ] of updatedValues.entries()) {
38
- const oldMultiplicity = __privateGet(this, _values).get(hashedValue) ?? 0;
29
+ const oldMultiplicity = this.#values.get(hashedValue) ?? 0;
39
30
  if (newMultiplicity === 0) {
40
- __privateGet(this, _values).delete(hashedValue);
31
+ this.#values.delete(hashedValue);
41
32
  } else {
42
- __privateGet(this, _values).set(hashedValue, newMultiplicity);
33
+ this.#values.set(hashedValue, newMultiplicity);
43
34
  }
44
35
  if (oldMultiplicity <= 0 && newMultiplicity > 0) {
45
- result.push([[hash(__privateGet(this, _by).call(this, value)), value[1]], 1]);
36
+ result.push([[hash(this.#by(value)), value[1]], 1]);
46
37
  } else if (oldMultiplicity > 0 && newMultiplicity <= 0) {
47
- result.push([[hash(__privateGet(this, _by).call(this, value)), value[1]], -1]);
38
+ result.push([[hash(this.#by(value)), value[1]], -1]);
48
39
  }
49
40
  }
50
41
  if (result.length > 0) {
@@ -52,8 +43,6 @@ class DistinctOperator extends UnaryOperator {
52
43
  }
53
44
  }
54
45
  }
55
- _by = new WeakMap();
56
- _values = new WeakMap();
57
46
  function distinct(by = (value) => value) {
58
47
  return (stream) => {
59
48
  const output = new StreamBuilder(
@@ -1 +1 @@
1
- {"version":3,"file":"distinct.js","sources":["../../../src/operators/distinct.ts"],"sourcesContent":["import { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport { hash } from \"../hashing/index.js\"\nimport { MultiSet } from \"../multiset.js\"\nimport type { Hash } from \"../hashing/index.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { IStreamBuilder, KeyValue } from \"../types.js\"\n\ntype Multiplicity = number\n\ntype GetValue<T> = T extends KeyValue<any, infer V> ? V : never\n\n/**\n * Operator that removes duplicates\n */\nexport class DistinctOperator<\n T extends KeyValue<any, any>,\n> extends UnaryOperator<T, KeyValue<number, GetValue<T>>> {\n #by: (value: T) => any\n #values: Map<Hash, Multiplicity> // keeps track of the number of times each value has been seen\n\n constructor(\n id: number,\n input: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<KeyValue<number, GetValue<T>>>,\n by: (value: T) => any = (value: T) => value\n ) {\n super(id, input, output)\n this.#by = by\n this.#values = new Map()\n }\n\n run(): void {\n const updatedValues = new Map<Hash, [Multiplicity, T]>()\n\n // Compute the new multiplicity for each value\n for (const message of this.inputMessages()) {\n for (const [value, diff] of message.getInner()) {\n const hashedValue = hash(this.#by(value))\n\n const oldMultiplicity =\n updatedValues.get(hashedValue)?.[0] ??\n this.#values.get(hashedValue) ??\n 0\n const newMultiplicity = oldMultiplicity + diff\n updatedValues.set(hashedValue, [newMultiplicity, value])\n }\n }\n\n const result: Array<[KeyValue<number, GetValue<T>>, number]> = []\n\n // Check which values became visible or disappeared\n for (const [\n hashedValue,\n [newMultiplicity, value],\n ] of updatedValues.entries()) {\n const oldMultiplicity = this.#values.get(hashedValue) ?? 0\n\n if (newMultiplicity === 0) {\n this.#values.delete(hashedValue)\n } else {\n this.#values.set(hashedValue, newMultiplicity)\n }\n\n if (oldMultiplicity <= 0 && newMultiplicity > 0) {\n // The value wasn't present in the stream\n // but with this change it is now present in the stream\n result.push([[hash(this.#by(value)), value[1]], 1])\n } else if (oldMultiplicity > 0 && newMultiplicity <= 0) {\n // The value was present in the stream\n // but with this change it is no longer present in the stream\n result.push([[hash(this.#by(value)), value[1]], -1])\n }\n }\n\n if (result.length > 0) {\n this.output.sendData(new MultiSet(result))\n }\n }\n}\n\n/**\n * Removes duplicate values\n */\nexport function distinct<T extends KeyValue<any, any>>(\n by: (value: T) => any = (value: T) => value\n) {\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 DistinctOperator<T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n by\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAeO,MAAM,yBAEH,cAAgD;AAAA;AAAA,EAIxD,YACE,IACA,OACA,QACA,KAAwB,CAAC,UAAa,OACtC;AACA,UAAM,IAAI,OAAO,MAAM;AATzB;AACA;AASE,uBAAK,KAAM;AACX,uBAAK,6BAAc,IAAA;AAAA,EACrB;AAAA,EAEA,MAAY;;AACV,UAAM,oCAAoB,IAAA;AAG1B,eAAW,WAAW,KAAK,iBAAiB;AAC1C,iBAAW,CAAC,OAAO,IAAI,KAAK,QAAQ,YAAY;AAC9C,cAAM,cAAc,KAAK,mBAAK,KAAL,WAAS,MAAM;AAExC,cAAM,oBACJ,mBAAc,IAAI,WAAW,MAA7B,mBAAiC,OACjC,mBAAK,SAAQ,IAAI,WAAW,KAC5B;AACF,cAAM,kBAAkB,kBAAkB;AAC1C,sBAAc,IAAI,aAAa,CAAC,iBAAiB,KAAK,CAAC;AAAA,MACzD;AAAA,IACF;AAEA,UAAM,SAAyD,CAAA;AAG/D,eAAW;AAAA,MACT;AAAA,MACA,CAAC,iBAAiB,KAAK;AAAA,IAAA,KACpB,cAAc,WAAW;AAC5B,YAAM,kBAAkB,mBAAK,SAAQ,IAAI,WAAW,KAAK;AAEzD,UAAI,oBAAoB,GAAG;AACzB,2BAAK,SAAQ,OAAO,WAAW;AAAA,MACjC,OAAO;AACL,2BAAK,SAAQ,IAAI,aAAa,eAAe;AAAA,MAC/C;AAEA,UAAI,mBAAmB,KAAK,kBAAkB,GAAG;AAG/C,eAAO,KAAK,CAAC,CAAC,KAAK,mBAAK,KAAL,WAAS,MAAM,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;AAAA,MACpD,WAAW,kBAAkB,KAAK,mBAAmB,GAAG;AAGtD,eAAO,KAAK,CAAC,CAAC,KAAK,mBAAK,KAAL,WAAS,MAAM,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;AAAA,MACrD;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,WAAK,OAAO,SAAS,IAAI,SAAS,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;AA7DE;AACA;AAiEK,SAAS,SACd,KAAwB,CAAC,UAAa,OACtC;AACA,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":"distinct.js","sources":["../../../src/operators/distinct.ts"],"sourcesContent":["import { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport { hash } from \"../hashing/index.js\"\nimport { MultiSet } from \"../multiset.js\"\nimport type { Hash } from \"../hashing/index.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { IStreamBuilder, KeyValue } from \"../types.js\"\n\ntype Multiplicity = number\n\ntype GetValue<T> = T extends KeyValue<any, infer V> ? V : never\n\n/**\n * Operator that removes duplicates\n */\nexport class DistinctOperator<\n T extends KeyValue<any, any>,\n> extends UnaryOperator<T, KeyValue<number, GetValue<T>>> {\n #by: (value: T) => any\n #values: Map<Hash, Multiplicity> // keeps track of the number of times each value has been seen\n\n constructor(\n id: number,\n input: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<KeyValue<number, GetValue<T>>>,\n by: (value: T) => any = (value: T) => value\n ) {\n super(id, input, output)\n this.#by = by\n this.#values = new Map()\n }\n\n run(): void {\n const updatedValues = new Map<Hash, [Multiplicity, T]>()\n\n // Compute the new multiplicity for each value\n for (const message of this.inputMessages()) {\n for (const [value, diff] of message.getInner()) {\n const hashedValue = hash(this.#by(value))\n\n const oldMultiplicity =\n updatedValues.get(hashedValue)?.[0] ??\n this.#values.get(hashedValue) ??\n 0\n const newMultiplicity = oldMultiplicity + diff\n updatedValues.set(hashedValue, [newMultiplicity, value])\n }\n }\n\n const result: Array<[KeyValue<number, GetValue<T>>, number]> = []\n\n // Check which values became visible or disappeared\n for (const [\n hashedValue,\n [newMultiplicity, value],\n ] of updatedValues.entries()) {\n const oldMultiplicity = this.#values.get(hashedValue) ?? 0\n\n if (newMultiplicity === 0) {\n this.#values.delete(hashedValue)\n } else {\n this.#values.set(hashedValue, newMultiplicity)\n }\n\n if (oldMultiplicity <= 0 && newMultiplicity > 0) {\n // The value wasn't present in the stream\n // but with this change it is now present in the stream\n result.push([[hash(this.#by(value)), value[1]], 1])\n } else if (oldMultiplicity > 0 && newMultiplicity <= 0) {\n // The value was present in the stream\n // but with this change it is no longer present in the stream\n result.push([[hash(this.#by(value)), value[1]], -1])\n }\n }\n\n if (result.length > 0) {\n this.output.sendData(new MultiSet(result))\n }\n }\n}\n\n/**\n * Removes duplicate values\n */\nexport function distinct<T extends KeyValue<any, any>>(\n by: (value: T) => any = (value: T) => value\n) {\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 DistinctOperator<T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n by\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n"],"names":[],"mappings":";;;;AAeO,MAAM,yBAEH,cAAgD;AAAA,EACxD;AAAA,EACA;AAAA;AAAA,EAEA,YACE,IACA,OACA,QACA,KAAwB,CAAC,UAAa,OACtC;AACA,UAAM,IAAI,OAAO,MAAM;AACvB,SAAK,MAAM;AACX,SAAK,8BAAc,IAAA;AAAA,EACrB;AAAA,EAEA,MAAY;AACV,UAAM,oCAAoB,IAAA;AAG1B,eAAW,WAAW,KAAK,iBAAiB;AAC1C,iBAAW,CAAC,OAAO,IAAI,KAAK,QAAQ,YAAY;AAC9C,cAAM,cAAc,KAAK,KAAK,IAAI,KAAK,CAAC;AAExC,cAAM,kBACJ,cAAc,IAAI,WAAW,IAAI,CAAC,KAClC,KAAK,QAAQ,IAAI,WAAW,KAC5B;AACF,cAAM,kBAAkB,kBAAkB;AAC1C,sBAAc,IAAI,aAAa,CAAC,iBAAiB,KAAK,CAAC;AAAA,MACzD;AAAA,IACF;AAEA,UAAM,SAAyD,CAAA;AAG/D,eAAW;AAAA,MACT;AAAA,MACA,CAAC,iBAAiB,KAAK;AAAA,IAAA,KACpB,cAAc,WAAW;AAC5B,YAAM,kBAAkB,KAAK,QAAQ,IAAI,WAAW,KAAK;AAEzD,UAAI,oBAAoB,GAAG;AACzB,aAAK,QAAQ,OAAO,WAAW;AAAA,MACjC,OAAO;AACL,aAAK,QAAQ,IAAI,aAAa,eAAe;AAAA,MAC/C;AAEA,UAAI,mBAAmB,KAAK,kBAAkB,GAAG;AAG/C,eAAO,KAAK,CAAC,CAAC,KAAK,KAAK,IAAI,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;AAAA,MACpD,WAAW,kBAAkB,KAAK,mBAAmB,GAAG;AAGtD,eAAO,KAAK,CAAC,CAAC,KAAK,KAAK,IAAI,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;AAAA,MACrD;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,WAAK,OAAO,SAAS,IAAI,SAAS,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;AAKO,SAAS,SACd,KAAwB,CAAC,UAAa,OACtC;AACA,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,24 +1,15 @@
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 FilterOperator 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
- return collection.filter(__privateGet(this, _f));
10
+ return collection.filter(this.#f);
19
11
  }
20
12
  }
21
- _f = new WeakMap();
22
13
  function filter(f) {
23
14
  return (stream) => {
24
15
  const output = new StreamBuilder(
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","sources":["../../../src/operators/filter.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 filters elements from the input stream\n */\nexport class FilterOperator<T> extends LinearUnaryOperator<T, T> {\n #f: (data: T) => boolean\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<T>,\n f: (data: T) => boolean\n ) {\n super(id, inputA, output)\n this.#f = f\n }\n\n inner(collection: MultiSet<T>): MultiSet<T> {\n return collection.filter(this.#f)\n }\n}\n\n/**\n * Filters elements from the input stream\n * @param f - The predicate to filter elements\n */\nexport function filter<T>(f: (data: T) => boolean): 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 FilterOperator<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,uBAA0B,oBAA0B;AAAA,EAG/D,YACE,IACA,QACA,QACA,GACA;AACA,UAAM,IAAI,QAAQ,MAAM;AAR1B;AASE,uBAAK,IAAK;AAAA,EACZ;AAAA,EAEA,MAAM,YAAsC;AAC1C,WAAO,WAAW,OAAO,mBAAK,GAAE;AAAA,EAClC;AACF;AAfE;AAqBK,SAAS,OAAU,GAA8C;AACtE,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":"filter.js","sources":["../../../src/operators/filter.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 filters elements from the input stream\n */\nexport class FilterOperator<T> extends LinearUnaryOperator<T, T> {\n #f: (data: T) => boolean\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<T>,\n f: (data: T) => boolean\n ) {\n super(id, inputA, output)\n this.#f = f\n }\n\n inner(collection: MultiSet<T>): MultiSet<T> {\n return collection.filter(this.#f)\n }\n}\n\n/**\n * Filters elements from the input stream\n * @param f - The predicate to filter elements\n */\nexport function filter<T>(f: (data: T) => boolean): 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 FilterOperator<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,uBAA0B,oBAA0B;AAAA,EAC/D;AAAA,EAEA,YACE,IACA,QACA,QACA,GACA;AACA,UAAM,IAAI,QAAQ,MAAM;AACxB,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,MAAM,YAAsC;AAC1C,WAAO,WAAW,OAAO,KAAK,EAAE;AAAA,EAClC;AACF;AAMO,SAAS,OAAU,GAA8C;AACtE,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 { KeyValue } from '../types.js';
2
- import { IStreamBuilder, PipedOperator } from '../types.js';
1
+ import { IStreamBuilder, KeyValue, PipedOperator } from '../types.js';
3
2
  /**
4
3
  * Filters the elements of a keyed stream, by keys of another stream.
5
4
  * This allows you to build pipelies where you have multiple outputs that are related,
@@ -1 +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;"}
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 { IStreamBuilder, KeyValue, PipedOperator } from \"../types.js\"\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":";;;AAYO,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;"}
@@ -30,7 +30,6 @@ function groupBy(keyExtractor, aggregates = {}) {
30
30
  );
31
31
  const reduced = withKeysAndValues.pipe(
32
32
  reduce((values) => {
33
- var _a, _b;
34
33
  let totalMultiplicity = 0;
35
34
  for (const [_, multiplicity] of values) {
36
35
  totalMultiplicity += multiplicity;
@@ -39,7 +38,7 @@ function groupBy(keyExtractor, aggregates = {}) {
39
38
  return [];
40
39
  }
41
40
  const result = {};
42
- const originalKey = (_b = (_a = values[0]) == null ? void 0 : _a[0]) == null ? void 0 : _b[KEY_SENTINEL];
41
+ const originalKey = values[0]?.[0]?.[KEY_SENTINEL];
43
42
  result[KEY_SENTINEL] = originalKey;
44
43
  for (const [name, aggregate] of Object.entries(basicAggregates)) {
45
44
  const preValues = values.map(