@loomcore/api 0.1.76 → 0.1.77
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/dist/__tests__/postgres-test-migrations/postgres-test-schema.js +7 -31
- package/dist/databases/operations/__tests__/models/client-report.model.d.ts +1 -0
- package/dist/databases/operations/__tests__/models/policy.model.d.ts +2 -0
- package/dist/databases/operations/__tests__/models/policy.model.js +1 -0
- package/dist/databases/postgres/utils/build-join-clauses.js +151 -73
- package/dist/databases/postgres/utils/build-select-clause.js +12 -1
- package/dist/databases/postgres/utils/transform-join-results.js +67 -3
- package/package.json +1 -1
|
@@ -146,30 +146,7 @@ export const getPostgresTestSchema = (config) => {
|
|
|
146
146
|
}
|
|
147
147
|
});
|
|
148
148
|
migrations.push({
|
|
149
|
-
name: '00000000000105_6_schema-
|
|
150
|
-
up: async ({ context: pool }) => {
|
|
151
|
-
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
152
|
-
await pool.query(`
|
|
153
|
-
CREATE TABLE IF NOT EXISTS "policies" (
|
|
154
|
-
"_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
155
|
-
${orgColumnDef}
|
|
156
|
-
"amount" NUMERIC NOT NULL,
|
|
157
|
-
"frequency" VARCHAR NOT NULL,
|
|
158
|
-
"_created" TIMESTAMPTZ NOT NULL,
|
|
159
|
-
"_createdBy" INTEGER NOT NULL,
|
|
160
|
-
"_updated" TIMESTAMPTZ NOT NULL,
|
|
161
|
-
"_updatedBy" INTEGER NOT NULL,
|
|
162
|
-
"_deleted" TIMESTAMPTZ,
|
|
163
|
-
"_deletedBy" INTEGER
|
|
164
|
-
)
|
|
165
|
-
`);
|
|
166
|
-
},
|
|
167
|
-
down: async ({ context: pool }) => {
|
|
168
|
-
await pool.query('DROP TABLE IF EXISTS "policies"');
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
migrations.push({
|
|
172
|
-
name: '00000000000105_7_schema-clients',
|
|
149
|
+
name: '00000000000105_6_schema-clients',
|
|
173
150
|
up: async ({ context: pool }) => {
|
|
174
151
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
175
152
|
await pool.query(`
|
|
@@ -195,29 +172,28 @@ export const getPostgresTestSchema = (config) => {
|
|
|
195
172
|
}
|
|
196
173
|
});
|
|
197
174
|
migrations.push({
|
|
198
|
-
name: '
|
|
175
|
+
name: '00000000000105_7_schema-policies',
|
|
199
176
|
up: async ({ context: pool }) => {
|
|
200
177
|
const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
|
|
201
178
|
await pool.query(`
|
|
202
|
-
CREATE TABLE IF NOT EXISTS
|
|
179
|
+
CREATE TABLE IF NOT EXISTS "policies" (
|
|
203
180
|
"_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
204
181
|
${orgColumnDef}
|
|
205
182
|
"client_id" INTEGER NOT NULL,
|
|
206
|
-
"
|
|
183
|
+
"amount" NUMERIC NOT NULL,
|
|
184
|
+
"frequency" VARCHAR NOT NULL,
|
|
207
185
|
"_created" TIMESTAMPTZ NOT NULL,
|
|
208
186
|
"_createdBy" INTEGER NOT NULL,
|
|
209
187
|
"_updated" TIMESTAMPTZ NOT NULL,
|
|
210
188
|
"_updatedBy" INTEGER NOT NULL,
|
|
211
189
|
"_deleted" TIMESTAMPTZ,
|
|
212
190
|
"_deletedBy" INTEGER,
|
|
213
|
-
CONSTRAINT
|
|
214
|
-
CONSTRAINT fk_clients_policies_policy_id FOREIGN KEY ("policy_id") REFERENCES policies("_id") ON DELETE CASCADE,
|
|
215
|
-
CONSTRAINT uk_clients_policies_client_policy UNIQUE ("client_id", "policy_id")
|
|
191
|
+
CONSTRAINT fk_policies_client_id FOREIGN KEY ("client_id") REFERENCES clients("_id") ON DELETE CASCADE
|
|
216
192
|
)
|
|
217
193
|
`);
|
|
218
194
|
},
|
|
219
195
|
down: async ({ context: pool }) => {
|
|
220
|
-
await pool.query('DROP TABLE IF EXISTS "
|
|
196
|
+
await pool.query('DROP TABLE IF EXISTS "policies"');
|
|
221
197
|
}
|
|
222
198
|
});
|
|
223
199
|
migrations.push({
|
|
@@ -42,6 +42,7 @@ export declare const clientReportsSchema: import("@sinclair/typebox").TObject<{
|
|
|
42
42
|
}>>;
|
|
43
43
|
}>>;
|
|
44
44
|
policies: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
45
|
+
client_id: import("@sinclair/typebox").TNumber;
|
|
45
46
|
amount: import("@sinclair/typebox").TNumber;
|
|
46
47
|
frequency: import("@sinclair/typebox").TString;
|
|
47
48
|
agents: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { IAuditable, IEntity } from "@loomcore/common/models";
|
|
2
2
|
import { IAgentModel } from "./agent.model.js";
|
|
3
3
|
export interface IPolicyModel extends IEntity, IAuditable {
|
|
4
|
+
client_id: number;
|
|
4
5
|
amount: number;
|
|
5
6
|
frequency: string;
|
|
6
7
|
agents?: IAgentModel[];
|
|
7
8
|
}
|
|
8
9
|
export declare const policySchema: import("@sinclair/typebox").TObject<{
|
|
10
|
+
client_id: import("@sinclair/typebox").TNumber;
|
|
9
11
|
amount: import("@sinclair/typebox").TNumber;
|
|
10
12
|
frequency: import("@sinclair/typebox").TString;
|
|
11
13
|
agents: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
@@ -2,6 +2,7 @@ import { entityUtils } from "@loomcore/common/utils";
|
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
3
|
import { agentSchema } from "./agent.model.js";
|
|
4
4
|
export const policySchema = Type.Object({
|
|
5
|
+
client_id: Type.Number(),
|
|
5
6
|
amount: Type.Number(),
|
|
6
7
|
frequency: Type.String(),
|
|
7
8
|
agents: Type.Optional(Type.Array(agentSchema))
|
|
@@ -8,13 +8,17 @@ export function buildJoinClauses(operations, mainTableName) {
|
|
|
8
8
|
const processedAliases = new Set();
|
|
9
9
|
const aliasesToSkip = new Set();
|
|
10
10
|
for (const operation of operations) {
|
|
11
|
-
if (operation instanceof JoinThroughMany && operation.localField.includes('.')) {
|
|
11
|
+
if ((operation instanceof JoinThroughMany || operation instanceof JoinMany) && operation.localField.includes('.')) {
|
|
12
12
|
const [tableAlias] = operation.localField.split('.');
|
|
13
13
|
const referencedJoinThroughMany = operations
|
|
14
14
|
.filter(op => op instanceof JoinThroughMany)
|
|
15
15
|
.find(jtm => jtm.as === tableAlias);
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const referencedJoinMany = operations
|
|
17
|
+
.filter(op => op instanceof JoinMany)
|
|
18
|
+
.find(jm => jm.as === tableAlias);
|
|
19
|
+
if (referencedJoinThroughMany || referencedJoinMany) {
|
|
20
|
+
const referencedJoin = referencedJoinThroughMany || referencedJoinMany;
|
|
21
|
+
const referencedIndex = operations.indexOf(referencedJoin);
|
|
18
22
|
const currentIndex = operations.indexOf(operation);
|
|
19
23
|
if (referencedIndex < currentIndex) {
|
|
20
24
|
aliasesToSkip.add(tableAlias);
|
|
@@ -90,58 +94,104 @@ export function buildJoinClauses(operations, mainTableName) {
|
|
|
90
94
|
const referencedJoinThroughMany = operations
|
|
91
95
|
.filter(op => op instanceof JoinThroughMany)
|
|
92
96
|
.find(jtm => jtm.as === tableAlias);
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
const referencedJoinMany = operations
|
|
98
|
+
.filter(op => op instanceof JoinMany)
|
|
99
|
+
.find(jm => jm.as === tableAlias);
|
|
100
|
+
if (referencedJoinThroughMany || referencedJoinMany) {
|
|
101
|
+
const referencedJoin = referencedJoinThroughMany || referencedJoinMany;
|
|
102
|
+
const referencedIndex = operations.indexOf(referencedJoin);
|
|
95
103
|
const currentIndex = operations.indexOf(operation);
|
|
96
104
|
if (referencedIndex < currentIndex) {
|
|
97
105
|
shouldSkipOriginalJoin = true;
|
|
98
106
|
const originalJoinWasSkipped = aliasesToSkip.has(tableAlias);
|
|
99
|
-
const originalJoin = referencedJoinThroughMany;
|
|
100
107
|
const mainTableRef = mainTableName ? `"${mainTableName}"."_id"` : '"_id"';
|
|
101
108
|
const isAgentsJoin = operation.from === 'agents';
|
|
109
|
+
const isJoinMany = referencedJoinMany !== undefined;
|
|
102
110
|
if (isAgentsJoin) {
|
|
103
111
|
if (originalJoinWasSkipped) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
112
|
+
if (isJoinMany) {
|
|
113
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
114
|
+
SELECT COALESCE(
|
|
115
|
+
JSON_AGG(
|
|
116
|
+
policy_elem.value || jsonb_build_object(
|
|
117
|
+
'agents',
|
|
118
|
+
COALESCE(
|
|
119
|
+
(SELECT JSON_AGG(agent_elem.value || jsonb_build_object('agent_person', person_data.value))
|
|
120
|
+
FROM jsonb_array_elements(COALESCE(agents_agg.agents, '[]'::json)::jsonb) AS agent_elem
|
|
121
|
+
LEFT JOIN LATERAL (
|
|
122
|
+
SELECT row_to_json(p) AS value
|
|
123
|
+
FROM "persons" AS p
|
|
124
|
+
WHERE p."_id" = (agent_elem.value->>'person_id')::integer
|
|
125
|
+
AND p."_deleted" IS NULL
|
|
126
|
+
LIMIT 1
|
|
127
|
+
) AS person_data ON true),
|
|
128
|
+
'[]'::json
|
|
129
|
+
)
|
|
120
130
|
)
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
131
|
+
),
|
|
132
|
+
'[]'::json
|
|
133
|
+
) AS aggregated
|
|
134
|
+
FROM (
|
|
135
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${tableAlias})), '[]'::json) AS aggregated
|
|
136
|
+
FROM "${referencedJoinMany.from}" AS ${tableAlias}
|
|
137
|
+
WHERE ${tableAlias}."${referencedJoinMany.foreignField}" = ${mainTableRef}
|
|
138
|
+
AND ${tableAlias}."_deleted" IS NULL
|
|
139
|
+
) AS policies_subquery
|
|
140
|
+
CROSS JOIN LATERAL jsonb_array_elements(policies_subquery.aggregated::jsonb) AS policy_elem
|
|
141
|
+
LEFT JOIN LATERAL (
|
|
142
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS agents
|
|
143
|
+
FROM "${operation.through}"
|
|
144
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
145
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
146
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = (policy_elem.value->>'${columnName}')::integer
|
|
147
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
148
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
149
|
+
) AS agents_agg ON true
|
|
150
|
+
) AS ${operation.as} ON true`;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
154
|
+
SELECT COALESCE(
|
|
155
|
+
JSON_AGG(
|
|
156
|
+
policy_elem.value || jsonb_build_object(
|
|
157
|
+
'agents',
|
|
158
|
+
COALESCE(
|
|
159
|
+
(SELECT JSON_AGG(agent_elem.value || jsonb_build_object('agent_person', person_data.value))
|
|
160
|
+
FROM jsonb_array_elements(COALESCE(agents_agg.agents, '[]'::json)::jsonb) AS agent_elem
|
|
161
|
+
LEFT JOIN LATERAL (
|
|
162
|
+
SELECT row_to_json(p) AS value
|
|
163
|
+
FROM "persons" AS p
|
|
164
|
+
WHERE p."_id" = (agent_elem.value->>'person_id')::integer
|
|
165
|
+
AND p."_deleted" IS NULL
|
|
166
|
+
LIMIT 1
|
|
167
|
+
) AS person_data ON true),
|
|
168
|
+
'[]'::json
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
),
|
|
172
|
+
'[]'::json
|
|
173
|
+
) AS aggregated
|
|
174
|
+
FROM (
|
|
175
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${tableAlias})), '[]'::json) AS aggregated
|
|
176
|
+
FROM "${referencedJoinThroughMany.through}"
|
|
177
|
+
INNER JOIN "${referencedJoinThroughMany.from}" AS ${tableAlias}
|
|
178
|
+
ON ${tableAlias}."${referencedJoinThroughMany.foreignField}" = "${referencedJoinThroughMany.through}"."${referencedJoinThroughMany.throughForeignField}"
|
|
179
|
+
WHERE "${referencedJoinThroughMany.through}"."${referencedJoinThroughMany.throughLocalField}" = ${mainTableRef}
|
|
180
|
+
AND "${referencedJoinThroughMany.through}"."_deleted" IS NULL
|
|
181
|
+
AND ${tableAlias}."_deleted" IS NULL
|
|
182
|
+
) AS policies_subquery
|
|
183
|
+
CROSS JOIN LATERAL jsonb_array_elements(policies_subquery.aggregated::jsonb) AS policy_elem
|
|
184
|
+
LEFT JOIN LATERAL (
|
|
185
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS agents
|
|
186
|
+
FROM "${operation.through}"
|
|
187
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
188
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
189
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = (policy_elem.value->>'${columnName}')::integer
|
|
190
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
191
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
192
|
+
) AS agents_agg ON true
|
|
193
|
+
) AS ${operation.as} ON true`;
|
|
194
|
+
}
|
|
145
195
|
}
|
|
146
196
|
else {
|
|
147
197
|
joinClauses += ` LEFT JOIN LATERAL (
|
|
@@ -180,33 +230,61 @@ export function buildJoinClauses(operations, mainTableName) {
|
|
|
180
230
|
}
|
|
181
231
|
else {
|
|
182
232
|
if (originalJoinWasSkipped) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
233
|
+
if (isJoinMany) {
|
|
234
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
235
|
+
SELECT COALESCE(
|
|
236
|
+
JSON_AGG(
|
|
237
|
+
policy_elem.value || jsonb_build_object('agents', COALESCE(agents_agg.agents, '[]'::json))
|
|
238
|
+
),
|
|
239
|
+
'[]'::json
|
|
240
|
+
) AS aggregated
|
|
241
|
+
FROM (
|
|
242
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${tableAlias})), '[]'::json) AS aggregated
|
|
243
|
+
FROM "${referencedJoinMany.from}" AS ${tableAlias}
|
|
244
|
+
WHERE ${tableAlias}."${referencedJoinMany.foreignField}" = ${mainTableRef}
|
|
245
|
+
AND ${tableAlias}."_deleted" IS NULL
|
|
246
|
+
) AS policies_subquery
|
|
247
|
+
CROSS JOIN LATERAL jsonb_array_elements(policies_subquery.aggregated::jsonb) AS policy_elem
|
|
248
|
+
LEFT JOIN LATERAL (
|
|
249
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS agents
|
|
250
|
+
FROM "${operation.through}"
|
|
251
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
252
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
253
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = (policy_elem.value->>'${columnName}')::integer
|
|
254
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
255
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
256
|
+
) AS agents_agg ON true
|
|
257
|
+
) AS ${operation.as} ON true`;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
joinClauses += ` LEFT JOIN LATERAL (
|
|
261
|
+
SELECT COALESCE(
|
|
262
|
+
JSON_AGG(
|
|
263
|
+
policy_elem.value || jsonb_build_object('agents', COALESCE(agents_agg.agents, '[]'::json))
|
|
264
|
+
),
|
|
265
|
+
'[]'::json
|
|
266
|
+
) AS aggregated
|
|
267
|
+
FROM (
|
|
268
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${tableAlias})), '[]'::json) AS aggregated
|
|
269
|
+
FROM "${referencedJoinThroughMany.through}"
|
|
270
|
+
INNER JOIN "${referencedJoinThroughMany.from}" AS ${tableAlias}
|
|
271
|
+
ON ${tableAlias}."${referencedJoinThroughMany.foreignField}" = "${referencedJoinThroughMany.through}"."${referencedJoinThroughMany.throughForeignField}"
|
|
272
|
+
WHERE "${referencedJoinThroughMany.through}"."${referencedJoinThroughMany.throughLocalField}" = ${mainTableRef}
|
|
273
|
+
AND "${referencedJoinThroughMany.through}"."_deleted" IS NULL
|
|
274
|
+
AND ${tableAlias}."_deleted" IS NULL
|
|
275
|
+
) AS policies_subquery
|
|
276
|
+
CROSS JOIN LATERAL jsonb_array_elements(policies_subquery.aggregated::jsonb) AS policy_elem
|
|
277
|
+
LEFT JOIN LATERAL (
|
|
278
|
+
SELECT COALESCE(JSON_AGG(row_to_json(${operation.as})), '[]'::json) AS agents
|
|
279
|
+
FROM "${operation.through}"
|
|
280
|
+
INNER JOIN "${operation.from}" AS ${operation.as}
|
|
281
|
+
ON ${operation.as}."${operation.foreignField}" = "${operation.through}"."${operation.throughForeignField}"
|
|
282
|
+
WHERE "${operation.through}"."${operation.throughLocalField}" = (policy_elem.value->>'${columnName}')::integer
|
|
283
|
+
AND "${operation.through}"."_deleted" IS NULL
|
|
284
|
+
AND ${operation.as}."_deleted" IS NULL
|
|
285
|
+
) AS agents_agg ON true
|
|
286
|
+
) AS ${operation.as} ON true`;
|
|
287
|
+
}
|
|
210
288
|
}
|
|
211
289
|
else {
|
|
212
290
|
joinClauses += ` LEFT JOIN LATERAL (
|
|
@@ -39,7 +39,9 @@ export async function buildSelectClause(client, mainTableName, mainTableAlias, o
|
|
|
39
39
|
for (const joinThroughMany of joinThroughManyOperations) {
|
|
40
40
|
if (joinThroughMany.localField.includes('.')) {
|
|
41
41
|
const [tableAlias] = joinThroughMany.localField.split('.');
|
|
42
|
-
const
|
|
42
|
+
const referencedJoinThroughMany = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
43
|
+
const referencedJoinMany = joinManyOperations.find(j => j.as === tableAlias);
|
|
44
|
+
const referencedJoin = referencedJoinThroughMany || referencedJoinMany;
|
|
43
45
|
if (referencedJoin) {
|
|
44
46
|
const referencedIndex = operations.indexOf(referencedJoin);
|
|
45
47
|
const currentIndex = operations.indexOf(joinThroughMany);
|
|
@@ -49,6 +51,15 @@ export async function buildSelectClause(client, mainTableName, mainTableAlias, o
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
}
|
|
54
|
+
for (const joinMany of joinManyOperations) {
|
|
55
|
+
if (replacedJoins.has(joinMany.as)) {
|
|
56
|
+
const replacingAlias = replacedJoins.get(joinMany.as);
|
|
57
|
+
joinSelects.push(`${replacingAlias}.aggregated AS "${joinMany.as}"`);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
joinSelects.push(`${joinMany.as}.aggregated AS "${joinMany.as}"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
52
63
|
for (const joinThroughMany of joinThroughManyOperations) {
|
|
53
64
|
if (replacedJoins.has(joinThroughMany.as)) {
|
|
54
65
|
const replacingAlias = replacedJoins.get(joinThroughMany.as);
|
|
@@ -149,7 +149,9 @@ export function transformJoinResults(rows, operations) {
|
|
|
149
149
|
for (const joinThroughMany of joinThroughManyOperations) {
|
|
150
150
|
if (joinThroughMany.localField.includes('.')) {
|
|
151
151
|
const [tableAlias] = joinThroughMany.localField.split('.');
|
|
152
|
-
const
|
|
152
|
+
const referencedJoinThroughMany = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
153
|
+
const referencedJoinMany = joinManyOperations.find(j => j.as === tableAlias);
|
|
154
|
+
const referencedJoin = referencedJoinThroughMany || referencedJoinMany;
|
|
153
155
|
if (referencedJoin) {
|
|
154
156
|
const referencedIndex = operations.indexOf(referencedJoin);
|
|
155
157
|
const currentIndex = operations.indexOf(joinThroughMany);
|
|
@@ -159,6 +161,21 @@ export function transformJoinResults(rows, operations) {
|
|
|
159
161
|
}
|
|
160
162
|
}
|
|
161
163
|
}
|
|
164
|
+
for (const joinMany of joinManyOperations) {
|
|
165
|
+
if (joinMany.localField.includes('.')) {
|
|
166
|
+
const [tableAlias] = joinMany.localField.split('.');
|
|
167
|
+
const referencedJoinThroughMany = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
168
|
+
const referencedJoinMany = joinManyOperations.find(j => j.as === tableAlias);
|
|
169
|
+
const referencedJoin = referencedJoinThroughMany || referencedJoinMany;
|
|
170
|
+
if (referencedJoin) {
|
|
171
|
+
const referencedIndex = operations.indexOf(referencedJoin);
|
|
172
|
+
const currentIndex = operations.indexOf(joinMany);
|
|
173
|
+
if (referencedIndex < currentIndex) {
|
|
174
|
+
replacedJoins.set(tableAlias, joinMany.as);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
162
179
|
for (const joinThroughMany of joinThroughManyOperations) {
|
|
163
180
|
if (replacedJoins.has(joinThroughMany.as)) {
|
|
164
181
|
continue;
|
|
@@ -180,11 +197,14 @@ export function transformJoinResults(rows, operations) {
|
|
|
180
197
|
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
181
198
|
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
182
199
|
const relatedJoinThroughMany = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
200
|
+
const relatedJoinMany = joinManyOperations.find(j => j.as === tableAlias);
|
|
183
201
|
if ((relatedJoin && transformed[relatedJoin.as]) ||
|
|
184
202
|
(relatedJoinThrough && transformed[relatedJoinThrough.as]) ||
|
|
185
|
-
(relatedJoinThroughMany && transformed[relatedJoinThroughMany.as])
|
|
203
|
+
(relatedJoinThroughMany && transformed[relatedJoinThroughMany.as]) ||
|
|
204
|
+
(relatedJoinMany && transformed[relatedJoinMany.as])) {
|
|
186
205
|
const targetAlias = relatedJoin ? relatedJoin.as :
|
|
187
|
-
(relatedJoinThrough ? relatedJoinThrough.as :
|
|
206
|
+
(relatedJoinThrough ? relatedJoinThrough.as :
|
|
207
|
+
(relatedJoinThroughMany ? relatedJoinThroughMany.as : relatedJoinMany.as));
|
|
188
208
|
if (replacedJoins.get(targetAlias) === joinThroughMany.as) {
|
|
189
209
|
transformed[targetAlias] = parsedValue;
|
|
190
210
|
}
|
|
@@ -204,6 +224,50 @@ export function transformJoinResults(rows, operations) {
|
|
|
204
224
|
transformed[aliasToUse] = parsedValue;
|
|
205
225
|
}
|
|
206
226
|
}
|
|
227
|
+
for (const joinMany of joinManyOperations) {
|
|
228
|
+
if (replacedJoins.has(joinMany.as)) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
const originalAlias = Array.from(replacedJoins.entries()).find(([_, replacing]) => replacing === joinMany.as)?.[0];
|
|
232
|
+
const aliasToUse = originalAlias || joinMany.as;
|
|
233
|
+
const jsonValue = row[aliasToUse];
|
|
234
|
+
let parsedValue;
|
|
235
|
+
if (jsonValue !== null && jsonValue !== undefined) {
|
|
236
|
+
parsedValue = typeof jsonValue === 'string'
|
|
237
|
+
? JSON.parse(jsonValue)
|
|
238
|
+
: jsonValue;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
parsedValue = [];
|
|
242
|
+
}
|
|
243
|
+
if (joinMany.localField.includes('.')) {
|
|
244
|
+
const [tableAlias] = joinMany.localField.split('.');
|
|
245
|
+
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
246
|
+
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
247
|
+
const relatedJoinThroughMany = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
248
|
+
const relatedJoinManyOther = joinManyOperations.find(j => j.as === tableAlias);
|
|
249
|
+
if ((relatedJoin && transformed[relatedJoin.as]) ||
|
|
250
|
+
(relatedJoinThrough && transformed[relatedJoinThrough.as]) ||
|
|
251
|
+
(relatedJoinThroughMany && transformed[relatedJoinThroughMany.as]) ||
|
|
252
|
+
(relatedJoinManyOther && transformed[relatedJoinManyOther.as])) {
|
|
253
|
+
const targetAlias = relatedJoin ? relatedJoin.as :
|
|
254
|
+
(relatedJoinThrough ? relatedJoinThrough.as :
|
|
255
|
+
(relatedJoinThroughMany ? relatedJoinThroughMany.as : relatedJoinManyOther.as));
|
|
256
|
+
if (replacedJoins.get(targetAlias) === joinMany.as) {
|
|
257
|
+
transformed[targetAlias] = parsedValue;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
transformed[targetAlias][joinMany.as] = parsedValue;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
transformed[aliasToUse] = parsedValue;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
transformed[aliasToUse] = parsedValue;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
207
271
|
return transformed;
|
|
208
272
|
});
|
|
209
273
|
}
|