@enspirit/bmg-js 1.0.0 → 1.0.2
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/LICENSE.md +21 -0
- package/dist/Relation/Memory.d.ts +45 -0
- package/dist/Relation/index.d.ts +1 -0
- package/dist/bmg.cjs +2 -0
- package/dist/bmg.cjs.map +1 -0
- package/dist/bmg.modern.js +2 -0
- package/dist/bmg.modern.js.map +1 -0
- package/dist/bmg.module.js +2 -0
- package/dist/bmg.module.js.map +1 -0
- package/dist/bmg.umd.js +2 -0
- package/dist/bmg.umd.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/lib-definitions.d.ts +1 -0
- package/dist/operators/_helpers.d.ts +142 -0
- package/dist/operators/allbut.d.ts +2 -0
- package/dist/operators/autowrap.d.ts +2 -0
- package/dist/operators/constants.d.ts +2 -0
- package/dist/operators/cross_product.d.ts +3 -0
- package/dist/operators/exclude.d.ts +2 -0
- package/dist/operators/extend.d.ts +2 -0
- package/dist/operators/group.d.ts +2 -0
- package/dist/operators/image.d.ts +2 -0
- package/dist/operators/index.d.ts +30 -0
- package/dist/operators/intersect.d.ts +2 -0
- package/dist/operators/isEqual.d.ts +2 -0
- package/dist/operators/isRelation.d.ts +1 -0
- package/dist/operators/join.d.ts +2 -0
- package/dist/operators/left_join.d.ts +2 -0
- package/dist/operators/matching.d.ts +2 -0
- package/dist/operators/minus.d.ts +2 -0
- package/dist/operators/not_matching.d.ts +2 -0
- package/dist/operators/one.d.ts +2 -0
- package/dist/operators/prefix.d.ts +2 -0
- package/dist/operators/project.d.ts +2 -0
- package/dist/operators/rename.d.ts +2 -0
- package/dist/operators/restrict.d.ts +2 -0
- package/dist/operators/suffix.d.ts +2 -0
- package/dist/operators/summarize.d.ts +2 -0
- package/dist/operators/transform.d.ts +2 -0
- package/dist/operators/ungroup.d.ts +2 -0
- package/dist/operators/union.d.ts +2 -0
- package/dist/operators/unwrap.d.ts +2 -0
- package/dist/operators/where.d.ts +1 -0
- package/dist/operators/wrap.d.ts +2 -0
- package/dist/operators/yByX.d.ts +2 -0
- package/dist/support/toPredicateFunc.d.ts +2 -0
- package/dist/types.d.ts +162 -0
- package/package.json +20 -6
- package/src/Relation/Memory.ts +13 -12
- package/src/index.ts +1 -1
- package/src/lib-definitions.ts +281 -0
- package/src/types.ts +142 -54
- package/.claude/safe-setup/.env.example +0 -3
- package/.claude/safe-setup/Dockerfile.claude +0 -36
- package/.claude/safe-setup/HACKING.md +0 -63
- package/.claude/safe-setup/Makefile +0 -22
- package/.claude/safe-setup/docker-compose.yml +0 -18
- package/.claude/safe-setup/entrypoint.sh +0 -13
- package/.claude/settings.local.json +0 -9
- package/.claude/typescript-annotations.md +0 -273
- package/.github/workflows/test.yml +0 -26
- package/CLAUDE.md +0 -48
- package/Makefile +0 -2
- package/example/README.md +0 -22
- package/example/index.ts +0 -316
- package/example/package.json +0 -16
- package/example/tsconfig.json +0 -11
- package/src/utility-types.ts +0 -77
- package/tests/bmg.test.ts +0 -16
- package/tests/fixtures.ts +0 -9
- package/tests/operators/allbut.test.ts +0 -51
- package/tests/operators/autowrap.test.ts +0 -82
- package/tests/operators/constants.test.ts +0 -37
- package/tests/operators/cross_product.test.ts +0 -90
- package/tests/operators/exclude.test.ts +0 -43
- package/tests/operators/extend.test.ts +0 -45
- package/tests/operators/group.test.ts +0 -69
- package/tests/operators/image.test.ts +0 -152
- package/tests/operators/intersect.test.ts +0 -53
- package/tests/operators/isEqual.test.ts +0 -111
- package/tests/operators/join.test.ts +0 -116
- package/tests/operators/left_join.test.ts +0 -116
- package/tests/operators/matching.test.ts +0 -91
- package/tests/operators/minus.test.ts +0 -47
- package/tests/operators/not_matching.test.ts +0 -104
- package/tests/operators/one.test.ts +0 -19
- package/tests/operators/prefix.test.ts +0 -37
- package/tests/operators/project.test.ts +0 -48
- package/tests/operators/rename.test.ts +0 -39
- package/tests/operators/restrict.test.ts +0 -27
- package/tests/operators/suffix.test.ts +0 -37
- package/tests/operators/summarize.test.ts +0 -109
- package/tests/operators/transform.test.ts +0 -94
- package/tests/operators/ungroup.test.ts +0 -67
- package/tests/operators/union.test.ts +0 -51
- package/tests/operators/unwrap.test.ts +0 -50
- package/tests/operators/where.test.ts +0 -33
- package/tests/operators/wrap.test.ts +0 -54
- package/tests/operators/yByX.test.ts +0 -32
- package/tests/types/relation.test.ts +0 -296
- package/tsconfig.json +0 -37
- package/tsconfig.node.json +0 -9
- package/vitest.config.ts +0 -15
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { Bmg } from 'src';
|
|
3
|
-
import { left_join , isEqual } from 'src/operators';
|
|
4
|
-
|
|
5
|
-
describe('.left_join', () => {
|
|
6
|
-
|
|
7
|
-
const orders = Bmg([
|
|
8
|
-
{ oid: 1, customer_id: 'C1', amount: 100 },
|
|
9
|
-
{ oid: 2, customer_id: 'C2', amount: 200 },
|
|
10
|
-
{ oid: 3, customer_id: 'C3', amount: 150 },
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
const customers = Bmg([
|
|
14
|
-
{ customer_id: 'C1', name: 'Alice' },
|
|
15
|
-
{ customer_id: 'C2', name: 'Bob' },
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
it('joins matching tuples and keeps non-matching with null', () => {
|
|
19
|
-
const result = orders.left_join(customers);
|
|
20
|
-
const expected = Bmg([
|
|
21
|
-
{ oid: 1, customer_id: 'C1', amount: 100, name: 'Alice' },
|
|
22
|
-
{ oid: 2, customer_id: 'C2', amount: 200, name: 'Bob' },
|
|
23
|
-
{ oid: 3, customer_id: 'C3', amount: 150, name: null },
|
|
24
|
-
]);
|
|
25
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('supports explicit keys as { left: right }', () => {
|
|
29
|
-
const suppliers = Bmg([
|
|
30
|
-
{ sid: 'S1', city: 'London' },
|
|
31
|
-
{ sid: 'S2', city: 'Paris' },
|
|
32
|
-
{ sid: 'S3', city: 'Athens' },
|
|
33
|
-
]);
|
|
34
|
-
const cities = Bmg([
|
|
35
|
-
{ location: 'London', country: 'UK' },
|
|
36
|
-
{ location: 'Paris', country: 'France' },
|
|
37
|
-
]);
|
|
38
|
-
const result = suppliers.left_join(cities, { city: 'location' });
|
|
39
|
-
const expected = Bmg([
|
|
40
|
-
{ sid: 'S1', city: 'London', country: 'UK' },
|
|
41
|
-
{ sid: 'S2', city: 'Paris', country: 'France' },
|
|
42
|
-
{ sid: 'S3', city: 'Athens', country: null },
|
|
43
|
-
]);
|
|
44
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('supports explicit keys as [common_attr]', () => {
|
|
48
|
-
const result = orders.left_join(customers, ['customer_id']);
|
|
49
|
-
const expected = Bmg([
|
|
50
|
-
{ oid: 1, customer_id: 'C1', amount: 100, name: 'Alice' },
|
|
51
|
-
{ oid: 2, customer_id: 'C2', amount: 200, name: 'Bob' },
|
|
52
|
-
{ oid: 3, customer_id: 'C3', amount: 150, name: null },
|
|
53
|
-
]);
|
|
54
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('supports multiple keys as [attr1, attr2]', () => {
|
|
58
|
-
const inventory = Bmg([
|
|
59
|
-
{ warehouse: 'W1', city: 'London', stock: 100 },
|
|
60
|
-
{ warehouse: 'W2', city: 'London', stock: 200 },
|
|
61
|
-
{ warehouse: 'W1', city: 'Paris', stock: 150 },
|
|
62
|
-
]);
|
|
63
|
-
const shipments = Bmg([
|
|
64
|
-
{ warehouse: 'W1', city: 'London', shipped: 50 },
|
|
65
|
-
]);
|
|
66
|
-
const result = inventory.left_join(shipments, ['warehouse', 'city']);
|
|
67
|
-
const expected = Bmg([
|
|
68
|
-
{ warehouse: 'W1', city: 'London', stock: 100, shipped: 50 },
|
|
69
|
-
{ warehouse: 'W2', city: 'London', stock: 200, shipped: null },
|
|
70
|
-
{ warehouse: 'W1', city: 'Paris', stock: 150, shipped: null },
|
|
71
|
-
]);
|
|
72
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('supports multiple keys as { left1: right1, left2: right2 }', () => {
|
|
76
|
-
const people = Bmg([
|
|
77
|
-
{ id: 1, first: 'John', last: 'Doe' },
|
|
78
|
-
{ id: 2, first: 'Jane', last: 'Smith' },
|
|
79
|
-
{ id: 3, first: 'John', last: 'Smith' },
|
|
80
|
-
]);
|
|
81
|
-
const records = Bmg([
|
|
82
|
-
{ fname: 'John', lname: 'Doe', score: 85 },
|
|
83
|
-
{ fname: 'Jane', lname: 'Smith', score: 90 },
|
|
84
|
-
]);
|
|
85
|
-
const result = people.left_join(records, { first: 'fname', last: 'lname' });
|
|
86
|
-
const expected = Bmg([
|
|
87
|
-
{ id: 1, first: 'John', last: 'Doe', score: 85 },
|
|
88
|
-
{ id: 2, first: 'Jane', last: 'Smith', score: 90 },
|
|
89
|
-
{ id: 3, first: 'John', last: 'Smith', score: null },
|
|
90
|
-
]);
|
|
91
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it('handles multiple matches', () => {
|
|
95
|
-
const left = Bmg([{ id: 1, city: 'Paris' }]);
|
|
96
|
-
const right = Bmg([
|
|
97
|
-
{ city: 'Paris', name: 'A' },
|
|
98
|
-
{ city: 'Paris', name: 'B' },
|
|
99
|
-
]);
|
|
100
|
-
const result = left.left_join(right);
|
|
101
|
-
const expected = Bmg([
|
|
102
|
-
{ id: 1, city: 'Paris', name: 'A' },
|
|
103
|
-
{ id: 1, city: 'Paris', name: 'B' },
|
|
104
|
-
]);
|
|
105
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
///
|
|
109
|
-
|
|
110
|
-
it('can be used standalone', () => {
|
|
111
|
-
const res = left_join(orders.toArray(), customers.toArray());
|
|
112
|
-
const expected = orders.left_join(customers);
|
|
113
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
});
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { Bmg } from 'src';
|
|
3
|
-
import { matching , isEqual } from 'src/operators';
|
|
4
|
-
|
|
5
|
-
describe('.matching', () => {
|
|
6
|
-
|
|
7
|
-
const orders = Bmg([
|
|
8
|
-
{ oid: 1, customer_id: 'C1', amount: 100 },
|
|
9
|
-
{ oid: 2, customer_id: 'C2', amount: 200 },
|
|
10
|
-
{ oid: 3, customer_id: 'C3', amount: 150 },
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
const customers = Bmg([
|
|
14
|
-
{ customer_id: 'C1', name: 'Alice' },
|
|
15
|
-
{ customer_id: 'C2', name: 'Bob' },
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
it('returns tuples from left that match right on common attrs', () => {
|
|
19
|
-
const result = orders.matching(customers);
|
|
20
|
-
const expected = Bmg([
|
|
21
|
-
{ oid: 1, customer_id: 'C1', amount: 100 },
|
|
22
|
-
{ oid: 2, customer_id: 'C2', amount: 200 },
|
|
23
|
-
]);
|
|
24
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('supports explicit keys as [common_attr]', () => {
|
|
28
|
-
const result = orders.matching(customers, ['customer_id']);
|
|
29
|
-
const expected = Bmg([
|
|
30
|
-
{ oid: 1, customer_id: 'C1', amount: 100 },
|
|
31
|
-
{ oid: 2, customer_id: 'C2', amount: 200 },
|
|
32
|
-
]);
|
|
33
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('supports multiple keys as [attr1, attr2]', () => {
|
|
37
|
-
const inventory = Bmg([
|
|
38
|
-
{ warehouse: 'W1', city: 'London', stock: 100 },
|
|
39
|
-
{ warehouse: 'W2', city: 'London', stock: 200 },
|
|
40
|
-
{ warehouse: 'W1', city: 'Paris', stock: 150 },
|
|
41
|
-
]);
|
|
42
|
-
const shipments = Bmg([
|
|
43
|
-
{ warehouse: 'W1', city: 'London' },
|
|
44
|
-
{ warehouse: 'W1', city: 'Paris' },
|
|
45
|
-
]);
|
|
46
|
-
const result = inventory.matching(shipments, ['warehouse', 'city']);
|
|
47
|
-
const expected = Bmg([
|
|
48
|
-
{ warehouse: 'W1', city: 'London', stock: 100 },
|
|
49
|
-
{ warehouse: 'W1', city: 'Paris', stock: 150 },
|
|
50
|
-
]);
|
|
51
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('supports explicit keys as { left: right }', () => {
|
|
55
|
-
const suppliers = Bmg([
|
|
56
|
-
{ sid: 'S1', city: 'London' },
|
|
57
|
-
{ sid: 'S2', city: 'Paris' },
|
|
58
|
-
]);
|
|
59
|
-
const cities = Bmg([{ location: 'London' }]);
|
|
60
|
-
const result = suppliers.matching(cities, { city: 'location' });
|
|
61
|
-
const expected = Bmg([{ sid: 'S1', city: 'London' }]);
|
|
62
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('supports multiple keys as { left1: right1, left2: right2 }', () => {
|
|
66
|
-
const people = Bmg([
|
|
67
|
-
{ id: 1, first: 'John', last: 'Doe' },
|
|
68
|
-
{ id: 2, first: 'Jane', last: 'Smith' },
|
|
69
|
-
{ id: 3, first: 'John', last: 'Smith' },
|
|
70
|
-
]);
|
|
71
|
-
const records = Bmg([
|
|
72
|
-
{ fname: 'John', lname: 'Doe' },
|
|
73
|
-
{ fname: 'Jane', lname: 'Smith' },
|
|
74
|
-
]);
|
|
75
|
-
const result = people.matching(records, { first: 'fname', last: 'lname' });
|
|
76
|
-
const expected = Bmg([
|
|
77
|
-
{ id: 1, first: 'John', last: 'Doe' },
|
|
78
|
-
{ id: 2, first: 'Jane', last: 'Smith' },
|
|
79
|
-
]);
|
|
80
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
///
|
|
84
|
-
|
|
85
|
-
it('can be used standalone', () => {
|
|
86
|
-
const res = matching(orders.toArray(), customers.toArray());
|
|
87
|
-
const expected = orders.matching(customers);
|
|
88
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
});
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { Bmg } from 'src';
|
|
3
|
-
import { minus , isEqual } from 'src/operators';
|
|
4
|
-
|
|
5
|
-
describe('.minus', () => {
|
|
6
|
-
|
|
7
|
-
const left = Bmg([
|
|
8
|
-
{ id: 1, name: 'Alice' },
|
|
9
|
-
{ id: 2, name: 'Bob' },
|
|
10
|
-
{ id: 3, name: 'Charlie' },
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
const right = Bmg([
|
|
14
|
-
{ id: 2, name: 'Bob' },
|
|
15
|
-
{ id: 4, name: 'Diana' },
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
it('returns tuples in left but not in right', () => {
|
|
19
|
-
const result = left.minus(right);
|
|
20
|
-
const expected = Bmg([
|
|
21
|
-
{ id: 1, name: 'Alice' },
|
|
22
|
-
{ id: 3, name: 'Charlie' },
|
|
23
|
-
]);
|
|
24
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('returns empty when left is subset of right', () => {
|
|
28
|
-
const small = Bmg([{ id: 2, name: 'Bob' }]);
|
|
29
|
-
const result = small.minus(right);
|
|
30
|
-
expect(result.isEqual(Bmg([]))).to.be.true;
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('returns all when no overlap', () => {
|
|
34
|
-
const other = Bmg([{ id: 99, name: 'Nobody' }]);
|
|
35
|
-
const result = left.minus(other);
|
|
36
|
-
expect(result.isEqual(left)).to.be.true;
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
///
|
|
40
|
-
|
|
41
|
-
it('can be used standalone', () => {
|
|
42
|
-
const res = minus(left.toArray(), right.toArray());
|
|
43
|
-
const expected = left.minus(right);
|
|
44
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
});
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { Bmg } from 'src';
|
|
3
|
-
import { not_matching , isEqual } from 'src/operators';
|
|
4
|
-
|
|
5
|
-
describe('.not_matching', () => {
|
|
6
|
-
|
|
7
|
-
const orders = Bmg([
|
|
8
|
-
{ oid: 1, customer_id: 'C1', amount: 100 },
|
|
9
|
-
{ oid: 2, customer_id: 'C2', amount: 200 },
|
|
10
|
-
{ oid: 3, customer_id: 'C3', amount: 150 },
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
const customers = Bmg([
|
|
14
|
-
{ customer_id: 'C1', name: 'Alice' },
|
|
15
|
-
{ customer_id: 'C2', name: 'Bob' },
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
it('returns tuples from left that do NOT match right', () => {
|
|
19
|
-
const result = orders.not_matching(customers);
|
|
20
|
-
const expected = Bmg([
|
|
21
|
-
{ oid: 3, customer_id: 'C3', amount: 150 },
|
|
22
|
-
]);
|
|
23
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('returns all when no matches', () => {
|
|
27
|
-
const empty = Bmg([{ customer_id: 'C99' }]);
|
|
28
|
-
const result = orders.not_matching(empty);
|
|
29
|
-
expect(result.isEqual(orders)).to.be.true;
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('returns empty when all match', () => {
|
|
33
|
-
const all = Bmg([
|
|
34
|
-
{ customer_id: 'C1' },
|
|
35
|
-
{ customer_id: 'C2' },
|
|
36
|
-
{ customer_id: 'C3' },
|
|
37
|
-
]);
|
|
38
|
-
const result = orders.not_matching(all);
|
|
39
|
-
expect(result.isEqual(Bmg([]))).to.be.true;
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('supports explicit keys as [common_attr]', () => {
|
|
43
|
-
const result = orders.not_matching(customers, ['customer_id']);
|
|
44
|
-
const expected = Bmg([
|
|
45
|
-
{ oid: 3, customer_id: 'C3', amount: 150 },
|
|
46
|
-
]);
|
|
47
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('supports multiple keys as [attr1, attr2]', () => {
|
|
51
|
-
const inventory = Bmg([
|
|
52
|
-
{ warehouse: 'W1', city: 'London', stock: 100 },
|
|
53
|
-
{ warehouse: 'W2', city: 'London', stock: 200 },
|
|
54
|
-
{ warehouse: 'W1', city: 'Paris', stock: 150 },
|
|
55
|
-
]);
|
|
56
|
-
const shipments = Bmg([
|
|
57
|
-
{ warehouse: 'W1', city: 'London' },
|
|
58
|
-
]);
|
|
59
|
-
const result = inventory.not_matching(shipments, ['warehouse', 'city']);
|
|
60
|
-
const expected = Bmg([
|
|
61
|
-
{ warehouse: 'W2', city: 'London', stock: 200 },
|
|
62
|
-
{ warehouse: 'W1', city: 'Paris', stock: 150 },
|
|
63
|
-
]);
|
|
64
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('supports explicit keys as { left: right }', () => {
|
|
68
|
-
const suppliers = Bmg([
|
|
69
|
-
{ sid: 'S1', city: 'London' },
|
|
70
|
-
{ sid: 'S2', city: 'Paris' },
|
|
71
|
-
{ sid: 'S3', city: 'Athens' },
|
|
72
|
-
]);
|
|
73
|
-
const cities = Bmg([{ location: 'London' }, { location: 'Paris' }]);
|
|
74
|
-
const result = suppliers.not_matching(cities, { city: 'location' });
|
|
75
|
-
const expected = Bmg([{ sid: 'S3', city: 'Athens' }]);
|
|
76
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('supports multiple keys as { left1: right1, left2: right2 }', () => {
|
|
80
|
-
const people = Bmg([
|
|
81
|
-
{ id: 1, first: 'John', last: 'Doe' },
|
|
82
|
-
{ id: 2, first: 'Jane', last: 'Smith' },
|
|
83
|
-
{ id: 3, first: 'John', last: 'Smith' },
|
|
84
|
-
]);
|
|
85
|
-
const records = Bmg([
|
|
86
|
-
{ fname: 'John', lname: 'Doe' },
|
|
87
|
-
{ fname: 'Jane', lname: 'Smith' },
|
|
88
|
-
]);
|
|
89
|
-
const result = people.not_matching(records, { first: 'fname', last: 'lname' });
|
|
90
|
-
const expected = Bmg([
|
|
91
|
-
{ id: 3, first: 'John', last: 'Smith' },
|
|
92
|
-
]);
|
|
93
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
///
|
|
97
|
-
|
|
98
|
-
it('can be used standalone', () => {
|
|
99
|
-
const res = not_matching(orders.toArray(), customers.toArray());
|
|
100
|
-
const expected = orders.not_matching(customers);
|
|
101
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { SUPPLIERS } from 'tests/fixtures';
|
|
3
|
-
import { one } from 'src/operators';
|
|
4
|
-
|
|
5
|
-
describe('.one', () => {
|
|
6
|
-
|
|
7
|
-
it('is available on relations', () => {
|
|
8
|
-
expect(typeof SUPPLIERS.one).to.eql('function')
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
///
|
|
12
|
-
|
|
13
|
-
it('can be used standalone', () => {
|
|
14
|
-
const tuple = { sid: 'S1' }
|
|
15
|
-
const tuples = [tuple]
|
|
16
|
-
expect(one(tuples)).to.eql(tuple)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { Bmg } from 'src';
|
|
3
|
-
import { SUPPLIERS } from 'tests/fixtures';
|
|
4
|
-
import { prefix , isEqual } from 'src/operators';
|
|
5
|
-
|
|
6
|
-
describe('.prefix', () => {
|
|
7
|
-
|
|
8
|
-
it('prefixes all attribute names', () => {
|
|
9
|
-
const prefixed = SUPPLIERS.prefix('supplier_');
|
|
10
|
-
const expected = Bmg([
|
|
11
|
-
{supplier_sid: 'S1', supplier_name: 'Smith', supplier_status: 20, supplier_city: 'London' },
|
|
12
|
-
{supplier_sid: 'S2', supplier_name: 'Jones', supplier_status: 10, supplier_city: 'Paris' },
|
|
13
|
-
{supplier_sid: 'S3', supplier_name: 'Blake', supplier_status: 30, supplier_city: 'Paris' },
|
|
14
|
-
{supplier_sid: 'S4', supplier_name: 'Clark', supplier_status: 20, supplier_city: 'London' },
|
|
15
|
-
{supplier_sid: 'S5', supplier_name: 'Adams', supplier_status: 30, supplier_city: 'Athens' },
|
|
16
|
-
]);
|
|
17
|
-
expect(prefixed.isEqual(expected)).to.be.true;
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('can exclude specific attributes', () => {
|
|
21
|
-
const prefixed = SUPPLIERS.prefix('s_', { except: ['sid'] });
|
|
22
|
-
const smith = prefixed.restrict({sid: 'S1'}).one();
|
|
23
|
-
expect(smith).to.have.property('sid', 'S1');
|
|
24
|
-
expect(smith).to.have.property('s_name', 'Smith');
|
|
25
|
-
expect(smith).to.have.property('s_city', 'London');
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
///
|
|
29
|
-
|
|
30
|
-
it('can be used standalone', () => {
|
|
31
|
-
const input = SUPPLIERS.toArray();
|
|
32
|
-
const res = prefix(input, 'x_');
|
|
33
|
-
const expected = SUPPLIERS.prefix('x_');
|
|
34
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { Bmg } from 'src';
|
|
3
|
-
import { SUPPLIERS } from 'tests/fixtures';
|
|
4
|
-
import { project , isEqual } from 'src/operators';
|
|
5
|
-
|
|
6
|
-
describe('.project', () => {
|
|
7
|
-
|
|
8
|
-
it('keeps only specified attributes', () => {
|
|
9
|
-
const result = SUPPLIERS.project(['name', 'city']);
|
|
10
|
-
const expected = Bmg([
|
|
11
|
-
{ name: 'Smith', city: 'London' },
|
|
12
|
-
{ name: 'Jones', city: 'Paris' },
|
|
13
|
-
{ name: 'Blake', city: 'Paris' },
|
|
14
|
-
{ name: 'Clark', city: 'London' },
|
|
15
|
-
{ name: 'Adams', city: 'Athens' },
|
|
16
|
-
]);
|
|
17
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('removes duplicates (set semantics)', () => {
|
|
21
|
-
// Projecting to 'city' only should yield 3 unique cities, not 5 tuples
|
|
22
|
-
const result = SUPPLIERS.project(['city']);
|
|
23
|
-
const expected = Bmg([
|
|
24
|
-
{ city: 'London' },
|
|
25
|
-
{ city: 'Paris' },
|
|
26
|
-
{ city: 'Athens' },
|
|
27
|
-
]);
|
|
28
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('ignores missing attributes', () => {
|
|
32
|
-
// @ts-expect-error - testing runtime behavior with invalid attribute
|
|
33
|
-
const result = SUPPLIERS.project(['name', 'nonexistent']);
|
|
34
|
-
const smith = result.restrict({ name: 'Smith' }).one();
|
|
35
|
-
expect(smith).to.have.property('name');
|
|
36
|
-
expect(smith).to.not.have.property('nonexistent');
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
///
|
|
40
|
-
|
|
41
|
-
it('can be used standalone', () => {
|
|
42
|
-
const input = SUPPLIERS.toArray();
|
|
43
|
-
const res = project(input, ['name', 'city']);
|
|
44
|
-
const expected = SUPPLIERS.project(['name', 'city']);
|
|
45
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { Bmg } from 'src';
|
|
3
|
-
import { SUPPLIERS } from 'tests/fixtures';
|
|
4
|
-
import { rename , isEqual } from 'src/operators';
|
|
5
|
-
|
|
6
|
-
describe('.rename', () => {
|
|
7
|
-
|
|
8
|
-
const renaming = {sid: 'id', name: 'lastname'}
|
|
9
|
-
|
|
10
|
-
it('allows renaming relation tuples', () => {
|
|
11
|
-
const renamed = SUPPLIERS.rename(renaming);
|
|
12
|
-
const expected = Bmg([
|
|
13
|
-
{id: 'S1', lastname: 'Smith', status: 20, city: 'London' },
|
|
14
|
-
{id: 'S2', lastname: 'Jones', status: 10, city: 'Paris' },
|
|
15
|
-
{id: 'S3', lastname: 'Blake', status: 30, city: 'Paris' },
|
|
16
|
-
{id: 'S4', lastname: 'Clark', status: 20, city: 'London' },
|
|
17
|
-
{id: 'S5', lastname: 'Adams', status: 30, city: 'Athens' },
|
|
18
|
-
]);
|
|
19
|
-
expect(renamed.isEqual(expected)).to.be.true;
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
///
|
|
23
|
-
|
|
24
|
-
it('can be used standalone', () => {
|
|
25
|
-
const input = SUPPLIERS.toArray();
|
|
26
|
-
const res = rename(input, renaming);
|
|
27
|
-
const expected = SUPPLIERS.rename(renaming);
|
|
28
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('supports a pure function', () => {
|
|
32
|
-
const input = SUPPLIERS.toArray();
|
|
33
|
-
const renamed = rename(input, (attr) => attr.toUpperCase()) as any[];
|
|
34
|
-
const smith = Bmg(renamed).restrict({ SID: 'S1' }).one();
|
|
35
|
-
const keys = Object.keys(smith).sort();
|
|
36
|
-
expect(keys).to.eql(['CITY', 'NAME', 'SID', 'STATUS']);
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
});
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { SUPPLIERS } from 'tests/fixtures';
|
|
4
|
-
import { restrict , isEqual } from 'src/operators';
|
|
5
|
-
|
|
6
|
-
describe('.restrict', () => {
|
|
7
|
-
|
|
8
|
-
it('allows filtering relations', () => {
|
|
9
|
-
const smith = SUPPLIERS.restrict((t) => t.sid === 'S1').one()
|
|
10
|
-
expect(smith.name).to.eql('Smith')
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('has a tuple shortcut', () => {
|
|
14
|
-
const smith = SUPPLIERS.restrict({sid: 'S1'}).one()
|
|
15
|
-
expect(smith.name).to.eql('Smith')
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
///
|
|
19
|
-
|
|
20
|
-
it('can be used standalone', () => {
|
|
21
|
-
const input = SUPPLIERS.toArray();
|
|
22
|
-
const res = restrict(input, { sid: 'S1' });
|
|
23
|
-
const expected = SUPPLIERS.restrict({ sid: 'S1' });
|
|
24
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { Bmg } from 'src';
|
|
3
|
-
import { SUPPLIERS } from 'tests/fixtures';
|
|
4
|
-
import { suffix , isEqual } from 'src/operators';
|
|
5
|
-
|
|
6
|
-
describe('.suffix', () => {
|
|
7
|
-
|
|
8
|
-
it('suffixes all attribute names', () => {
|
|
9
|
-
const suffixed = SUPPLIERS.suffix('_s');
|
|
10
|
-
const expected = Bmg([
|
|
11
|
-
{sid_s: 'S1', name_s: 'Smith', status_s: 20, city_s: 'London' },
|
|
12
|
-
{sid_s: 'S2', name_s: 'Jones', status_s: 10, city_s: 'Paris' },
|
|
13
|
-
{sid_s: 'S3', name_s: 'Blake', status_s: 30, city_s: 'Paris' },
|
|
14
|
-
{sid_s: 'S4', name_s: 'Clark', status_s: 20, city_s: 'London' },
|
|
15
|
-
{sid_s: 'S5', name_s: 'Adams', status_s: 30, city_s: 'Athens' },
|
|
16
|
-
]);
|
|
17
|
-
expect(suffixed.isEqual(expected)).to.be.true;
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('can exclude specific attributes', () => {
|
|
21
|
-
const suffixed = SUPPLIERS.suffix('_x', { except: ['sid'] });
|
|
22
|
-
const smith = suffixed.restrict({sid: 'S1'}).one();
|
|
23
|
-
expect(smith).to.have.property('sid', 'S1');
|
|
24
|
-
expect(smith).to.have.property('name_x', 'Smith');
|
|
25
|
-
expect(smith).to.have.property('city_x', 'London');
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
///
|
|
29
|
-
|
|
30
|
-
it('can be used standalone', () => {
|
|
31
|
-
const input = SUPPLIERS.toArray();
|
|
32
|
-
const res = suffix(input, '_y');
|
|
33
|
-
const expected = SUPPLIERS.suffix('_y');
|
|
34
|
-
expect(isEqual(res, expected)).to.be.true;
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
});
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { SUPPLIERS } from 'tests/fixtures';
|
|
3
|
-
import { Bmg } from 'src';
|
|
4
|
-
import { summarize, isEqual } from 'src/operators';
|
|
5
|
-
|
|
6
|
-
describe('.summarize', () => {
|
|
7
|
-
|
|
8
|
-
it('counts tuples per group', () => {
|
|
9
|
-
const result = SUPPLIERS.summarize(['city'], { count: 'count' });
|
|
10
|
-
const expected = Bmg([
|
|
11
|
-
{ city: 'London', count: 2 },
|
|
12
|
-
{ city: 'Paris', count: 2 },
|
|
13
|
-
{ city: 'Athens', count: 1 },
|
|
14
|
-
]);
|
|
15
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('sums values per group', () => {
|
|
19
|
-
const result = SUPPLIERS.summarize(['city'], {
|
|
20
|
-
totalStatus: { op: 'sum', attr: 'status' }
|
|
21
|
-
});
|
|
22
|
-
const expected = Bmg([
|
|
23
|
-
{ city: 'London', totalStatus: 40 }, // 20 + 20
|
|
24
|
-
{ city: 'Paris', totalStatus: 40 }, // 10 + 30
|
|
25
|
-
{ city: 'Athens', totalStatus: 30 },
|
|
26
|
-
]);
|
|
27
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it('computes min/max per group', () => {
|
|
31
|
-
const result = SUPPLIERS.summarize(['city'], {
|
|
32
|
-
minStatus: { op: 'min', attr: 'status' },
|
|
33
|
-
maxStatus: { op: 'max', attr: 'status' }
|
|
34
|
-
});
|
|
35
|
-
const expected = Bmg([
|
|
36
|
-
{ city: 'London', minStatus: 20, maxStatus: 20 },
|
|
37
|
-
{ city: 'Paris', minStatus: 10, maxStatus: 30 },
|
|
38
|
-
{ city: 'Athens', minStatus: 30, maxStatus: 30 },
|
|
39
|
-
]);
|
|
40
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('computes average per group', () => {
|
|
44
|
-
const result = SUPPLIERS.summarize(['city'], {
|
|
45
|
-
avgStatus: { op: 'avg', attr: 'status' }
|
|
46
|
-
});
|
|
47
|
-
const expected = Bmg([
|
|
48
|
-
{ city: 'London', avgStatus: 20 }, // (20 + 20) / 2
|
|
49
|
-
{ city: 'Paris', avgStatus: 20 }, // (10 + 30) / 2
|
|
50
|
-
{ city: 'Athens', avgStatus: 30 },
|
|
51
|
-
]);
|
|
52
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('collects values per group', () => {
|
|
56
|
-
const result = SUPPLIERS.summarize(['city'], {
|
|
57
|
-
names: { op: 'collect', attr: 'name' }
|
|
58
|
-
});
|
|
59
|
-
// collect returns arrays - check specific group
|
|
60
|
-
const paris = result.restrict({ city: 'Paris' }).one();
|
|
61
|
-
expect(paris.names).to.include('Jones');
|
|
62
|
-
expect(paris.names).to.include('Blake');
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('supports custom aggregator functions', () => {
|
|
66
|
-
const data = Bmg([
|
|
67
|
-
{ city: 'NYC', name: 'Alice' },
|
|
68
|
-
{ city: 'NYC', name: 'Bob' },
|
|
69
|
-
]);
|
|
70
|
-
const result = data.summarize(['city'], {
|
|
71
|
-
names: (tuples) => tuples.map(t => t.name).sort().join(', ')
|
|
72
|
-
});
|
|
73
|
-
const expected = Bmg([
|
|
74
|
-
{ city: 'NYC', names: 'Alice, Bob' }
|
|
75
|
-
]);
|
|
76
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('supports multiple group-by attributes', () => {
|
|
80
|
-
const data = Bmg([
|
|
81
|
-
{ a: 1, b: 'x', v: 10 },
|
|
82
|
-
{ a: 1, b: 'x', v: 20 },
|
|
83
|
-
{ a: 1, b: 'y', v: 30 },
|
|
84
|
-
{ a: 2, b: 'x', v: 40 },
|
|
85
|
-
]);
|
|
86
|
-
const result = data.summarize(['a', 'b'], { sum: { op: 'sum', attr: 'v' } });
|
|
87
|
-
const expected = Bmg([
|
|
88
|
-
{ a: 1, b: 'x', sum: 30 },
|
|
89
|
-
{ a: 1, b: 'y', sum: 30 },
|
|
90
|
-
{ a: 2, b: 'x', sum: 40 },
|
|
91
|
-
]);
|
|
92
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('handles empty by array (grand total)', () => {
|
|
96
|
-
const result = SUPPLIERS.summarize([], { total: 'count' });
|
|
97
|
-
const expected = Bmg([{ total: 5 }]);
|
|
98
|
-
expect(result.isEqual(expected)).to.be.true;
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
///
|
|
102
|
-
|
|
103
|
-
it('can be used standalone', () => {
|
|
104
|
-
const standalone = summarize(SUPPLIERS.toArray(), ['city'], { count: 'count' });
|
|
105
|
-
const expected = SUPPLIERS.summarize(['city'], { count: 'count' });
|
|
106
|
-
expect(isEqual(standalone, expected)).to.be.true;
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
});
|