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.
@@ -140,17 +140,17 @@ class RelationalTypeBase extends Type {
140
140
  };
141
141
 
142
142
  let target = {
143
- Model: leftContext.Model,
144
- modelName: leftContext.modelName,
145
- field: leftContext.Field,
146
- fieldName: leftContext.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: rightContext.Model,
151
- modelName: rightContext.modelName,
152
- field: rightContext.Field,
153
- fieldName: rightContext.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: targetModel,
209
- modelName: targetModelName,
210
- field: targetField,
211
- fieldName: targetFieldName,
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: targetModel,
226
- modelName: targetModelName,
227
- field: targetField,
228
- fieldName: targetFieldName,
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: TargetModel,
249
- modelName: targetModelName,
250
- Field: TargetField,
251
- fieldName: TargetField.fieldName,
248
+ Model: TargetModel,
249
+ modelName: targetModelName,
250
+ Field: TargetField,
251
+ fieldName: TargetField.fieldName,
252
252
  };
253
253
  let target = {
254
- Model: PrimaryModel,
255
- modelName: PrimaryModel.getModelName(),
256
- Field: context.field,
257
- fieldName: context.field.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))
@@ -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;
@@ -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
  };
@@ -127,19 +127,18 @@ function fieldToFullyQualifiedName(field, Model) {
127
127
  }
128
128
 
129
129
  function sortModelNamesByDependencyOrder(connection, _modelNames, dependencyHelper) {
130
- const recursiveAdd = (modelName, _depth) => {
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, depth + 1);
155
+ recursiveAdd(dependentModelName, alreadyVisited);
157
156
  }
158
157
 
159
158
  finalOrder.set(modelName, dependentModelNames);
160
159
  };
161
160
 
162
- let modelOrderMap = {};
163
- let modelNames = Nife.toArray(_modelNames).slice().sort();
164
- let finalOrder = new Map();
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: !self.isPersisted(),
210
- instance: self,
211
- modelName: primaryModelName,
212
- Model: PrimaryModel,
213
- fields: new Map(),
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>;
@@ -34,19 +34,19 @@ const Nife = require('nife');
34
34
  // WHERE firstName IN ('John', 'Bob', 'Mary')
35
35
 
36
36
  const FILTER_OPERATORS = {
37
- '=': (Model, fieldName, query, value) => {
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
- '>': (Model, fieldName, query, value) => {
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
- '<': (Model, fieldName, query, value) => {
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
- '*': (Model, fieldName, query, value) => {
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mythix-orm",
3
- "version": "1.10.2",
3
+ "version": "1.11.0",
4
4
  "description": "ORM for Mythix framework",
5
5
  "main": "lib/index",
6
6
  "type": "commonjs",