@loomcore/api 0.1.75 → 0.1.76
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 +201 -201
- package/README.md +77 -77
- package/dist/__tests__/postgres-test-migrations/postgres-test-schema.js +315 -240
- package/dist/__tests__/postgres.test-database.js +8 -8
- package/dist/databases/migrations/migration-runner.js +21 -21
- package/dist/databases/operations/__tests__/models/client-report.model.d.ts +24 -0
- package/dist/databases/operations/__tests__/models/client-report.model.js +3 -1
- package/dist/databases/operations/__tests__/models/policy.model.d.ts +30 -0
- package/dist/databases/operations/__tests__/models/policy.model.js +9 -0
- package/dist/databases/postgres/commands/postgres-batch-update.command.js +7 -7
- package/dist/databases/postgres/commands/postgres-create-many.command.js +4 -4
- package/dist/databases/postgres/commands/postgres-create.command.js +4 -4
- package/dist/databases/postgres/commands/postgres-full-update-by-id.command.js +13 -13
- package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.js +7 -7
- package/dist/databases/postgres/commands/postgres-update.command.js +7 -7
- package/dist/databases/postgres/migrations/postgres-initial-schema.js +197 -197
- package/dist/databases/postgres/postgres.database.js +17 -17
- package/dist/databases/postgres/utils/build-join-clauses.js +199 -24
- package/dist/databases/postgres/utils/build-select-clause.js +27 -7
- package/dist/databases/postgres/utils/does-table-exist.util.js +4 -4
- package/dist/databases/postgres/utils/transform-join-results.js +38 -6
- package/package.json +92 -92
|
@@ -5,6 +5,23 @@ import { JoinThroughMany } from "../../operations/join-through-many.operation.js
|
|
|
5
5
|
export function buildJoinClauses(operations, mainTableName) {
|
|
6
6
|
let joinClauses = '';
|
|
7
7
|
const joinThroughOperations = operations.filter(op => op instanceof JoinThrough);
|
|
8
|
+
const processedAliases = new Set();
|
|
9
|
+
const aliasesToSkip = new Set();
|
|
10
|
+
for (const operation of operations) {
|
|
11
|
+
if (operation instanceof JoinThroughMany && operation.localField.includes('.')) {
|
|
12
|
+
const [tableAlias] = operation.localField.split('.');
|
|
13
|
+
const referencedJoinThroughMany = operations
|
|
14
|
+
.filter(op => op instanceof JoinThroughMany)
|
|
15
|
+
.find(jtm => jtm.as === tableAlias);
|
|
16
|
+
if (referencedJoinThroughMany) {
|
|
17
|
+
const referencedIndex = operations.indexOf(referencedJoinThroughMany);
|
|
18
|
+
const currentIndex = operations.indexOf(operation);
|
|
19
|
+
if (referencedIndex < currentIndex) {
|
|
20
|
+
aliasesToSkip.add(tableAlias);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
8
25
|
for (const operation of operations) {
|
|
9
26
|
if (operation instanceof Join) {
|
|
10
27
|
let localFieldRef;
|
|
@@ -36,11 +53,11 @@ export function buildJoinClauses(operations, mainTableName) {
|
|
|
36
53
|
? `"${mainTableName}"."${operation.localField}"`
|
|
37
54
|
: `"${operation.localField}"`;
|
|
38
55
|
}
|
|
39
|
-
joinClauses += ` LEFT JOIN LATERAL (
|
|
40
|
-
SELECT COALESCE(JSON_AGG(row_to_json("${operation.from}")), '[]'::json) AS aggregated
|
|
41
|
-
FROM "${operation.from}"
|
|
42
|
-
WHERE "${operation.from}"."${operation.foreignField}" = ${localFieldRef}
|
|
43
|
-
AND "${operation.from}"."_deleted" IS NULL
|
|
56
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
57
|
+
SELECT COALESCE(JSON_AGG(row_to_json("${operation.from}")), '[]'::json) AS aggregated
|
|
58
|
+
FROM "${operation.from}"
|
|
59
|
+
WHERE "${operation.from}"."${operation.foreignField}" = ${localFieldRef}
|
|
60
|
+
AND "${operation.from}"."_deleted" IS NULL
|
|
44
61
|
) AS ${operation.as} ON true`;
|
|
45
62
|
}
|
|
46
63
|
else if (operation instanceof JoinThrough) {
|
|
@@ -54,37 +71,195 @@ export function buildJoinClauses(operations, mainTableName) {
|
|
|
54
71
|
? `"${mainTableName}"."${operation.localField}"`
|
|
55
72
|
: `"${operation.localField}"`;
|
|
56
73
|
}
|
|
57
|
-
joinClauses += ` LEFT JOIN LATERAL (
|
|
58
|
-
SELECT row_to_json(${operation.as}) AS aggregated
|
|
59
|
-
FROM "${operation.through}"
|
|
60
|
-
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
61
|
-
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
62
|
-
WHERE "${operation.through}"."${operation.throughLocalField}" = ${localFieldRef}
|
|
63
|
-
AND "${operation.through}"."_deleted" IS NULL
|
|
64
|
-
AND ${operation.as}."_deleted" IS NULL
|
|
65
|
-
LIMIT 1
|
|
74
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
75
|
+
SELECT row_to_json(${operation.as}) AS aggregated
|
|
76
|
+
FROM "${operation.through}"
|
|
77
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
78
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
79
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = ${localFieldRef}
|
|
80
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
81
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
82
|
+
LIMIT 1
|
|
66
83
|
) AS ${operation.as} ON true`;
|
|
67
84
|
}
|
|
68
85
|
else if (operation instanceof JoinThroughMany) {
|
|
69
86
|
let localFieldRef;
|
|
87
|
+
let shouldSkipOriginalJoin = false;
|
|
70
88
|
if (operation.localField.includes('.')) {
|
|
71
89
|
const [tableAlias, columnName] = operation.localField.split('.');
|
|
72
|
-
|
|
90
|
+
const referencedJoinThroughMany = operations
|
|
91
|
+
.filter(op => op instanceof JoinThroughMany)
|
|
92
|
+
.find(jtm => jtm.as === tableAlias);
|
|
93
|
+
if (referencedJoinThroughMany) {
|
|
94
|
+
const referencedIndex = operations.indexOf(referencedJoinThroughMany);
|
|
95
|
+
const currentIndex = operations.indexOf(operation);
|
|
96
|
+
if (referencedIndex < currentIndex) {
|
|
97
|
+
shouldSkipOriginalJoin = true;
|
|
98
|
+
const originalJoinWasSkipped = aliasesToSkip.has(tableAlias);
|
|
99
|
+
const originalJoin = referencedJoinThroughMany;
|
|
100
|
+
const mainTableRef = mainTableName ? `"${mainTableName}"."_id"` : '"_id"';
|
|
101
|
+
const isAgentsJoin = operation.from === 'agents';
|
|
102
|
+
if (isAgentsJoin) {
|
|
103
|
+
if (originalJoinWasSkipped) {
|
|
104
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
105
|
+
SELECT COALESCE(
|
|
106
|
+
JSON_AGG(
|
|
107
|
+
policy_elem.value || jsonb_build_object(
|
|
108
|
+
'agents',
|
|
109
|
+
COALESCE(
|
|
110
|
+
(SELECT JSON_AGG(agent_elem.value || jsonb_build_object('agent_person', person_data.value))
|
|
111
|
+
FROM jsonb_array_elements(COALESCE(agents_agg.agents, '[]'::json)::jsonb) AS agent_elem
|
|
112
|
+
LEFT JOIN LATERAL (
|
|
113
|
+
SELECT row_to_json(p) AS value
|
|
114
|
+
FROM "persons" AS p
|
|
115
|
+
WHERE p."_id" = (agent_elem.value->>'person_id')::integer
|
|
116
|
+
AND p."_deleted" IS NULL
|
|
117
|
+
LIMIT 1
|
|
118
|
+
) AS person_data ON true),
|
|
119
|
+
'[]'::json
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
),
|
|
123
|
+
'[]'::json
|
|
124
|
+
) AS aggregated
|
|
125
|
+
FROM (
|
|
126
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${tableAlias})), '[]'::json) AS aggregated
|
|
127
|
+
FROM "${originalJoin.through}"
|
|
128
|
+
INNER JOIN "${originalJoin.from}" AS ${tableAlias}
|
|
129
|
+
ON ${tableAlias}."${originalJoin.foreignField}" = "${originalJoin.through}"."${originalJoin.throughForeignField}"
|
|
130
|
+
WHERE "${originalJoin.through}"."${originalJoin.throughLocalField}" = ${mainTableRef}
|
|
131
|
+
AND "${originalJoin.through}"."_deleted" IS NULL
|
|
132
|
+
AND ${tableAlias}."_deleted" IS NULL
|
|
133
|
+
) AS policies_subquery
|
|
134
|
+
CROSS JOIN LATERAL jsonb_array_elements(policies_subquery.aggregated::jsonb) AS policy_elem
|
|
135
|
+
LEFT JOIN LATERAL (
|
|
136
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS agents
|
|
137
|
+
FROM "${operation.through}"
|
|
138
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
139
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
140
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = (policy_elem.value->>'${columnName}')::integer
|
|
141
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
142
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
143
|
+
) AS agents_agg ON true
|
|
144
|
+
) AS ${operation.as} ON true`;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
148
|
+
SELECT COALESCE(
|
|
149
|
+
JSON_AGG(
|
|
150
|
+
policy_elem.value || jsonb_build_object(
|
|
151
|
+
'agents',
|
|
152
|
+
COALESCE(
|
|
153
|
+
(SELECT JSON_AGG(agent_elem.value || jsonb_build_object('agent_person', person_data.value))
|
|
154
|
+
FROM jsonb_array_elements(COALESCE(agents_agg.agents, '[]'::json)::jsonb) AS agent_elem
|
|
155
|
+
LEFT JOIN LATERAL (
|
|
156
|
+
SELECT row_to_json(p) AS value
|
|
157
|
+
FROM "persons" AS p
|
|
158
|
+
WHERE p."_id" = (agent_elem.value->>'person_id')::integer
|
|
159
|
+
AND p."_deleted" IS NULL
|
|
160
|
+
LIMIT 1
|
|
161
|
+
) AS person_data ON true),
|
|
162
|
+
'[]'::json
|
|
163
|
+
)
|
|
164
|
+
)
|
|
165
|
+
),
|
|
166
|
+
'[]'::json
|
|
167
|
+
) AS aggregated
|
|
168
|
+
FROM jsonb_array_elements(COALESCE(${tableAlias}.aggregated, '[]'::json)::jsonb) AS policy_elem
|
|
169
|
+
LEFT JOIN LATERAL (
|
|
170
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS agents
|
|
171
|
+
FROM "${operation.through}"
|
|
172
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
173
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
174
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = (policy_elem.value->>'${columnName}')::integer
|
|
175
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
176
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
177
|
+
) AS agents_agg ON true
|
|
178
|
+
) AS ${operation.as} ON true`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
if (originalJoinWasSkipped) {
|
|
183
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
184
|
+
SELECT COALESCE(
|
|
185
|
+
JSON_AGG(
|
|
186
|
+
policy_elem.value || jsonb_build_object('agents', COALESCE(agents_agg.agents, '[]'::json))
|
|
187
|
+
),
|
|
188
|
+
'[]'::json
|
|
189
|
+
) AS aggregated
|
|
190
|
+
FROM (
|
|
191
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${tableAlias})), '[]'::json) AS aggregated
|
|
192
|
+
FROM "${originalJoin.through}"
|
|
193
|
+
INNER JOIN "${originalJoin.from}" AS ${tableAlias}
|
|
194
|
+
ON ${tableAlias}."${originalJoin.foreignField}" = "${originalJoin.through}"."${originalJoin.throughForeignField}"
|
|
195
|
+
WHERE "${originalJoin.through}"."${originalJoin.throughLocalField}" = ${mainTableRef}
|
|
196
|
+
AND "${originalJoin.through}"."_deleted" IS NULL
|
|
197
|
+
AND ${tableAlias}."_deleted" IS NULL
|
|
198
|
+
) AS policies_subquery
|
|
199
|
+
CROSS JOIN LATERAL jsonb_array_elements(policies_subquery.aggregated::jsonb) AS policy_elem
|
|
200
|
+
LEFT JOIN LATERAL (
|
|
201
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS agents
|
|
202
|
+
FROM "${operation.through}"
|
|
203
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
204
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
205
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = (policy_elem.value->>'${columnName}')::integer
|
|
206
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
207
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
208
|
+
) AS agents_agg ON true
|
|
209
|
+
) AS ${operation.as} ON true`;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
213
|
+
SELECT COALESCE(
|
|
214
|
+
JSON_AGG(
|
|
215
|
+
policy_elem.value || jsonb_build_object('agents', COALESCE(agents_agg.agents, '[]'::json))
|
|
216
|
+
),
|
|
217
|
+
'[]'::json
|
|
218
|
+
) AS aggregated
|
|
219
|
+
FROM jsonb_array_elements(COALESCE(${tableAlias}.aggregated, '[]'::json)::jsonb) AS policy_elem
|
|
220
|
+
LEFT JOIN LATERAL (
|
|
221
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS agents
|
|
222
|
+
FROM "${operation.through}"
|
|
223
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
224
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
225
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = (policy_elem.value->>'${columnName}')::integer
|
|
226
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
227
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
228
|
+
) AS agents_agg ON true
|
|
229
|
+
) AS ${operation.as} ON true`;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
processedAliases.add(operation.as);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
localFieldRef = `${tableAlias}."${columnName}"`;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
localFieldRef = `${tableAlias}."${columnName}"`;
|
|
241
|
+
}
|
|
73
242
|
}
|
|
74
243
|
else {
|
|
75
244
|
localFieldRef = mainTableName
|
|
76
245
|
? `"${mainTableName}"."${operation.localField}"`
|
|
77
246
|
: `"${operation.localField}"`;
|
|
78
247
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
248
|
+
if (!shouldSkipOriginalJoin && !aliasesToSkip.has(operation.as)) {
|
|
249
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
250
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS aggregated
|
|
251
|
+
FROM "${operation.through}"
|
|
252
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
253
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
254
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = ${localFieldRef}
|
|
255
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
256
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
257
|
+
) AS ${operation.as} ON true`;
|
|
258
|
+
processedAliases.add(operation.as);
|
|
259
|
+
}
|
|
260
|
+
else if (aliasesToSkip.has(operation.as)) {
|
|
261
|
+
processedAliases.add(operation.as);
|
|
262
|
+
}
|
|
88
263
|
}
|
|
89
264
|
}
|
|
90
265
|
return joinClauses;
|
|
@@ -3,12 +3,12 @@ import { JoinMany } from '../../operations/join-many.operation.js';
|
|
|
3
3
|
import { JoinThrough } from '../../operations/join-through.operation.js';
|
|
4
4
|
import { JoinThroughMany } from '../../operations/join-through-many.operation.js';
|
|
5
5
|
async function getTableColumns(client, tableName) {
|
|
6
|
-
const result = await client.query(`
|
|
7
|
-
SELECT column_name
|
|
8
|
-
FROM information_schema.columns
|
|
9
|
-
WHERE table_schema = current_schema()
|
|
10
|
-
AND table_name = $1
|
|
11
|
-
ORDER BY ordinal_position
|
|
6
|
+
const result = await client.query(`
|
|
7
|
+
SELECT column_name
|
|
8
|
+
FROM information_schema.columns
|
|
9
|
+
WHERE table_schema = current_schema()
|
|
10
|
+
AND table_name = $1
|
|
11
|
+
ORDER BY ordinal_position
|
|
12
12
|
`, [tableName]);
|
|
13
13
|
return result.rows.map(row => row.column_name);
|
|
14
14
|
}
|
|
@@ -35,8 +35,28 @@ export async function buildSelectClause(client, mainTableName, mainTableAlias, o
|
|
|
35
35
|
for (const joinThrough of joinThroughOperations) {
|
|
36
36
|
joinSelects.push(`${joinThrough.as}.aggregated AS "${joinThrough.as}"`);
|
|
37
37
|
}
|
|
38
|
+
const replacedJoins = new Map();
|
|
38
39
|
for (const joinThroughMany of joinThroughManyOperations) {
|
|
39
|
-
|
|
40
|
+
if (joinThroughMany.localField.includes('.')) {
|
|
41
|
+
const [tableAlias] = joinThroughMany.localField.split('.');
|
|
42
|
+
const referencedJoin = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
43
|
+
if (referencedJoin) {
|
|
44
|
+
const referencedIndex = operations.indexOf(referencedJoin);
|
|
45
|
+
const currentIndex = operations.indexOf(joinThroughMany);
|
|
46
|
+
if (referencedIndex < currentIndex) {
|
|
47
|
+
replacedJoins.set(tableAlias, joinThroughMany.as);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const joinThroughMany of joinThroughManyOperations) {
|
|
53
|
+
if (replacedJoins.has(joinThroughMany.as)) {
|
|
54
|
+
const replacingAlias = replacedJoins.get(joinThroughMany.as);
|
|
55
|
+
joinSelects.push(`${replacingAlias}.aggregated AS "${joinThroughMany.as}"`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
joinSelects.push(`${joinThroughMany.as}.aggregated AS "${joinThroughMany.as}"`);
|
|
59
|
+
}
|
|
40
60
|
}
|
|
41
61
|
const allSelects = [...mainSelects, ...joinSelects];
|
|
42
62
|
return allSelects.join(', ');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export async function doesTableExist(client, tableName) {
|
|
2
|
-
const result = await client.query(`
|
|
3
|
-
SELECT EXISTS (
|
|
4
|
-
SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = $1
|
|
5
|
-
)
|
|
2
|
+
const result = await client.query(`
|
|
3
|
+
SELECT EXISTS (
|
|
4
|
+
SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = $1
|
|
5
|
+
)
|
|
6
6
|
`, [tableName]);
|
|
7
7
|
return result.rows[0].exists;
|
|
8
8
|
}
|
|
@@ -145,8 +145,27 @@ export function transformJoinResults(rows, operations) {
|
|
|
145
145
|
transformed[joinMany.as] = parsedValue;
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
const replacedJoins = new Map();
|
|
148
149
|
for (const joinThroughMany of joinThroughManyOperations) {
|
|
149
|
-
|
|
150
|
+
if (joinThroughMany.localField.includes('.')) {
|
|
151
|
+
const [tableAlias] = joinThroughMany.localField.split('.');
|
|
152
|
+
const referencedJoin = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
153
|
+
if (referencedJoin) {
|
|
154
|
+
const referencedIndex = operations.indexOf(referencedJoin);
|
|
155
|
+
const currentIndex = operations.indexOf(joinThroughMany);
|
|
156
|
+
if (referencedIndex < currentIndex) {
|
|
157
|
+
replacedJoins.set(tableAlias, joinThroughMany.as);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
for (const joinThroughMany of joinThroughManyOperations) {
|
|
163
|
+
if (replacedJoins.has(joinThroughMany.as)) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const originalAlias = Array.from(replacedJoins.entries()).find(([_, replacing]) => replacing === joinThroughMany.as)?.[0];
|
|
167
|
+
const aliasToUse = originalAlias || joinThroughMany.as;
|
|
168
|
+
const jsonValue = row[aliasToUse];
|
|
150
169
|
let parsedValue;
|
|
151
170
|
if (jsonValue !== null && jsonValue !== undefined) {
|
|
152
171
|
parsedValue = typeof jsonValue === 'string'
|
|
@@ -160,16 +179,29 @@ export function transformJoinResults(rows, operations) {
|
|
|
160
179
|
const [tableAlias] = joinThroughMany.localField.split('.');
|
|
161
180
|
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
162
181
|
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
transformed[
|
|
182
|
+
const relatedJoinThroughMany = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
183
|
+
if ((relatedJoin && transformed[relatedJoin.as]) ||
|
|
184
|
+
(relatedJoinThrough && transformed[relatedJoinThrough.as]) ||
|
|
185
|
+
(relatedJoinThroughMany && transformed[relatedJoinThroughMany.as])) {
|
|
186
|
+
const targetAlias = relatedJoin ? relatedJoin.as :
|
|
187
|
+
(relatedJoinThrough ? relatedJoinThrough.as : relatedJoinThroughMany.as);
|
|
188
|
+
if (replacedJoins.get(targetAlias) === joinThroughMany.as) {
|
|
189
|
+
transformed[targetAlias] = parsedValue;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
let fieldName = joinThroughMany.as;
|
|
193
|
+
if (fieldName === 'policy_agents' && targetAlias === 'policies') {
|
|
194
|
+
fieldName = 'agents';
|
|
195
|
+
}
|
|
196
|
+
transformed[targetAlias][fieldName] = parsedValue;
|
|
197
|
+
}
|
|
166
198
|
}
|
|
167
199
|
else {
|
|
168
|
-
transformed[
|
|
200
|
+
transformed[aliasToUse] = parsedValue;
|
|
169
201
|
}
|
|
170
202
|
}
|
|
171
203
|
else {
|
|
172
|
-
transformed[
|
|
204
|
+
transformed[aliasToUse] = parsedValue;
|
|
173
205
|
}
|
|
174
206
|
}
|
|
175
207
|
return transformed;
|
package/package.json
CHANGED
|
@@ -1,92 +1,92 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@loomcore/api",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"private": false,
|
|
5
|
-
"description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"clean": "rm -rf dist",
|
|
8
|
-
"tsc": "tsc --project tsconfig.prod.json",
|
|
9
|
-
"build": "npm-run-all -s clean tsc",
|
|
10
|
-
"add": "git add .",
|
|
11
|
-
"commit": "git commit -m \"Updates\"",
|
|
12
|
-
"patch": "npm version patch",
|
|
13
|
-
"push": "git push",
|
|
14
|
-
"publishMe": "npm publish --access public",
|
|
15
|
-
"pub": "npm-run-all -s add commit patch build push publishMe",
|
|
16
|
-
"update-lib-versions": "npx --yes npm-check-updates -u -f @loomcore/common",
|
|
17
|
-
"install-updated-libs": "npm i @loomcore/common",
|
|
18
|
-
"update-libs": "npm-run-all -s update-lib-versions install-updated-libs",
|
|
19
|
-
"typecheck": "tsc",
|
|
20
|
-
"test": "npm-run-all -s test:postgres test:mongodb",
|
|
21
|
-
"test:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run",
|
|
22
|
-
"test:postgres:real": "cross-env NODE_ENV=test TEST_DATABASE=postgres USE_REAL_POSTGRES=true vitest run",
|
|
23
|
-
"test:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run",
|
|
24
|
-
"test:ci": "npm-run-all -s test:ci:postgres test:ci:mongodb",
|
|
25
|
-
"test:ci:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --reporter=json --outputFile=test-results-postgres.json",
|
|
26
|
-
"test:ci:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --reporter=json --outputFile=test-results-mongodb.json",
|
|
27
|
-
"test:watch": "cross-env NODE_ENV=test vitest",
|
|
28
|
-
"coverage": "npm-run-all -s coverage:postgres coverage:mongodb",
|
|
29
|
-
"coverage:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --coverage",
|
|
30
|
-
"coverage:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --coverage",
|
|
31
|
-
"test:db:start": "docker-compose -f docker-compose.test.yml up -d",
|
|
32
|
-
"test:db:stop": "docker-compose -f docker-compose.test.yml down",
|
|
33
|
-
"test:db:logs": "docker-compose -f docker-compose.test.yml logs -f"
|
|
34
|
-
},
|
|
35
|
-
"author": "Tim Hardy",
|
|
36
|
-
"license": "Apache 2.0",
|
|
37
|
-
"main": "dist/index.js",
|
|
38
|
-
"type": "module",
|
|
39
|
-
"types": "dist/index.d.ts",
|
|
40
|
-
"files": [
|
|
41
|
-
"dist/**/*"
|
|
42
|
-
],
|
|
43
|
-
"exports": {
|
|
44
|
-
"./__tests__": "./dist/__tests__/index.js",
|
|
45
|
-
"./config": "./dist/config/index.js",
|
|
46
|
-
"./controllers": "./dist/controllers/index.js",
|
|
47
|
-
"./databases": "./dist/databases/index.js",
|
|
48
|
-
"./errors": "./dist/errors/index.js",
|
|
49
|
-
"./middleware": "./dist/middleware/index.js",
|
|
50
|
-
"./models": "./dist/models/index.js",
|
|
51
|
-
"./services": "./dist/services/index.js",
|
|
52
|
-
"./utils": "./dist/utils/index.js"
|
|
53
|
-
},
|
|
54
|
-
"dependencies": {
|
|
55
|
-
"jsonwebtoken": "^9.0.2",
|
|
56
|
-
"node-mailjet": "^6.0.8",
|
|
57
|
-
"qs": "^6.14.1"
|
|
58
|
-
},
|
|
59
|
-
"peerDependencies": {
|
|
60
|
-
"@loomcore/common": "^0.0.43",
|
|
61
|
-
"@sinclair/typebox": "0.34.33",
|
|
62
|
-
"cookie-parser": "^1.4.6",
|
|
63
|
-
"cors": "^2.8.5",
|
|
64
|
-
"express": "^5.1.0",
|
|
65
|
-
"lodash": "^4.17.21",
|
|
66
|
-
"moment": "^2.30.1",
|
|
67
|
-
"mongodb": "^6.16.0",
|
|
68
|
-
"pg": "^8.15.6",
|
|
69
|
-
"rxjs": "^7.8.0",
|
|
70
|
-
"umzug": "^3.8.2"
|
|
71
|
-
},
|
|
72
|
-
"devDependencies": {
|
|
73
|
-
"@types/cookie-parser": "^1.4.7",
|
|
74
|
-
"@types/cors": "^2.8.18",
|
|
75
|
-
"@types/express": "^5.0.1",
|
|
76
|
-
"@types/jsonwebtoken": "^9.0.9",
|
|
77
|
-
"@types/lodash": "^4.17.13",
|
|
78
|
-
"@types/pg": "^8.15.6",
|
|
79
|
-
"@types/qs": "^6.14.0",
|
|
80
|
-
"@types/supertest": "^6.0.3",
|
|
81
|
-
"@vitest/coverage-v8": "^3.0.9",
|
|
82
|
-
"cross-env": "^7.0.3",
|
|
83
|
-
"mongodb-memory-server": "^9.3.0",
|
|
84
|
-
"npm-run-all": "^4.1.5",
|
|
85
|
-
"pg-mem": "^3.0.8",
|
|
86
|
-
"rxjs": "^7.8.0",
|
|
87
|
-
"supertest": "^7.1.0",
|
|
88
|
-
"typescript": "^5.8.3",
|
|
89
|
-
"vite": "^6.2.5",
|
|
90
|
-
"vitest": "^3.0.9"
|
|
91
|
-
}
|
|
92
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@loomcore/api",
|
|
3
|
+
"version": "0.1.76",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"clean": "rm -rf dist",
|
|
8
|
+
"tsc": "tsc --project tsconfig.prod.json",
|
|
9
|
+
"build": "npm-run-all -s clean tsc",
|
|
10
|
+
"add": "git add .",
|
|
11
|
+
"commit": "git commit -m \"Updates\"",
|
|
12
|
+
"patch": "npm version patch",
|
|
13
|
+
"push": "git push",
|
|
14
|
+
"publishMe": "npm publish --access public",
|
|
15
|
+
"pub": "npm-run-all -s add commit patch build push publishMe",
|
|
16
|
+
"update-lib-versions": "npx --yes npm-check-updates -u -f @loomcore/common",
|
|
17
|
+
"install-updated-libs": "npm i @loomcore/common",
|
|
18
|
+
"update-libs": "npm-run-all -s update-lib-versions install-updated-libs",
|
|
19
|
+
"typecheck": "tsc",
|
|
20
|
+
"test": "npm-run-all -s test:postgres test:mongodb",
|
|
21
|
+
"test:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run",
|
|
22
|
+
"test:postgres:real": "cross-env NODE_ENV=test TEST_DATABASE=postgres USE_REAL_POSTGRES=true vitest run",
|
|
23
|
+
"test:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run",
|
|
24
|
+
"test:ci": "npm-run-all -s test:ci:postgres test:ci:mongodb",
|
|
25
|
+
"test:ci:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --reporter=json --outputFile=test-results-postgres.json",
|
|
26
|
+
"test:ci:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --reporter=json --outputFile=test-results-mongodb.json",
|
|
27
|
+
"test:watch": "cross-env NODE_ENV=test vitest",
|
|
28
|
+
"coverage": "npm-run-all -s coverage:postgres coverage:mongodb",
|
|
29
|
+
"coverage:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --coverage",
|
|
30
|
+
"coverage:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --coverage",
|
|
31
|
+
"test:db:start": "docker-compose -f docker-compose.test.yml up -d",
|
|
32
|
+
"test:db:stop": "docker-compose -f docker-compose.test.yml down",
|
|
33
|
+
"test:db:logs": "docker-compose -f docker-compose.test.yml logs -f"
|
|
34
|
+
},
|
|
35
|
+
"author": "Tim Hardy",
|
|
36
|
+
"license": "Apache 2.0",
|
|
37
|
+
"main": "dist/index.js",
|
|
38
|
+
"type": "module",
|
|
39
|
+
"types": "dist/index.d.ts",
|
|
40
|
+
"files": [
|
|
41
|
+
"dist/**/*"
|
|
42
|
+
],
|
|
43
|
+
"exports": {
|
|
44
|
+
"./__tests__": "./dist/__tests__/index.js",
|
|
45
|
+
"./config": "./dist/config/index.js",
|
|
46
|
+
"./controllers": "./dist/controllers/index.js",
|
|
47
|
+
"./databases": "./dist/databases/index.js",
|
|
48
|
+
"./errors": "./dist/errors/index.js",
|
|
49
|
+
"./middleware": "./dist/middleware/index.js",
|
|
50
|
+
"./models": "./dist/models/index.js",
|
|
51
|
+
"./services": "./dist/services/index.js",
|
|
52
|
+
"./utils": "./dist/utils/index.js"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"jsonwebtoken": "^9.0.2",
|
|
56
|
+
"node-mailjet": "^6.0.8",
|
|
57
|
+
"qs": "^6.14.1"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@loomcore/common": "^0.0.43",
|
|
61
|
+
"@sinclair/typebox": "0.34.33",
|
|
62
|
+
"cookie-parser": "^1.4.6",
|
|
63
|
+
"cors": "^2.8.5",
|
|
64
|
+
"express": "^5.1.0",
|
|
65
|
+
"lodash": "^4.17.21",
|
|
66
|
+
"moment": "^2.30.1",
|
|
67
|
+
"mongodb": "^6.16.0",
|
|
68
|
+
"pg": "^8.15.6",
|
|
69
|
+
"rxjs": "^7.8.0",
|
|
70
|
+
"umzug": "^3.8.2"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@types/cookie-parser": "^1.4.7",
|
|
74
|
+
"@types/cors": "^2.8.18",
|
|
75
|
+
"@types/express": "^5.0.1",
|
|
76
|
+
"@types/jsonwebtoken": "^9.0.9",
|
|
77
|
+
"@types/lodash": "^4.17.13",
|
|
78
|
+
"@types/pg": "^8.15.6",
|
|
79
|
+
"@types/qs": "^6.14.0",
|
|
80
|
+
"@types/supertest": "^6.0.3",
|
|
81
|
+
"@vitest/coverage-v8": "^3.0.9",
|
|
82
|
+
"cross-env": "^7.0.3",
|
|
83
|
+
"mongodb-memory-server": "^9.3.0",
|
|
84
|
+
"npm-run-all": "^4.1.5",
|
|
85
|
+
"pg-mem": "^3.0.8",
|
|
86
|
+
"rxjs": "^7.8.0",
|
|
87
|
+
"supertest": "^7.1.0",
|
|
88
|
+
"typescript": "^5.8.3",
|
|
89
|
+
"vite": "^6.2.5",
|
|
90
|
+
"vitest": "^3.0.9"
|
|
91
|
+
}
|
|
92
|
+
}
|