@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.
- package/README.md +3 -2
- package/dist/AsyncRelation/Base.d.ts +47 -0
- package/dist/AsyncRelation/index.d.ts +25 -0
- package/dist/Relation/Memory.d.ts +2 -1
- package/dist/Relation/index.d.ts +1 -1
- package/dist/async/Relation/Base.d.ts +47 -0
- package/dist/async/Relation/index.d.ts +25 -0
- package/dist/async/operators/_helpers.d.ts +16 -0
- package/dist/async/operators/autowrap.d.ts +7 -0
- package/dist/async/operators/constants.d.ts +6 -0
- package/dist/async/operators/cross_product.d.ts +9 -0
- package/dist/async/operators/extend.d.ts +7 -0
- package/dist/async/operators/group.d.ts +7 -0
- package/dist/async/operators/image.d.ts +8 -0
- package/dist/async/operators/index.d.ts +28 -0
- package/dist/async/operators/intersect.d.ts +7 -0
- package/dist/async/operators/isEqual.d.ts +7 -0
- package/dist/async/operators/join.d.ts +7 -0
- package/dist/async/operators/left_join.d.ts +8 -0
- package/dist/async/operators/matching.d.ts +7 -0
- package/dist/async/operators/minus.d.ts +7 -0
- package/dist/async/operators/not_matching.d.ts +7 -0
- package/dist/async/operators/one.d.ts +6 -0
- package/dist/async/operators/prefix.d.ts +6 -0
- package/dist/async/operators/project.d.ts +10 -0
- package/dist/async/operators/rename.d.ts +6 -0
- package/dist/async/operators/restrict.d.ts +14 -0
- package/dist/async/operators/suffix.d.ts +6 -0
- package/dist/async/operators/summarize.d.ts +8 -0
- package/dist/async/operators/toArray.d.ts +5 -0
- package/dist/async/operators/transform.d.ts +9 -0
- package/dist/async/operators/ungroup.d.ts +7 -0
- package/dist/async/operators/union.d.ts +6 -0
- package/dist/async/operators/unwrap.d.ts +6 -0
- package/dist/async/operators/wrap.d.ts +6 -0
- package/dist/async/operators/yByX.d.ts +7 -0
- package/dist/async/types.d.ts +58 -0
- package/dist/async-operators/_helpers.d.ts +16 -0
- package/dist/async-operators/autowrap.d.ts +7 -0
- package/dist/async-operators/constants.d.ts +6 -0
- package/dist/async-operators/cross_product.d.ts +9 -0
- package/dist/async-operators/extend.d.ts +7 -0
- package/dist/async-operators/group.d.ts +7 -0
- package/dist/async-operators/image.d.ts +8 -0
- package/dist/async-operators/index.d.ts +28 -0
- package/dist/async-operators/intersect.d.ts +7 -0
- package/dist/async-operators/isEqual.d.ts +7 -0
- package/dist/async-operators/join.d.ts +7 -0
- package/dist/async-operators/left_join.d.ts +8 -0
- package/dist/async-operators/matching.d.ts +7 -0
- package/dist/async-operators/minus.d.ts +7 -0
- package/dist/async-operators/not_matching.d.ts +7 -0
- package/dist/async-operators/one.d.ts +6 -0
- package/dist/async-operators/prefix.d.ts +6 -0
- package/dist/async-operators/project.d.ts +10 -0
- package/dist/async-operators/rename.d.ts +6 -0
- package/dist/async-operators/restrict.d.ts +14 -0
- package/dist/async-operators/suffix.d.ts +6 -0
- package/dist/async-operators/summarize.d.ts +8 -0
- package/dist/async-operators/toArray.d.ts +5 -0
- package/dist/async-operators/transform.d.ts +9 -0
- package/dist/async-operators/ungroup.d.ts +7 -0
- package/dist/async-operators/union.d.ts +6 -0
- package/dist/async-operators/unwrap.d.ts +6 -0
- package/dist/async-operators/wrap.d.ts +6 -0
- package/dist/async-operators/yByX.d.ts +7 -0
- package/dist/async-types.d.ts +58 -0
- package/dist/async.d.ts +4 -0
- package/dist/bmg.cjs +1 -1
- package/dist/bmg.cjs.map +1 -1
- package/dist/bmg.modern.js +1 -1
- package/dist/bmg.modern.js.map +1 -1
- package/dist/bmg.module.js +1 -1
- package/dist/bmg.module.js.map +1 -1
- package/dist/bmg.umd.js +1 -1
- package/dist/bmg.umd.js.map +1 -1
- package/dist/index.d.ts +14 -3
- package/dist/lib-definitions.d.ts +1 -1
- package/dist/operators/index.d.ts +1 -30
- package/dist/operators/isEqual.d.ts +1 -2
- package/dist/operators/isRelation.d.ts +2 -1
- package/dist/sync/Relation/Memory.d.ts +46 -0
- package/dist/sync/Relation/index.d.ts +1 -0
- package/dist/sync/operators/_helpers.d.ts +142 -0
- package/dist/sync/operators/allbut.d.ts +2 -0
- package/dist/sync/operators/autowrap.d.ts +2 -0
- package/dist/sync/operators/constants.d.ts +2 -0
- package/dist/sync/operators/cross_product.d.ts +3 -0
- package/dist/sync/operators/exclude.d.ts +2 -0
- package/dist/sync/operators/extend.d.ts +2 -0
- package/dist/sync/operators/group.d.ts +2 -0
- package/dist/sync/operators/image.d.ts +2 -0
- package/dist/sync/operators/index.d.ts +30 -0
- package/dist/sync/operators/intersect.d.ts +2 -0
- package/dist/sync/operators/isEqual.d.ts +1 -0
- package/dist/sync/operators/isRelation.d.ts +2 -0
- package/dist/sync/operators/join.d.ts +2 -0
- package/dist/sync/operators/left_join.d.ts +2 -0
- package/dist/sync/operators/matching.d.ts +2 -0
- package/dist/sync/operators/minus.d.ts +2 -0
- package/dist/sync/operators/not_matching.d.ts +2 -0
- package/dist/sync/operators/one.d.ts +2 -0
- package/dist/sync/operators/prefix.d.ts +2 -0
- package/dist/sync/operators/project.d.ts +2 -0
- package/dist/sync/operators/rename.d.ts +2 -0
- package/dist/sync/operators/restrict.d.ts +2 -0
- package/dist/sync/operators/suffix.d.ts +2 -0
- package/dist/sync/operators/summarize.d.ts +2 -0
- package/dist/sync/operators/transform.d.ts +2 -0
- package/dist/sync/operators/ungroup.d.ts +2 -0
- package/dist/sync/operators/union.d.ts +2 -0
- package/dist/sync/operators/unwrap.d.ts +2 -0
- package/dist/sync/operators/wrap.d.ts +2 -0
- package/dist/sync/operators/yByX.d.ts +2 -0
- package/dist/types.d.ts +7 -0
- package/dist/writer/Text.d.ts +40 -0
- package/dist/writer/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/Relation/index.ts +2 -1
- package/src/async/Relation/Base.ts +245 -0
- package/src/async/Relation/index.ts +31 -0
- package/src/async/operators/_helpers.ts +60 -0
- package/src/async/operators/autowrap.ts +31 -0
- package/src/async/operators/constants.ts +26 -0
- package/src/async/operators/cross_product.ts +39 -0
- package/src/async/operators/extend.ts +36 -0
- package/src/async/operators/group.ts +61 -0
- package/src/async/operators/image.ts +42 -0
- package/src/async/operators/index.ts +28 -0
- package/src/async/operators/intersect.ts +28 -0
- package/src/async/operators/isEqual.ts +39 -0
- package/src/async/operators/join.ts +39 -0
- package/src/async/operators/left_join.ts +55 -0
- package/src/async/operators/matching.ts +39 -0
- package/src/async/operators/minus.ts +28 -0
- package/src/async/operators/not_matching.ts +39 -0
- package/src/async/operators/one.ts +25 -0
- package/src/async/operators/prefix.ts +15 -0
- package/src/async/operators/project.ts +64 -0
- package/src/async/operators/rename.ts +33 -0
- package/src/async/operators/restrict.ts +61 -0
- package/src/async/operators/suffix.ts +15 -0
- package/src/async/operators/summarize.ts +90 -0
- package/src/async/operators/toArray.ts +18 -0
- package/src/async/operators/transform.ts +43 -0
- package/src/async/operators/ungroup.ts +43 -0
- package/src/async/operators/union.ts +29 -0
- package/src/async/operators/unwrap.ts +31 -0
- package/src/async/operators/wrap.ts +32 -0
- package/src/async/operators/yByX.ts +19 -0
- package/src/async/types.ts +86 -0
- package/src/async.ts +4 -0
- package/src/index.ts +16 -3
- package/src/lib-definitions.ts +11 -0
- package/src/operators/index.ts +2 -31
- package/src/{Relation → sync/Relation}/Memory.ts +9 -1
- package/src/sync/Relation/index.ts +1 -0
- package/src/{operators → sync/operators}/_helpers.ts +1 -1
- package/src/{operators → sync/operators}/allbut.ts +1 -1
- package/src/{operators → sync/operators}/autowrap.ts +1 -1
- package/src/{operators → sync/operators}/constants.ts +1 -1
- package/src/{operators → sync/operators}/cross_product.ts +1 -1
- package/src/{operators → sync/operators}/exclude.ts +2 -2
- package/src/{operators → sync/operators}/extend.ts +1 -1
- package/src/{operators → sync/operators}/group.ts +2 -2
- package/src/{operators → sync/operators}/image.ts +2 -2
- package/src/sync/operators/index.ts +31 -0
- package/src/{operators → sync/operators}/intersect.ts +1 -1
- package/src/{operators → sync/operators}/isEqual.ts +1 -2
- package/src/sync/operators/isRelation.ts +6 -0
- package/src/{operators → sync/operators}/join.ts +1 -1
- package/src/{operators → sync/operators}/left_join.ts +1 -1
- package/src/{operators → sync/operators}/matching.ts +1 -1
- package/src/{operators → sync/operators}/minus.ts +1 -1
- package/src/{operators → sync/operators}/not_matching.ts +1 -1
- package/src/{operators → sync/operators}/one.ts +1 -1
- package/src/{operators → sync/operators}/prefix.ts +1 -1
- package/src/{operators → sync/operators}/project.ts +1 -1
- package/src/{operators → sync/operators}/rename.ts +1 -1
- package/src/{operators → sync/operators}/restrict.ts +2 -2
- package/src/{operators → sync/operators}/suffix.ts +1 -1
- package/src/{operators → sync/operators}/summarize.ts +1 -1
- package/src/{operators → sync/operators}/transform.ts +1 -1
- package/src/{operators → sync/operators}/ungroup.ts +1 -1
- package/src/{operators → sync/operators}/union.ts +1 -1
- package/src/{operators → sync/operators}/unwrap.ts +1 -1
- package/src/sync/operators/where.ts +1 -0
- package/src/{operators → sync/operators}/wrap.ts +1 -1
- package/src/{operators → sync/operators}/yByX.ts +1 -1
- package/src/types.ts +11 -0
- package/src/writer/Text.ts +305 -0
- package/src/writer/index.ts +1 -0
- package/src/operators/isRelation.ts +0 -5
- /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 "
|
|
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 "
|
|
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 "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { RelationOperand, Predicate, Tuple } from "
|
|
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 "
|
|
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 "
|
|
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 "
|
|
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,7 +1,6 @@
|
|
|
1
|
-
import { RelationOperand } from "../types";
|
|
2
1
|
import { toOperationalOperand, tupleKey } from "./_helpers";
|
|
3
2
|
|
|
4
|
-
export const isEqual = (left:
|
|
3
|
+
export const isEqual = (left: any, right: any): boolean => {
|
|
5
4
|
const opLeft = toOperationalOperand(left);
|
|
6
5
|
const opRight = toOperationalOperand(right);
|
|
7
6
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RelationOperand, JoinKeys, Tuple, AttrName } from "
|
|
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 "
|
|
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 "
|
|
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, JoinKeys, Tuple } from "
|
|
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 { PrefixOptions, RelationOperand } from "
|
|
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 "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { RelationOperand, Predicate, Tuple } from "
|
|
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 "
|
|
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 "
|
|
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 "
|
|
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 => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { restrict as where } from './restrict';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RelationOperand, AttrName, Tuple } from "
|
|
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 => {
|
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';
|
|
File without changes
|