mythix-orm 1.10.2 → 1.11.0
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/lib/connection/connection-base.js +4 -20
- package/lib/connection/literals/literal-base.js +20 -1
- package/lib/connection/query-generator-base.d.ts +1 -15
- package/lib/connection/query-generator-base.js +55 -583
- package/lib/field.js +9 -2
- package/lib/model.d.ts +0 -2
- package/lib/model.js +58 -71
- package/lib/query-engine/field-scope.js +57 -24
- package/lib/query-engine/model-scope.js +168 -35
- package/lib/query-engine/query-engine-base.js +46 -13
- package/lib/query-engine/query-engine.d.ts +8 -4
- package/lib/query-engine/query-engine.js +47 -54
- package/lib/types/concrete/datetime-type.js +1 -1
- package/lib/types/concrete/serialized-type.js +2 -2
- package/lib/types/virtual/model-type.js +3 -3
- package/lib/types/virtual/relational-type-base.js +24 -24
- package/lib/utils/index.js +2 -2
- package/lib/utils/misc-utils.d.ts +0 -1
- package/lib/utils/misc-utils.js +0 -24
- package/lib/utils/model-utils.js +17 -17
- package/lib/utils/query-utils.d.ts +7 -0
- package/lib/utils/query-utils.js +175 -4
- package/package.json +1 -1
|
@@ -140,17 +140,17 @@ class RelationalTypeBase extends Type {
|
|
|
140
140
|
};
|
|
141
141
|
|
|
142
142
|
let target = {
|
|
143
|
-
Model:
|
|
144
|
-
modelName:
|
|
145
|
-
field:
|
|
146
|
-
fieldName:
|
|
143
|
+
Model: leftContext.Model,
|
|
144
|
+
modelName: leftContext.modelName,
|
|
145
|
+
field: leftContext.Field,
|
|
146
|
+
fieldName: leftContext.fieldName,
|
|
147
147
|
};
|
|
148
148
|
|
|
149
149
|
let source = {
|
|
150
|
-
Model:
|
|
151
|
-
modelName:
|
|
152
|
-
field:
|
|
153
|
-
fieldName:
|
|
150
|
+
Model: rightContext.Model,
|
|
151
|
+
modelName: rightContext.modelName,
|
|
152
|
+
field: rightContext.Field,
|
|
153
|
+
fieldName: rightContext.fieldName,
|
|
154
154
|
};
|
|
155
155
|
|
|
156
156
|
// The primary model is always the target
|
|
@@ -205,10 +205,10 @@ class RelationalTypeBase extends Type {
|
|
|
205
205
|
let targetField = fkField.getTargetField(connection);
|
|
206
206
|
let targetFieldName = fkField.getTargetFieldName(connection);
|
|
207
207
|
let fkContext = {
|
|
208
|
-
Model:
|
|
209
|
-
modelName:
|
|
210
|
-
field:
|
|
211
|
-
fieldName:
|
|
208
|
+
Model: targetModel,
|
|
209
|
+
modelName: targetModelName,
|
|
210
|
+
field: targetField,
|
|
211
|
+
fieldName: targetFieldName,
|
|
212
212
|
};
|
|
213
213
|
|
|
214
214
|
if (!isAlreadyVisited(fkContext, rightQueryContext))
|
|
@@ -222,10 +222,10 @@ class RelationalTypeBase extends Type {
|
|
|
222
222
|
let targetField = fkField.getTargetField(connection);
|
|
223
223
|
let targetFieldName = fkField.getTargetFieldName(connection);
|
|
224
224
|
let fkContext = {
|
|
225
|
-
Model:
|
|
226
|
-
modelName:
|
|
227
|
-
field:
|
|
228
|
-
fieldName:
|
|
225
|
+
Model: targetModel,
|
|
226
|
+
modelName: targetModelName,
|
|
227
|
+
field: targetField,
|
|
228
|
+
fieldName: targetFieldName,
|
|
229
229
|
};
|
|
230
230
|
|
|
231
231
|
if (!isAlreadyVisited(leftQueryContext, fkContext))
|
|
@@ -245,16 +245,16 @@ class RelationalTypeBase extends Type {
|
|
|
245
245
|
// be copying field values from
|
|
246
246
|
let targetModelName = TargetModel.getModelName();
|
|
247
247
|
let source = {
|
|
248
|
-
Model:
|
|
249
|
-
modelName:
|
|
250
|
-
Field:
|
|
251
|
-
fieldName:
|
|
248
|
+
Model: TargetModel,
|
|
249
|
+
modelName: targetModelName,
|
|
250
|
+
Field: TargetField,
|
|
251
|
+
fieldName: TargetField.fieldName,
|
|
252
252
|
};
|
|
253
253
|
let target = {
|
|
254
|
-
Model:
|
|
255
|
-
modelName:
|
|
256
|
-
Field:
|
|
257
|
-
fieldName:
|
|
254
|
+
Model: PrimaryModel,
|
|
255
|
+
modelName: PrimaryModel.getModelName(),
|
|
256
|
+
Field: context.field,
|
|
257
|
+
fieldName: context.field.fieldName,
|
|
258
258
|
};
|
|
259
259
|
|
|
260
260
|
if (!isAlreadyVisited(source, target))
|
package/lib/utils/index.js
CHANGED
|
@@ -7,7 +7,6 @@ const AsyncStore = require('./async-store');
|
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
9
|
collect,
|
|
10
|
-
objectAssignSpecial,
|
|
11
10
|
valueToDateTime,
|
|
12
11
|
} = MiscUtils;
|
|
13
12
|
|
|
@@ -31,6 +30,7 @@ const {
|
|
|
31
30
|
const {
|
|
32
31
|
parseFilterFieldAndOperator,
|
|
33
32
|
generateQueryFromFilter,
|
|
33
|
+
margeFields,
|
|
34
34
|
} = QueryUtils;
|
|
35
35
|
|
|
36
36
|
const {
|
|
@@ -48,7 +48,6 @@ module.exports = {
|
|
|
48
48
|
|
|
49
49
|
// MiscUtils
|
|
50
50
|
collect,
|
|
51
|
-
objectAssignSpecial,
|
|
52
51
|
valueToDateTime,
|
|
53
52
|
|
|
54
53
|
// ModelUtils
|
|
@@ -70,6 +69,7 @@ module.exports = {
|
|
|
70
69
|
// QueryUtils
|
|
71
70
|
parseFilterFieldAndOperator,
|
|
72
71
|
generateQueryFromFilter,
|
|
72
|
+
margeFields,
|
|
73
73
|
|
|
74
74
|
// AsyncStore
|
|
75
75
|
getContextStore,
|
|
@@ -2,5 +2,4 @@ import { DateTime } from 'luxon';
|
|
|
2
2
|
import { GenericObject } from '../interfaces/common';
|
|
3
3
|
|
|
4
4
|
declare function collect(iterator: AsyncIterator<any>): Promise<Array<any>>;
|
|
5
|
-
declare function objectAssignSpecial(obj: GenericObject, proto?: GenericObject | null, skipKeys?: Array<string> | GenericObject): GenericObject;
|
|
6
5
|
declare function valueToDateTime(value: DateTime | Date | number | BigInt | string, format?: string): DateTime;
|
package/lib/utils/misc-utils.js
CHANGED
|
@@ -12,29 +12,6 @@ async function collect(iterator) {
|
|
|
12
12
|
return items;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
function objectAssignSpecial(obj, proto, skipKeys) {
|
|
16
|
-
const isKeySkipped = (key) => {
|
|
17
|
-
if (Array.isArray(skipKeys))
|
|
18
|
-
return (skipKeys.indexOf(key) >= 0);
|
|
19
|
-
|
|
20
|
-
return Object.prototype.hasOwnProperty.call(skipKeys, key);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
let newObj = Object.create(proto || {});
|
|
24
|
-
let keys = Object.keys(obj);
|
|
25
|
-
|
|
26
|
-
// eslint-disable-next-line guard-for-in
|
|
27
|
-
for (let i = 0, il = keys.length; i < il; i++) {
|
|
28
|
-
let key = keys[i];
|
|
29
|
-
if (skipKeys && isKeySkipped(key))
|
|
30
|
-
continue;
|
|
31
|
-
|
|
32
|
-
newObj[key] = obj[key];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return newObj;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
15
|
function valueToDateTime(value, format) {
|
|
39
16
|
if (DateTime.isDateTime(value)) {
|
|
40
17
|
return value;
|
|
@@ -59,6 +36,5 @@ function valueToDateTime(value, format) {
|
|
|
59
36
|
|
|
60
37
|
module.exports = {
|
|
61
38
|
collect,
|
|
62
|
-
objectAssignSpecial,
|
|
63
39
|
valueToDateTime,
|
|
64
40
|
};
|
package/lib/utils/model-utils.js
CHANGED
|
@@ -127,19 +127,18 @@ function fieldToFullyQualifiedName(field, Model) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function sortModelNamesByDependencyOrder(connection, _modelNames, dependencyHelper) {
|
|
130
|
-
const recursiveAdd = (modelName,
|
|
130
|
+
const recursiveAdd = (modelName, alreadyVisisted) => {
|
|
131
131
|
if (modelNames.indexOf(modelName) < 0)
|
|
132
132
|
return;
|
|
133
133
|
|
|
134
|
-
let depth = _depth || 0;
|
|
135
|
-
|
|
136
|
-
// eslint-disable-next-line no-magic-numbers
|
|
137
|
-
if (depth > 10)
|
|
138
|
-
throw new Error(`ModelUtils::sortModelNamesByDependencyOrder: Cyclic dependency detected with model "${modelName}".`);
|
|
139
|
-
|
|
140
134
|
if (finalOrder.has(modelName))
|
|
141
135
|
return;
|
|
142
136
|
|
|
137
|
+
if (alreadyVisited.has(modelName))
|
|
138
|
+
return;
|
|
139
|
+
|
|
140
|
+
alreadyVisited.add(modelName);
|
|
141
|
+
|
|
143
142
|
let dependentModelNames = modelOrderMap[modelName];
|
|
144
143
|
if (dependentModelNames == null) {
|
|
145
144
|
let Model = connection.getModel(modelName);
|
|
@@ -153,22 +152,23 @@ function sortModelNamesByDependencyOrder(connection, _modelNames, dependencyHelp
|
|
|
153
152
|
|
|
154
153
|
for (let j = 0, jl = dependentModelNames.length; j < jl; j++) {
|
|
155
154
|
let dependentModelName = dependentModelNames[j];
|
|
156
|
-
recursiveAdd(dependentModelName,
|
|
155
|
+
recursiveAdd(dependentModelName, alreadyVisited);
|
|
157
156
|
}
|
|
158
157
|
|
|
159
158
|
finalOrder.set(modelName, dependentModelNames);
|
|
160
159
|
};
|
|
161
160
|
|
|
162
|
-
let modelOrderMap
|
|
163
|
-
let modelNames
|
|
164
|
-
let finalOrder
|
|
161
|
+
let modelOrderMap = {};
|
|
162
|
+
let modelNames = Nife.toArray(_modelNames).slice().sort();
|
|
163
|
+
let finalOrder = new Map();
|
|
164
|
+
let alreadyVisited = new Set();
|
|
165
165
|
|
|
166
166
|
for (let i = 0, il = modelNames.length; i < il; i++) {
|
|
167
167
|
let modelName = modelNames[i];
|
|
168
168
|
if (!modelName)
|
|
169
169
|
continue;
|
|
170
170
|
|
|
171
|
-
recursiveAdd(modelName);
|
|
171
|
+
recursiveAdd(modelName, alreadyVisited);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
let sortedModelNames = Array.from(finalOrder.keys());
|
|
@@ -206,11 +206,11 @@ async function getRelationalModelStatusForField(connection, self, field, ...args
|
|
|
206
206
|
let primaryModelName = self.getModelName();
|
|
207
207
|
let relationalMap = {
|
|
208
208
|
[primaryModelName]: {
|
|
209
|
-
create:
|
|
210
|
-
instance:
|
|
211
|
-
modelName:
|
|
212
|
-
Model:
|
|
213
|
-
fields:
|
|
209
|
+
create: !self.isPersisted(),
|
|
210
|
+
instance: self,
|
|
211
|
+
modelName: primaryModelName,
|
|
212
|
+
Model: PrimaryModel,
|
|
213
|
+
fields: new Map(),
|
|
214
214
|
},
|
|
215
215
|
};
|
|
216
216
|
|
|
@@ -4,8 +4,15 @@ import { Model, ModelClass } from '../model';
|
|
|
4
4
|
import { QueryEngine } from '../query-engine';
|
|
5
5
|
|
|
6
6
|
export declare function parseFilterFieldAndOperator(fieldName: string): { field: string, operator: string };
|
|
7
|
+
|
|
7
8
|
export declare function generateQueryFromFilter(
|
|
8
9
|
connection: ConnectionBase,
|
|
9
10
|
Model: ModelClass,
|
|
10
11
|
filter: Array<GenericObject | Model> | GenericObject | Model,
|
|
11
12
|
): QueryEngine;
|
|
13
|
+
|
|
14
|
+
export declare function margeFields(
|
|
15
|
+
connection: ConnectionBase,
|
|
16
|
+
currentFields: Map<string, any>,
|
|
17
|
+
incomingFields: Array<any>
|
|
18
|
+
): Map<string, any>;
|
package/lib/utils/query-utils.js
CHANGED
|
@@ -34,19 +34,19 @@ const Nife = require('nife');
|
|
|
34
34
|
// WHERE firstName IN ('John', 'Bob', 'Mary')
|
|
35
35
|
|
|
36
36
|
const FILTER_OPERATORS = {
|
|
37
|
-
'=':
|
|
37
|
+
'=': (Model, fieldName, query, value) => {
|
|
38
38
|
return query.AND[fieldName].EQ(value);
|
|
39
39
|
},
|
|
40
40
|
'!=': (Model, fieldName, query, value) => {
|
|
41
41
|
return query.AND[fieldName].NEQ(value);
|
|
42
42
|
},
|
|
43
|
-
'>':
|
|
43
|
+
'>': (Model, fieldName, query, value) => {
|
|
44
44
|
return query.AND[fieldName].GT(value);
|
|
45
45
|
},
|
|
46
46
|
'>=': (Model, fieldName, query, value) => {
|
|
47
47
|
return query.AND[fieldName].GTE(value);
|
|
48
48
|
},
|
|
49
|
-
'<':
|
|
49
|
+
'<': (Model, fieldName, query, value) => {
|
|
50
50
|
return query.AND[fieldName].LT(value);
|
|
51
51
|
},
|
|
52
52
|
'<=': (Model, fieldName, query, value) => {
|
|
@@ -61,7 +61,7 @@ const FILTER_OPERATORS = {
|
|
|
61
61
|
return query.AND(Model.where[fieldName].LT(value[0]).OR[fieldName].GT(value[1]));
|
|
62
62
|
},
|
|
63
63
|
// Like
|
|
64
|
-
'*':
|
|
64
|
+
'*': (Model, fieldName, query, value) => {
|
|
65
65
|
return query.AND[fieldName].LIKE(value);
|
|
66
66
|
},
|
|
67
67
|
// NOT Like
|
|
@@ -180,7 +180,178 @@ function generateQueryFromFilter(connection, Model, _filter, _depth) {
|
|
|
180
180
|
return query;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
function margeFields(queryEngine, currentFields, _incomingFields, extraData, _options) {
|
|
184
|
+
const RESET = 0;
|
|
185
|
+
const ADD = 1;
|
|
186
|
+
const SUB = 2;
|
|
187
|
+
|
|
188
|
+
const getInitialMode = (incomingFields) => {
|
|
189
|
+
for (let i = 0, il = incomingFields.length; i < il; i++) {
|
|
190
|
+
let incomingField = incomingFields[i];
|
|
191
|
+
if (!incomingField)
|
|
192
|
+
continue;
|
|
193
|
+
|
|
194
|
+
if (typeof incomingField.isLiteral === 'function' && incomingField.isLiteral(incomingField))
|
|
195
|
+
return RESET;
|
|
196
|
+
|
|
197
|
+
if (typeof incomingField.isModelClass === 'function' && incomingField.isModelClass(incomingField))
|
|
198
|
+
return RESET;
|
|
199
|
+
|
|
200
|
+
if (typeof incomingField.isField === 'function' && incomingField.isField(incomingField))
|
|
201
|
+
return RESET;
|
|
202
|
+
|
|
203
|
+
if (!Nife.instanceOf(incomingField, 'string'))
|
|
204
|
+
RESET;
|
|
205
|
+
|
|
206
|
+
let firstChar = incomingField.charAt(0);
|
|
207
|
+
if (firstChar === '+')
|
|
208
|
+
return ADD;
|
|
209
|
+
|
|
210
|
+
if (firstChar === '-')
|
|
211
|
+
return SUB;
|
|
212
|
+
|
|
213
|
+
return RESET;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const addOrRemove = (mode, key, item) => {
|
|
218
|
+
if (mode === ADD)
|
|
219
|
+
fields.set(key, { ...(extraData || {}), value: item });
|
|
220
|
+
else
|
|
221
|
+
fields.delete(key);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const addOrRemoveAllModelFields = (mode, Model) => {
|
|
225
|
+
let modelName = Model.getModelName();
|
|
226
|
+
|
|
227
|
+
Model.iterateFields(({ field, fieldName }) => {
|
|
228
|
+
if (field.type.isVirtual())
|
|
229
|
+
return;
|
|
230
|
+
|
|
231
|
+
let fullFieldName = `${modelName}:${fieldName}`;
|
|
232
|
+
addOrRemove(mode, fullFieldName, field);
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
let context = queryEngine.getOperationContext();
|
|
237
|
+
let incomingFields = _incomingFields.filter(Boolean);
|
|
238
|
+
if (Nife.isEmpty(incomingFields))
|
|
239
|
+
return new Map();
|
|
240
|
+
|
|
241
|
+
let options = _options || {};
|
|
242
|
+
let connection = queryEngine.getConnection();
|
|
243
|
+
let RootModel = context.rootModel;
|
|
244
|
+
let rootModelName = RootModel.getModelName();
|
|
245
|
+
let mode = getInitialMode(incomingFields);
|
|
246
|
+
let fields = (mode === RESET) ? new Map() : new Map(currentFields);
|
|
247
|
+
let allQueryModels;
|
|
248
|
+
|
|
249
|
+
if (mode === RESET)
|
|
250
|
+
mode = ADD;
|
|
251
|
+
|
|
252
|
+
for (let i = 0, il = incomingFields.length; i < il; i++) {
|
|
253
|
+
let incomingField = incomingFields[i];
|
|
254
|
+
if (!incomingField)
|
|
255
|
+
continue;
|
|
256
|
+
|
|
257
|
+
if (typeof incomingField.isLiteral === 'function' && incomingField.isLiteral(incomingField)) {
|
|
258
|
+
if (!connection)
|
|
259
|
+
throw new Error('QueryUtils::margeFields: "connection" is required, but not found.');
|
|
260
|
+
|
|
261
|
+
let result = incomingField.toString(connection, options);
|
|
262
|
+
addOrRemove(mode, result, result);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (typeof incomingField.isModelClass === 'function' && incomingField.isModelClass(incomingField)) {
|
|
267
|
+
addOrRemoveAllModelFields(mode, incomingField);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (typeof incomingField.isField === 'function' && incomingField.isField(incomingField)) {
|
|
272
|
+
let fullFieldName = `${incomingField.Model.getModelName()}:${incomingField.fieldName}`;
|
|
273
|
+
addOrRemove(mode, fullFieldName, incomingField);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!Nife.instanceOf(incomingField, 'string'))
|
|
278
|
+
continue;
|
|
279
|
+
|
|
280
|
+
if (!connection)
|
|
281
|
+
throw new Error('QueryUtils::margeFields: "connection" is required, but not found.');
|
|
282
|
+
|
|
283
|
+
if (!incomingField)
|
|
284
|
+
continue;
|
|
285
|
+
|
|
286
|
+
let firstChar = incomingField.charAt(0);
|
|
287
|
+
let currentMode = mode;
|
|
288
|
+
|
|
289
|
+
if (firstChar === '+') {
|
|
290
|
+
if (incomingField.length === 1) {
|
|
291
|
+
mode = ADD;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
currentMode = ADD;
|
|
296
|
+
incomingField = incomingField.substring(1);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (firstChar === '-') {
|
|
300
|
+
if (incomingField.length === 1) {
|
|
301
|
+
mode = SUB;
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
currentMode = SUB;
|
|
306
|
+
incomingField = incomingField.substring(1);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (incomingField.charAt(0) === '@') {
|
|
310
|
+
incomingField = incomingField.substring(1);
|
|
311
|
+
addOrRemove(currentMode, incomingField, incomingField);
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (incomingField === '*') {
|
|
316
|
+
if (!allQueryModels)
|
|
317
|
+
allQueryModels = queryEngine.getAllModelsUsedInQuery();
|
|
318
|
+
|
|
319
|
+
for (let i = 0, il = allQueryModels.length; i < il; i++) {
|
|
320
|
+
let Model = allQueryModels[i];
|
|
321
|
+
addOrRemoveAllModelFields(currentMode, Model);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
let def = connection.parseQualifiedName(incomingField);
|
|
328
|
+
if (!def.modelName)
|
|
329
|
+
def.modelName = rootModelName;
|
|
330
|
+
|
|
331
|
+
let Model = connection.getModel(def.modelName);
|
|
332
|
+
if (!Model)
|
|
333
|
+
throw new Error(`QueryUtils::margeFields: Model "${def.modelName}" not found.`);
|
|
334
|
+
|
|
335
|
+
if (Nife.isEmpty(def.fieldNames)) {
|
|
336
|
+
addOrRemoveAllModelFields(currentMode, Model);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
let modelName = Model.getModelName();
|
|
341
|
+
let fieldName = def.fieldNames[0];
|
|
342
|
+
let field = connection.getField(fieldName, modelName);
|
|
343
|
+
if (!field)
|
|
344
|
+
throw new Error(`QueryUtils::margeFields: Field "${fieldName}" not found.`);
|
|
345
|
+
|
|
346
|
+
let fullFieldName = `${modelName}:${fieldName}`;
|
|
347
|
+
addOrRemove(currentMode, fullFieldName, field);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return fields;
|
|
351
|
+
}
|
|
352
|
+
|
|
183
353
|
module.exports = {
|
|
184
354
|
parseFilterFieldAndOperator,
|
|
185
355
|
generateQueryFromFilter,
|
|
356
|
+
margeFields,
|
|
186
357
|
};
|