@enspirit/bmg-js 1.0.2 → 1.1.0

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 +14 -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 +40 -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 +16 -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 +305 -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
@@ -34,6 +34,7 @@ import type {
34
34
  AutowrapOptions,
35
35
  Relation,
36
36
  RelationOperand,
37
+ TextOptions,
37
38
  Transformation,
38
39
  Tuple,
39
40
  TypedPredicate,
@@ -50,7 +51,8 @@ import type {
50
51
  AggregatorResults,
51
52
  TypedJoinKeysArray,
52
53
  TypedJoinKeysObject,
53
- } from "../types";
54
+ } from "../../types";
55
+ import { toText } from "../../writer";
54
56
 
55
57
  /**
56
58
  * In-memory implementation of the Relation interface.
@@ -211,4 +213,10 @@ export class MemoryRelation<T = Tuple> implements Relation<T> {
211
213
  return isEqual(this as any, right as any);
212
214
  }
213
215
 
216
+ // === Display ===
217
+
218
+ toText(options?: TextOptions): string {
219
+ return toText(this as any, options);
220
+ }
221
+
214
222
  }
@@ -0,0 +1 @@
1
+ export * from './Memory';
@@ -1,5 +1,5 @@
1
1
  import { OperationalOperand, Relation, RelationOperand, Renaming, RenamingFunc, Tuple, JoinKeys, AttrName } from "@/types";
2
- import { MemoryRelation } from '@/Relation';
2
+ import { MemoryRelation } from '@/sync/Relation';
3
3
  import { isRelation } from "./isRelation";
4
4
 
5
5
  const valueKey = (value: unknown): unknown => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, AttrName, Tuple } from "../types";
1
+ import { RelationOperand, AttrName, Tuple } from "../../types";
2
2
  import { toOperationalOperand, deduplicate } from "./_helpers";
3
3
 
4
4
  export const allbut = (operand: RelationOperand, attrs: AttrName[]): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { AutowrapOptions, RelationOperand, Tuple } from "../types";
1
+ import { AutowrapOptions, RelationOperand, Tuple } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
 
4
4
  export const autowrap = (operand: RelationOperand, options?: AutowrapOptions): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Tuple } from "../types";
1
+ import { RelationOperand, Tuple } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
 
4
4
  export const constants = (operand: RelationOperand, consts: Tuple): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Tuple } from "../types";
1
+ import { RelationOperand, Tuple } from "../../types";
2
2
  import { toOperationalOperand, deduplicate } from "./_helpers";
3
3
 
4
4
  export const cross_product = (left: RelationOperand, right: RelationOperand): RelationOperand => {
@@ -1,5 +1,5 @@
1
- import { toPredicateFunc } from "../support/toPredicateFunc";
2
- import { RelationOperand, Predicate, Tuple } from "../types";
1
+ import { toPredicateFunc } from "../../support/toPredicateFunc";
2
+ import { RelationOperand, Predicate, Tuple } from "../../types";
3
3
  import { toOperationalOperand } from "./_helpers";
4
4
 
5
5
  export const exclude = (operand: RelationOperand, p: Predicate): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Extension, Tuple } from "../types";
1
+ import { RelationOperand, Extension, Tuple } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
 
4
4
  export const extend = (operand: RelationOperand, extension: Extension): RelationOperand => {
@@ -1,6 +1,6 @@
1
- import { RelationOperand, AttrName, Tuple } from "../types";
1
+ import { RelationOperand, AttrName, Tuple } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
- import { MemoryRelation } from "@/Relation";
3
+ import { MemoryRelation } from "@/sync/Relation";
4
4
 
5
5
  const groupKey = (tuple: Tuple, byAttrs: AttrName[]): string => {
6
6
  const keyParts = byAttrs.map(attr => JSON.stringify(tuple[attr]));
@@ -1,6 +1,6 @@
1
- import { RelationOperand, JoinKeys, Tuple, AttrName } from "../types";
1
+ import { RelationOperand, JoinKeys, Tuple, AttrName } from "../../types";
2
2
  import { toOperationalOperand, normalizeKeys, tuplesMatch, projectOutKeys } from "./_helpers";
3
- import { MemoryRelation } from "@/Relation";
3
+ import { MemoryRelation } from "@/sync/Relation";
4
4
 
5
5
  export const image = (left: RelationOperand, right: RelationOperand, as: AttrName, keys?: JoinKeys): RelationOperand => {
6
6
  const opLeft = toOperationalOperand(left);
@@ -0,0 +1,31 @@
1
+ export * from './restrict'
2
+ export * from './where'
3
+ export * from './exclude'
4
+ export * from './constants'
5
+ export * from './rename'
6
+ export * from './prefix'
7
+ export * from './suffix'
8
+ export * from './project'
9
+ export * from './allbut'
10
+ export * from './extend'
11
+ export * from './union'
12
+ export * from './minus'
13
+ export * from './intersect'
14
+ export * from './matching'
15
+ export * from './not_matching'
16
+ export * from './join'
17
+ export * from './left_join'
18
+ export * from './cross_product'
19
+ export * from './image'
20
+ export * from './summarize'
21
+ export * from './group'
22
+ export * from './ungroup'
23
+ export * from './wrap'
24
+ export * from './unwrap'
25
+ export * from './autowrap'
26
+ export * from './transform'
27
+
28
+ export * from './isRelation'
29
+ export * from './isEqual'
30
+ export * from './one'
31
+ export * from './yByX'
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Tuple } from "../types";
1
+ import { RelationOperand, Tuple } from "../../types";
2
2
  import { toOperationalOperand, tupleKey } from "./_helpers";
3
3
 
4
4
  export const intersect = (left: RelationOperand, right: RelationOperand): RelationOperand => {
@@ -1,7 +1,6 @@
1
- import { RelationOperand } from "../types";
2
1
  import { toOperationalOperand, tupleKey } from "./_helpers";
3
2
 
4
- export const isEqual = (left: RelationOperand, right: RelationOperand): boolean => {
3
+ export const isEqual = (left: any, right: any): boolean => {
5
4
  const opLeft = toOperationalOperand(left);
6
5
  const opRight = toOperationalOperand(right);
7
6
 
@@ -0,0 +1,6 @@
1
+ import { MemoryRelation } from "@/sync/Relation";
2
+ import { Relation } from "@/types";
3
+
4
+ export const isRelation = (op: unknown): op is Relation => {
5
+ return op != null && (op as object).constructor === MemoryRelation;
6
+ }
@@ -1,4 +1,4 @@
1
- import { RelationOperand, JoinKeys, Tuple, AttrName } from "../types";
1
+ import { RelationOperand, JoinKeys, Tuple, AttrName } from "../../types";
2
2
  import { toOperationalOperand, normalizeKeys, tuplesMatch, projectOutKeys } from "./_helpers";
3
3
 
4
4
  const mergeTuples = (left: Tuple, right: Tuple, keyMap: Record<AttrName, AttrName>): Tuple => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, JoinKeys, Tuple, AttrName } from "../types";
1
+ import { RelationOperand, JoinKeys, Tuple, AttrName } from "../../types";
2
2
  import { toOperationalOperand, normalizeKeys, tuplesMatch } from "./_helpers";
3
3
 
4
4
  const getRightAttrs = (rightTuples: Tuple[], keyMap: Record<AttrName, AttrName>): AttrName[] => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, JoinKeys, Tuple } from "../types";
1
+ import { RelationOperand, JoinKeys, Tuple } from "../../types";
2
2
  import { toOperationalOperand, normalizeKeys, matchKey } from "./_helpers";
3
3
 
4
4
  export const matching = (left: RelationOperand, right: RelationOperand, keys?: JoinKeys): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Tuple } from "../types";
1
+ import { RelationOperand, Tuple } from "../../types";
2
2
  import { toOperationalOperand, tupleKey } from "./_helpers";
3
3
 
4
4
  export const minus = (left: RelationOperand, right: RelationOperand): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, JoinKeys, Tuple } from "../types";
1
+ import { RelationOperand, JoinKeys, Tuple } from "../../types";
2
2
  import { toOperationalOperand, normalizeKeys, matchKey } from "./_helpers";
3
3
 
4
4
  export const not_matching = (left: RelationOperand, right: RelationOperand, keys?: JoinKeys): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Tuple } from "../types";
1
+ import { RelationOperand, Tuple } from "../../types";
2
2
  import { toOperationalOperand, error } from "./_helpers";
3
3
 
4
4
  export const one = (operand: RelationOperand): Tuple => {
@@ -1,4 +1,4 @@
1
- import { PrefixOptions, RelationOperand } from "../types";
1
+ import { PrefixOptions, RelationOperand } from "../../types";
2
2
  import { rename } from "./rename";
3
3
 
4
4
  export const prefix = (operand: RelationOperand, pfx: string, options?: PrefixOptions): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, AttrName, Tuple } from "../types";
1
+ import { RelationOperand, AttrName, Tuple } from "../../types";
2
2
  import { toOperationalOperand, deduplicate } from "./_helpers";
3
3
 
4
4
  export const project = (operand: RelationOperand, attrs: AttrName[]): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Renaming, Tuple } from "../types";
1
+ import { RelationOperand, Renaming, Tuple } from "../../types";
2
2
  import { toOperationalOperand, toRenamingFunc } from "./_helpers";
3
3
 
4
4
  export const rename = (operand: RelationOperand, renaming: Renaming): RelationOperand => {
@@ -1,5 +1,5 @@
1
- import { toPredicateFunc } from "../support/toPredicateFunc";
2
- import { RelationOperand, Predicate, Tuple } from "../types";
1
+ import { toPredicateFunc } from "../../support/toPredicateFunc";
2
+ import { RelationOperand, Predicate, Tuple } from "../../types";
3
3
  import { toOperationalOperand } from "./_helpers";
4
4
 
5
5
  export const restrict = (operand: RelationOperand, p: Predicate): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, SuffixOptions } from "../types";
1
+ import { RelationOperand, SuffixOptions } from "../../types";
2
2
  import { rename } from "./rename";
3
3
 
4
4
  export const suffix = (operand: RelationOperand, sfx: string, options?: SuffixOptions): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, AttrName, Tuple, Aggregator, Aggregators } from "../types";
1
+ import { RelationOperand, AttrName, Tuple, Aggregator, Aggregators } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
 
4
4
  const groupKey = (tuple: Tuple, by: AttrName[]): string => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Transformation, Tuple } from "../types";
1
+ import { RelationOperand, Transformation, Tuple } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
 
4
4
  export const transform = (operand: RelationOperand, transformation: Transformation): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, AttrName, Tuple, Relation } from "../types";
1
+ import { RelationOperand, AttrName, Tuple, Relation } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
  import { isRelation } from "./isRelation";
4
4
 
@@ -1,4 +1,4 @@
1
- import { RelationOperand, Tuple } from "../types";
1
+ import { RelationOperand, Tuple } from "../../types";
2
2
  import { toOperationalOperand, tupleKey } from "./_helpers";
3
3
 
4
4
  export const union = (left: RelationOperand, right: RelationOperand): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { RelationOperand, AttrName, Tuple } from "../types";
1
+ import { RelationOperand, AttrName, Tuple } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
 
4
4
  export const unwrap = (operand: RelationOperand, attr: AttrName): RelationOperand => {
@@ -0,0 +1 @@
1
+ export { restrict as where } from './restrict';
@@ -1,4 +1,4 @@
1
- import { RelationOperand, AttrName, Tuple } from "../types";
1
+ import { RelationOperand, AttrName, Tuple } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
 
4
4
  export const wrap = (operand: RelationOperand, attrs: AttrName[], as: AttrName): RelationOperand => {
@@ -1,4 +1,4 @@
1
- import { AttrName, RelationOperand, Tuple } from "../types";
1
+ import { AttrName, RelationOperand, Tuple } from "../../types";
2
2
  import { toOperationalOperand } from "./_helpers";
3
3
 
4
4
  export const yByX = (operand: RelationOperand, y: AttrName, x: AttrName): Tuple => {
package/src/types.ts CHANGED
@@ -148,6 +148,13 @@ export interface PrefixOptions {
148
148
  except?: AttrName[]
149
149
  }
150
150
 
151
+ export interface TextOptions {
152
+ /** Precision for floating point numbers (default: 3) */
153
+ floatPrecision?: number;
154
+ /** Maximum width to trim output at */
155
+ trimAt?: number;
156
+ }
157
+
151
158
  export interface SuffixOptions {
152
159
  except?: AttrName[]
153
160
  }
@@ -252,6 +259,10 @@ export interface Relation<T = Tuple> {
252
259
  yByX<Y extends keyof T, X extends keyof T>(y: Y, x: X): Record<T[X] & PropertyKey, T[Y]>
253
260
  toArray(): T[]
254
261
  isEqual(right: any): boolean
262
+
263
+ // === Display ===
264
+
265
+ toText(options?: TextOptions): string
255
266
  }
256
267
 
257
268
  // ============================================================================
@@ -0,0 +1,305 @@
1
+ import { Relation, Tuple } from '../types';
2
+ import { isRelation } from '../sync/operators/isRelation';
3
+
4
+ /**
5
+ * Options for text rendering
6
+ */
7
+ export interface TextOptions {
8
+ /** Format string for floating point numbers (default: '%.3f' style) */
9
+ floatPrecision?: number;
10
+ /** Maximum width to trim output at */
11
+ trimAt?: number;
12
+ }
13
+
14
+ // Type guards
15
+ const isTupleLike = (t: unknown): t is Tuple =>
16
+ t !== null && typeof t === 'object' && !Array.isArray(t);
17
+
18
+ const isRelationLike = (r: unknown): r is Relation | Tuple[] =>
19
+ isRelation(r) || (Array.isArray(r) && r.every(isTupleLike));
20
+
21
+ /**
22
+ * Utility function to get max of two nullable numbers
23
+ */
24
+ const max = (x: number | null, y: number | null): number => {
25
+ if (x === null) return y ?? 0;
26
+ if (y === null) return x;
27
+ return x > y ? x : y;
28
+ };
29
+
30
+ /**
31
+ * Represents a single cell in the table
32
+ */
33
+ class Cell {
34
+ private value: unknown;
35
+ private renderer: TextWriter;
36
+ private _textRendering: string | null = null;
37
+ private _minWidth: number | null = null;
38
+
39
+ constructor(renderer: TextWriter, value: unknown) {
40
+ this.renderer = renderer;
41
+ this.value = value;
42
+ }
43
+
44
+ get minWidth(): number {
45
+ if (this._minWidth === null) {
46
+ this._minWidth = this.renderingLines().reduce(
47
+ (maxLen, line) => max(maxLen, line.length),
48
+ 0
49
+ );
50
+ }
51
+ return this._minWidth;
52
+ }
53
+
54
+ renderingLines(size?: number): string[] {
55
+ if (size === undefined) {
56
+ return this.textRendering.split('\n');
57
+ } else if (typeof this.value === 'number') {
58
+ // Right-align numbers
59
+ return this.renderingLines().map(l => l.padStart(size));
60
+ } else {
61
+ // Left-align other values
62
+ return this.renderingLines().map(l => l.padEnd(size));
63
+ }
64
+ }
65
+
66
+ get textRendering(): string {
67
+ if (this._textRendering === null) {
68
+ this._textRendering = this.computeTextRendering();
69
+ }
70
+ return this._textRendering;
71
+ }
72
+
73
+ private computeTextRendering(): string {
74
+ const value = this.value;
75
+
76
+ if (value === null) {
77
+ return '[null]';
78
+ }
79
+ if (value === undefined) {
80
+ return '[undefined]';
81
+ }
82
+ if (typeof value === 'symbol') {
83
+ return value.toString();
84
+ }
85
+ if (typeof value === 'number') {
86
+ if (Number.isInteger(value)) {
87
+ return String(value);
88
+ }
89
+ const precision = this.renderer.options.floatPrecision ?? 3;
90
+ return value.toFixed(precision);
91
+ }
92
+ if (isRelationLike(value)) {
93
+ return this.renderer.render(value, '');
94
+ }
95
+ if (Array.isArray(value)) {
96
+ return this.arrayRendering(value);
97
+ }
98
+ if (value instanceof Date) {
99
+ return value.toISOString();
100
+ }
101
+ if (typeof value === 'object') {
102
+ return JSON.stringify(value);
103
+ }
104
+ return String(value);
105
+ }
106
+
107
+ private arrayRendering(value: unknown[]): string {
108
+ if (value.length > 0 && isTupleLike(value[0])) {
109
+ return this.renderer.render(value as Tuple[], '');
110
+ }
111
+ if (value.length === 0) {
112
+ return '[]';
113
+ }
114
+ const values = value.map(x => {
115
+ const cell = new Cell(this.renderer, x);
116
+ return cell.textRendering;
117
+ });
118
+ const totalLength = values.reduce((sum, s) => sum + s.length, 0);
119
+ if (totalLength < 20) {
120
+ return '[' + values.join(', ') + ']';
121
+ } else {
122
+ return '[' + values.join(',\n ') + ']';
123
+ }
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Represents a row of cells in the table
129
+ */
130
+ class Row {
131
+ private cells: Cell[];
132
+
133
+ constructor(renderer: TextWriter, values: unknown[]) {
134
+ this.cells = values.map(v => new Cell(renderer, v));
135
+ }
136
+
137
+ minWidths(): number[] {
138
+ return this.cells.map(cell => cell.minWidth);
139
+ }
140
+
141
+ renderingLines(sizes: number[]): string[] {
142
+ let nbLines = 0;
143
+ const byCell = this.cells.map((cell, i) => {
144
+ const lines = cell.renderingLines(sizes[i]);
145
+ nbLines = max(nbLines, lines.length);
146
+ return lines;
147
+ });
148
+
149
+ const grid: string[] = [];
150
+ for (let lineI = 0; lineI < nbLines; lineI++) {
151
+ const lineContent = byCell
152
+ .map((cellLines, i) => cellLines[lineI] ?? ' '.repeat(sizes[i]))
153
+ .join(' | ');
154
+ grid.push('| ' + lineContent + ' |');
155
+ }
156
+
157
+ return grid.length === 0 ? ['| |'] : grid;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Represents the entire table structure
163
+ */
164
+ class Table {
165
+ private renderer: TextWriter;
166
+ private header: Row;
167
+ private rows: Row[];
168
+ private _sizes: number[] | null = null;
169
+ private _sep: string | null = null;
170
+
171
+ constructor(renderer: TextWriter, records: unknown[][], attributes: string[]) {
172
+ this.renderer = renderer;
173
+ this.header = new Row(renderer, attributes);
174
+ this.rows = records.map(r => new Row(renderer, r));
175
+ }
176
+
177
+ get sizes(): number[] {
178
+ if (this._sizes === null) {
179
+ const headerWidths = this.header.minWidths();
180
+ this._sizes = this.rows.reduce((memo, row) => {
181
+ const rowWidths = row.minWidths();
182
+ return memo.map((w, i) => max(w, rowWidths[i] ?? 0));
183
+ }, headerWidths);
184
+ }
185
+ return this._sizes;
186
+ }
187
+
188
+ get sep(): string {
189
+ if (this._sep === null) {
190
+ this._sep = '+-' + this.sizes.map(s => '-'.repeat(s)).join('-+-') + '-+';
191
+ }
192
+ return this._sep;
193
+ }
194
+
195
+ *eachLine(): Generator<string> {
196
+ const trimAt = this.renderer.options.trimAt;
197
+
198
+ if (trimAt !== undefined) {
199
+ for (const line of this.eachLineRaw()) {
200
+ yield line.substring(0, trimAt);
201
+ }
202
+ } else {
203
+ yield* this.eachLineRaw();
204
+ }
205
+ }
206
+
207
+ private *eachLineRaw(): Generator<string> {
208
+ yield this.sep;
209
+ yield this.header.renderingLines(this.sizes)[0];
210
+ yield this.sep;
211
+ for (const row of this.rows) {
212
+ for (const line of row.renderingLines(this.sizes)) {
213
+ yield line;
214
+ }
215
+ }
216
+ yield this.sep;
217
+ }
218
+
219
+ *[Symbol.iterator](): Generator<string> {
220
+ for (const line of this.eachLine()) {
221
+ yield line.trimEnd() + '\n';
222
+ }
223
+ }
224
+
225
+ toString(): string {
226
+ let result = '';
227
+ for (const line of this) {
228
+ result += line;
229
+ }
230
+ return result;
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Text writer for rendering relations as ASCII tables
236
+ */
237
+ export class TextWriter {
238
+ readonly options: TextOptions;
239
+
240
+ constructor(options: TextOptions = {}) {
241
+ this.options = options;
242
+ }
243
+
244
+ /**
245
+ * Renders a relation or tuple array to an ASCII table string
246
+ */
247
+ render(input: Relation | Tuple[] | Tuple, output: string = ''): string {
248
+ for (const line of this.eachLine(input)) {
249
+ output += line;
250
+ }
251
+ return output;
252
+ }
253
+
254
+ *eachLine(input: Relation | Tuple[] | Tuple): Generator<string> {
255
+ // Handle single tuple
256
+ let tuples: Tuple[];
257
+ if (isTupleLike(input) && !isRelation(input)) {
258
+ tuples = [input];
259
+ } else if (isRelation(input)) {
260
+ tuples = input.toArray();
261
+ } else {
262
+ tuples = input;
263
+ }
264
+
265
+ // Collect all attribute names across all tuples
266
+ const attrs = tuples.reduce((memo: string[], tuple) => {
267
+ for (const key of Object.keys(tuple)) {
268
+ if (!memo.includes(key)) {
269
+ memo.push(key);
270
+ }
271
+ }
272
+ return memo;
273
+ }, []);
274
+
275
+ // Build records array (values in attribute order)
276
+ const records = tuples.map(t => attrs.map(a => t[a]));
277
+
278
+ const table = new Table(this, records, attrs);
279
+ yield* table;
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Renders a relation as an ASCII table string
285
+ *
286
+ * @param operand - The relation or tuple array to render
287
+ * @param options - Text rendering options
288
+ * @returns ASCII table string representation
289
+ *
290
+ * @example
291
+ * const r = Bmg([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);
292
+ * console.log(toText(r));
293
+ * // +----+-------+
294
+ * // | id | name |
295
+ * // +----+-------+
296
+ * // | 1 | Alice |
297
+ * // | 2 | Bob |
298
+ * // +----+-------+
299
+ */
300
+ export const toText = (
301
+ operand: Relation | Tuple[] | Tuple,
302
+ options: TextOptions = {}
303
+ ): string => {
304
+ return new TextWriter(options).render(operand);
305
+ };
@@ -0,0 +1 @@
1
+ export * from './Text';
@@ -1,5 +0,0 @@
1
- import { MemoryRelation } from "@/Relation";
2
-
3
- export const isRelation = (op) => {
4
- return op != null && op.constructor === MemoryRelation;
5
- }