@loomcore/api 0.1.76 → 0.1.78
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 +29 -28
- package/dist/databases/operations/__tests__/models/agent.model.d.ts +2 -2
- package/dist/databases/operations/__tests__/models/client-report.model.d.ts +14 -8
- package/dist/databases/operations/__tests__/models/client-report.model.js +1 -1
- package/dist/databases/operations/__tests__/models/person.model.d.ts +4 -4
- package/dist/databases/operations/__tests__/models/person.model.js +2 -2
- package/dist/databases/operations/__tests__/models/policy.model.d.ts +11 -2
- package/dist/databases/operations/__tests__/models/policy.model.js +4 -1
- package/dist/databases/operations/__tests__/models/premium.model.d.ts +12 -0
- package/dist/databases/operations/__tests__/models/premium.model.js +8 -0
- package/dist/databases/operations/join-many.operation.js +3 -0
- package/dist/databases/operations/join-through-many.operation.js +3 -0
- package/dist/databases/operations/join-through.operation.js +3 -0
- package/dist/databases/operations/join.operation.js +3 -0
- package/dist/databases/postgres/utils/build-join-clauses.js +278 -190
- package/dist/databases/postgres/utils/build-select-clause.js +20 -24
- package/dist/databases/postgres/utils/transform-join-results.js +205 -137
- package/package.json +1 -1
|
@@ -2,22 +2,87 @@ import { Join } from '../../operations/join.operation.js';
|
|
|
2
2
|
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
|
+
function findNestedObject(obj, alias, path = []) {
|
|
6
|
+
if (obj[alias] !== undefined && obj[alias] !== null) {
|
|
7
|
+
return { obj: obj[alias], path: [...path, alias] };
|
|
8
|
+
}
|
|
9
|
+
for (const key in obj) {
|
|
10
|
+
if (obj[key] && typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
|
|
11
|
+
const found = findNestedObject(obj[key], alias, [...path, key]);
|
|
12
|
+
if (found !== null) {
|
|
13
|
+
return found;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else if (Array.isArray(obj[key])) {
|
|
17
|
+
for (const item of obj[key]) {
|
|
18
|
+
if (item && typeof item === 'object') {
|
|
19
|
+
const found = findNestedObject(item, alias, [...path, key]);
|
|
20
|
+
if (found !== null) {
|
|
21
|
+
return found;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
function parseJsonValue(value) {
|
|
30
|
+
if (value === null || value === undefined) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
if (typeof value === 'string') {
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(value);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
function findEnrichmentTarget(operation, operations) {
|
|
44
|
+
if (!operation.localField.includes('.')) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const [alias] = operation.localField.split('.');
|
|
48
|
+
const target = operations.find(op => (op instanceof JoinMany || op instanceof JoinThroughMany) && op.as === alias);
|
|
49
|
+
if (target && operations.indexOf(target) < operations.indexOf(operation)) {
|
|
50
|
+
return target;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function mapEnrichmentFieldName(fieldName, targetAlias) {
|
|
55
|
+
if (fieldName === 'policy_agents' && (targetAlias === 'client_policies' || targetAlias === 'policies')) {
|
|
56
|
+
return 'agents';
|
|
57
|
+
}
|
|
58
|
+
return fieldName;
|
|
59
|
+
}
|
|
5
60
|
export function transformJoinResults(rows, operations) {
|
|
6
61
|
const joinOperations = operations.filter(op => op instanceof Join);
|
|
7
62
|
const joinManyOperations = operations.filter(op => op instanceof JoinMany);
|
|
8
63
|
const joinThroughOperations = operations.filter(op => op instanceof JoinThrough);
|
|
9
64
|
const joinThroughManyOperations = operations.filter(op => op instanceof JoinThroughMany);
|
|
10
|
-
if (joinOperations.length === 0 &&
|
|
65
|
+
if (joinOperations.length === 0 &&
|
|
66
|
+
joinManyOperations.length === 0 &&
|
|
67
|
+
joinThroughOperations.length === 0 &&
|
|
68
|
+
joinThroughManyOperations.length === 0) {
|
|
11
69
|
return rows;
|
|
12
70
|
}
|
|
71
|
+
const allJoinAliases = [
|
|
72
|
+
...joinOperations.map(j => j.as),
|
|
73
|
+
...joinManyOperations.map(j => j.as),
|
|
74
|
+
...joinThroughOperations.map(j => j.as),
|
|
75
|
+
...joinThroughManyOperations.map(j => j.as)
|
|
76
|
+
];
|
|
77
|
+
const enrichmentMap = new Map();
|
|
78
|
+
for (const op of [...joinManyOperations, ...joinThroughManyOperations]) {
|
|
79
|
+
const target = findEnrichmentTarget(op, operations);
|
|
80
|
+
if (target) {
|
|
81
|
+
enrichmentMap.set(op, target);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
13
84
|
return rows.map(row => {
|
|
14
85
|
const transformed = {};
|
|
15
|
-
const allJoinAliases = [
|
|
16
|
-
...joinOperations.map(j => j.as),
|
|
17
|
-
...joinManyOperations.map(j => j.as),
|
|
18
|
-
...joinThroughOperations.map(j => j.as),
|
|
19
|
-
...joinThroughManyOperations.map(j => j.as)
|
|
20
|
-
];
|
|
21
86
|
for (const key of Object.keys(row)) {
|
|
22
87
|
const hasJoinPrefix = joinOperations.some(join => key.startsWith(`${join.as}__`));
|
|
23
88
|
const isJoinAlias = allJoinAliases.includes(key);
|
|
@@ -26,34 +91,10 @@ export function transformJoinResults(rows, operations) {
|
|
|
26
91
|
}
|
|
27
92
|
}
|
|
28
93
|
for (const operation of operations) {
|
|
29
|
-
if (operation
|
|
30
|
-
|
|
31
|
-
let parsedValue;
|
|
32
|
-
if (jsonValue !== null && jsonValue !== undefined) {
|
|
33
|
-
parsedValue = typeof jsonValue === 'string'
|
|
34
|
-
? JSON.parse(jsonValue)
|
|
35
|
-
: jsonValue;
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
parsedValue = null;
|
|
39
|
-
}
|
|
40
|
-
if (operation.localField.includes('.')) {
|
|
41
|
-
const [tableAlias] = operation.localField.split('.');
|
|
42
|
-
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
43
|
-
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
44
|
-
if ((relatedJoin && transformed[relatedJoin.as]) || (relatedJoinThrough && transformed[relatedJoinThrough.as])) {
|
|
45
|
-
const targetAlias = relatedJoin ? relatedJoin.as : relatedJoinThrough.as;
|
|
46
|
-
transformed[targetAlias][operation.as] = parsedValue;
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
transformed[operation.as] = parsedValue;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
transformed[operation.as] = parsedValue;
|
|
54
|
-
}
|
|
94
|
+
if (enrichmentMap.has(operation)) {
|
|
95
|
+
continue;
|
|
55
96
|
}
|
|
56
|
-
|
|
97
|
+
if (operation instanceof Join) {
|
|
57
98
|
const prefix = `${operation.as}__`;
|
|
58
99
|
const joinedData = {};
|
|
59
100
|
let hasAnyData = false;
|
|
@@ -71,45 +112,21 @@ export function transformJoinResults(rows, operations) {
|
|
|
71
112
|
const [tableAlias] = operation.localField.split('.');
|
|
72
113
|
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
73
114
|
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
74
|
-
const findNestedObject = (obj, alias, path = []) => {
|
|
75
|
-
if (obj[alias] !== undefined && obj[alias] !== null) {
|
|
76
|
-
return { obj: obj[alias], path: [...path, alias] };
|
|
77
|
-
}
|
|
78
|
-
for (const key in obj) {
|
|
79
|
-
if (obj[key] && typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
|
|
80
|
-
const found = findNestedObject(obj[key], alias, [...path, key]);
|
|
81
|
-
if (found !== null) {
|
|
82
|
-
return found;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
};
|
|
88
115
|
let targetObject = null;
|
|
89
|
-
if (relatedJoin) {
|
|
90
|
-
|
|
91
|
-
targetObject = transformed[relatedJoin.as];
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
const found = findNestedObject(transformed, relatedJoin.as);
|
|
95
|
-
if (found !== null && found.obj !== undefined && found.obj !== null) {
|
|
96
|
-
targetObject = found.obj;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
116
|
+
if (relatedJoin && transformed[relatedJoin.as]) {
|
|
117
|
+
targetObject = transformed[relatedJoin.as];
|
|
99
118
|
}
|
|
100
|
-
else if (relatedJoinThrough) {
|
|
101
|
-
|
|
102
|
-
|
|
119
|
+
else if (relatedJoinThrough && transformed[relatedJoinThrough.as]) {
|
|
120
|
+
targetObject = transformed[relatedJoinThrough.as];
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const found = findNestedObject(transformed, tableAlias);
|
|
124
|
+
if (found) {
|
|
103
125
|
targetObject = found.obj;
|
|
104
126
|
}
|
|
105
127
|
}
|
|
106
128
|
if (targetObject) {
|
|
107
|
-
|
|
108
|
-
targetObject[operation.as] = joinedData;
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
targetObject[operation.as] = null;
|
|
112
|
-
}
|
|
129
|
+
targetObject[operation.as] = hasAnyData ? joinedData : null;
|
|
113
130
|
}
|
|
114
131
|
else {
|
|
115
132
|
transformed[operation.as] = hasAnyData ? joinedData : null;
|
|
@@ -119,89 +136,140 @@ export function transformJoinResults(rows, operations) {
|
|
|
119
136
|
transformed[operation.as] = hasAnyData ? joinedData : null;
|
|
120
137
|
}
|
|
121
138
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
+
else if (operation instanceof JoinThrough) {
|
|
140
|
+
const jsonValue = parseJsonValue(row[operation.as]);
|
|
141
|
+
if (operation.localField.includes('.')) {
|
|
142
|
+
const [tableAlias] = operation.localField.split('.');
|
|
143
|
+
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
144
|
+
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
145
|
+
let targetObject = null;
|
|
146
|
+
if (relatedJoin && transformed[relatedJoin.as]) {
|
|
147
|
+
targetObject = transformed[relatedJoin.as];
|
|
148
|
+
}
|
|
149
|
+
else if (relatedJoinThrough) {
|
|
150
|
+
const found = findNestedObject(transformed, relatedJoinThrough.as);
|
|
151
|
+
if (found) {
|
|
152
|
+
targetObject = found.obj;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (targetObject) {
|
|
156
|
+
targetObject[operation.as] = jsonValue;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
transformed[operation.as] = jsonValue;
|
|
160
|
+
}
|
|
139
161
|
}
|
|
140
162
|
else {
|
|
141
|
-
transformed[
|
|
163
|
+
transformed[operation.as] = jsonValue;
|
|
142
164
|
}
|
|
143
165
|
}
|
|
144
|
-
else {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
166
|
+
else if (operation instanceof JoinMany) {
|
|
167
|
+
const jsonValue = parseJsonValue(row[operation.as]);
|
|
168
|
+
let parsedValue = Array.isArray(jsonValue) ? jsonValue : (jsonValue ? [jsonValue] : []);
|
|
169
|
+
const enrichments = Array.from(enrichmentMap.entries())
|
|
170
|
+
.filter(([_, target]) => target === operation)
|
|
171
|
+
.map(([enrichOp]) => enrichOp);
|
|
172
|
+
if (enrichments.length > 0 && Array.isArray(parsedValue)) {
|
|
173
|
+
for (const item of parsedValue) {
|
|
174
|
+
if (item && typeof item === 'object') {
|
|
175
|
+
for (const enrichment of enrichments) {
|
|
176
|
+
if (item[enrichment.as] !== undefined) {
|
|
177
|
+
const mappedName = mapEnrichmentFieldName(enrichment.as, operation.as);
|
|
178
|
+
if (mappedName !== enrichment.as) {
|
|
179
|
+
item[mappedName] = item[enrichment.as];
|
|
180
|
+
delete item[enrichment.as];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
158
185
|
}
|
|
159
186
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
let parsedValue;
|
|
170
|
-
if (jsonValue !== null && jsonValue !== undefined) {
|
|
171
|
-
parsedValue = typeof jsonValue === 'string'
|
|
172
|
-
? JSON.parse(jsonValue)
|
|
173
|
-
: jsonValue;
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
parsedValue = [];
|
|
177
|
-
}
|
|
178
|
-
if (joinThroughMany.localField.includes('.')) {
|
|
179
|
-
const [tableAlias] = joinThroughMany.localField.split('.');
|
|
180
|
-
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
181
|
-
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
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;
|
|
187
|
+
if (operation.localField.includes('.')) {
|
|
188
|
+
const [tableAlias] = operation.localField.split('.');
|
|
189
|
+
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
190
|
+
const relatedJoinMany = joinManyOperations.find(j => j.as === tableAlias);
|
|
191
|
+
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
192
|
+
const relatedJoinThroughMany = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
193
|
+
let targetObject = null;
|
|
194
|
+
if (relatedJoin && transformed[relatedJoin.as]) {
|
|
195
|
+
targetObject = transformed[relatedJoin.as];
|
|
190
196
|
}
|
|
191
|
-
else {
|
|
192
|
-
|
|
193
|
-
if (
|
|
194
|
-
|
|
197
|
+
else if (relatedJoinThrough) {
|
|
198
|
+
const found = findNestedObject(transformed, relatedJoinThrough.as);
|
|
199
|
+
if (found) {
|
|
200
|
+
targetObject = found.obj;
|
|
195
201
|
}
|
|
196
|
-
|
|
202
|
+
}
|
|
203
|
+
else if (relatedJoinMany && transformed[relatedJoinMany.as]) {
|
|
204
|
+
targetObject = transformed[relatedJoinMany.as];
|
|
205
|
+
}
|
|
206
|
+
else if (relatedJoinThroughMany && transformed[relatedJoinThroughMany.as]) {
|
|
207
|
+
targetObject = transformed[relatedJoinThroughMany.as];
|
|
208
|
+
}
|
|
209
|
+
if (targetObject) {
|
|
210
|
+
targetObject[operation.as] = parsedValue;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
transformed[operation.as] = parsedValue;
|
|
197
214
|
}
|
|
198
215
|
}
|
|
199
216
|
else {
|
|
200
|
-
transformed[
|
|
217
|
+
transformed[operation.as] = parsedValue;
|
|
201
218
|
}
|
|
202
219
|
}
|
|
203
|
-
else {
|
|
204
|
-
|
|
220
|
+
else if (operation instanceof JoinThroughMany) {
|
|
221
|
+
const jsonValue = parseJsonValue(row[operation.as]);
|
|
222
|
+
let parsedValue = Array.isArray(jsonValue) ? jsonValue : (jsonValue ? [jsonValue] : []);
|
|
223
|
+
const enrichments = Array.from(enrichmentMap.entries())
|
|
224
|
+
.filter(([_, target]) => target === operation)
|
|
225
|
+
.map(([enrichOp]) => enrichOp);
|
|
226
|
+
if (enrichments.length > 0 && Array.isArray(parsedValue)) {
|
|
227
|
+
for (const item of parsedValue) {
|
|
228
|
+
if (item && typeof item === 'object') {
|
|
229
|
+
for (const enrichment of enrichments) {
|
|
230
|
+
if (item[enrichment.as] !== undefined) {
|
|
231
|
+
const mappedName = mapEnrichmentFieldName(enrichment.as, operation.as);
|
|
232
|
+
if (mappedName !== enrichment.as) {
|
|
233
|
+
item[mappedName] = item[enrichment.as];
|
|
234
|
+
delete item[enrichment.as];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (operation.localField.includes('.')) {
|
|
242
|
+
const [tableAlias] = operation.localField.split('.');
|
|
243
|
+
const relatedJoin = joinOperations.find(j => j.as === tableAlias);
|
|
244
|
+
const relatedJoinMany = joinManyOperations.find(j => j.as === tableAlias);
|
|
245
|
+
const relatedJoinThrough = joinThroughOperations.find(j => j.as === tableAlias);
|
|
246
|
+
const relatedJoinThroughMany = joinThroughManyOperations.find(j => j.as === tableAlias);
|
|
247
|
+
let targetObject = null;
|
|
248
|
+
if (relatedJoin && transformed[relatedJoin.as]) {
|
|
249
|
+
targetObject = transformed[relatedJoin.as];
|
|
250
|
+
}
|
|
251
|
+
else if (relatedJoinThrough) {
|
|
252
|
+
const found = findNestedObject(transformed, relatedJoinThrough.as);
|
|
253
|
+
if (found) {
|
|
254
|
+
targetObject = found.obj;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else if (relatedJoinMany && transformed[relatedJoinMany.as]) {
|
|
258
|
+
targetObject = transformed[relatedJoinMany.as];
|
|
259
|
+
}
|
|
260
|
+
else if (relatedJoinThroughMany && transformed[relatedJoinThroughMany.as]) {
|
|
261
|
+
targetObject = transformed[relatedJoinThroughMany.as];
|
|
262
|
+
}
|
|
263
|
+
if (targetObject) {
|
|
264
|
+
targetObject[operation.as] = parsedValue;
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
transformed[operation.as] = parsedValue;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
transformed[operation.as] = parsedValue;
|
|
272
|
+
}
|
|
205
273
|
}
|
|
206
274
|
}
|
|
207
275
|
return transformed;
|