mythix-orm 1.8.3 → 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.d.ts +1 -0
- package/lib/connection/connection-base.js +71 -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 +56 -584
- package/lib/field.js +9 -2
- package/lib/model.d.ts +17 -2
- package/lib/model.js +63 -71
- package/lib/query-engine/field-scope.js +58 -25
- package/lib/query-engine/model-scope.js +168 -35
- package/lib/query-engine/query-engine-base.js +153 -47
- package/lib/query-engine/query-engine.d.ts +37 -28
- package/lib/query-engine/query-engine.js +75 -71
- 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/models-type.js +1 -1
- package/lib/types/virtual/relational-type-base.js +26 -26
- 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 +20 -19
- package/lib/utils/query-utils.d.ts +7 -0
- package/lib/utils/query-utils.js +175 -4
- package/package.json +1 -1
|
@@ -3,11 +3,64 @@
|
|
|
3
3
|
const Nife = require('nife');
|
|
4
4
|
const ProxyClass = require('../proxy-class');
|
|
5
5
|
const QueryEngineBase = require('./query-engine-base');
|
|
6
|
+
const QueryUtils = require('../utils/query-utils');
|
|
6
7
|
const {
|
|
7
8
|
LiteralBase,
|
|
8
9
|
DistinctLiteral,
|
|
9
10
|
} = require('../connection/literals');
|
|
10
11
|
|
|
12
|
+
function applyOrderClause(extraData, ...args) {
|
|
13
|
+
let entities = Nife.arrayFlatten(args);
|
|
14
|
+
|
|
15
|
+
entities = Nife.toArray(entities).map((value) => {
|
|
16
|
+
if (value == null)
|
|
17
|
+
return;
|
|
18
|
+
|
|
19
|
+
// Pass literals directly through
|
|
20
|
+
if (LiteralBase.isLiteral(value))
|
|
21
|
+
return value;
|
|
22
|
+
|
|
23
|
+
// Is the projection a field?
|
|
24
|
+
if (value.Model && value.fieldName)
|
|
25
|
+
return `${value.Model.getModelName()}:${value.fieldName}`;
|
|
26
|
+
|
|
27
|
+
if (!Nife.instanceOf(value, 'string'))
|
|
28
|
+
throw new Error('QueryEngine::ModelScope::ORDER: Invalid value provided. All values provided must be strings, fields, or literals. If you want to change the sort order of a given column, add "+" (ASC) or "-" (DESC) to be beginning of the field name. Example: .ORDER("+createdAt"), or .ORDER([ "-name", "+createdAt" ]).');
|
|
29
|
+
|
|
30
|
+
return value;
|
|
31
|
+
}).filter(Boolean);
|
|
32
|
+
|
|
33
|
+
let context = this.getOperationContext();
|
|
34
|
+
let order = this.margeFields(
|
|
35
|
+
context.order,
|
|
36
|
+
entities,
|
|
37
|
+
extraData,
|
|
38
|
+
{ isOrderBy: true },
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
this._pushOperationOntoStack({
|
|
42
|
+
control: true,
|
|
43
|
+
operator: 'ORDER',
|
|
44
|
+
queryProp: 'ORDER',
|
|
45
|
+
value: entities,
|
|
46
|
+
order,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return this._fetchScope('model');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function wrapOrderClause(func) {
|
|
53
|
+
func.DESC = (...args) => {
|
|
54
|
+
return applyOrderClause.call(this, { direction: '-' }, ...args);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
func.ASC = (...args) => {
|
|
58
|
+
return applyOrderClause.call(this, { direction: '+' }, ...args);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return func;
|
|
62
|
+
}
|
|
63
|
+
|
|
11
64
|
class ModelScope extends QueryEngineBase {
|
|
12
65
|
_getField(fieldName) {
|
|
13
66
|
let Model = this.currentContext.Model;
|
|
@@ -46,18 +99,22 @@ class ModelScope extends QueryEngineBase {
|
|
|
46
99
|
return this.currentContext.queryEngineScope.toString(...args);
|
|
47
100
|
}
|
|
48
101
|
|
|
102
|
+
margeFields(currentFields, incomingFields, extraData, options) {
|
|
103
|
+
return QueryUtils.margeFields(this, currentFields, incomingFields, extraData, options);
|
|
104
|
+
}
|
|
105
|
+
|
|
49
106
|
NOT = ProxyClass.autoCall(function() {
|
|
50
|
-
this.
|
|
107
|
+
this._pushOperationOntoStack({ logical: true, operator: 'NOT', queryProp: 'NOT', not: !this.currentContext.not });
|
|
51
108
|
return this._fetchScope('model');
|
|
52
109
|
});
|
|
53
110
|
|
|
54
111
|
AND = ProxyClass.autoCall(function(value) {
|
|
55
|
-
this.
|
|
112
|
+
this._pushOperationOntoStack({ logical: true, operator: 'AND', queryProp: 'AND', and: true, or: false, not: false, value });
|
|
56
113
|
return this._fetchScope('model');
|
|
57
114
|
});
|
|
58
115
|
|
|
59
116
|
OR = ProxyClass.autoCall(function(value) {
|
|
60
|
-
this.
|
|
117
|
+
this._pushOperationOntoStack({ logical: true, operator: 'OR', queryProp: 'OR', and: false, or: true, not: false, value });
|
|
61
118
|
return this._fetchScope('model');
|
|
62
119
|
});
|
|
63
120
|
|
|
@@ -67,7 +124,7 @@ class ModelScope extends QueryEngineBase {
|
|
|
67
124
|
throw new Error('QueryEngine::ModelScope::LIMIT: Value provided must be a valid positive number, or Infinity.');
|
|
68
125
|
|
|
69
126
|
value = Math.round(value);
|
|
70
|
-
this.
|
|
127
|
+
this._pushOperationOntoStack({ control: true, operator: 'LIMIT', queryProp: 'LIMIT', value, limit: value });
|
|
71
128
|
|
|
72
129
|
return this._fetchScope('model');
|
|
73
130
|
}
|
|
@@ -78,32 +135,93 @@ class ModelScope extends QueryEngineBase {
|
|
|
78
135
|
throw new Error('QueryEngine::ModelScope::OFFSET: Value provided must be a valid positive number.');
|
|
79
136
|
|
|
80
137
|
value = Math.round(value);
|
|
81
|
-
this.
|
|
138
|
+
this._pushOperationOntoStack({ control: true, operator: 'OFFSET', queryProp: 'OFFSET', value, offset: value });
|
|
82
139
|
|
|
83
140
|
return this._fetchScope('model');
|
|
84
141
|
}
|
|
85
142
|
|
|
86
|
-
ORDER(...args) {
|
|
87
|
-
|
|
143
|
+
ORDER = wrapOrderClause.call(this, (...args) => {
|
|
144
|
+
return applyOrderClause.call(this, { direction: '+' }, ...args);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
GROUP_BY(...args) {
|
|
148
|
+
let entities = Nife.arrayFlatten(args);
|
|
88
149
|
|
|
89
|
-
|
|
150
|
+
entities = Nife.toArray(entities).map((value) => {
|
|
90
151
|
if (value == null)
|
|
91
|
-
return
|
|
152
|
+
return;
|
|
153
|
+
|
|
154
|
+
// Pass literals directly through
|
|
155
|
+
if (LiteralBase.isLiteral(value))
|
|
156
|
+
return value;
|
|
157
|
+
|
|
158
|
+
// Is the projection a field?
|
|
159
|
+
if (value.Model && value.fieldName)
|
|
160
|
+
return `${value.Model.getModelName()}:${value.fieldName}`;
|
|
92
161
|
|
|
93
162
|
if (!Nife.instanceOf(value, 'string'))
|
|
94
|
-
throw new Error('QueryEngine::ModelScope::
|
|
163
|
+
throw new Error('QueryEngine::ModelScope::GROUP_BY: Invalid value provided. All values provided must be strings, fields, or literals. If you want to change the sort order of a given column, add "+" (ASC) or "-" (DESC) to be beginning of the field name. Example: .ORDER("+createdAt"), or .ORDER([ "-name", "+createdAt" ]).');
|
|
164
|
+
|
|
165
|
+
return value;
|
|
166
|
+
}).filter(Boolean);
|
|
167
|
+
|
|
168
|
+
let context = this.getOperationContext();
|
|
169
|
+
let groupBy = this.margeFields(
|
|
170
|
+
context.groupBy,
|
|
171
|
+
entities,
|
|
172
|
+
{},
|
|
173
|
+
{ isGroupBy: true },
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
this._pushOperationOntoStack({
|
|
177
|
+
control: true,
|
|
178
|
+
operator: 'GROUP_BY',
|
|
179
|
+
queryProp: 'GROUP_BY',
|
|
180
|
+
value: entities,
|
|
181
|
+
groupBy,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
return this._fetchScope('model');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
HAVING(query) {
|
|
188
|
+
this._pushOperationOntoStack({ control: true, operator: 'HAVING', queryProp: 'HAVING', value: query, having: query });
|
|
189
|
+
return this._fetchScope('model');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
EXISTS(_query) {
|
|
193
|
+
let query = _query;
|
|
194
|
+
let queryContext = (QueryEngineBase.isQuery(query)) ? query.getOperationContext() : null;
|
|
195
|
+
if (!queryContext || !queryContext.hasCondition)
|
|
196
|
+
throw new Error('QueryEngine::ModelScope::EXISTS: Provided value must be a query with conditions.');
|
|
197
|
+
|
|
198
|
+
if (!queryContext.projection) {
|
|
199
|
+
let Model = queryContext.Model;
|
|
200
|
+
let pkField = Model.getPrimaryKeyField();
|
|
201
|
+
|
|
202
|
+
if (pkField)
|
|
203
|
+
query = query.clone().PROJECT(pkField);
|
|
204
|
+
else
|
|
205
|
+
throw new Error('QueryEngine::ModelScope::EXISTS: Provided query must have only a single field projected.');
|
|
206
|
+
}
|
|
95
207
|
|
|
96
|
-
|
|
208
|
+
this._pushOperationOntoStack({
|
|
209
|
+
condition: true,
|
|
210
|
+
operator: 'EXISTS',
|
|
211
|
+
inverseOperator: 'NOT EXISTS',
|
|
212
|
+
queryProp: 'EXISTS',
|
|
213
|
+
value: query,
|
|
214
|
+
having: query,
|
|
215
|
+
hasCondition: true,
|
|
97
216
|
});
|
|
98
217
|
|
|
99
|
-
this._addToQuery({ control: true, operator: 'ORDER', value: values, order: values });
|
|
100
218
|
return this._fetchScope('model');
|
|
101
219
|
}
|
|
102
220
|
|
|
103
221
|
PROJECT(...args) {
|
|
104
|
-
let
|
|
222
|
+
let entities = Nife.arrayFlatten(args);
|
|
105
223
|
|
|
106
|
-
|
|
224
|
+
entities = Nife.toArray(entities).map((value) => {
|
|
107
225
|
if (value == null)
|
|
108
226
|
return;
|
|
109
227
|
|
|
@@ -119,63 +237,78 @@ class ModelScope extends QueryEngineBase {
|
|
|
119
237
|
if (value.Model && value.fieldName)
|
|
120
238
|
return value;
|
|
121
239
|
|
|
122
|
-
if (!Nife.instanceOf(value, 'string'))
|
|
123
|
-
|
|
240
|
+
if (!Nife.instanceOf(value, 'string')) {
|
|
241
|
+
console.log(entities);
|
|
242
|
+
throw new Error(`QueryEngine::ModelScope::PROJECT: Invalid value provided [${value.toString()}]. All values provided must be strings.`);
|
|
243
|
+
}
|
|
124
244
|
|
|
125
245
|
return value;
|
|
126
246
|
}).filter(Boolean);
|
|
127
247
|
|
|
128
|
-
this.
|
|
248
|
+
let context = this.getOperationContext();
|
|
249
|
+
let projection = this.margeFields(
|
|
250
|
+
context.projection,
|
|
251
|
+
entities,
|
|
252
|
+
{},
|
|
253
|
+
{ isProjection: true },
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
this._pushOperationOntoStack({
|
|
257
|
+
control: true,
|
|
258
|
+
operator: 'PROJECT',
|
|
259
|
+
queryProp: 'PROJECT',
|
|
260
|
+
value: entities,
|
|
261
|
+
projection,
|
|
262
|
+
});
|
|
263
|
+
|
|
129
264
|
return this._fetchScope('model');
|
|
130
265
|
}
|
|
131
266
|
|
|
132
267
|
DISTINCT = ProxyClass.autoCall(function(fullyQualifiedName) {
|
|
133
268
|
let currentQuery = this;
|
|
134
269
|
let distinctValue = fullyQualifiedName;
|
|
270
|
+
let context = this.getOperationContext();
|
|
135
271
|
|
|
136
272
|
if (arguments.length === 0) {
|
|
137
|
-
let context = this._getRawQueryContext();
|
|
138
273
|
let rootModel = context.rootModel;
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
currentQuery = this.PROJECT(`-${rootModel.getModelName()}:${pkFieldName}`);
|
|
274
|
+
if (rootModel) {
|
|
275
|
+
let pkFieldName = rootModel.getPrimaryKeyFieldName();
|
|
276
|
+
if (pkFieldName)
|
|
277
|
+
distinctValue = new DistinctLiteral(`${rootModel.getModelName()}:${pkFieldName}`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (!distinctValue)
|
|
281
|
+
distinctValue = new DistinctLiteral();
|
|
148
282
|
} else if (fullyQualifiedName) {
|
|
149
283
|
distinctValue = new DistinctLiteral(fullyQualifiedName);
|
|
150
|
-
currentQuery = this.PROJECT(`-${fullyQualifiedName}`);
|
|
151
284
|
}
|
|
152
285
|
|
|
153
|
-
currentQuery.
|
|
286
|
+
currentQuery._pushOperationOntoStack({ sqlFunc: true, operator: 'DISTINCT', queryProp: 'DISTINCT', value: distinctValue, distinct: distinctValue });
|
|
154
287
|
return this._fetchScope('model');
|
|
155
288
|
});
|
|
156
289
|
|
|
157
290
|
INNER_JOIN = ProxyClass.autoCall(function() {
|
|
158
|
-
this.
|
|
291
|
+
this._pushOperationOntoStack({ join: true, operator: 'JOIN', queryProp: 'INNER_JOIN', value: 'inner', joinType: 'inner', joinOuter: false });
|
|
159
292
|
return this._fetchScope('model');
|
|
160
293
|
});
|
|
161
294
|
|
|
162
295
|
LEFT_JOIN = ProxyClass.autoCall(function(outerJoin) {
|
|
163
|
-
this.
|
|
296
|
+
this._pushOperationOntoStack({ join: true, operator: 'JOIN', queryProp: 'LEFT_JOIN', value: 'left', joinType: 'left', joinOuter: !!outerJoin });
|
|
164
297
|
return this._fetchScope('model');
|
|
165
298
|
});
|
|
166
299
|
|
|
167
300
|
RIGHT_JOIN = ProxyClass.autoCall(function(outerJoin) {
|
|
168
|
-
this.
|
|
301
|
+
this._pushOperationOntoStack({ join: true, operator: 'JOIN', queryProp: 'RIGHT_JOIN', value: 'right', joinType: 'right', joinOuter: !!outerJoin });
|
|
169
302
|
return this._fetchScope('model');
|
|
170
303
|
});
|
|
171
304
|
|
|
172
305
|
FULL_JOIN = ProxyClass.autoCall(function(outerJoin) {
|
|
173
|
-
this.
|
|
306
|
+
this._pushOperationOntoStack({ join: true, operator: 'JOIN', queryProp: 'FULL_JOIN', value: 'full', joinType: 'full', joinOuter: !!outerJoin });
|
|
174
307
|
return this._fetchScope('model');
|
|
175
308
|
});
|
|
176
309
|
|
|
177
310
|
CROSS_JOIN = ProxyClass.autoCall(function() {
|
|
178
|
-
this.
|
|
311
|
+
this._pushOperationOntoStack({ join: true, operator: 'JOIN', queryProp: 'CROSS_JOIN', value: 'cross', joinType: 'cross', joinOuter: false });
|
|
179
312
|
return this._fetchScope('model');
|
|
180
313
|
});
|
|
181
314
|
|
|
@@ -183,7 +316,7 @@ class ModelScope extends QueryEngineBase {
|
|
|
183
316
|
if (!(Nife.instanceOf(type, 'string') || LiteralBase.isLiteral(type)))
|
|
184
317
|
throw new Error('QueryEngine::ModelScope::JOIN: Invalid value provided. Value must be a valid string or Literal specifying JOIN type.');
|
|
185
318
|
|
|
186
|
-
this.
|
|
319
|
+
this._pushOperationOntoStack({ join: true, operator: 'JOIN', queryProp: 'JOIN', value: type, joinType: type, joinOuter: false });
|
|
187
320
|
return this._fetchScope('model');
|
|
188
321
|
}
|
|
189
322
|
}
|
|
@@ -13,8 +13,8 @@ class QueryEngineBase extends ProxyClass {
|
|
|
13
13
|
return uuid++;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
static
|
|
17
|
-
return !!(value && value.
|
|
16
|
+
static isQueryOperationContext(value) {
|
|
17
|
+
return !!(value && value.isQueryOperationContext);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
static isQuery(value) {
|
|
@@ -27,13 +27,13 @@ class QueryEngineBase extends ProxyClass {
|
|
|
27
27
|
if (value._isQueryEngine)
|
|
28
28
|
return true;
|
|
29
29
|
|
|
30
|
-
if (typeof value.
|
|
30
|
+
if (typeof value.getOperationContext === 'function')
|
|
31
31
|
return true;
|
|
32
32
|
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
static
|
|
36
|
+
static queryOperationInfo(queryContext) {
|
|
37
37
|
let contextParams = {
|
|
38
38
|
hasCondition: false,
|
|
39
39
|
hasField: false,
|
|
@@ -63,6 +63,10 @@ class QueryEngineBase extends ProxyClass {
|
|
|
63
63
|
return this.getQueryEngineScope().getFieldScopeClass();
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
getQueryEngineScopeClass() {
|
|
67
|
+
return this.getQueryEngineScope().constructor;
|
|
68
|
+
}
|
|
69
|
+
|
|
66
70
|
_inheritContext(context, name, ...args) {
|
|
67
71
|
let newContext = Object.assign(
|
|
68
72
|
Object.create(context),
|
|
@@ -82,7 +86,7 @@ class QueryEngineBase extends ProxyClass {
|
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
_fetchScope(...scopeNames) {
|
|
85
|
-
let context = this.
|
|
89
|
+
let context = this.getOperationContext();
|
|
86
90
|
|
|
87
91
|
for (let i = 0, il = scopeNames.length; i < il; i++) {
|
|
88
92
|
let scopeName = scopeNames[i];
|
|
@@ -120,8 +124,10 @@ class QueryEngineBase extends ProxyClass {
|
|
|
120
124
|
let modelName = Model.getModelName();
|
|
121
125
|
let context = this.currentContext;
|
|
122
126
|
let extra = {};
|
|
127
|
+
let isFirst = !context.rootModel;
|
|
128
|
+
let connection = this.getConnection();
|
|
123
129
|
|
|
124
|
-
if (
|
|
130
|
+
if (isFirst) {
|
|
125
131
|
extra.rootModelName = modelName;
|
|
126
132
|
extra.rootModel = Model;
|
|
127
133
|
}
|
|
@@ -137,19 +143,19 @@ class QueryEngineBase extends ProxyClass {
|
|
|
137
143
|
throw new Error(`QueryEngine: Model "${Model.getModelName()}" is on a different connection dialect than the current query dialect of "${context.dialect}". You can not match different connection dialects in the same query.`);
|
|
138
144
|
}
|
|
139
145
|
|
|
140
|
-
if (!dialect)
|
|
141
|
-
|
|
142
|
-
if (connection)
|
|
143
|
-
dialect = connection.dialect;
|
|
144
|
-
}
|
|
146
|
+
if (!dialect && connection)
|
|
147
|
+
dialect = connection.dialect;
|
|
145
148
|
|
|
146
|
-
let newContext = this._inheritContext(context, 'model', { operator: 'MODEL', Model, modelName, dialect }, extra);
|
|
149
|
+
let newContext = this._inheritContext(context, 'model', { operator: 'MODEL', queryProp: 'Model', Model, modelName, dialect, value: modelName }, extra);
|
|
147
150
|
let newScope = new ModelScopeClass(newContext);
|
|
148
151
|
|
|
149
152
|
// We shouldn't add this scope if this is
|
|
150
153
|
// already the current model of the scope
|
|
151
154
|
if (context.Model !== Model)
|
|
152
|
-
context.
|
|
155
|
+
context.operationStack.push(newContext);
|
|
156
|
+
|
|
157
|
+
if (isFirst)
|
|
158
|
+
newScope = newScope.PROJECT(Model);
|
|
153
159
|
|
|
154
160
|
// But we always need to return the scope
|
|
155
161
|
// for the proxy to work properly
|
|
@@ -167,13 +173,13 @@ class QueryEngineBase extends ProxyClass {
|
|
|
167
173
|
extra.rootField = Field;
|
|
168
174
|
}
|
|
169
175
|
|
|
170
|
-
let newContext = this._inheritContext(context, 'field', { operator: 'FIELD', fieldName, Field }, extra);
|
|
176
|
+
let newContext = this._inheritContext(context, 'field', { operator: 'FIELD', queryProp: 'Field', fieldName, Field, value: fieldName }, extra);
|
|
171
177
|
let newScope = new FieldScopeClass(newContext);
|
|
172
178
|
|
|
173
179
|
// We shouldn't add this scope if this is
|
|
174
180
|
// already the current field of the scope
|
|
175
181
|
if (context.Field !== Field)
|
|
176
|
-
context.
|
|
182
|
+
context.operationStack.push(newContext);
|
|
177
183
|
|
|
178
184
|
// But we always need to return the scope
|
|
179
185
|
// for the proxy to work properly
|
|
@@ -193,8 +199,8 @@ class QueryEngineBase extends ProxyClass {
|
|
|
193
199
|
context.rootContext = context;
|
|
194
200
|
}
|
|
195
201
|
|
|
196
|
-
if (!context.
|
|
197
|
-
context.
|
|
202
|
+
if (!context.operationStack)
|
|
203
|
+
context.operationStack = [];
|
|
198
204
|
|
|
199
205
|
if (!('and' in context))
|
|
200
206
|
context.and = true;
|
|
@@ -204,40 +210,40 @@ class QueryEngineBase extends ProxyClass {
|
|
|
204
210
|
|
|
205
211
|
// console.log(`Creating new ${this.constructor.name} scope: `, context, Object.getPrototypeOf(context));
|
|
206
212
|
|
|
207
|
-
let
|
|
213
|
+
let operationStack = context.operationStack;
|
|
208
214
|
Object.defineProperties(this, {
|
|
209
|
-
|
|
215
|
+
operationStack: {
|
|
210
216
|
writable: false,
|
|
211
217
|
enumerable: false,
|
|
212
218
|
configurable: true,
|
|
213
|
-
value:
|
|
219
|
+
value: operationStack,
|
|
214
220
|
},
|
|
215
221
|
currentContext: {
|
|
216
222
|
enumerable: false,
|
|
217
223
|
configurable: true,
|
|
218
224
|
get: () => {
|
|
219
|
-
let currentContext =
|
|
225
|
+
let currentContext = operationStack[operationStack.length - 1];
|
|
220
226
|
return currentContext || context;
|
|
221
227
|
},
|
|
222
|
-
set:
|
|
228
|
+
set: () => {},
|
|
223
229
|
},
|
|
224
230
|
});
|
|
225
231
|
}
|
|
226
232
|
|
|
227
|
-
|
|
233
|
+
getQueryID() {
|
|
228
234
|
return this.currentContext.contextID;
|
|
229
235
|
}
|
|
230
236
|
|
|
231
|
-
|
|
237
|
+
getOperationContext() {
|
|
232
238
|
return this.currentContext;
|
|
233
239
|
}
|
|
234
240
|
|
|
235
|
-
|
|
236
|
-
return this.currentContext.
|
|
241
|
+
getOperationStack() {
|
|
242
|
+
return this.currentContext.operationStack;
|
|
237
243
|
}
|
|
238
244
|
|
|
239
|
-
|
|
240
|
-
let queryParts = this.
|
|
245
|
+
isLastOperationControl() {
|
|
246
|
+
let queryParts = this.getOperationStack();
|
|
241
247
|
let lastPart = queryParts[queryParts.length - 1];
|
|
242
248
|
|
|
243
249
|
if (Object.prototype.hasOwnProperty.call(lastPart, 'control') && lastPart.control === true)
|
|
@@ -246,8 +252,8 @@ class QueryEngineBase extends ProxyClass {
|
|
|
246
252
|
return false;
|
|
247
253
|
}
|
|
248
254
|
|
|
249
|
-
|
|
250
|
-
let queryParts = this.
|
|
255
|
+
isLastOperationCondition() {
|
|
256
|
+
let queryParts = this.getOperationStack();
|
|
251
257
|
let lastPart = queryParts[queryParts.length - 1];
|
|
252
258
|
|
|
253
259
|
if (Object.prototype.hasOwnProperty.call(lastPart, 'condition') && lastPart.condition === true)
|
|
@@ -256,13 +262,13 @@ class QueryEngineBase extends ProxyClass {
|
|
|
256
262
|
return false;
|
|
257
263
|
}
|
|
258
264
|
|
|
259
|
-
|
|
260
|
-
let context = this.
|
|
265
|
+
queryHasConditions() {
|
|
266
|
+
let context = this.getOperationContext();
|
|
261
267
|
return context.hasCondition;
|
|
262
268
|
}
|
|
263
269
|
|
|
264
|
-
|
|
265
|
-
let queryParts = this.
|
|
270
|
+
queryHasJoins() {
|
|
271
|
+
let queryParts = this.getOperationStack();
|
|
266
272
|
for (let i = 0, il = queryParts.length; i < il; i++) {
|
|
267
273
|
let queryPart = queryParts[i];
|
|
268
274
|
if (QueryEngineBase.isQuery(queryPart.value) && !queryPart.value.hasCondition)
|
|
@@ -272,8 +278,8 @@ class QueryEngineBase extends ProxyClass {
|
|
|
272
278
|
return false;
|
|
273
279
|
}
|
|
274
280
|
|
|
275
|
-
|
|
276
|
-
let query = this.
|
|
281
|
+
logQueryOperations() {
|
|
282
|
+
let query = this.getOperationStack();
|
|
277
283
|
for (let i = 0, il = query.length; i < il; i++) {
|
|
278
284
|
let queryPart = query[i];
|
|
279
285
|
let operator = queryPart.operator;
|
|
@@ -285,14 +291,13 @@ class QueryEngineBase extends ProxyClass {
|
|
|
285
291
|
else
|
|
286
292
|
console.log(`${operator} -> ${queryPart.value}`);
|
|
287
293
|
}
|
|
288
|
-
|
|
289
294
|
}
|
|
290
295
|
|
|
291
|
-
|
|
292
|
-
let context = _context || this.
|
|
293
|
-
let
|
|
296
|
+
_pushOperationOntoStack(queryPart, _context) {
|
|
297
|
+
let context = _context || this.getOperationContext();
|
|
298
|
+
let operationStack = context.operationStack;
|
|
294
299
|
|
|
295
|
-
|
|
300
|
+
operationStack.push(
|
|
296
301
|
this._inheritContext(
|
|
297
302
|
context,
|
|
298
303
|
null,
|
|
@@ -327,14 +332,115 @@ class QueryEngineBase extends ProxyClass {
|
|
|
327
332
|
}
|
|
328
333
|
|
|
329
334
|
clone() {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
let queryRootCopy = this._getRawQuery().slice();
|
|
333
|
-
let newContext = Object.assign(Object.create(context), { queryRoot: queryRootCopy });
|
|
335
|
+
return this.map((part) => part)._fetchScope('model');
|
|
336
|
+
}
|
|
334
337
|
|
|
335
|
-
|
|
338
|
+
filter(callback) {
|
|
339
|
+
const Klass = this.getQueryEngineScopeClass();
|
|
340
|
+
let context = this.getOperationContext();
|
|
341
|
+
let parts = this.getOperationStack();
|
|
342
|
+
let query = new Klass({
|
|
343
|
+
...context.rootContext,
|
|
344
|
+
connection: this.getConnection(),
|
|
345
|
+
operationStack: [],
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
for (let i = 0, il = parts.length; i < il; i++) {
|
|
349
|
+
let part = parts[i];
|
|
350
|
+
if (!part)
|
|
351
|
+
continue;
|
|
352
|
+
|
|
353
|
+
if (!callback(part, i, parts, query))
|
|
354
|
+
continue;
|
|
355
|
+
|
|
356
|
+
query._pushOperationOntoStack({ ...part });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return query;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
map(callback) {
|
|
363
|
+
const Klass = this.getQueryEngineScopeClass();
|
|
364
|
+
let context = this.getOperationContext();
|
|
365
|
+
let parts = this.getOperationStack();
|
|
366
|
+
let query = new Klass({
|
|
367
|
+
...context.rootContext,
|
|
368
|
+
connection: this.getConnection(),
|
|
369
|
+
operationStack: [],
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
for (let i = 0, il = parts.length; i < il; i++) {
|
|
373
|
+
let part = parts[i];
|
|
374
|
+
if (!part)
|
|
375
|
+
continue;
|
|
376
|
+
|
|
377
|
+
let newPart = callback({ ...part }, i, parts, query);
|
|
378
|
+
if (!newPart || typeof newPart !== 'object')
|
|
379
|
+
continue;
|
|
380
|
+
|
|
381
|
+
query._pushOperationOntoStack(newPart);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return query;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
walk(callback, _checkContextKeys) {
|
|
388
|
+
const walkQueries = (query, parent, contextKey, depth) => {
|
|
389
|
+
let parts = query.getOperationStack();
|
|
390
|
+
for (let i = 0, il = parts.length; i < il; i++) {
|
|
391
|
+
let part = parts[i];
|
|
392
|
+
if (!part)
|
|
393
|
+
continue;
|
|
394
|
+
|
|
395
|
+
for (let j = 0, jl = checkContextKeys.length; j < jl; j++) {
|
|
396
|
+
let contextKey = checkContextKeys[j];
|
|
397
|
+
if (!Object.prototype.hasOwnProperty.call(part, contextKey))
|
|
398
|
+
continue;
|
|
399
|
+
|
|
400
|
+
let value = part[contextKey];
|
|
401
|
+
if (value && this.constructor.isQuery(value))
|
|
402
|
+
walkQueries(value, part, contextKey, depth + 1);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (parent !== null)
|
|
407
|
+
callback(query, parent, contextKey, depth);
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
let checkContextKeys = _checkContextKeys || [ 'value' ];
|
|
411
|
+
walkQueries(this, null, null, 0);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
getAllModelsUsedInQuery() {
|
|
415
|
+
let Models = new Set();
|
|
416
|
+
let query = this.getOperationStack();
|
|
417
|
+
|
|
418
|
+
for (let i = 0, il = query.length; i < il; i++) {
|
|
419
|
+
let queryPart = query[i];
|
|
420
|
+
|
|
421
|
+
if (Object.prototype.hasOwnProperty.call(queryPart, 'operator') && queryPart.operator === 'MODEL') {
|
|
422
|
+
let Model = queryPart.Model;
|
|
423
|
+
Models.add(Model);
|
|
424
|
+
} else if (Object.prototype.hasOwnProperty.call(queryPart, 'condition') && queryPart.condition === true) {
|
|
425
|
+
let operatorValue = queryPart.value;
|
|
426
|
+
if (!QueryEngineBase.isQuery(operatorValue) || operatorValue.queryHasConditions())
|
|
427
|
+
continue;
|
|
428
|
+
|
|
429
|
+
let SubModels = operatorValue.getAllModelsUsedInQuery();
|
|
430
|
+
for (let j = 0, jl = SubModels.length; j < jl; j++) {
|
|
431
|
+
let Model = SubModels[j];
|
|
432
|
+
Models.add(Model);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
let allModels = Array.from(Models.values());
|
|
438
|
+
return allModels;
|
|
439
|
+
}
|
|
336
440
|
|
|
337
|
-
|
|
441
|
+
isModelUsedInQuery(Model) {
|
|
442
|
+
let allModels = this.getAllModelsUsedInQuery();
|
|
443
|
+
return (allModels.indexOf(Model) >= 0);
|
|
338
444
|
}
|
|
339
445
|
}
|
|
340
446
|
|