mythix-orm 1.0.1
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/.eslintrc.js +94 -0
- package/.vscode/launch.json +34 -0
- package/.vscode/settings.json +10 -0
- package/LICENSE +21 -0
- package/README.md +15 -0
- package/lib/connection/connection-base.js +877 -0
- package/lib/connection/index.js +11 -0
- package/lib/connection/literals/average-literal.js +14 -0
- package/lib/connection/literals/count-literal.js +18 -0
- package/lib/connection/literals/distinct-literal.js +14 -0
- package/lib/connection/literals/index.js +23 -0
- package/lib/connection/literals/literal-base.js +62 -0
- package/lib/connection/literals/literal-field-base.js +45 -0
- package/lib/connection/literals/literal.js +11 -0
- package/lib/connection/literals/max-literal.js +14 -0
- package/lib/connection/literals/min-literal.js +14 -0
- package/lib/connection/literals/sum-literal.js +14 -0
- package/lib/connection/query-generator-base.js +864 -0
- package/lib/errors/base-error.js +14 -0
- package/lib/errors/connection/access-denied-error.js +13 -0
- package/lib/errors/connection/connection-acquire-timeout-error.js +13 -0
- package/lib/errors/connection/connection-refused-error.js +13 -0
- package/lib/errors/connection/connection-timed-out-error.js +13 -0
- package/lib/errors/connection/host-not-found-error.js +13 -0
- package/lib/errors/connection/host-not-reachable-error.js +13 -0
- package/lib/errors/connection/index.js +19 -0
- package/lib/errors/connection/invalid-connection-error.js +13 -0
- package/lib/errors/connection-base-error.js +13 -0
- package/lib/errors/database/exclusion-constraint-error.js +13 -0
- package/lib/errors/database/foreign-key-constraint-error.js +13 -0
- package/lib/errors/database/index.js +13 -0
- package/lib/errors/database/timeout-error.js +13 -0
- package/lib/errors/database/unknown-constraint-error.js +13 -0
- package/lib/errors/database-base-error.js +17 -0
- package/lib/errors/index.js +44 -0
- package/lib/field.js +18 -0
- package/lib/index.js +43 -0
- package/lib/model.js +1374 -0
- package/lib/proxy-class/index.js +3 -0
- package/lib/proxy-class/proxy-class.js +269 -0
- package/lib/query-engine/field-scope.js +99 -0
- package/lib/query-engine/index.js +13 -0
- package/lib/query-engine/model-scope.js +198 -0
- package/lib/query-engine/query-engine-base.js +325 -0
- package/lib/query-engine/query-engine.js +212 -0
- package/lib/types/concrete/bigint-type.js +62 -0
- package/lib/types/concrete/blob-type.js +46 -0
- package/lib/types/concrete/boolean-type.js +41 -0
- package/lib/types/concrete/char-type.js +39 -0
- package/lib/types/concrete/date-type.js +87 -0
- package/lib/types/concrete/datetime-type.js +92 -0
- package/lib/types/concrete/float-type.js +47 -0
- package/lib/types/concrete/foreign-key-type.js +208 -0
- package/lib/types/concrete/index.js +53 -0
- package/lib/types/concrete/integer-type.js +51 -0
- package/lib/types/concrete/string-type.js +44 -0
- package/lib/types/concrete/text-type.js +44 -0
- package/lib/types/concrete/uuid-base.js +77 -0
- package/lib/types/concrete/uuid-v1-type.js +99 -0
- package/lib/types/concrete/uuid-v3-type.js +108 -0
- package/lib/types/concrete/uuid-v4-type.js +90 -0
- package/lib/types/concrete/uuid-v5-type.js +108 -0
- package/lib/types/concrete/xid-type.js +58 -0
- package/lib/types/helpers/default-helpers.js +127 -0
- package/lib/types/helpers/index.js +35 -0
- package/lib/types/index.js +94 -0
- package/lib/types/type.js +244 -0
- package/lib/types/virtual/index.js +14 -0
- package/lib/types/virtual/model-type.js +141 -0
- package/lib/types/virtual/models-type.js +264 -0
- package/lib/types/virtual/relational-type-base.js +323 -0
- package/lib/utils/index.js +65 -0
- package/lib/utils/misc-utils.js +73 -0
- package/lib/utils/model-utils.js +704 -0
- package/lib/utils/query-utils.js +186 -0
- package/package.json +63 -0
- package/playground/test01.js +15 -0
- package/spec/connection/connection-base-spec.js +126 -0
- package/spec/connection/literals/average-literal-spec.js +45 -0
- package/spec/connection/literals/count-literal-spec.js +42 -0
- package/spec/connection/literals/distinct-literal-spec.js +42 -0
- package/spec/connection/literals/literal-spec.js +26 -0
- package/spec/connection/literals/max-literal-spec.js +42 -0
- package/spec/connection/literals/min-literal-spec.js +42 -0
- package/spec/connection/literals/sum-literal-spec.js +42 -0
- package/spec/helpers/default-helpers-spec.js +108 -0
- package/spec/model-spec.js +736 -0
- package/spec/proxy-class/proxy-class-spec.js +173 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_chain_query_conditions-001.snapshot +94 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_construct_a_query_context_with_a_model_call-001.snapshot +35 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_construct_a_query_context_with_a_model_sub-001.snapshot +35 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_set_a_default_scope_on_a_model-001.snapshot +57 -0
- package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_unscope_default_scope_on_a_model-001.snapshot +35 -0
- package/spec/query-engine/query-engine-spec.js +99 -0
- package/spec/support/jasmine.json +13 -0
- package/spec/support/models/blob-test-model.js +19 -0
- package/spec/support/models/extended-user-model.js +38 -0
- package/spec/support/models/index.js +27 -0
- package/spec/support/models/number-model.js +24 -0
- package/spec/support/models/role-model.js +26 -0
- package/spec/support/models/role-thing-model.js +41 -0
- package/spec/support/models/scoped-user-model.js +13 -0
- package/spec/support/models/time-model.js +36 -0
- package/spec/support/models/user-model.js +70 -0
- package/spec/support/models/user-role-model.js +36 -0
- package/spec/support/models/user-thing-model.js +46 -0
- package/spec/support/models/validation-test-model.js +40 -0
- package/spec/support/snapshots.js +293 -0
- package/spec/support/test-helpers.js +13 -0
- package/spec/types/concrete/bigint-type-spec.js +84 -0
- package/spec/types/concrete/boolean-type-spec.js +83 -0
- package/spec/types/concrete/date-type-spec.js +85 -0
- package/spec/types/concrete/datetime-type-spec.js +87 -0
- package/spec/types/concrete/float-type-spec.js +71 -0
- package/spec/types/concrete/foreign-key-type-spec.js +64 -0
- package/spec/types/concrete/integer-type-spec.js +71 -0
- package/spec/types/concrete/string-type-spec.js +91 -0
- package/spec/types/concrete/uuid-v1-type-spec.js +73 -0
- package/spec/types/concrete/uuid-v4-type-spec.js +65 -0
- package/spec/types/type-spec.js +101 -0
- package/spec/types/virtual/model-types-spec.js +401 -0
- package/spec/utils/misc-utils-spec.js +61 -0
- package/spec/utils/model-utils-spec.js +55 -0
- package/spec/utils/query-utils-spec.js +105 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
/* eslint-disable max-classes-per-file */
|
|
3
|
+
/* eslint-disable lines-between-class-members */
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const APPLY = Symbol.for('@_apply');
|
|
8
|
+
const CALLABLE = Symbol.for('@_callable');
|
|
9
|
+
const CONSTRUCT = Symbol.for('@_construct');
|
|
10
|
+
const DEFINE_PROPERTY = Symbol.for('@_defineProperty');
|
|
11
|
+
const DELETE_PROPERTY = Symbol.for('@_deleteProperty');
|
|
12
|
+
const GET = Symbol.for('@_get');
|
|
13
|
+
const GET_OWN_PROPERTY_DESCRIPTOR = Symbol.for('@_getOwnPropertyDescriptor');
|
|
14
|
+
const GET_PROTOTYPEOF = Symbol.for('@_getPrototypeOf');
|
|
15
|
+
const HAS = Symbol.for('@_has');
|
|
16
|
+
const IS_EXTENSIBLE = Symbol.for('@_isExtensible');
|
|
17
|
+
const MISSING = Symbol.for('@_missing');
|
|
18
|
+
const OWN_KEYS = Symbol.for('@_ownKeys');
|
|
19
|
+
const PREVENT_EXTENSIONS = Symbol.for('@_preventExtensions');
|
|
20
|
+
const SET = Symbol.for('@_set');
|
|
21
|
+
const SET_PROTOTYPEOF = Symbol.for('@_setPrototypeOf');
|
|
22
|
+
const PROXY = Symbol.for('@__proxy');
|
|
23
|
+
const TARGET = Symbol.for('@__target');
|
|
24
|
+
const SELF = Symbol.for('@__rootInstance');
|
|
25
|
+
const AUTO_CALL_CALLER = Symbol.for('@__autoCallCaller');
|
|
26
|
+
const AUTO_CALL_CALLED = Symbol.for('@__autoCallCalled');
|
|
27
|
+
const AUTO_CALL = Symbol.for('@__autoCall');
|
|
28
|
+
|
|
29
|
+
function shouldSkipProxy(prop) {
|
|
30
|
+
if (prop === PROXY || prop === TARGET || prop === SELF || prop === AUTO_CALL_CALLER || prop === AUTO_CALL_CALLED || prop === AUTO_CALL)
|
|
31
|
+
return true;
|
|
32
|
+
|
|
33
|
+
if (prop in Object.prototype)
|
|
34
|
+
return true;
|
|
35
|
+
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class ProxyClass {
|
|
40
|
+
static APPLY = APPLY;
|
|
41
|
+
static CALLABLE = CALLABLE;
|
|
42
|
+
static CONSTRUCT = CONSTRUCT;
|
|
43
|
+
static DEFINE_PROPERTY = DEFINE_PROPERTY;
|
|
44
|
+
static DELETE_PROPERTY = DELETE_PROPERTY;
|
|
45
|
+
static GET = GET;
|
|
46
|
+
static GET_OWN_PROPERTY_DESCRIPTOR = GET_OWN_PROPERTY_DESCRIPTOR;
|
|
47
|
+
static GET_PROTOTYPEOF = GET_PROTOTYPEOF;
|
|
48
|
+
static HAS = HAS;
|
|
49
|
+
static IS_EXTENSIBLE = IS_EXTENSIBLE;
|
|
50
|
+
static MISSING = MISSING;
|
|
51
|
+
static OWN_KEYS = OWN_KEYS;
|
|
52
|
+
static PREVENT_EXTENSIONS = PREVENT_EXTENSIONS;
|
|
53
|
+
static SET = SET;
|
|
54
|
+
static SET_PROTOTYPEOF = SET_PROTOTYPEOF;
|
|
55
|
+
static PROXY = PROXY;
|
|
56
|
+
static TARGET = TARGET;
|
|
57
|
+
static SELF = SELF;
|
|
58
|
+
static AUTO_CALL_CALLER = AUTO_CALL_CALLER;
|
|
59
|
+
static AUTO_CALL_CALLED = AUTO_CALL_CALLED;
|
|
60
|
+
static AUTO_CALL = AUTO_CALL;
|
|
61
|
+
|
|
62
|
+
static shouldSkipProxy = shouldSkipProxy;
|
|
63
|
+
|
|
64
|
+
static autoCall(func) {
|
|
65
|
+
Object.defineProperties(func, {
|
|
66
|
+
[AUTO_CALL]: {
|
|
67
|
+
writable: true,
|
|
68
|
+
enumberable: false,
|
|
69
|
+
configurable: true,
|
|
70
|
+
value: true,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return func;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static createProxy(_proxyTarget, forceSpecifiedContext) {
|
|
78
|
+
let me = (forceSpecifiedContext) ? this : (this[SELF] || this);
|
|
79
|
+
let proxyTarget = _proxyTarget || me[CALLABLE] || me;
|
|
80
|
+
|
|
81
|
+
let proxy = new Proxy(proxyTarget, {
|
|
82
|
+
apply: function(target, thisArg, argumentsList) {
|
|
83
|
+
return me[APPLY].call(me, target, thisArg, argumentsList);
|
|
84
|
+
},
|
|
85
|
+
construct: function(target, argumentsList, newTarget) {
|
|
86
|
+
return me[CONSTRUCT].call(me, target, argumentsList, newTarget);
|
|
87
|
+
},
|
|
88
|
+
defineProperty: function(target, key, descriptor) {
|
|
89
|
+
return me[DEFINE_PROPERTY].call(me, target, key, descriptor);
|
|
90
|
+
},
|
|
91
|
+
deleteProperty: function(target, prop) {
|
|
92
|
+
return me[DELETE_PROPERTY].call(me, target, prop);
|
|
93
|
+
},
|
|
94
|
+
get: function(target, prop, receiver) {
|
|
95
|
+
if (shouldSkipProxy(prop))
|
|
96
|
+
return me[prop];
|
|
97
|
+
|
|
98
|
+
if (typeof prop !== 'symbol' && prop !== '__autoCall' && prop !== '__call') {
|
|
99
|
+
let autoCall = me[AUTO_CALL_CALLER];
|
|
100
|
+
if (typeof autoCall === 'function' && me[AUTO_CALL_CALLED] === false) {
|
|
101
|
+
me[AUTO_CALL_CALLED] = true;
|
|
102
|
+
autoCall.call(me);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (prop in me) {
|
|
107
|
+
let value = me[GET].call(me, target, prop, receiver);
|
|
108
|
+
|
|
109
|
+
if (typeof value === 'function' && value[AUTO_CALL] === true)
|
|
110
|
+
return me.constructor.createProxy.call(Object.create(me), value, true).__autoCall(value);
|
|
111
|
+
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return me[MISSING].call(me, target, prop, receiver);
|
|
116
|
+
},
|
|
117
|
+
getOwnPropertyDescriptor: function(target, prop) {
|
|
118
|
+
return me[GET_OWN_PROPERTY_DESCRIPTOR].call(me, target, prop);
|
|
119
|
+
},
|
|
120
|
+
getPrototypeOf: function(target) {
|
|
121
|
+
return me[GET_PROTOTYPEOF].call(me, target);
|
|
122
|
+
},
|
|
123
|
+
has: function(target, prop) {
|
|
124
|
+
return me[HAS].call(me, target, prop);
|
|
125
|
+
},
|
|
126
|
+
isExtensible: function(target) {
|
|
127
|
+
return me[IS_EXTENSIBLE].call(me, target);
|
|
128
|
+
},
|
|
129
|
+
ownKeys: function(target) {
|
|
130
|
+
return me[OWN_KEYS].call(me, target);
|
|
131
|
+
},
|
|
132
|
+
preventExtensions: function(target) {
|
|
133
|
+
return me[PREVENT_EXTENSIONS].call(me, target);
|
|
134
|
+
},
|
|
135
|
+
set: function(target, prop, value, receiver) {
|
|
136
|
+
if (typeof prop !== 'symbol' && prop !== '__autoCall' && prop !== '__call') {
|
|
137
|
+
let autoCall = me[AUTO_CALL_CALLER];
|
|
138
|
+
if (typeof autoCall === 'function' && me[AUTO_CALL_CALLED] === false) {
|
|
139
|
+
me[AUTO_CALL_CALLED] = true;
|
|
140
|
+
autoCall.call(me);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return me[SET].call(me, target, prop, value, receiver);
|
|
145
|
+
},
|
|
146
|
+
setPrototypeOf: function(target, prototype) {
|
|
147
|
+
return me[SET_PROTOTYPEOF].call(me, target, prototype);
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
Object.defineProperties(me, {
|
|
152
|
+
[PROXY]: {
|
|
153
|
+
writable: true,
|
|
154
|
+
enumberable: false,
|
|
155
|
+
configurable: true,
|
|
156
|
+
value: proxy,
|
|
157
|
+
},
|
|
158
|
+
[TARGET]: {
|
|
159
|
+
writable: true,
|
|
160
|
+
enumberable: false,
|
|
161
|
+
configurable: true,
|
|
162
|
+
value: proxyTarget,
|
|
163
|
+
},
|
|
164
|
+
[SELF]: {
|
|
165
|
+
writable: true,
|
|
166
|
+
enumberable: false,
|
|
167
|
+
configurable: true,
|
|
168
|
+
value: me,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return proxy;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
constructor() {
|
|
176
|
+
Object.defineProperties(this, {
|
|
177
|
+
[AUTO_CALL_CALLER]: {
|
|
178
|
+
writable: true,
|
|
179
|
+
enumberable: false,
|
|
180
|
+
configurable: true,
|
|
181
|
+
value: null,
|
|
182
|
+
},
|
|
183
|
+
[AUTO_CALL_CALLED]: {
|
|
184
|
+
writable: true,
|
|
185
|
+
enumberable: false,
|
|
186
|
+
configurable: true,
|
|
187
|
+
value: false,
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
let proxy = ProxyClass.createProxy.call(this);
|
|
192
|
+
return proxy;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
__autoCall(caller) {
|
|
196
|
+
this[AUTO_CALL_CALLER] = caller;
|
|
197
|
+
this[AUTO_CALL_CALLED] = false;
|
|
198
|
+
|
|
199
|
+
return this;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
__call(caller) {
|
|
203
|
+
return ProxyClass.createProxy.call(this, caller.bind(this[PROXY]));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
[APPLY](target, thisArg, argumentsList) {
|
|
207
|
+
return target.apply(thisArg, argumentsList);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
[CONSTRUCT](target, argumentsList, newTarget) {
|
|
211
|
+
let self = Object.create(target.prototype);
|
|
212
|
+
let result = newTarget.apply(self, argumentsList);
|
|
213
|
+
|
|
214
|
+
if (!result || typeof result !== 'object')
|
|
215
|
+
return self;
|
|
216
|
+
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
[DEFINE_PROPERTY](target, key, descriptor) {
|
|
221
|
+
return Object.defineProperty(this, key, descriptor);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
[DELETE_PROPERTY](target, prop) {
|
|
225
|
+
return delete this[prop];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
[GET](target, prop) {
|
|
229
|
+
return this[prop];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
[GET_OWN_PROPERTY_DESCRIPTOR](target, prop) {
|
|
233
|
+
return Object.getOwnPropertyDescriptor(target, prop);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
[GET_PROTOTYPEOF](target) {
|
|
237
|
+
return Object.getPrototypeOf(this);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
[HAS](target, prop) {
|
|
241
|
+
return (prop in this);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
[IS_EXTENSIBLE](target) {
|
|
245
|
+
return Object.isExtensible(this);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
[MISSING]() {
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
[OWN_KEYS](target) {
|
|
252
|
+
return Reflect.ownKeys(this);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
[PREVENT_EXTENSIONS](target) {
|
|
256
|
+
return Object.preventExtensions(this);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
[SET](target, prop, value) {
|
|
260
|
+
this[prop] = value;
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
[SET_PROTOTYPEOF](target, prototype) {
|
|
265
|
+
return Object.setPrototypeOf(this, prototype);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
module.exports = ProxyClass;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Nife = require('nife');
|
|
4
|
+
const ProxyClass = require('../proxy-class');
|
|
5
|
+
const QueryEngineBase = require('./query-engine-base');
|
|
6
|
+
|
|
7
|
+
function addOperatorToQuery(name, inverseName, value) {
|
|
8
|
+
if (Nife.instanceOf(value, 'object'))
|
|
9
|
+
throw new Error(`QueryEngine::addOperatorToQuery: ${name}(${value}) makes no sense...`);
|
|
10
|
+
|
|
11
|
+
this._addToQuery({
|
|
12
|
+
condition: true,
|
|
13
|
+
operator: name,
|
|
14
|
+
inverseOperator: inverseName,
|
|
15
|
+
value: this._fetchOperatorValue(value),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return this._fetchScope('model');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class FieldScope extends QueryEngineBase {
|
|
22
|
+
NOT = ProxyClass.autoCall(function() {
|
|
23
|
+
this._addToQuery({ logical: true, operator: 'NOT', not: !this.currentContext.not });
|
|
24
|
+
return this[ProxyClass.PROXY];
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
unscoped() {
|
|
28
|
+
return this.currentContext.queryEngineScope.unscoped(this.currentContext);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
toString(...args) {
|
|
32
|
+
if (args.length === 0)
|
|
33
|
+
return `${this.constructor.name} {}`;
|
|
34
|
+
|
|
35
|
+
return this.currentContext.queryEngineScope.toString(...args);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
toSQL() {
|
|
39
|
+
return this.currentContext.queryEngineScope.toSQL();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
_fetchOperatorValue(_value) {
|
|
43
|
+
let value = _value;
|
|
44
|
+
if (!value)
|
|
45
|
+
return value;
|
|
46
|
+
|
|
47
|
+
if (value._isMythixModel) {
|
|
48
|
+
// If a model class was supplied, then get the model query engine
|
|
49
|
+
// and the primary key of the model
|
|
50
|
+
|
|
51
|
+
let pkFieldName = value.getPrimaryKeyFieldName();
|
|
52
|
+
if (Nife.isEmpty(pkFieldName))
|
|
53
|
+
throw new Error(`${this.constructor.name}::_fetchOperatorValue: Invalid operation: You asked me to match against a model class, but model has no primary key, so I do not know what to match against.`);
|
|
54
|
+
|
|
55
|
+
return value.where(this.getConnection())[pkFieldName];
|
|
56
|
+
} else if (value._mythixModelInstance) {
|
|
57
|
+
// If a model instance was supplied
|
|
58
|
+
// then get the model's PK value
|
|
59
|
+
let pkFieldName = value.getPrimaryKeyFieldName();
|
|
60
|
+
if (Nife.isEmpty(pkFieldName))
|
|
61
|
+
throw new Error(`${this.constructor.name}::_fetchOperatorValue: Invalid operation: You asked me to match against a model instance, but model has no primary key, so I do not know what to match against.`);
|
|
62
|
+
|
|
63
|
+
return value[pkFieldName];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
EQ(value) {
|
|
70
|
+
return addOperatorToQuery.call(this, 'EQ', 'NEQ', value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
NEQ(value) {
|
|
74
|
+
return addOperatorToQuery.call(this, 'NEQ', 'EQ', value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
GT(value) {
|
|
78
|
+
return addOperatorToQuery.call(this, 'GT', 'LTE', value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
GTE(value) {
|
|
82
|
+
return addOperatorToQuery.call(this, 'GTE', 'LT', value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
LT(value) {
|
|
86
|
+
return addOperatorToQuery.call(this, 'LT', 'GTE', value);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
LTE(value) {
|
|
90
|
+
return addOperatorToQuery.call(this, 'LTE', 'GT', value);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
[ProxyClass.MISSING](target, prop) {
|
|
94
|
+
let lowerScope = this._fetchScope('model');
|
|
95
|
+
return lowerScope[prop];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = FieldScope;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const QueryEngineBase = require('./query-engine-base');
|
|
4
|
+
const QueryEngine = require('./query-engine');
|
|
5
|
+
const ModelScope = require('./model-scope');
|
|
6
|
+
const FieldScope = require('./field-scope');
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
QueryEngineBase,
|
|
10
|
+
QueryEngine,
|
|
11
|
+
ModelScope,
|
|
12
|
+
FieldScope,
|
|
13
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Nife = require('nife');
|
|
4
|
+
const ProxyClass = require('../proxy-class');
|
|
5
|
+
const QueryEngineBase = require('./query-engine-base');
|
|
6
|
+
const {
|
|
7
|
+
LiteralBase,
|
|
8
|
+
DistinctLiteral,
|
|
9
|
+
} = require('../connection/literals');
|
|
10
|
+
|
|
11
|
+
class ModelScope extends QueryEngineBase {
|
|
12
|
+
_getField(fieldName) {
|
|
13
|
+
let Model = this.currentContext.Model;
|
|
14
|
+
return Model.getField(fieldName);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
_getQueryEngineClass() {
|
|
18
|
+
return this.currentContext.queryEngine;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Field(fieldName) {
|
|
22
|
+
let field = this._getField(fieldName);
|
|
23
|
+
if (!field)
|
|
24
|
+
throw new Error(`QueryEngine::ModelScope::Field: Requested field "${fieldName}" not found.`);
|
|
25
|
+
|
|
26
|
+
return this._newFieldScope(field);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
[ProxyClass.MISSING](target, prop) {
|
|
30
|
+
if (prop === 'where' || prop === '$')
|
|
31
|
+
return this._fetchScope('model');
|
|
32
|
+
|
|
33
|
+
let field = this._getField(prop);
|
|
34
|
+
if (field)
|
|
35
|
+
return this._newFieldScope(field);
|
|
36
|
+
|
|
37
|
+
let lowerScope = this._fetchScope('queryEngine');
|
|
38
|
+
return lowerScope[prop];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
unscoped() {
|
|
42
|
+
return this.currentContext.queryEngineScope.unscoped(this.currentContext);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
toString(...args) {
|
|
46
|
+
if (args.length === 0)
|
|
47
|
+
return `${this.constructor.name} {}`;
|
|
48
|
+
|
|
49
|
+
return this.currentContext.queryEngineScope.toString(...args);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
toSQL() {
|
|
53
|
+
return this.currentContext.queryEngineScope.toSQL();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
NOT = ProxyClass.autoCall(function() {
|
|
57
|
+
this._addToQuery({ logical: true, operator: 'NOT', not: !this.currentContext.not });
|
|
58
|
+
return this._fetchScope('model');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
AND = ProxyClass.autoCall(function(value) {
|
|
62
|
+
this._addToQuery({ logical: true, operator: 'AND', and: true, or: false, not: false, value });
|
|
63
|
+
return this._fetchScope('model');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
OR = ProxyClass.autoCall(function(value) {
|
|
67
|
+
this._addToQuery({ logical: true, operator: 'OR', and: false, or: true, not: false, value });
|
|
68
|
+
return this._fetchScope('model');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
LIMIT(_value) {
|
|
72
|
+
let value = _value;
|
|
73
|
+
if (typeof value !== 'number' || isNaN(value) || value < 0)
|
|
74
|
+
throw new Error('QueryEngine::ModelScope::LIMIT: Value provided must be a valid positive number, or Infinity.');
|
|
75
|
+
|
|
76
|
+
value = Math.round(value);
|
|
77
|
+
this._addToQuery({ control: true, operator: 'LIMIT', value, limit: value });
|
|
78
|
+
|
|
79
|
+
return this._fetchScope('model');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
OFFSET(_value) {
|
|
83
|
+
let value = _value;
|
|
84
|
+
if (typeof value !== 'number' || !isFinite(value) || value < 0)
|
|
85
|
+
throw new Error('QueryEngine::ModelScope::OFFSET: Value provided must be a valid positive number.');
|
|
86
|
+
|
|
87
|
+
value = Math.round(value);
|
|
88
|
+
this._addToQuery({ control: true, operator: 'OFFSET', value, offset: value });
|
|
89
|
+
|
|
90
|
+
return this._fetchScope('model');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
ORDER(...args) {
|
|
94
|
+
let values = Nife.arrayFlatten(args);
|
|
95
|
+
|
|
96
|
+
values = Nife.toArray(values).filter((value) => {
|
|
97
|
+
if (value == null)
|
|
98
|
+
return false;
|
|
99
|
+
|
|
100
|
+
if (!Nife.instanceOf(value, 'string'))
|
|
101
|
+
throw new Error('QueryEngine::ModelScope::ORDER: Invalid value provided. All values provided must be strings. 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" ]).');
|
|
102
|
+
|
|
103
|
+
return true;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
this._addToQuery({ control: true, operator: 'ORDER', value: values, order: values });
|
|
107
|
+
return this._fetchScope('model');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
PROJECT(...args) {
|
|
111
|
+
let values = Nife.arrayFlatten(args);
|
|
112
|
+
|
|
113
|
+
values = Nife.toArray(values).map((value) => {
|
|
114
|
+
if (value == null)
|
|
115
|
+
return;
|
|
116
|
+
|
|
117
|
+
// Pass literals directly through
|
|
118
|
+
if (value instanceof LiteralBase)
|
|
119
|
+
return value;
|
|
120
|
+
|
|
121
|
+
// Is the projection a model?
|
|
122
|
+
if (value._isMythixModel)
|
|
123
|
+
return value;
|
|
124
|
+
|
|
125
|
+
// Is the projection a field?
|
|
126
|
+
if (value.Model && value.fieldName)
|
|
127
|
+
return value;
|
|
128
|
+
|
|
129
|
+
if (!Nife.instanceOf(value, 'string'))
|
|
130
|
+
throw new Error('QueryEngine::ModelScope::PROJECT: Invalid value provided. All values provided must be strings.');
|
|
131
|
+
|
|
132
|
+
return value;
|
|
133
|
+
}).filter(Boolean);
|
|
134
|
+
|
|
135
|
+
this._addToQuery({ control: true, operator: 'PROJECT', value: values });
|
|
136
|
+
return this._fetchScope('model');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
DISTINCT = ProxyClass.autoCall(function(fullyQualifiedName) {
|
|
140
|
+
let currentQuery = this;
|
|
141
|
+
let distinctValue = fullyQualifiedName;
|
|
142
|
+
|
|
143
|
+
if (arguments.length === 0) {
|
|
144
|
+
let context = this._getRawQueryContext();
|
|
145
|
+
let rootModel = context.rootModel;
|
|
146
|
+
if (!rootModel)
|
|
147
|
+
throw new Error(`${this.constructor.name}::DISTINCT: Attempted to apply DISTINCT to the root model of the query, but no root model was found.`);
|
|
148
|
+
|
|
149
|
+
let pkFieldName = rootModel.getPrimaryKeyFieldName();
|
|
150
|
+
if (!pkFieldName)
|
|
151
|
+
throw new Error(`${this.constructor.name}::DISTINCT: Attempted to apply DISTINCT to the root model of the query, but the root model has no primary key. Try directly specifying the DISTINCT field instead.`);
|
|
152
|
+
|
|
153
|
+
distinctValue = new DistinctLiteral(`${rootModel.getModelName()}:${pkFieldName}`);
|
|
154
|
+
currentQuery = this.PROJECT(`-${rootModel.getModelName()}:${pkFieldName}`);
|
|
155
|
+
} else if (fullyQualifiedName) {
|
|
156
|
+
distinctValue = new DistinctLiteral(fullyQualifiedName);
|
|
157
|
+
currentQuery = this.PROJECT(`-${fullyQualifiedName}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
currentQuery._addToQuery({ control: true, operator: 'DISTINCT', value: distinctValue, distinct: distinctValue });
|
|
161
|
+
return this._fetchScope('model');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
INNER_JOIN = ProxyClass.autoCall(function() {
|
|
165
|
+
this._addToQuery({ control: true, operator: 'JOIN', value: 'inner', joinType: 'inner', joinOuter: false });
|
|
166
|
+
return this._fetchScope('model');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
LEFT_JOIN = ProxyClass.autoCall(function(outerJoin) {
|
|
170
|
+
this._addToQuery({ control: true, operator: 'JOIN', value: 'left', joinType: 'left', joinOuter: !!outerJoin });
|
|
171
|
+
return this._fetchScope('model');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
RIGHT_JOIN = ProxyClass.autoCall(function(outerJoin) {
|
|
175
|
+
this._addToQuery({ control: true, operator: 'JOIN', value: 'right', joinType: 'right', joinOuter: !!outerJoin });
|
|
176
|
+
return this._fetchScope('model');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
FULL_JOIN = ProxyClass.autoCall(function(outerJoin) {
|
|
180
|
+
this._addToQuery({ control: true, operator: 'JOIN', value: 'full', joinType: 'full', joinOuter: !!outerJoin });
|
|
181
|
+
return this._fetchScope('model');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
CROSS_JOIN = ProxyClass.autoCall(function() {
|
|
185
|
+
this._addToQuery({ control: true, operator: 'JOIN', value: 'cross', joinType: 'cross', joinOuter: false });
|
|
186
|
+
return this._fetchScope('model');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
JOIN(type) {
|
|
190
|
+
if (Nife.isEmpty(type) || !Nife.instanceOf(type, 'string'))
|
|
191
|
+
throw new Error('QueryEngine::ModelScope::JOIN: Invalid value provided. Value must be a valid string specifying JOIN type.');
|
|
192
|
+
|
|
193
|
+
this._addToQuery({ control: true, operator: 'JOIN', value: type, joinType: type, joinOuter: false });
|
|
194
|
+
return this._fetchScope('model');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
module.exports = ModelScope;
|