relation-matcher 1.0.3
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/.prettierrc +4 -0
- package/.vscode/settings.json +3 -0
- package/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +1 -0
- package/dist/dist/jest.config.js +10 -0
- package/dist/dist/src/index.js +107 -0
- package/dist/dist/src/index.test.js +81 -0
- package/dist/dist/src/testing/file-output.js +9 -0
- package/dist/dist/src/testing/test-data.js +164 -0
- package/dist/dist/src/types/generic-bases.js +1 -0
- package/dist/dist/src/types/generic-less.js +1 -0
- package/dist/dist/src/types/inputs.js +1 -0
- package/dist/dist/src/types/return.js +1 -0
- package/dist/dist/src/types/typetest.js +6 -0
- package/dist/dist/src/types/utils.js +1 -0
- package/dist/dist/src/utils/invertInput.js +17 -0
- package/dist/dist/src/utils/keys.js +1 -0
- package/dist/dist/src/utils/matcher.js +1 -0
- package/dist/jest.config.js +10 -0
- package/dist/src/index.js +107 -0
- package/dist/src/index.test.js +81 -0
- package/dist/src/testing/file-output.js +9 -0
- package/dist/src/testing/test-data.js +164 -0
- package/dist/src/types/generic-bases.js +1 -0
- package/dist/src/types/generic-less.js +1 -0
- package/dist/src/types/inputs.js +1 -0
- package/dist/src/types/return.js +1 -0
- package/dist/src/types/typetest.js +6 -0
- package/dist/src/types/utils.js +1 -0
- package/dist/src/utils/invertInput.js +17 -0
- package/dist/src/utils/keys.js +1 -0
- package/dist/src/utils/matcher.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/jest.config.js +12 -0
- package/package.json +25 -0
- package/result.json +136 -0
- package/src/index.test.ts +88 -0
- package/src/index.ts +184 -0
- package/src/testing/file-output.ts +15 -0
- package/src/testing/test-data.ts +171 -0
- package/src/types/generic-bases.ts +9 -0
- package/src/types/generic-less.ts +14 -0
- package/src/types/inputs.ts +29 -0
- package/src/types/return.ts +37 -0
- package/src/types/typetest.ts +46 -0
- package/src/types/utils.ts +16 -0
- package/src/utils/invertInput.ts +28 -0
- package/src/utils/keys.ts +1 -0
- package/src/utils/matcher.ts +8 -0
- package/tsconfig.json +36 -0
package/.prettierrc
ADDED
|
Binary file
|
package/.yarnrc.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nodeLinker: node-modules
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createDefaultPreset } from "ts-jest";
|
|
2
|
+
const tsJestTransformCfg = createDefaultPreset().transform;
|
|
3
|
+
/** @type {import("jest").Config} **/
|
|
4
|
+
export default {
|
|
5
|
+
preset: "ts-jest",
|
|
6
|
+
testEnvironment: "node",
|
|
7
|
+
transform: {
|
|
8
|
+
...tsJestTransformCfg,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import invertInput, {} from "./utils/invertInput";
|
|
2
|
+
import { getJoinFinalKey } from "./utils/keys";
|
|
3
|
+
import { matcherFunc } from "./utils/matcher";
|
|
4
|
+
export const relationMatcherRoot = (inputs, output) => {
|
|
5
|
+
const invertedInput = invertInput(inputs);
|
|
6
|
+
const baseItems = invertedInput[output.base].reduce((final, row) => {
|
|
7
|
+
if (!row) {
|
|
8
|
+
return final;
|
|
9
|
+
}
|
|
10
|
+
// if (final[row[output.id as string] as string]) {
|
|
11
|
+
// return final;
|
|
12
|
+
// }
|
|
13
|
+
const relations = Object.entries(output).reduce((final, [key, value]) => {
|
|
14
|
+
// Filters out base parameters so value is only joins;
|
|
15
|
+
// value will be similar to { base: "team_to_user"; joinsTo: "team_id"; joinsFrom: "id"; joinType: "single"; }
|
|
16
|
+
if (typeof value === "object") {
|
|
17
|
+
const finalKey = getJoinFinalKey(key);
|
|
18
|
+
if (value.joinType === "array") {
|
|
19
|
+
const baseObjArr = invertedInput[value.base].filter(matcherFunc(row, value));
|
|
20
|
+
final[finalKey] = Object.values(baseObjArr.reduce((final, item) => {
|
|
21
|
+
if (!item
|
|
22
|
+
// final[item[value.id as string] as string]
|
|
23
|
+
)
|
|
24
|
+
return final;
|
|
25
|
+
// if (!item[value.joinsFrom as string]) {
|
|
26
|
+
console.log(item, value.joinsFrom);
|
|
27
|
+
// }
|
|
28
|
+
final[item[value.id]] = {
|
|
29
|
+
...item,
|
|
30
|
+
...relationMatcherJoiner(invertedInput, value, item),
|
|
31
|
+
};
|
|
32
|
+
return final;
|
|
33
|
+
}, {}));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const item = invertedInput[value.base].find(matcherFunc(row, value)) ?? null;
|
|
37
|
+
if (item) {
|
|
38
|
+
final[finalKey] = {
|
|
39
|
+
...item,
|
|
40
|
+
...relationMatcherJoiner(invertedInput, value, item),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// if (value.joinType === 'array')
|
|
45
|
+
// final[finalKey] = relationMatcherJoiner(
|
|
46
|
+
// invertedInput,
|
|
47
|
+
// value as Output,
|
|
48
|
+
// row[value.joinsFrom as string] as string,
|
|
49
|
+
// );
|
|
50
|
+
}
|
|
51
|
+
return final;
|
|
52
|
+
}, {});
|
|
53
|
+
final[row[output.id]] = { ...row, ...relations };
|
|
54
|
+
return final;
|
|
55
|
+
}, {});
|
|
56
|
+
return baseItems;
|
|
57
|
+
};
|
|
58
|
+
export const relationMatcher = relationMatcherRoot;
|
|
59
|
+
export default relationMatcherRoot;
|
|
60
|
+
const relationMatcherJoiner = (input, output, joiningFrom) => {
|
|
61
|
+
return Object.entries(output).reduce((final, [key, value]) => {
|
|
62
|
+
if (typeof value === "object") {
|
|
63
|
+
// console.log(value.base);
|
|
64
|
+
const finalKey = key.replace(/^_/, "");
|
|
65
|
+
const matcherFunc = (item) => item?.[value.joinsTo] === joiningFrom[value.joinsFrom];
|
|
66
|
+
if (value.joinType === "array") {
|
|
67
|
+
const baseObjArr = input[value.base].filter(matcherFunc);
|
|
68
|
+
// console.log("BaseObjArr:", baseObjArr);
|
|
69
|
+
// console.log(
|
|
70
|
+
// "input[value.base]:",
|
|
71
|
+
// input[value.base]?.[0]?.[value.joinsTo],
|
|
72
|
+
// );
|
|
73
|
+
// console.log("joiningId", joiningId);
|
|
74
|
+
final[finalKey] = Object.values(baseObjArr.reduce((final, item) => {
|
|
75
|
+
if (!item)
|
|
76
|
+
return final;
|
|
77
|
+
const propertyKey = item[value.id];
|
|
78
|
+
if (final[propertyKey])
|
|
79
|
+
return final;
|
|
80
|
+
final[propertyKey] = {
|
|
81
|
+
...item,
|
|
82
|
+
...relationMatcherJoiner(input, value, item),
|
|
83
|
+
};
|
|
84
|
+
return final;
|
|
85
|
+
}, {}));
|
|
86
|
+
// baseObjArr.map(item => (item ? {
|
|
87
|
+
// ...item,
|
|
88
|
+
// ...relationMatcherJoiner(input, value, item[value.joinsFrom as keyof TInputBase])
|
|
89
|
+
// } : null))
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
const item = input[value.base].find(matcherFunc) ?? null;
|
|
93
|
+
// console.log("item:", item);
|
|
94
|
+
// console.log("input[value.base]:", input[value.base]);
|
|
95
|
+
// console.log("joiningId:", joiningId);
|
|
96
|
+
// console.log("value:", value);
|
|
97
|
+
if (item) {
|
|
98
|
+
final[finalKey] = {
|
|
99
|
+
...item,
|
|
100
|
+
...relationMatcherJoiner(input, value, item),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return final;
|
|
106
|
+
}, {});
|
|
107
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { relationMatcherRoot } from ".";
|
|
2
|
+
import { testData, testSchema } from "./testing/test-data";
|
|
3
|
+
test("Tests output of mapper.", () => {
|
|
4
|
+
const relationMatcherData = relationMatcherRoot(testData, testSchema);
|
|
5
|
+
console.log(JSON.stringify(relationMatcherData, null, "\t"));
|
|
6
|
+
expect(relationMatcherData).toStrictEqual({
|
|
7
|
+
"c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01": {
|
|
8
|
+
id: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
9
|
+
clerkId: "user_abc123",
|
|
10
|
+
email: "alice@example.com",
|
|
11
|
+
createdAt: "2025-01-12T09:41:22.000Z",
|
|
12
|
+
teamToUsers: [
|
|
13
|
+
{
|
|
14
|
+
teamId: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
15
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
16
|
+
role: "admin",
|
|
17
|
+
team: {
|
|
18
|
+
id: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
19
|
+
name: "Red Dragons",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
24
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
25
|
+
role: "member",
|
|
26
|
+
team: {
|
|
27
|
+
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
28
|
+
name: "Blue Sharks",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
posts: [
|
|
33
|
+
{
|
|
34
|
+
id: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
35
|
+
title: "First post",
|
|
36
|
+
published: true,
|
|
37
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
38
|
+
comments: [
|
|
39
|
+
{
|
|
40
|
+
id: "9d1a7c3b-2f6a-4f7c-bf4b-8f6e3c5d9e01",
|
|
41
|
+
body: "Nice post!",
|
|
42
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
43
|
+
authorEmail: "bob@example.com",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "e3c9b5a2-7f42-4b7e-9e3d-4a6f1d8b2c44",
|
|
47
|
+
body: "Thanks for sharing",
|
|
48
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
49
|
+
authorEmail: "charlie@example.com",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "6bcb2b74-9b2f-4b38-bdb5-77c2e63d9c10",
|
|
55
|
+
title: "Second post",
|
|
56
|
+
published: false,
|
|
57
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
58
|
+
comments: [],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
"f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55": {
|
|
63
|
+
id: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
64
|
+
clerkId: "user_xyz789",
|
|
65
|
+
email: "dave@example.com",
|
|
66
|
+
createdAt: "2025-02-03T14:18:10.000Z",
|
|
67
|
+
teamToUsers: [
|
|
68
|
+
{
|
|
69
|
+
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
70
|
+
userId: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
71
|
+
role: "admin",
|
|
72
|
+
team: {
|
|
73
|
+
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
74
|
+
name: "Blue Sharks",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
posts: [],
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { relationMatcherRoot } from "..";
|
|
4
|
+
import { testData, testSchema } from "./test-data";
|
|
5
|
+
const main = async () => {
|
|
6
|
+
const result = relationMatcherRoot(testData, testSchema);
|
|
7
|
+
await fs.writeFile(path.join(process.cwd(), "/result.json"), JSON.stringify(result, null, "\t"));
|
|
8
|
+
};
|
|
9
|
+
void main();
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
export const testData = [
|
|
2
|
+
{
|
|
3
|
+
users: {
|
|
4
|
+
id: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
5
|
+
clerkId: "user_abc123",
|
|
6
|
+
email: "alice@example.com",
|
|
7
|
+
createdAt: "2025-01-12T09:41:22.000Z",
|
|
8
|
+
},
|
|
9
|
+
teamToUser: {
|
|
10
|
+
teamId: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
11
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
12
|
+
role: "admin",
|
|
13
|
+
},
|
|
14
|
+
teams: {
|
|
15
|
+
id: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
16
|
+
name: "Red Dragons",
|
|
17
|
+
},
|
|
18
|
+
posts: {
|
|
19
|
+
id: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
20
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
21
|
+
title: "First post",
|
|
22
|
+
published: true,
|
|
23
|
+
},
|
|
24
|
+
comments: {
|
|
25
|
+
id: "9d1a7c3b-2f6a-4f7c-bf4b-8f6e3c5d9e01",
|
|
26
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
27
|
+
body: "Nice post!",
|
|
28
|
+
authorEmail: "bob@example.com",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
users: {
|
|
33
|
+
id: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
34
|
+
clerkId: "user_abc123",
|
|
35
|
+
email: "alice@example.com",
|
|
36
|
+
createdAt: "2025-01-12T09:41:22.000Z",
|
|
37
|
+
},
|
|
38
|
+
teamToUser: {
|
|
39
|
+
teamId: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
40
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
41
|
+
role: "admin",
|
|
42
|
+
},
|
|
43
|
+
teams: {
|
|
44
|
+
id: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
45
|
+
name: "Red Dragons",
|
|
46
|
+
},
|
|
47
|
+
posts: {
|
|
48
|
+
id: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
49
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
50
|
+
title: "First post",
|
|
51
|
+
published: true,
|
|
52
|
+
},
|
|
53
|
+
comments: {
|
|
54
|
+
id: "e3c9b5a2-7f42-4b7e-9e3d-4a6f1d8b2c44",
|
|
55
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
56
|
+
body: "Thanks for sharing",
|
|
57
|
+
authorEmail: "charlie@example.com",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
users: {
|
|
62
|
+
id: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
63
|
+
clerkId: "user_abc123",
|
|
64
|
+
email: "alice@example.com",
|
|
65
|
+
createdAt: "2025-01-12T09:41:22.000Z",
|
|
66
|
+
},
|
|
67
|
+
teamToUser: {
|
|
68
|
+
teamId: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
69
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
70
|
+
role: "admin",
|
|
71
|
+
},
|
|
72
|
+
teams: {
|
|
73
|
+
id: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
74
|
+
name: "Red Dragons",
|
|
75
|
+
},
|
|
76
|
+
posts: {
|
|
77
|
+
id: "6bcb2b74-9b2f-4b38-bdb5-77c2e63d9c10",
|
|
78
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
79
|
+
title: "Second post",
|
|
80
|
+
published: false,
|
|
81
|
+
},
|
|
82
|
+
comments: null,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
users: {
|
|
86
|
+
id: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
87
|
+
clerkId: "user_abc123",
|
|
88
|
+
email: "alice@example.com",
|
|
89
|
+
createdAt: "2025-01-12T09:41:22.000Z",
|
|
90
|
+
},
|
|
91
|
+
teamToUser: {
|
|
92
|
+
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
93
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
94
|
+
role: "member",
|
|
95
|
+
},
|
|
96
|
+
teams: {
|
|
97
|
+
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
98
|
+
name: "Blue Sharks",
|
|
99
|
+
},
|
|
100
|
+
posts: {
|
|
101
|
+
id: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
102
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
103
|
+
title: "First post",
|
|
104
|
+
published: true,
|
|
105
|
+
},
|
|
106
|
+
comments: {
|
|
107
|
+
id: "9d1a7c3b-2f6a-4f7c-bf4b-8f6e3c5d9e01",
|
|
108
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
109
|
+
body: "Nice post!",
|
|
110
|
+
authorEmail: "bob@example.com",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
users: {
|
|
115
|
+
id: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
116
|
+
clerkId: "user_xyz789",
|
|
117
|
+
email: "dave@example.com",
|
|
118
|
+
createdAt: "2025-02-03T14:18:10.000Z",
|
|
119
|
+
},
|
|
120
|
+
teamToUser: {
|
|
121
|
+
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
122
|
+
userId: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
123
|
+
role: "admin",
|
|
124
|
+
},
|
|
125
|
+
teams: {
|
|
126
|
+
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
127
|
+
name: "Blue Sharks",
|
|
128
|
+
},
|
|
129
|
+
posts: null,
|
|
130
|
+
comments: null,
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
export const testSchema = {
|
|
134
|
+
base: "users",
|
|
135
|
+
id: "id",
|
|
136
|
+
_teamToUsers: {
|
|
137
|
+
base: "teamToUser",
|
|
138
|
+
id: "teamId",
|
|
139
|
+
joinsFrom: "id",
|
|
140
|
+
joinsTo: "userId",
|
|
141
|
+
joinType: "array",
|
|
142
|
+
_team: {
|
|
143
|
+
base: "teams",
|
|
144
|
+
id: "id",
|
|
145
|
+
joinsFrom: "teamId",
|
|
146
|
+
joinsTo: "id",
|
|
147
|
+
joinType: "single",
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
_posts: {
|
|
151
|
+
base: "posts",
|
|
152
|
+
id: "id",
|
|
153
|
+
joinsFrom: "id",
|
|
154
|
+
joinsTo: "userId",
|
|
155
|
+
joinType: "array",
|
|
156
|
+
_comments: {
|
|
157
|
+
base: "comments",
|
|
158
|
+
id: "id",
|
|
159
|
+
joinsFrom: "id",
|
|
160
|
+
joinsTo: "postId",
|
|
161
|
+
joinType: "array",
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const invertInput = (inputs) => {
|
|
2
|
+
const invertedInput = inputs.reduce((final, row) => {
|
|
3
|
+
Object.entries(row).forEach(([header, value]) => {
|
|
4
|
+
if (!value)
|
|
5
|
+
return;
|
|
6
|
+
if (final[header]) {
|
|
7
|
+
final[header].push(value);
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
final[header] = [value];
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
return final;
|
|
14
|
+
}, {});
|
|
15
|
+
return invertedInput;
|
|
16
|
+
};
|
|
17
|
+
export default invertInput;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const getJoinFinalKey = (key) => key.substring(1);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const matcherFunc = (row, value) => (item) => row?.[value.joinsFrom] === item?.[value.joinsTo];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createDefaultPreset } from "ts-jest";
|
|
2
|
+
const tsJestTransformCfg = createDefaultPreset().transform;
|
|
3
|
+
/** @type {import("jest").Config} **/
|
|
4
|
+
export default {
|
|
5
|
+
preset: "ts-jest",
|
|
6
|
+
testEnvironment: "node",
|
|
7
|
+
transform: {
|
|
8
|
+
...tsJestTransformCfg,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import invertInput, {} from "./utils/invertInput";
|
|
2
|
+
import { getJoinFinalKey } from "./utils/keys";
|
|
3
|
+
import { matcherFunc } from "./utils/matcher";
|
|
4
|
+
export const relationMatcherRoot = (inputs, output) => {
|
|
5
|
+
const invertedInput = invertInput(inputs);
|
|
6
|
+
const baseItems = invertedInput[output.base].reduce((final, row) => {
|
|
7
|
+
if (!row) {
|
|
8
|
+
return final;
|
|
9
|
+
}
|
|
10
|
+
// if (final[row[output.id as string] as string]) {
|
|
11
|
+
// return final;
|
|
12
|
+
// }
|
|
13
|
+
const relations = Object.entries(output).reduce((final, [key, value]) => {
|
|
14
|
+
// Filters out base parameters so value is only joins;
|
|
15
|
+
// value will be similar to { base: "team_to_user"; joinsTo: "team_id"; joinsFrom: "id"; joinType: "single"; }
|
|
16
|
+
if (typeof value === "object") {
|
|
17
|
+
const finalKey = getJoinFinalKey(key);
|
|
18
|
+
if (value.joinType === "array") {
|
|
19
|
+
const baseObjArr = invertedInput[value.base].filter(matcherFunc(row, value));
|
|
20
|
+
final[finalKey] = Object.values(baseObjArr.reduce((final, item) => {
|
|
21
|
+
if (!item
|
|
22
|
+
// final[item[value.id as string] as string]
|
|
23
|
+
)
|
|
24
|
+
return final;
|
|
25
|
+
// if (!item[value.joinsFrom as string]) {
|
|
26
|
+
console.log(item, value.joinsFrom);
|
|
27
|
+
// }
|
|
28
|
+
final[item[value.id]] = {
|
|
29
|
+
...item,
|
|
30
|
+
...relationMatcherJoiner(invertedInput, value, item),
|
|
31
|
+
};
|
|
32
|
+
return final;
|
|
33
|
+
}, {}));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const item = invertedInput[value.base].find(matcherFunc(row, value)) ?? null;
|
|
37
|
+
if (item) {
|
|
38
|
+
final[finalKey] = {
|
|
39
|
+
...item,
|
|
40
|
+
...relationMatcherJoiner(invertedInput, value, item),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// if (value.joinType === 'array')
|
|
45
|
+
// final[finalKey] = relationMatcherJoiner(
|
|
46
|
+
// invertedInput,
|
|
47
|
+
// value as Output,
|
|
48
|
+
// row[value.joinsFrom as string] as string,
|
|
49
|
+
// );
|
|
50
|
+
}
|
|
51
|
+
return final;
|
|
52
|
+
}, {});
|
|
53
|
+
final[row[output.id]] = { ...row, ...relations };
|
|
54
|
+
return final;
|
|
55
|
+
}, {});
|
|
56
|
+
return baseItems;
|
|
57
|
+
};
|
|
58
|
+
export const relationMatcher = relationMatcherRoot;
|
|
59
|
+
export default relationMatcherRoot;
|
|
60
|
+
const relationMatcherJoiner = (input, output, joiningFrom) => {
|
|
61
|
+
return Object.entries(output).reduce((final, [key, value]) => {
|
|
62
|
+
if (typeof value === "object") {
|
|
63
|
+
// console.log(value.base);
|
|
64
|
+
const finalKey = key.replace(/^_/, "");
|
|
65
|
+
const matcherFunc = (item) => item?.[value.joinsTo] === joiningFrom[value.joinsFrom];
|
|
66
|
+
if (value.joinType === "array") {
|
|
67
|
+
const baseObjArr = input[value.base].filter(matcherFunc);
|
|
68
|
+
// console.log("BaseObjArr:", baseObjArr);
|
|
69
|
+
// console.log(
|
|
70
|
+
// "input[value.base]:",
|
|
71
|
+
// input[value.base]?.[0]?.[value.joinsTo],
|
|
72
|
+
// );
|
|
73
|
+
// console.log("joiningId", joiningId);
|
|
74
|
+
final[finalKey] = Object.values(baseObjArr.reduce((final, item) => {
|
|
75
|
+
if (!item)
|
|
76
|
+
return final;
|
|
77
|
+
const propertyKey = item[value.id];
|
|
78
|
+
if (final[propertyKey])
|
|
79
|
+
return final;
|
|
80
|
+
final[propertyKey] = {
|
|
81
|
+
...item,
|
|
82
|
+
...relationMatcherJoiner(input, value, item),
|
|
83
|
+
};
|
|
84
|
+
return final;
|
|
85
|
+
}, {}));
|
|
86
|
+
// baseObjArr.map(item => (item ? {
|
|
87
|
+
// ...item,
|
|
88
|
+
// ...relationMatcherJoiner(input, value, item[value.joinsFrom as keyof TInputBase])
|
|
89
|
+
// } : null))
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
const item = input[value.base].find(matcherFunc) ?? null;
|
|
93
|
+
// console.log("item:", item);
|
|
94
|
+
// console.log("input[value.base]:", input[value.base]);
|
|
95
|
+
// console.log("joiningId:", joiningId);
|
|
96
|
+
// console.log("value:", value);
|
|
97
|
+
if (item) {
|
|
98
|
+
final[finalKey] = {
|
|
99
|
+
...item,
|
|
100
|
+
...relationMatcherJoiner(input, value, item),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return final;
|
|
106
|
+
}, {});
|
|
107
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { relationMatcherRoot } from ".";
|
|
2
|
+
import { testData, testSchema } from "./testing/test-data";
|
|
3
|
+
test("Tests output of mapper.", () => {
|
|
4
|
+
const relationMatcherData = relationMatcherRoot(testData, testSchema);
|
|
5
|
+
console.log(JSON.stringify(relationMatcherData, null, "\t"));
|
|
6
|
+
expect(relationMatcherData).toStrictEqual({
|
|
7
|
+
"c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01": {
|
|
8
|
+
id: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
9
|
+
clerkId: "user_abc123",
|
|
10
|
+
email: "alice@example.com",
|
|
11
|
+
createdAt: "2025-01-12T09:41:22.000Z",
|
|
12
|
+
teamToUsers: [
|
|
13
|
+
{
|
|
14
|
+
teamId: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
15
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
16
|
+
role: "admin",
|
|
17
|
+
team: {
|
|
18
|
+
id: "a2e5a3de-6d14-4e9b-9c9f-3cbb2cdb8a10",
|
|
19
|
+
name: "Red Dragons",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
24
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
25
|
+
role: "member",
|
|
26
|
+
team: {
|
|
27
|
+
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
28
|
+
name: "Blue Sharks",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
posts: [
|
|
33
|
+
{
|
|
34
|
+
id: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
35
|
+
title: "First post",
|
|
36
|
+
published: true,
|
|
37
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
38
|
+
comments: [
|
|
39
|
+
{
|
|
40
|
+
id: "9d1a7c3b-2f6a-4f7c-bf4b-8f6e3c5d9e01",
|
|
41
|
+
body: "Nice post!",
|
|
42
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
43
|
+
authorEmail: "bob@example.com",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "e3c9b5a2-7f42-4b7e-9e3d-4a6f1d8b2c44",
|
|
47
|
+
body: "Thanks for sharing",
|
|
48
|
+
postId: "f13d8f22-0b61-4d6a-8b1e-5b6b3d0c8a21",
|
|
49
|
+
authorEmail: "charlie@example.com",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "6bcb2b74-9b2f-4b38-bdb5-77c2e63d9c10",
|
|
55
|
+
title: "Second post",
|
|
56
|
+
published: false,
|
|
57
|
+
userId: "c7a2c1c8-9f4c-4f89-9d72-6b5a2f0c1e01",
|
|
58
|
+
comments: [],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
"f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55": {
|
|
63
|
+
id: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
64
|
+
clerkId: "user_xyz789",
|
|
65
|
+
email: "dave@example.com",
|
|
66
|
+
createdAt: "2025-02-03T14:18:10.000Z",
|
|
67
|
+
teamToUsers: [
|
|
68
|
+
{
|
|
69
|
+
teamId: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
70
|
+
userId: "f44a8c17-3c6d-4e38-9f61-0a9f2b1c8d55",
|
|
71
|
+
role: "admin",
|
|
72
|
+
team: {
|
|
73
|
+
id: "d91f42a6-8cbb-4e63-9b5c-8d1b4f2a7e77",
|
|
74
|
+
name: "Blue Sharks",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
posts: [],
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { relationMatcherRoot } from "..";
|
|
4
|
+
import { testData, testSchema } from "./test-data";
|
|
5
|
+
const main = async () => {
|
|
6
|
+
const result = relationMatcherRoot(testData, testSchema);
|
|
7
|
+
await fs.writeFile(path.join(process.cwd(), "/result.json"), JSON.stringify(result, null, "\t"));
|
|
8
|
+
};
|
|
9
|
+
void main();
|