relation-matcher 1.0.13 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +4 -4
- package/.yarn/install-state.gz +0 -0
- package/.yarn/releases/yarn-4.13.0.cjs +940 -940
- package/.yarnrc.yml +3 -3
- package/README.md +185 -150
- package/dist/src/index.d.ts +10 -5
- package/dist/src/index.js +35 -46
- package/dist/src/types/generic-bases.d.ts +2 -1
- package/dist/src/types/generic-less.d.ts +8 -3
- package/dist/src/types/inputs.d.ts +14 -7
- package/dist/src/types/return.d.ts +5 -2
- package/dist/src/types/typetest.d.ts +1 -0
- package/dist/src/types/utils.d.ts +3 -0
- package/dist/src/utils/invertInput.d.ts +2 -1
- package/dist/src/utils/invertInput.js +4 -9
- package/dist/src/utils/isNullable.d.ts +2 -0
- package/dist/src/utils/isNullable.js +6 -0
- package/dist/src/utils/joins.d.ts +5 -0
- package/dist/src/utils/joins.js +9 -0
- package/dist/src/utils/keys.js +6 -1
- package/dist/src/utils/matcher.d.ts +3 -3
- package/dist/src/utils/matcher.js +2 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +36 -36
- package/src/index.test.ts +105 -105
- package/src/index.ts +124 -151
- package/src/testing/file-output.ts +15 -15
- package/src/testing/test-data.ts +172 -172
- package/src/types/generic-bases.ts +10 -9
- package/src/types/generic-less.ts +20 -14
- package/src/types/index.ts +5 -5
- package/src/types/inputs.ts +36 -30
- package/src/types/return.ts +65 -67
- package/src/types/typetest.ts +87 -84
- package/src/types/utils.ts +33 -28
- package/src/utils/invertInput.ts +27 -28
- package/src/utils/isNullable.ts +11 -0
- package/src/utils/joins.ts +22 -0
- package/src/utils/keys.ts +7 -1
- package/src/utils/matcher.ts +16 -8
package/package.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "relation-matcher",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A utility to convert table data (such as out of a SQL query) into structured JSON.",
|
|
5
|
-
"license": "ISC",
|
|
6
|
-
"author": "",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"main": "dist/src/index.js",
|
|
9
|
-
"types": "dist/src/index.d.ts",
|
|
10
|
-
"exports": {
|
|
11
|
-
".": {
|
|
12
|
-
"default": "./dist/src/index.js",
|
|
13
|
-
"types": "./dist/src/index.d.ts"
|
|
14
|
-
},
|
|
15
|
-
"./types": {
|
|
16
|
-
"default": "./dist/src/types/index.js",
|
|
17
|
-
"types": "./dist/src/types/index.d.ts"
|
|
18
|
-
},
|
|
19
|
-
"./source": "./src/index.ts",
|
|
20
|
-
"./source/types": "./src/types/index.ts"
|
|
21
|
-
},
|
|
22
|
-
"scripts": {
|
|
23
|
-
"test": "jest && tsc --noEmit",
|
|
24
|
-
"file-output": "tsx --watch src/file-output.ts",
|
|
25
|
-
"build": "tsc",
|
|
26
|
-
"build:publish": "yarn run test && yarn run build && npm publish"
|
|
27
|
-
},
|
|
28
|
-
"packageManager": "yarn@4.13.0",
|
|
29
|
-
"devDependencies": {
|
|
30
|
-
"@types/jest": "^30.0.0",
|
|
31
|
-
"@types/node": "^25.0.10",
|
|
32
|
-
"jest": "^30.2.0",
|
|
33
|
-
"ts-jest": "^29.4.6",
|
|
34
|
-
"typescript": "^5.9.3"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "relation-matcher",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "A utility to convert table data (such as out of a SQL query) into structured JSON.",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/src/index.js",
|
|
9
|
+
"types": "dist/src/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"default": "./dist/src/index.js",
|
|
13
|
+
"types": "./dist/src/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./types": {
|
|
16
|
+
"default": "./dist/src/types/index.js",
|
|
17
|
+
"types": "./dist/src/types/index.d.ts"
|
|
18
|
+
},
|
|
19
|
+
"./source": "./src/index.ts",
|
|
20
|
+
"./source/types": "./src/types/index.ts"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"test": "jest && tsc --noEmit",
|
|
24
|
+
"file-output": "tsx --watch src/file-output.ts",
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"build:publish": "yarn run test && yarn run build && npm publish"
|
|
27
|
+
},
|
|
28
|
+
"packageManager": "yarn@4.13.0",
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/jest": "^30.0.0",
|
|
31
|
+
"@types/node": "^25.0.10",
|
|
32
|
+
"jest": "^30.2.0",
|
|
33
|
+
"ts-jest": "^29.4.6",
|
|
34
|
+
"typescript": "^5.9.3"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/index.test.ts
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
import { relationMatcherRoot } from ".";
|
|
2
|
-
import { testData, testSchema } from "./testing/test-data";
|
|
3
|
-
|
|
4
|
-
test("Tests output of mapper.", () => {
|
|
5
|
-
const relationMatcherData = relationMatcherRoot(testData, testSchema);
|
|
6
|
-
|
|
7
|
-
console.log(JSON.stringify(relationMatcherData, null, "\t"));
|
|
8
|
-
|
|
9
|
-
expect(relationMatcherData).toStrictEqual({
|
|
10
|
-
"c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01": {
|
|
11
|
-
id: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
12
|
-
clerkId: "user_abc123",
|
|
13
|
-
email: "alice@example.com",
|
|
14
|
-
createdAt: "2025-01-12T09:41:22.000Z",
|
|
15
|
-
|
|
16
|
-
teamToUsers: [
|
|
17
|
-
{
|
|
18
|
-
teamId: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
19
|
-
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
20
|
-
role: "admin",
|
|
21
|
-
team: {
|
|
22
|
-
id: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
23
|
-
name: "Red Dragons",
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
28
|
-
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
29
|
-
role: "member",
|
|
30
|
-
team: {
|
|
31
|
-
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
32
|
-
name: "Blue Sharks",
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
],
|
|
36
|
-
|
|
37
|
-
posts: [
|
|
38
|
-
{
|
|
39
|
-
id: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
40
|
-
title: "First post",
|
|
41
|
-
published: true,
|
|
42
|
-
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
43
|
-
comments: [
|
|
44
|
-
{
|
|
45
|
-
id: "9d1a7c3b-2f6a-4f7c-bf4b-8f6e3c5d9e01",
|
|
46
|
-
body: "Nice post!",
|
|
47
|
-
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
48
|
-
authorEmail: "bob@example.com",
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
id: "e3c9b5a2-7f42-4b7e-9e3d-4a6f1d8b2c44",
|
|
52
|
-
body: "Thanks for sharing",
|
|
53
|
-
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
54
|
-
authorEmail: "charlie@example.com",
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
id: "6bcb2b74-9b2f-4b38-bdb5-77c2e63d9c10",
|
|
60
|
-
title: "Second post",
|
|
61
|
-
published: false,
|
|
62
|
-
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
63
|
-
comments: [],
|
|
64
|
-
},
|
|
65
|
-
],
|
|
66
|
-
},
|
|
67
|
-
"f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55": {
|
|
68
|
-
id: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
69
|
-
clerkId: "user_xyz789",
|
|
70
|
-
email: "dave@example.com",
|
|
71
|
-
createdAt: "2025-02-03T14:18:10.000Z",
|
|
72
|
-
|
|
73
|
-
teamToUsers: [
|
|
74
|
-
{
|
|
75
|
-
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
76
|
-
userId: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
77
|
-
role: "admin",
|
|
78
|
-
team: {
|
|
79
|
-
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
80
|
-
name: "Blue Sharks",
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
|
|
85
|
-
posts: [],
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test("Tests empty input.", () => {
|
|
91
|
-
type InputRow = {
|
|
92
|
-
user: {
|
|
93
|
-
clerk_id: string;
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const input: InputRow[] = [];
|
|
98
|
-
|
|
99
|
-
expect(
|
|
100
|
-
relationMatcherRoot(input, {
|
|
101
|
-
base: "user",
|
|
102
|
-
id: "clerk_id",
|
|
103
|
-
}),
|
|
104
|
-
).toStrictEqual({});
|
|
105
|
-
});
|
|
1
|
+
import { relationMatcherRoot } from ".";
|
|
2
|
+
import { testData, testSchema } from "./testing/test-data";
|
|
3
|
+
|
|
4
|
+
test("Tests output of mapper.", () => {
|
|
5
|
+
const relationMatcherData = relationMatcherRoot(testData, testSchema);
|
|
6
|
+
|
|
7
|
+
console.log(JSON.stringify(relationMatcherData, null, "\t"));
|
|
8
|
+
|
|
9
|
+
expect(relationMatcherData).toStrictEqual({
|
|
10
|
+
"c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01": {
|
|
11
|
+
id: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
12
|
+
clerkId: "user_abc123",
|
|
13
|
+
email: "alice@example.com",
|
|
14
|
+
createdAt: "2025-01-12T09:41:22.000Z",
|
|
15
|
+
|
|
16
|
+
teamToUsers: [
|
|
17
|
+
{
|
|
18
|
+
teamId: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
19
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
20
|
+
role: "admin",
|
|
21
|
+
team: {
|
|
22
|
+
id: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
23
|
+
name: "Red Dragons",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
28
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
29
|
+
role: "member",
|
|
30
|
+
team: {
|
|
31
|
+
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
32
|
+
name: "Blue Sharks",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
|
|
37
|
+
posts: [
|
|
38
|
+
{
|
|
39
|
+
id: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
40
|
+
title: "First post",
|
|
41
|
+
published: true,
|
|
42
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
43
|
+
comments: [
|
|
44
|
+
{
|
|
45
|
+
id: "9d1a7c3b-2f6a-4f7c-bf4b-8f6e3c5d9e01",
|
|
46
|
+
body: "Nice post!",
|
|
47
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
48
|
+
authorEmail: "bob@example.com",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "e3c9b5a2-7f42-4b7e-9e3d-4a6f1d8b2c44",
|
|
52
|
+
body: "Thanks for sharing",
|
|
53
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
54
|
+
authorEmail: "charlie@example.com",
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "6bcb2b74-9b2f-4b38-bdb5-77c2e63d9c10",
|
|
60
|
+
title: "Second post",
|
|
61
|
+
published: false,
|
|
62
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
63
|
+
comments: [],
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
"f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55": {
|
|
68
|
+
id: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
69
|
+
clerkId: "user_xyz789",
|
|
70
|
+
email: "dave@example.com",
|
|
71
|
+
createdAt: "2025-02-03T14:18:10.000Z",
|
|
72
|
+
|
|
73
|
+
teamToUsers: [
|
|
74
|
+
{
|
|
75
|
+
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
76
|
+
userId: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
77
|
+
role: "admin",
|
|
78
|
+
team: {
|
|
79
|
+
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
80
|
+
name: "Blue Sharks",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
|
|
85
|
+
posts: [],
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("Tests empty input.", () => {
|
|
91
|
+
type InputRow = {
|
|
92
|
+
user: {
|
|
93
|
+
clerk_id: string;
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const input: InputRow[] = [];
|
|
98
|
+
|
|
99
|
+
expect(
|
|
100
|
+
relationMatcherRoot(input, {
|
|
101
|
+
base: "user",
|
|
102
|
+
id: "clerk_id",
|
|
103
|
+
}),
|
|
104
|
+
).toStrictEqual({});
|
|
105
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,151 +1,124 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
final[propertyKey] = {
|
|
127
|
-
...item,
|
|
128
|
-
...relationMatcherJoiner(input, value, item),
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
return final;
|
|
132
|
-
}, {}),
|
|
133
|
-
);
|
|
134
|
-
} else {
|
|
135
|
-
const item =
|
|
136
|
-
(input[value.base]!.find(matcherFunc) as
|
|
137
|
-
| InvertedInput[string][number]
|
|
138
|
-
| undefined) ?? null;
|
|
139
|
-
|
|
140
|
-
if (item) {
|
|
141
|
-
final[finalKey] = {
|
|
142
|
-
...item,
|
|
143
|
-
...relationMatcherJoiner(input, value, item),
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return final;
|
|
150
|
-
}, {});
|
|
151
|
-
};
|
|
1
|
+
import type { MaybeArray, MaybeNull, SRecord } from "./types";
|
|
2
|
+
import type { TInputBase, TInputBaseJoin } from "./types/generic-bases";
|
|
3
|
+
import type { Output, OutputRoot } from "./types/generic-less";
|
|
4
|
+
import type { RelationMapRoot as Root } from "./types/inputs";
|
|
5
|
+
import type { RelationMapperReturnRoot as ReturnRoot } from "./types/return";
|
|
6
|
+
import invertInput, { type InvertedInput } from "./utils/invertInput";
|
|
7
|
+
import { assertIsNullable } from "./utils/isNullable";
|
|
8
|
+
import { arrayJoinBase, singleJoinBase } from "./utils/joins";
|
|
9
|
+
import { getJoinFinalKey } from "./utils/keys";
|
|
10
|
+
import { createMatcherFunc } from "./utils/matcher";
|
|
11
|
+
|
|
12
|
+
export const relationMatcherRoot = <
|
|
13
|
+
TInput extends TInputBase,
|
|
14
|
+
TOutputRoot extends Root<TInput>,
|
|
15
|
+
>(
|
|
16
|
+
inputs: TInput[],
|
|
17
|
+
output: TOutputRoot,
|
|
18
|
+
): SRecord<ReturnRoot<TInput, TOutputRoot>> => {
|
|
19
|
+
if (!inputs.length) return {};
|
|
20
|
+
|
|
21
|
+
if (!Array.isArray(inputs)) {
|
|
22
|
+
throw new Error("Input must be an array.");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const invertedInput = invertInput<TInput>(inputs);
|
|
26
|
+
|
|
27
|
+
type BaseItems = SRecord<TInput[TOutputRoot["base"]]>;
|
|
28
|
+
const baseItems = invertedInput[output.base].reduce<BaseItems>(
|
|
29
|
+
(final, inputRow) => {
|
|
30
|
+
if (!inputRow) {
|
|
31
|
+
return final;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const relations = joiner(
|
|
35
|
+
invertedInput,
|
|
36
|
+
output as OutputRoot,
|
|
37
|
+
inputRow,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const rowId = inputRow[output.id as string];
|
|
41
|
+
|
|
42
|
+
final[rowId as string] = {
|
|
43
|
+
...inputRow,
|
|
44
|
+
...relations,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return final;
|
|
48
|
+
},
|
|
49
|
+
{},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return baseItems as unknown as Record<
|
|
53
|
+
string,
|
|
54
|
+
ReturnRoot<TInput, TOutputRoot>
|
|
55
|
+
>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const relationMatcher = relationMatcherRoot;
|
|
59
|
+
export default relationMatcherRoot;
|
|
60
|
+
|
|
61
|
+
const joiner = (
|
|
62
|
+
input: InvertedInput,
|
|
63
|
+
output: Output | OutputRoot,
|
|
64
|
+
joiningFrom: SRecord<unknown>,
|
|
65
|
+
) => {
|
|
66
|
+
type Return = SRecord<MaybeArray<MaybeNull<TInputBaseJoin>>>;
|
|
67
|
+
return Object.entries(output).reduce<Return>((final, [key, value]) => {
|
|
68
|
+
if (typeof value !== "object") return final;
|
|
69
|
+
|
|
70
|
+
const finalKey = getJoinFinalKey(key);
|
|
71
|
+
const matcherFunc = createMatcherFunc(joiningFrom, value);
|
|
72
|
+
|
|
73
|
+
const joinType = input[value.base];
|
|
74
|
+
|
|
75
|
+
if (!joinType)
|
|
76
|
+
throw new Error(`Input is missing rows for ${value.base}.`);
|
|
77
|
+
|
|
78
|
+
switch (value.joinType) {
|
|
79
|
+
case "array": {
|
|
80
|
+
const baseObjArr = arrayJoinBase(joinType, matcherFunc);
|
|
81
|
+
|
|
82
|
+
type FinalRow = SRecord<NonNullable<TInputBase[string]>>;
|
|
83
|
+
final[finalKey] = Object.values(
|
|
84
|
+
baseObjArr.reduce<FinalRow>((final, item) => {
|
|
85
|
+
const propertyKey = item[value.id] as string;
|
|
86
|
+
|
|
87
|
+
final[propertyKey] ??= {
|
|
88
|
+
...item,
|
|
89
|
+
...joiner(input, value, item),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return final;
|
|
93
|
+
}, {}),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "single": {
|
|
99
|
+
const item = singleJoinBase(joinType, matcherFunc);
|
|
100
|
+
|
|
101
|
+
assertIsNullable(item, value.isNullable);
|
|
102
|
+
|
|
103
|
+
if (item) {
|
|
104
|
+
final[finalKey] = {
|
|
105
|
+
...item,
|
|
106
|
+
...joiner(input, value, item),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
default: {
|
|
113
|
+
value.joinType satisfies never;
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Unhandled join type. Relation matcher can not handle ${value.joinType}.`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return final;
|
|
121
|
+
}, {});
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export { joiner as relationMatcherJoiner };
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import fs from "fs/promises";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { relationMatcherRoot } from "..";
|
|
4
|
-
import { testData, testSchema } from "./test-data";
|
|
5
|
-
|
|
6
|
-
const main = async () => {
|
|
7
|
-
const result = relationMatcherRoot(testData, testSchema);
|
|
8
|
-
|
|
9
|
-
await fs.writeFile(
|
|
10
|
-
path.join(process.cwd(), "/result.json"),
|
|
11
|
-
JSON.stringify(result, null, "\t"),
|
|
12
|
-
);
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
void main();
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { relationMatcherRoot } from "..";
|
|
4
|
+
import { testData, testSchema } from "./test-data";
|
|
5
|
+
|
|
6
|
+
const main = async () => {
|
|
7
|
+
const result = relationMatcherRoot(testData, testSchema);
|
|
8
|
+
|
|
9
|
+
await fs.writeFile(
|
|
10
|
+
path.join(process.cwd(), "/result.json"),
|
|
11
|
+
JSON.stringify(result, null, "\t"),
|
|
12
|
+
);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
void main();
|