@enspirit/bmg-js 1.0.2 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +3 -2
  2. package/dist/AsyncRelation/Base.d.ts +47 -0
  3. package/dist/AsyncRelation/index.d.ts +25 -0
  4. package/dist/Relation/Memory.d.ts +2 -1
  5. package/dist/Relation/index.d.ts +1 -1
  6. package/dist/async/Relation/Base.d.ts +47 -0
  7. package/dist/async/Relation/index.d.ts +25 -0
  8. package/dist/async/operators/_helpers.d.ts +16 -0
  9. package/dist/async/operators/autowrap.d.ts +7 -0
  10. package/dist/async/operators/constants.d.ts +6 -0
  11. package/dist/async/operators/cross_product.d.ts +9 -0
  12. package/dist/async/operators/extend.d.ts +7 -0
  13. package/dist/async/operators/group.d.ts +7 -0
  14. package/dist/async/operators/image.d.ts +8 -0
  15. package/dist/async/operators/index.d.ts +28 -0
  16. package/dist/async/operators/intersect.d.ts +7 -0
  17. package/dist/async/operators/isEqual.d.ts +7 -0
  18. package/dist/async/operators/join.d.ts +7 -0
  19. package/dist/async/operators/left_join.d.ts +8 -0
  20. package/dist/async/operators/matching.d.ts +7 -0
  21. package/dist/async/operators/minus.d.ts +7 -0
  22. package/dist/async/operators/not_matching.d.ts +7 -0
  23. package/dist/async/operators/one.d.ts +6 -0
  24. package/dist/async/operators/prefix.d.ts +6 -0
  25. package/dist/async/operators/project.d.ts +10 -0
  26. package/dist/async/operators/rename.d.ts +6 -0
  27. package/dist/async/operators/restrict.d.ts +14 -0
  28. package/dist/async/operators/suffix.d.ts +6 -0
  29. package/dist/async/operators/summarize.d.ts +8 -0
  30. package/dist/async/operators/toArray.d.ts +5 -0
  31. package/dist/async/operators/transform.d.ts +9 -0
  32. package/dist/async/operators/ungroup.d.ts +7 -0
  33. package/dist/async/operators/union.d.ts +6 -0
  34. package/dist/async/operators/unwrap.d.ts +6 -0
  35. package/dist/async/operators/wrap.d.ts +6 -0
  36. package/dist/async/operators/yByX.d.ts +7 -0
  37. package/dist/async/types.d.ts +58 -0
  38. package/dist/async-operators/_helpers.d.ts +16 -0
  39. package/dist/async-operators/autowrap.d.ts +7 -0
  40. package/dist/async-operators/constants.d.ts +6 -0
  41. package/dist/async-operators/cross_product.d.ts +9 -0
  42. package/dist/async-operators/extend.d.ts +7 -0
  43. package/dist/async-operators/group.d.ts +7 -0
  44. package/dist/async-operators/image.d.ts +8 -0
  45. package/dist/async-operators/index.d.ts +28 -0
  46. package/dist/async-operators/intersect.d.ts +7 -0
  47. package/dist/async-operators/isEqual.d.ts +7 -0
  48. package/dist/async-operators/join.d.ts +7 -0
  49. package/dist/async-operators/left_join.d.ts +8 -0
  50. package/dist/async-operators/matching.d.ts +7 -0
  51. package/dist/async-operators/minus.d.ts +7 -0
  52. package/dist/async-operators/not_matching.d.ts +7 -0
  53. package/dist/async-operators/one.d.ts +6 -0
  54. package/dist/async-operators/prefix.d.ts +6 -0
  55. package/dist/async-operators/project.d.ts +10 -0
  56. package/dist/async-operators/rename.d.ts +6 -0
  57. package/dist/async-operators/restrict.d.ts +14 -0
  58. package/dist/async-operators/suffix.d.ts +6 -0
  59. package/dist/async-operators/summarize.d.ts +8 -0
  60. package/dist/async-operators/toArray.d.ts +5 -0
  61. package/dist/async-operators/transform.d.ts +9 -0
  62. package/dist/async-operators/ungroup.d.ts +7 -0
  63. package/dist/async-operators/union.d.ts +6 -0
  64. package/dist/async-operators/unwrap.d.ts +6 -0
  65. package/dist/async-operators/wrap.d.ts +6 -0
  66. package/dist/async-operators/yByX.d.ts +7 -0
  67. package/dist/async-types.d.ts +58 -0
  68. package/dist/async.d.ts +4 -0
  69. package/dist/bmg.cjs +1 -1
  70. package/dist/bmg.cjs.map +1 -1
  71. package/dist/bmg.modern.js +1 -1
  72. package/dist/bmg.modern.js.map +1 -1
  73. package/dist/bmg.module.js +1 -1
  74. package/dist/bmg.module.js.map +1 -1
  75. package/dist/bmg.umd.js +1 -1
  76. package/dist/bmg.umd.js.map +1 -1
  77. package/dist/index.d.ts +15 -3
  78. package/dist/lib-definitions.d.ts +1 -1
  79. package/dist/operators/index.d.ts +1 -30
  80. package/dist/operators/isEqual.d.ts +1 -2
  81. package/dist/operators/isRelation.d.ts +2 -1
  82. package/dist/sync/Relation/Memory.d.ts +46 -0
  83. package/dist/sync/Relation/index.d.ts +1 -0
  84. package/dist/sync/operators/_helpers.d.ts +142 -0
  85. package/dist/sync/operators/allbut.d.ts +2 -0
  86. package/dist/sync/operators/autowrap.d.ts +2 -0
  87. package/dist/sync/operators/constants.d.ts +2 -0
  88. package/dist/sync/operators/cross_product.d.ts +3 -0
  89. package/dist/sync/operators/exclude.d.ts +2 -0
  90. package/dist/sync/operators/extend.d.ts +2 -0
  91. package/dist/sync/operators/group.d.ts +2 -0
  92. package/dist/sync/operators/image.d.ts +2 -0
  93. package/dist/sync/operators/index.d.ts +30 -0
  94. package/dist/sync/operators/intersect.d.ts +2 -0
  95. package/dist/sync/operators/isEqual.d.ts +1 -0
  96. package/dist/sync/operators/isRelation.d.ts +2 -0
  97. package/dist/sync/operators/join.d.ts +2 -0
  98. package/dist/sync/operators/left_join.d.ts +2 -0
  99. package/dist/sync/operators/matching.d.ts +2 -0
  100. package/dist/sync/operators/minus.d.ts +2 -0
  101. package/dist/sync/operators/not_matching.d.ts +2 -0
  102. package/dist/sync/operators/one.d.ts +2 -0
  103. package/dist/sync/operators/prefix.d.ts +2 -0
  104. package/dist/sync/operators/project.d.ts +2 -0
  105. package/dist/sync/operators/rename.d.ts +2 -0
  106. package/dist/sync/operators/restrict.d.ts +2 -0
  107. package/dist/sync/operators/suffix.d.ts +2 -0
  108. package/dist/sync/operators/summarize.d.ts +2 -0
  109. package/dist/sync/operators/transform.d.ts +2 -0
  110. package/dist/sync/operators/ungroup.d.ts +2 -0
  111. package/dist/sync/operators/union.d.ts +2 -0
  112. package/dist/sync/operators/unwrap.d.ts +2 -0
  113. package/dist/sync/operators/wrap.d.ts +2 -0
  114. package/dist/sync/operators/yByX.d.ts +2 -0
  115. package/dist/types.d.ts +7 -0
  116. package/dist/writer/Text.d.ts +68 -0
  117. package/dist/writer/index.d.ts +1 -0
  118. package/package.json +1 -1
  119. package/src/Relation/index.ts +2 -1
  120. package/src/async/Relation/Base.ts +245 -0
  121. package/src/async/Relation/index.ts +31 -0
  122. package/src/async/operators/_helpers.ts +60 -0
  123. package/src/async/operators/autowrap.ts +31 -0
  124. package/src/async/operators/constants.ts +26 -0
  125. package/src/async/operators/cross_product.ts +39 -0
  126. package/src/async/operators/extend.ts +36 -0
  127. package/src/async/operators/group.ts +61 -0
  128. package/src/async/operators/image.ts +42 -0
  129. package/src/async/operators/index.ts +28 -0
  130. package/src/async/operators/intersect.ts +28 -0
  131. package/src/async/operators/isEqual.ts +39 -0
  132. package/src/async/operators/join.ts +39 -0
  133. package/src/async/operators/left_join.ts +55 -0
  134. package/src/async/operators/matching.ts +39 -0
  135. package/src/async/operators/minus.ts +28 -0
  136. package/src/async/operators/not_matching.ts +39 -0
  137. package/src/async/operators/one.ts +25 -0
  138. package/src/async/operators/prefix.ts +15 -0
  139. package/src/async/operators/project.ts +64 -0
  140. package/src/async/operators/rename.ts +33 -0
  141. package/src/async/operators/restrict.ts +61 -0
  142. package/src/async/operators/suffix.ts +15 -0
  143. package/src/async/operators/summarize.ts +90 -0
  144. package/src/async/operators/toArray.ts +18 -0
  145. package/src/async/operators/transform.ts +43 -0
  146. package/src/async/operators/ungroup.ts +43 -0
  147. package/src/async/operators/union.ts +29 -0
  148. package/src/async/operators/unwrap.ts +31 -0
  149. package/src/async/operators/wrap.ts +32 -0
  150. package/src/async/operators/yByX.ts +19 -0
  151. package/src/async/types.ts +86 -0
  152. package/src/async.ts +4 -0
  153. package/src/index.ts +17 -3
  154. package/src/lib-definitions.ts +11 -0
  155. package/src/operators/index.ts +2 -31
  156. package/src/{Relation → sync/Relation}/Memory.ts +9 -1
  157. package/src/sync/Relation/index.ts +1 -0
  158. package/src/{operators → sync/operators}/_helpers.ts +1 -1
  159. package/src/{operators → sync/operators}/allbut.ts +1 -1
  160. package/src/{operators → sync/operators}/autowrap.ts +1 -1
  161. package/src/{operators → sync/operators}/constants.ts +1 -1
  162. package/src/{operators → sync/operators}/cross_product.ts +1 -1
  163. package/src/{operators → sync/operators}/exclude.ts +2 -2
  164. package/src/{operators → sync/operators}/extend.ts +1 -1
  165. package/src/{operators → sync/operators}/group.ts +2 -2
  166. package/src/{operators → sync/operators}/image.ts +2 -2
  167. package/src/sync/operators/index.ts +31 -0
  168. package/src/{operators → sync/operators}/intersect.ts +1 -1
  169. package/src/{operators → sync/operators}/isEqual.ts +1 -2
  170. package/src/sync/operators/isRelation.ts +6 -0
  171. package/src/{operators → sync/operators}/join.ts +1 -1
  172. package/src/{operators → sync/operators}/left_join.ts +1 -1
  173. package/src/{operators → sync/operators}/matching.ts +1 -1
  174. package/src/{operators → sync/operators}/minus.ts +1 -1
  175. package/src/{operators → sync/operators}/not_matching.ts +1 -1
  176. package/src/{operators → sync/operators}/one.ts +1 -1
  177. package/src/{operators → sync/operators}/prefix.ts +1 -1
  178. package/src/{operators → sync/operators}/project.ts +1 -1
  179. package/src/{operators → sync/operators}/rename.ts +1 -1
  180. package/src/{operators → sync/operators}/restrict.ts +2 -2
  181. package/src/{operators → sync/operators}/suffix.ts +1 -1
  182. package/src/{operators → sync/operators}/summarize.ts +1 -1
  183. package/src/{operators → sync/operators}/transform.ts +1 -1
  184. package/src/{operators → sync/operators}/ungroup.ts +1 -1
  185. package/src/{operators → sync/operators}/union.ts +1 -1
  186. package/src/{operators → sync/operators}/unwrap.ts +1 -1
  187. package/src/sync/operators/where.ts +1 -0
  188. package/src/{operators → sync/operators}/wrap.ts +1 -1
  189. package/src/{operators → sync/operators}/yByX.ts +1 -1
  190. package/src/types.ts +11 -0
  191. package/src/writer/Text.ts +415 -0
  192. package/src/writer/index.ts +1 -0
  193. package/src/operators/isRelation.ts +0 -5
  194. /package/{src/operators/where.ts → dist/sync/operators/where.d.ts} +0 -0
@@ -0,0 +1,245 @@
1
+ import type { AsyncRelation, AsyncRelationOperand } from '../types';
2
+ import type { Tuple, TypedPredicate, TypedExtension, AttrName, Relation, RenameMap, Renamed, Prefixed, Suffixed, Transformation, JoinKeys, Aggregators, AutowrapOptions, TextOptions } from '../../types';
3
+ import { MemoryRelation } from '../../sync/Relation';
4
+ import {
5
+ restrict as restrictOp,
6
+ where as whereOp,
7
+ exclude as excludeOp,
8
+ } from '../operators/restrict';
9
+ import {
10
+ project as projectOp,
11
+ allbut as allbutOp,
12
+ } from '../operators/project';
13
+ import { extend as extendOp } from '../operators/extend';
14
+ import { constants as constantsOp } from '../operators/constants';
15
+ import { rename as renameOp } from '../operators/rename';
16
+ import { prefix as prefixOp } from '../operators/prefix';
17
+ import { suffix as suffixOp } from '../operators/suffix';
18
+ import { transform as transformOp } from '../operators/transform';
19
+ import { union as unionOp } from '../operators/union';
20
+ import { minus as minusOp } from '../operators/minus';
21
+ import { intersect as intersectOp } from '../operators/intersect';
22
+ import { matching as matchingOp } from '../operators/matching';
23
+ import { not_matching as notMatchingOp } from '../operators/not_matching';
24
+ import { join as joinOp } from '../operators/join';
25
+ import { left_join as leftJoinOp } from '../operators/left_join';
26
+ import { cross_product as crossProductOp } from '../operators/cross_product';
27
+ import { group as groupOp } from '../operators/group';
28
+ import { ungroup as ungroupOp } from '../operators/ungroup';
29
+ import { wrap as wrapOp } from '../operators/wrap';
30
+ import { unwrap as unwrapOp } from '../operators/unwrap';
31
+ import { image as imageOp } from '../operators/image';
32
+ import { summarize as summarizeOp } from '../operators/summarize';
33
+ import { autowrap as autowrapOp } from '../operators/autowrap';
34
+ import { yByX as yByXOp } from '../operators/yByX';
35
+ import { one as oneOp } from '../operators/one';
36
+ import { toArray as toArrayOp } from '../operators/toArray';
37
+ import { toText as toTextSync } from '../../writer';
38
+
39
+ /**
40
+ * Base implementation of AsyncRelation using lazy evaluation.
41
+ * Each operator returns a new BaseAsyncRelation wrapping the transformed iterable.
42
+ */
43
+ export class BaseAsyncRelation<T = Tuple> implements AsyncRelation<T> {
44
+ constructor(private source: AsyncIterable<T>) {}
45
+
46
+ // === Type-preserving operators ===
47
+
48
+ restrict(p: TypedPredicate<T>): AsyncRelation<T> {
49
+ return new BaseAsyncRelation(restrictOp(this.source, p as any));
50
+ }
51
+
52
+ where(p: TypedPredicate<T>): AsyncRelation<T> {
53
+ return new BaseAsyncRelation(whereOp(this.source, p as any));
54
+ }
55
+
56
+ exclude(p: TypedPredicate<T>): AsyncRelation<T> {
57
+ return new BaseAsyncRelation(excludeOp(this.source, p as any));
58
+ }
59
+
60
+ // === Projection operators ===
61
+
62
+ project<K extends keyof T>(attrs: K[]): AsyncRelation<Pick<T, K>> {
63
+ return new BaseAsyncRelation(
64
+ projectOp(this.source, attrs as AttrName[])
65
+ ) as unknown as AsyncRelation<Pick<T, K>>;
66
+ }
67
+
68
+ allbut<K extends keyof T>(attrs: K[]): AsyncRelation<Omit<T, K>> {
69
+ return new BaseAsyncRelation(
70
+ allbutOp(this.source, attrs as AttrName[])
71
+ ) as unknown as AsyncRelation<Omit<T, K>>;
72
+ }
73
+
74
+ // === Extension operators ===
75
+
76
+ extend<E extends Record<string, unknown>>(e: TypedExtension<T, E>): AsyncRelation<T & E> {
77
+ return new BaseAsyncRelation(
78
+ extendOp(this.source, e as any)
79
+ ) as unknown as AsyncRelation<T & E>;
80
+ }
81
+
82
+ constants<C extends Tuple>(consts: C): AsyncRelation<T & C> {
83
+ return new BaseAsyncRelation(
84
+ constantsOp(this.source, consts)
85
+ ) as unknown as AsyncRelation<T & C>;
86
+ }
87
+
88
+ // === Rename operators ===
89
+
90
+ rename<R extends RenameMap<T>>(r: R): AsyncRelation<Renamed<T, R>> {
91
+ return new BaseAsyncRelation(
92
+ renameOp(this.source, r as any)
93
+ ) as unknown as AsyncRelation<Renamed<T, R>>;
94
+ }
95
+
96
+ prefix<P extends string, Ex extends keyof T = never>(pfx: P, options?: { except?: Ex[] }): AsyncRelation<Prefixed<T, P, Ex>> {
97
+ return new BaseAsyncRelation(
98
+ prefixOp(this.source, pfx, options as any)
99
+ ) as unknown as AsyncRelation<Prefixed<T, P, Ex>>;
100
+ }
101
+
102
+ suffix<S extends string, Ex extends keyof T = never>(sfx: S, options?: { except?: Ex[] }): AsyncRelation<Suffixed<T, S, Ex>> {
103
+ return new BaseAsyncRelation(
104
+ suffixOp(this.source, sfx, options as any)
105
+ ) as unknown as AsyncRelation<Suffixed<T, S, Ex>>;
106
+ }
107
+
108
+ transform(t: Transformation): AsyncRelation<T> {
109
+ return new BaseAsyncRelation(
110
+ transformOp(this.source, t)
111
+ ) as unknown as AsyncRelation<T>;
112
+ }
113
+
114
+ // === Set operations ===
115
+
116
+ union(other: AsyncRelationOperand<T>): AsyncRelation<T> {
117
+ return new BaseAsyncRelation(
118
+ unionOp(this.source, other)
119
+ ) as unknown as AsyncRelation<T>;
120
+ }
121
+
122
+ minus(other: AsyncRelationOperand<T>): AsyncRelation<T> {
123
+ return new BaseAsyncRelation(
124
+ minusOp(this.source, other)
125
+ ) as unknown as AsyncRelation<T>;
126
+ }
127
+
128
+ intersect(other: AsyncRelationOperand<T>): AsyncRelation<T> {
129
+ return new BaseAsyncRelation(
130
+ intersectOp(this.source, other)
131
+ ) as unknown as AsyncRelation<T>;
132
+ }
133
+
134
+ // === Semi-joins ===
135
+
136
+ matching<U>(other: AsyncRelationOperand<U>, keys?: JoinKeys): AsyncRelation<T> {
137
+ return new BaseAsyncRelation(
138
+ matchingOp(this.source, other, keys)
139
+ ) as unknown as AsyncRelation<T>;
140
+ }
141
+
142
+ not_matching<U>(other: AsyncRelationOperand<U>, keys?: JoinKeys): AsyncRelation<T> {
143
+ return new BaseAsyncRelation(
144
+ notMatchingOp(this.source, other, keys)
145
+ ) as unknown as AsyncRelation<T>;
146
+ }
147
+
148
+ // === Joins ===
149
+
150
+ join<U>(other: AsyncRelationOperand<U>, keys?: JoinKeys): AsyncRelation<T & U> {
151
+ return new BaseAsyncRelation(
152
+ joinOp(this.source, other, keys)
153
+ ) as unknown as AsyncRelation<T & U>;
154
+ }
155
+
156
+ left_join<U>(other: AsyncRelationOperand<U>, keys?: JoinKeys): AsyncRelation<T & Partial<U>> {
157
+ return new BaseAsyncRelation(
158
+ leftJoinOp(this.source, other, keys)
159
+ ) as unknown as AsyncRelation<T & Partial<U>>;
160
+ }
161
+
162
+ cross_product<U>(other: AsyncRelationOperand<U>): AsyncRelation<T & U> {
163
+ return new BaseAsyncRelation(
164
+ crossProductOp(this.source, other)
165
+ ) as unknown as AsyncRelation<T & U>;
166
+ }
167
+
168
+ cross_join<U>(other: AsyncRelationOperand<U>): AsyncRelation<T & U> {
169
+ return this.cross_product(other);
170
+ }
171
+
172
+ // === Nesting/Grouping ===
173
+
174
+ group<K extends keyof T>(attrs: K[], as: string): AsyncRelation<Omit<T, K> & Record<string, Relation<Pick<T, K>>>> {
175
+ return new BaseAsyncRelation(
176
+ groupOp(this.source, attrs as string[], as)
177
+ ) as unknown as AsyncRelation<Omit<T, K> & Record<string, Relation<Pick<T, K>>>>;
178
+ }
179
+
180
+ ungroup(attr: string): AsyncRelation<Tuple> {
181
+ return new BaseAsyncRelation(
182
+ ungroupOp(this.source, attr)
183
+ ) as unknown as AsyncRelation<Tuple>;
184
+ }
185
+
186
+ wrap<K extends keyof T>(attrs: K[], as: string): AsyncRelation<Omit<T, K> & Record<string, Pick<T, K>>> {
187
+ return new BaseAsyncRelation(
188
+ wrapOp(this.source, attrs as string[], as)
189
+ ) as unknown as AsyncRelation<Omit<T, K> & Record<string, Pick<T, K>>>;
190
+ }
191
+
192
+ unwrap(attr: string): AsyncRelation<Tuple> {
193
+ return new BaseAsyncRelation(
194
+ unwrapOp(this.source, attr)
195
+ ) as unknown as AsyncRelation<Tuple>;
196
+ }
197
+
198
+ image<U>(other: AsyncRelationOperand<U>, as: string, keys?: JoinKeys): AsyncRelation<T & Record<string, Relation<U>>> {
199
+ return new BaseAsyncRelation(
200
+ imageOp(this.source, other, as, keys)
201
+ ) as unknown as AsyncRelation<T & Record<string, Relation<U>>>;
202
+ }
203
+
204
+ summarize<K extends keyof T>(by: K[], aggs: Aggregators): AsyncRelation<Pick<T, K> & Tuple> {
205
+ return new BaseAsyncRelation(
206
+ summarizeOp(this.source, by as string[], aggs)
207
+ ) as unknown as AsyncRelation<Pick<T, K> & Tuple>;
208
+ }
209
+
210
+ autowrap(options?: AutowrapOptions): AsyncRelation<Tuple> {
211
+ return new BaseAsyncRelation(
212
+ autowrapOp(this.source, options)
213
+ ) as unknown as AsyncRelation<Tuple>;
214
+ }
215
+
216
+ // === Terminal operations ===
217
+
218
+ one(): Promise<T> {
219
+ return oneOp(this.source);
220
+ }
221
+
222
+ toArray(): Promise<T[]> {
223
+ return toArrayOp(this.source);
224
+ }
225
+
226
+ async toRelation(): Promise<Relation<T>> {
227
+ const tuples = await toArrayOp(this.source);
228
+ return new MemoryRelation<T>(tuples);
229
+ }
230
+
231
+ yByX(y: string, x: string): Promise<Tuple> {
232
+ return yByXOp(this.source, y, x);
233
+ }
234
+
235
+ async toText(options?: TextOptions): Promise<string> {
236
+ const tuples = await toArrayOp(this.source);
237
+ return toTextSync(tuples as Tuple[], options);
238
+ }
239
+
240
+ // === Async iteration ===
241
+
242
+ [Symbol.asyncIterator](): AsyncIterator<T> {
243
+ return this.source[Symbol.asyncIterator]();
244
+ }
245
+ }
@@ -0,0 +1,31 @@
1
+ import { BaseAsyncRelation } from './Base';
2
+ import type { AsyncRelation, AsyncRelationOperand } from '../types';
3
+ import { isEqual as isEqualOp } from '../operators/isEqual';
4
+
5
+ export { BaseAsyncRelation };
6
+
7
+ /**
8
+ * Creates a new async relation from an AsyncIterable source.
9
+ *
10
+ * @typeParam T - The tuple type. Inferred from input or explicitly provided.
11
+ *
12
+ * @example
13
+ * // From an async iterable
14
+ * const suppliers = AsyncBmg(fetchSuppliersFromDB());
15
+ *
16
+ * @example
17
+ * // Chained operations (lazy - no execution yet)
18
+ * const query = AsyncBmg(source)
19
+ * .restrict({ city: 'London' })
20
+ * .project(['sid', 'name']);
21
+ *
22
+ * // Terminal operation triggers execution
23
+ * const results = await query.toArray();
24
+ */
25
+ export function AsyncBmg<T>(source: AsyncIterable<T>): AsyncRelation<T> {
26
+ return new BaseAsyncRelation<T>(source);
27
+ }
28
+
29
+ AsyncBmg.isEqual = <T, U>(left: AsyncRelationOperand<T>, right: AsyncRelationOperand<U>): Promise<boolean> => {
30
+ return isEqualOp(left, right);
31
+ };
@@ -0,0 +1,60 @@
1
+ import type { AsyncRelationOperand, AsyncOperationalOperand, AsyncRelation } from '../types';
2
+ import type { Tuple } from '../../types';
3
+ import { tupleKey } from '../../sync/operators/_helpers';
4
+
5
+ /**
6
+ * Type guard to check if a value implements AsyncRelation.
7
+ */
8
+ export const isAsyncRelation = <T>(value: unknown): value is AsyncRelation<T> => {
9
+ return (
10
+ value !== null &&
11
+ typeof value === 'object' &&
12
+ 'restrict' in value &&
13
+ 'project' in value &&
14
+ 'one' in value &&
15
+ Symbol.asyncIterator in value
16
+ );
17
+ };
18
+
19
+ /**
20
+ * Converts an AsyncRelationOperand to an AsyncOperationalOperand
21
+ * that provides a uniform interface for async iteration and output.
22
+ */
23
+ export const toAsyncOperationalOperand = <T>(
24
+ operand: AsyncRelationOperand<T>
25
+ ): AsyncOperationalOperand<T> => {
26
+ if (isAsyncRelation<T>(operand)) {
27
+ return {
28
+ tuples: () => operand,
29
+ output: (tuples) => tuples,
30
+ };
31
+ } else if (Symbol.asyncIterator in operand) {
32
+ return {
33
+ tuples: () => operand as AsyncIterable<T>,
34
+ output: (tuples) => tuples,
35
+ };
36
+ } else {
37
+ throw new Error(`Unable to iterate ${operand}`);
38
+ }
39
+ };
40
+
41
+ /**
42
+ * Async generator that removes duplicate tuples.
43
+ * Uses tupleKey() for equality comparison.
44
+ */
45
+ export async function* deduplicateAsync<T>(
46
+ source: AsyncIterable<T>
47
+ ): AsyncGenerator<T> {
48
+ const seen = new Set<string>();
49
+ for await (const tuple of source) {
50
+ const key = tupleKey(tuple as Tuple);
51
+ if (!seen.has(key)) {
52
+ seen.add(key);
53
+ yield tuple;
54
+ }
55
+ }
56
+ }
57
+
58
+ export const error = (msg: string): never => {
59
+ throw new Error(msg);
60
+ };
@@ -0,0 +1,31 @@
1
+ import type { AsyncRelationOperand } from '../types';
2
+ import type { AutowrapOptions, Tuple } from '../../types';
3
+
4
+ /**
5
+ * Automatically wraps attributes based on naming convention.
6
+ * Attributes with separator (default '_') are grouped into nested objects.
7
+ */
8
+ export async function* autowrap<T>(
9
+ operand: AsyncRelationOperand<T>,
10
+ options?: AutowrapOptions
11
+ ): AsyncIterable<Tuple> {
12
+ const sep = options?.separator ?? '_';
13
+
14
+ for await (const tuple of operand) {
15
+ const t = tuple as Tuple;
16
+ const wrapped: Tuple = {};
17
+
18
+ for (const [attr, value] of Object.entries(t)) {
19
+ const parts = attr.split(sep);
20
+ if (parts.length === 1) {
21
+ wrapped[attr] = value;
22
+ } else {
23
+ const [prefix, ...rest] = parts;
24
+ wrapped[prefix] = wrapped[prefix] ?? {};
25
+ (wrapped[prefix] as Tuple)[rest.join(sep)] = value;
26
+ }
27
+ }
28
+
29
+ yield wrapped;
30
+ }
31
+ }
@@ -0,0 +1,26 @@
1
+ import type { AsyncRelationOperand } from '../types';
2
+ import type { Tuple } from '../../types';
3
+ import { toAsyncOperationalOperand } from './_helpers';
4
+
5
+ /**
6
+ * Async generator that adds constant attributes to each tuple.
7
+ */
8
+ async function* constantsGen<T>(
9
+ source: AsyncIterable<T>,
10
+ consts: Tuple
11
+ ): AsyncGenerator<Tuple> {
12
+ for await (const tuple of source) {
13
+ yield { ...(tuple as Tuple), ...consts };
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Adds constant attributes to each tuple.
19
+ */
20
+ export const constants = <T>(
21
+ operand: AsyncRelationOperand<T>,
22
+ consts: Tuple
23
+ ): AsyncIterable<Tuple> => {
24
+ const op = toAsyncOperationalOperand(operand);
25
+ return constantsGen(op.tuples(), consts);
26
+ };
@@ -0,0 +1,39 @@
1
+ import type { AsyncRelationOperand } from '../types';
2
+ import type { Tuple } from '../../types';
3
+ import { tupleKey } from '../../sync/operators/_helpers';
4
+
5
+ /**
6
+ * Cartesian product: combines every left tuple with every right tuple.
7
+ * Left attributes override right on clash. Removes duplicates.
8
+ * Materializes both sides.
9
+ */
10
+ export async function* cross_product<T, U>(
11
+ left: AsyncRelationOperand<T>,
12
+ right: AsyncRelationOperand<U>
13
+ ): AsyncIterable<Tuple> {
14
+ // Materialize both sides
15
+ const leftTuples: Tuple[] = [];
16
+ const rightTuples: Tuple[] = [];
17
+
18
+ for await (const tuple of left) {
19
+ leftTuples.push(tuple as Tuple);
20
+ }
21
+ for await (const tuple of right) {
22
+ rightTuples.push(tuple as Tuple);
23
+ }
24
+
25
+ // Cartesian product with deduplication
26
+ const seen = new Set<string>();
27
+ for (const l of leftTuples) {
28
+ for (const r of rightTuples) {
29
+ const combined = { ...r, ...l };
30
+ const key = tupleKey(combined);
31
+ if (!seen.has(key)) {
32
+ seen.add(key);
33
+ yield combined;
34
+ }
35
+ }
36
+ }
37
+ }
38
+
39
+ export { cross_product as cross_join };
@@ -0,0 +1,36 @@
1
+ import type { AsyncRelationOperand } from '../types';
2
+ import type { Extension, Tuple } from '../../types';
3
+ import { toAsyncOperationalOperand } from './_helpers';
4
+
5
+ /**
6
+ * Async generator that extends tuples with computed or copied attributes.
7
+ */
8
+ async function* extendGen<T>(
9
+ source: AsyncIterable<T>,
10
+ extension: Extension
11
+ ): AsyncGenerator<Tuple> {
12
+ for await (const tuple of source) {
13
+ const t = tuple as Tuple;
14
+ const extended = { ...t };
15
+ for (const [attr, spec] of Object.entries(extension)) {
16
+ if (typeof spec === 'function') {
17
+ extended[attr] = spec(t);
18
+ } else {
19
+ extended[attr] = t[spec];
20
+ }
21
+ }
22
+ yield extended;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Extends each tuple with new attributes.
28
+ * Extension can be functions (computed) or attribute names (copied).
29
+ */
30
+ export const extend = <T>(
31
+ operand: AsyncRelationOperand<T>,
32
+ extension: Extension
33
+ ): AsyncIterable<Tuple> => {
34
+ const op = toAsyncOperationalOperand(operand);
35
+ return extendGen(op.tuples(), extension);
36
+ };
@@ -0,0 +1,61 @@
1
+ import type { AsyncRelationOperand } from '../types';
2
+ import type { AttrName, Tuple } from '../../types';
3
+ import { MemoryRelation } from '../../sync/Relation';
4
+
5
+ const groupKey = (tuple: Tuple, byAttrs: AttrName[]): string => {
6
+ const keyParts = byAttrs.map(attr => JSON.stringify(tuple[attr]));
7
+ return keyParts.join('|');
8
+ };
9
+
10
+ const pickAttrs = (tuple: Tuple, attrs: AttrName[]): Tuple => {
11
+ return attrs.reduce((acc, attr) => {
12
+ acc[attr] = tuple[attr];
13
+ return acc;
14
+ }, {} as Tuple);
15
+ };
16
+
17
+ /**
18
+ * Groups specified attributes into a nested relation.
19
+ * Materializes all tuples to perform grouping.
20
+ */
21
+ export async function* group<T>(
22
+ operand: AsyncRelationOperand<T>,
23
+ attrs: AttrName[],
24
+ as: AttrName
25
+ ): AsyncIterable<Tuple> {
26
+ // Materialize all tuples
27
+ const tuples: Tuple[] = [];
28
+ for await (const tuple of operand) {
29
+ tuples.push(tuple as Tuple);
30
+ }
31
+
32
+ if (tuples.length === 0) {
33
+ return;
34
+ }
35
+
36
+ // Determine which attributes to keep at the top level (all except grouped ones)
37
+ const allAttrs = Object.keys(tuples[0]);
38
+ const groupedSet = new Set(attrs);
39
+ const byAttrs = allAttrs.filter(a => !groupedSet.has(a));
40
+
41
+ // Group tuples
42
+ const groups = new Map<string, { base: Tuple; nested: Tuple[] }>();
43
+ for (const tuple of tuples) {
44
+ const key = groupKey(tuple, byAttrs);
45
+ if (!groups.has(key)) {
46
+ groups.set(key, {
47
+ base: pickAttrs(tuple, byAttrs),
48
+ nested: []
49
+ });
50
+ }
51
+ groups.get(key)!.nested.push(pickAttrs(tuple, attrs));
52
+ }
53
+
54
+ // Yield results with nested relations
55
+ for (const { base, nested } of groups.values()) {
56
+ yield {
57
+ ...base,
58
+ [as]: new MemoryRelation(nested)
59
+ };
60
+ }
61
+ }
@@ -0,0 +1,42 @@
1
+ import type { AsyncRelationOperand } from '../types';
2
+ import type { JoinKeys, Tuple, AttrName } from '../../types';
3
+ import { normalizeKeys, tuplesMatch, projectOutKeys } from '../../sync/operators/_helpers';
4
+ import { MemoryRelation } from '../../sync/Relation';
5
+
6
+ /**
7
+ * Adds a relation-valued attribute with matching tuples from right.
8
+ * Each left tuple gets a nested relation of matching right tuples.
9
+ * Materializes both sides.
10
+ */
11
+ export async function* image<T, U>(
12
+ left: AsyncRelationOperand<T>,
13
+ right: AsyncRelationOperand<U>,
14
+ as: AttrName,
15
+ keys?: JoinKeys
16
+ ): AsyncIterable<Tuple> {
17
+ // Materialize both sides
18
+ const leftTuples: Tuple[] = [];
19
+ const rightTuples: Tuple[] = [];
20
+
21
+ for await (const tuple of left) {
22
+ leftTuples.push(tuple as Tuple);
23
+ }
24
+ for await (const tuple of right) {
25
+ rightTuples.push(tuple as Tuple);
26
+ }
27
+
28
+ const keyMap = normalizeKeys(keys, leftTuples, rightTuples);
29
+
30
+ for (const leftTuple of leftTuples) {
31
+ const matches: Tuple[] = [];
32
+ for (const rightTuple of rightTuples) {
33
+ if (tuplesMatch(leftTuple, rightTuple, keyMap)) {
34
+ matches.push(projectOutKeys(rightTuple, keyMap));
35
+ }
36
+ }
37
+ yield {
38
+ ...leftTuple,
39
+ [as]: new MemoryRelation(matches)
40
+ };
41
+ }
42
+ }
@@ -0,0 +1,28 @@
1
+ export { restrict, where, exclude } from './restrict';
2
+ export { project, allbut } from './project';
3
+ export { extend } from './extend';
4
+ export { constants } from './constants';
5
+ export { rename } from './rename';
6
+ export { prefix } from './prefix';
7
+ export { suffix } from './suffix';
8
+ export { transform } from './transform';
9
+ export { union } from './union';
10
+ export { minus } from './minus';
11
+ export { intersect } from './intersect';
12
+ export { matching } from './matching';
13
+ export { not_matching } from './not_matching';
14
+ export { join } from './join';
15
+ export { left_join } from './left_join';
16
+ export { cross_product, cross_join } from './cross_product';
17
+ export { group } from './group';
18
+ export { ungroup } from './ungroup';
19
+ export { wrap } from './wrap';
20
+ export { unwrap } from './unwrap';
21
+ export { image } from './image';
22
+ export { summarize } from './summarize';
23
+ export { autowrap } from './autowrap';
24
+ export { yByX } from './yByX';
25
+ export { isEqual } from './isEqual';
26
+ export { one } from './one';
27
+ export { toArray } from './toArray';
28
+ export { isAsyncRelation, toAsyncOperationalOperand, deduplicateAsync } from './_helpers';
@@ -0,0 +1,28 @@
1
+ import type { AsyncRelationOperand } from '../types';
2
+ import type { Tuple } from '../../types';
3
+ import { tupleKey } from '../../sync/operators/_helpers';
4
+
5
+ /**
6
+ * Set intersection: returns tuples present in both relations.
7
+ * Materializes right side first, then streams left.
8
+ */
9
+ export async function* intersect<T>(
10
+ left: AsyncRelationOperand<T>,
11
+ right: AsyncRelationOperand<T>
12
+ ): AsyncIterable<Tuple> {
13
+ // Materialize right side into a set of keys
14
+ const rightKeys = new Set<string>();
15
+ for await (const tuple of right) {
16
+ rightKeys.add(tupleKey(tuple as Tuple));
17
+ }
18
+
19
+ // Stream left, keeping tuples present in right
20
+ const seen = new Set<string>();
21
+ for await (const tuple of left) {
22
+ const key = tupleKey(tuple as Tuple);
23
+ if (rightKeys.has(key) && !seen.has(key)) {
24
+ seen.add(key);
25
+ yield tuple as Tuple;
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,39 @@
1
+ import type { AsyncRelationOperand } from '../types';
2
+ import type { Tuple } from '../../types';
3
+ import { toAsyncOperationalOperand } from './_helpers';
4
+ import { tupleKey } from '../../sync/operators/_helpers';
5
+
6
+ /**
7
+ * Compares two async relations for equality.
8
+ * Two relations are equal if they contain the exact same set of tuples.
9
+ * Terminal operation - returns a Promise.
10
+ */
11
+ export const isEqual = async <T, U>(
12
+ left: AsyncRelationOperand<T>,
13
+ right: AsyncRelationOperand<U>
14
+ ): Promise<boolean> => {
15
+ const opLeft = toAsyncOperationalOperand(left);
16
+ const opRight = toAsyncOperationalOperand(right);
17
+
18
+ const leftKeys = new Set<string>();
19
+ for await (const tuple of opLeft.tuples()) {
20
+ leftKeys.add(tupleKey(tuple as Tuple));
21
+ }
22
+
23
+ const rightKeys = new Set<string>();
24
+ for await (const tuple of opRight.tuples()) {
25
+ rightKeys.add(tupleKey(tuple as Tuple));
26
+ }
27
+
28
+ if (leftKeys.size !== rightKeys.size) {
29
+ return false;
30
+ }
31
+
32
+ for (const key of leftKeys) {
33
+ if (!rightKeys.has(key)) {
34
+ return false;
35
+ }
36
+ }
37
+
38
+ return true;
39
+ };