mythix-orm 1.11.7 → 1.13.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/lib/connection/connection-base.js +29 -35
- package/lib/connection/literals/literal-base.js +14 -2
- package/lib/connection/query-generator-base.js +273 -0
- package/lib/model.js +16 -2
- package/lib/proxy-class/proxy-class.js +156 -21
- package/lib/query-engine/model-scope.js +12 -12
- package/lib/utils/async-store.js +80 -3
- package/lib/utils/index.js +2 -2
- package/lib/utils/misc-utils.js +38 -0
- package/lib/utils/query-utils.d.ts +1 -1
- package/lib/utils/query-utils.js +128 -37
- package/package.json +1 -2
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const { DateTime } = require('luxon');
|
|
4
4
|
const EventEmitter = require('events');
|
|
5
5
|
const Nife = require('nife');
|
|
6
|
-
const SqlString = require('sqlstring');
|
|
7
6
|
const { QueryEngine } = require('../query-engine');
|
|
8
7
|
const Utils = require('../utils');
|
|
9
8
|
const { Model: ModelBase } = require('../model');
|
|
@@ -230,6 +229,8 @@ class ConnectionBase extends EventEmitter {
|
|
|
230
229
|
|
|
231
230
|
if (!options.queryGenerator)
|
|
232
231
|
options.queryGenerator = this.createQueryGenerator(options);
|
|
232
|
+
else
|
|
233
|
+
options.queryGenerator.setConnection(this);
|
|
233
234
|
|
|
234
235
|
Object.defineProperties(this, {
|
|
235
236
|
'dialect': {
|
|
@@ -395,11 +396,9 @@ class ConnectionBase extends EventEmitter {
|
|
|
395
396
|
/// options: object
|
|
396
397
|
/// Operation specific options (i.e. options for a "select" call)
|
|
397
398
|
///
|
|
398
|
-
/// Return:
|
|
399
|
-
///
|
|
400
|
-
///
|
|
401
|
-
/// are also valid return values (in which case no order will be
|
|
402
|
-
/// applied to the given operation).
|
|
399
|
+
/// Return: Map<string, { value: Field | Literal | string; direction?: '+' | '-'; ... }>
|
|
400
|
+
/// Return the field-set for the default ordering to apply to the operation taking place.
|
|
401
|
+
/// This `Map` should have the same format as is returned by <see>ModelScope.mergeFields</see>.
|
|
403
402
|
getDefaultOrder(Model, options) {
|
|
404
403
|
}
|
|
405
404
|
|
|
@@ -751,7 +750,7 @@ class ConnectionBase extends EventEmitter {
|
|
|
751
750
|
/// it was created.
|
|
752
751
|
///
|
|
753
752
|
/// Arguments:
|
|
754
|
-
///
|
|
753
|
+
/// models: Array<class <see>Model</see>> | { [key: string]: class <see>Model</see> }
|
|
755
754
|
/// The model classes to register with this connection. If no models are bound, then
|
|
756
755
|
/// they will simply exist in the model pool for this connection. If bound, then
|
|
757
756
|
/// this connection will bind itself to every model being registered.
|
|
@@ -761,13 +760,14 @@ class ConnectionBase extends EventEmitter {
|
|
|
761
760
|
/// provided to the connection when it was created. If you specify either of these
|
|
762
761
|
/// options they simply override the connection's default.
|
|
763
762
|
///
|
|
764
|
-
/// Return: class <see>Model</see>
|
|
763
|
+
/// Return: { [key: string]: class <see>Model</see> }
|
|
765
764
|
/// The registered model classes, **which may have changed during registration**.
|
|
766
765
|
/// It is not uncommon for the connection driver itself to modify the model
|
|
767
766
|
/// classes, or to return a new model classes that inherit from your model classes.
|
|
768
767
|
/// The classes that are returned should be the classes that you use for this connection,
|
|
769
768
|
/// and will be the same classes returned by a call to <see>Connection.getModel</see>,
|
|
770
|
-
/// or <see>Connection.getModels</see>.
|
|
769
|
+
/// or <see>Connection.getModels</see>. An object is returned, where each key is
|
|
770
|
+
/// a model name, and each value is a model class.
|
|
771
771
|
registerModels(models, options) {
|
|
772
772
|
if (!models)
|
|
773
773
|
return;
|
|
@@ -1054,7 +1054,14 @@ class ConnectionBase extends EventEmitter {
|
|
|
1054
1054
|
/// Return the <see>QueryGenerator</see> for this connection,
|
|
1055
1055
|
/// or return `null` if none is defined for this connection.
|
|
1056
1056
|
getQueryGenerator() {
|
|
1057
|
-
|
|
1057
|
+
let queryGenerator = this.queryGenerator;
|
|
1058
|
+
if (queryGenerator) {
|
|
1059
|
+
let connection = queryGenerator.getConnection();
|
|
1060
|
+
if (!connection)
|
|
1061
|
+
queryGenerator.setConnection(this);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
return queryGenerator;
|
|
1058
1065
|
}
|
|
1059
1066
|
|
|
1060
1067
|
/// Set the <see>QueryGenerator</see> instance for this
|
|
@@ -1078,15 +1085,10 @@ class ConnectionBase extends EventEmitter {
|
|
|
1078
1085
|
}
|
|
1079
1086
|
|
|
1080
1087
|
/// The low-level DB interface for escaping a
|
|
1081
|
-
/// value. By default this function
|
|
1082
|
-
///
|
|
1083
|
-
///
|
|
1084
|
-
///
|
|
1085
|
-
/// using should be used instead of this. This is
|
|
1086
|
-
/// a "default implementation" that is meant as a
|
|
1087
|
-
/// fallback when a connection doesn't provide its
|
|
1088
|
-
/// own, but each connection should provide its own
|
|
1089
|
-
/// when it is able.
|
|
1088
|
+
/// value. By default this function simply returns
|
|
1089
|
+
/// the value it is provided. It is up to the
|
|
1090
|
+
/// database driver itself to provide a proper
|
|
1091
|
+
/// implementation of this method.
|
|
1090
1092
|
///
|
|
1091
1093
|
/// Note:
|
|
1092
1094
|
/// This method escapes "values" that are given in
|
|
@@ -1095,8 +1097,7 @@ class ConnectionBase extends EventEmitter {
|
|
|
1095
1097
|
/// instead.
|
|
1096
1098
|
///
|
|
1097
1099
|
/// Return: string
|
|
1098
|
-
/// The value provided
|
|
1099
|
-
/// underlying database driver.
|
|
1100
|
+
/// The value provided.
|
|
1100
1101
|
///
|
|
1101
1102
|
/// Arguments:
|
|
1102
1103
|
/// value: any
|
|
@@ -1104,10 +1105,7 @@ class ConnectionBase extends EventEmitter {
|
|
|
1104
1105
|
/// a string, or anything else that can be provided to your
|
|
1105
1106
|
/// specific database.
|
|
1106
1107
|
_escape(value) {
|
|
1107
|
-
|
|
1108
|
-
return `'${value.replace(/'/g, '\'\'')}'`;
|
|
1109
|
-
|
|
1110
|
-
return SqlString.escape(value);
|
|
1108
|
+
return value;
|
|
1111
1109
|
}
|
|
1112
1110
|
|
|
1113
1111
|
/// Unlike <see>ConnectionBase._escape</see> --which is
|
|
@@ -1198,22 +1196,18 @@ class ConnectionBase extends EventEmitter {
|
|
|
1198
1196
|
/// provides as a "fallback" to database drivers that don't
|
|
1199
1197
|
/// supply their own.
|
|
1200
1198
|
///
|
|
1201
|
-
///
|
|
1202
|
-
///
|
|
1203
|
-
///
|
|
1204
|
-
/// `escapeId` method, finally re-joining the parts with a period `.` character.
|
|
1205
|
-
///
|
|
1206
|
-
/// The extra processing is to allow for already escaped identifiers to not be double-escaped.
|
|
1199
|
+
/// This method simply returns the value provided. It is
|
|
1200
|
+
/// expected that each database driver will properly overload
|
|
1201
|
+
/// this method to provide the correct escaping for identifiers.
|
|
1207
1202
|
///
|
|
1208
1203
|
/// Return: string
|
|
1209
|
-
/// The provided identifier
|
|
1204
|
+
/// The provided identifier.
|
|
1210
1205
|
///
|
|
1211
1206
|
/// Arguments:
|
|
1212
1207
|
/// value: string
|
|
1213
1208
|
/// The identifier to escape.
|
|
1214
1209
|
_escapeID(value) {
|
|
1215
|
-
|
|
1216
|
-
return parts.map((part) => SqlString.escapeId(part).replace(/^`/, '"').replace(/`$/, '"')).join('.');
|
|
1210
|
+
return value;
|
|
1217
1211
|
}
|
|
1218
1212
|
|
|
1219
1213
|
/// This method is very similar to <see>ConnectionBase._escapeID</see>,
|
|
@@ -2789,7 +2783,7 @@ class ConnectionBase extends EventEmitter {
|
|
|
2789
2783
|
/// Create a table/bucket using the provided model class.
|
|
2790
2784
|
///
|
|
2791
2785
|
/// The provided `options` are database specific,
|
|
2792
|
-
/// but might contain things like `
|
|
2786
|
+
/// but might contain things like `ifNotExists`, for
|
|
2793
2787
|
/// example.
|
|
2794
2788
|
///
|
|
2795
2789
|
/// Return: any
|
|
@@ -243,9 +243,21 @@ class LiteralBase {
|
|
|
243
243
|
/// Convert the literal value provided to the `constructor`
|
|
244
244
|
/// to a string.
|
|
245
245
|
///
|
|
246
|
+
/// Arguments:
|
|
247
|
+
/// connection?: <see>Connection</see>
|
|
248
|
+
/// The connection to use to stringify the literal. If
|
|
249
|
+
/// not provided, then a "representation" of the literal
|
|
250
|
+
/// (for logging/debugging) will be returned instead.
|
|
251
|
+
/// options?: object
|
|
252
|
+
/// Any options needed to stringify the literal. These are often
|
|
253
|
+
/// literal and/or database specific.
|
|
254
|
+
///
|
|
246
255
|
/// Return: string
|
|
247
|
-
/// The
|
|
248
|
-
|
|
256
|
+
/// The stringified literal, ready to be used in the underlying database
|
|
257
|
+
/// (if a `connection` was provided), or a logging/debugging representation
|
|
258
|
+
/// of the literal if no `connection` is provided.
|
|
259
|
+
// eslint-disable-next-line no-unused-vars
|
|
260
|
+
toString(connection, options) {
|
|
249
261
|
if (!this.literal)
|
|
250
262
|
return ('' + this.literal);
|
|
251
263
|
|
|
@@ -2,8 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
/// The base query generator class.
|
|
4
4
|
///
|
|
5
|
+
/// A "query generator" is an interface that will take
|
|
6
|
+
/// parameters (usually a <see>QueryEngine</see> or a
|
|
7
|
+
/// <see>Model</see>) and generate database query statements
|
|
8
|
+
/// from the input. For SQL type databases this would mean
|
|
9
|
+
/// generating `SELECT`, `INSERT`, `UPDATE`, and `DELETE`
|
|
10
|
+
/// statements, as well as generators for creating and altering
|
|
11
|
+
/// tables, among other things.
|
|
12
|
+
///
|
|
13
|
+
/// The methods of this class are generally many, with the
|
|
14
|
+
/// design pattern for most generators being that nearly
|
|
15
|
+
/// all methods are split apart and added to the class, allowing
|
|
16
|
+
/// by deliberate design much finer control when using overloaded
|
|
17
|
+
/// methods, to modify or replace any parts of the generator.
|
|
18
|
+
///
|
|
19
|
+
/// Any connection can be provided a custom query generator
|
|
20
|
+
/// interface via the `queryGenerator` option that can be
|
|
21
|
+
/// used when instantiating a connection. Most connections
|
|
22
|
+
/// will supply their own by default.
|
|
23
|
+
///
|
|
24
|
+
/// A connection should always be bound to a query generator
|
|
25
|
+
/// instance. If not when first created, then at least when
|
|
26
|
+
/// provided to a connection. The connection is a required
|
|
27
|
+
/// part of the generator interface, and will do things, such
|
|
28
|
+
/// as for example, escaping values and ids using the connection
|
|
29
|
+
/// itself. The connection may be used for other operations as
|
|
30
|
+
/// well.
|
|
31
|
+
///
|
|
32
|
+
/// Note:
|
|
33
|
+
/// Some database drivers may not have a generator at all. Though
|
|
34
|
+
/// database drivers commonly do have a database statement generator,
|
|
35
|
+
/// a connection isn't required to have one.
|
|
36
|
+
///
|
|
5
37
|
/// Alias: QueryGenerator
|
|
6
38
|
class QueryGeneratorBase {
|
|
39
|
+
/// Construct a new query generator
|
|
40
|
+
///
|
|
41
|
+
/// Arguments:
|
|
42
|
+
/// connection?: <see>Connection</see>
|
|
43
|
+
/// The connection that this interface is for. Sometimes the connection
|
|
44
|
+
/// isn't yet available when creating the query generator, so this argument
|
|
45
|
+
/// is optional. When provided to a <see>Connection</see>, the connection
|
|
46
|
+
/// will call <see>QueryGenerator.setConnection</see> with itself to set
|
|
47
|
+
/// the connection for the query generator.
|
|
7
48
|
constructor(connection) {
|
|
8
49
|
Object.defineProperties(this, {
|
|
9
50
|
'connection': {
|
|
@@ -15,57 +56,289 @@ class QueryGeneratorBase {
|
|
|
15
56
|
});
|
|
16
57
|
}
|
|
17
58
|
|
|
59
|
+
/// Get the <see>Connection</see> bound to this
|
|
60
|
+
/// query generator.
|
|
61
|
+
///
|
|
62
|
+
/// Return: <see>Connection</see>
|
|
63
|
+
/// The connection bound to this query generator. A connection
|
|
64
|
+
/// should always be bound before any generating methods of
|
|
65
|
+
/// the class are called.
|
|
66
|
+
getConnection() {
|
|
67
|
+
return this.connection;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// Set the <see>Connection</see> bound to this
|
|
71
|
+
/// query generator.
|
|
72
|
+
///
|
|
73
|
+
/// Arguments:
|
|
74
|
+
/// connection: <see>Connection</see>
|
|
75
|
+
/// The connection to bind to this query generator.
|
|
76
|
+
///
|
|
77
|
+
/// Return: <see>QueryGenerator</see>
|
|
78
|
+
/// Return `this` to allow for chaining.
|
|
79
|
+
setConnection(connection) {
|
|
80
|
+
this.connection = connection;
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// This call proxies to <see>Connection.stackAssign</see>.
|
|
85
|
+
/// Refer to the documentation of that method for more information.
|
|
86
|
+
///
|
|
87
|
+
/// See: Connection.stackAssign
|
|
18
88
|
stackAssign(obj, ...args) {
|
|
19
89
|
return this.connection.stackAssign(obj, ...args);
|
|
20
90
|
}
|
|
21
91
|
|
|
92
|
+
/// This call proxies to <see>Connection.escape</see>.
|
|
93
|
+
/// Refer to the documentation of that method for more information.
|
|
94
|
+
///
|
|
95
|
+
/// See: Connection.escape
|
|
22
96
|
escape(...args) {
|
|
23
97
|
return this.connection.escape(...args);
|
|
24
98
|
}
|
|
25
99
|
|
|
100
|
+
/// This call proxies to <see>Connection.escapeID</see>.
|
|
101
|
+
/// Refer to the documentation of that method for more information.
|
|
102
|
+
///
|
|
103
|
+
/// See: Connection.escapeID
|
|
26
104
|
escapeID(...args) {
|
|
27
105
|
return this.connection.escapeID(...args);
|
|
28
106
|
}
|
|
29
107
|
|
|
108
|
+
/// Convert an <see>AverageLiteral</see> into a
|
|
109
|
+
/// string representation for the underlying database.
|
|
110
|
+
///
|
|
111
|
+
/// It is expected that each database driver will implement
|
|
112
|
+
/// this method. By default it will simply throw an
|
|
113
|
+
/// "unsupported" error.
|
|
114
|
+
///
|
|
115
|
+
/// Refer to the specific documentation for your database
|
|
116
|
+
/// driver for more information.
|
|
117
|
+
///
|
|
118
|
+
/// Arguments:
|
|
119
|
+
/// literal: <see>AverageLiteral</see>
|
|
120
|
+
/// The literal to stringify for the underlying database.
|
|
121
|
+
/// options?: object
|
|
122
|
+
/// Options for the stringify process. These are often database
|
|
123
|
+
/// driver specific. However, one common option is the `as`
|
|
124
|
+
/// option, which will allow you to give your literal an alias.
|
|
125
|
+
///
|
|
126
|
+
/// Return: string
|
|
127
|
+
/// The literal, converted into the proper string for the underlying
|
|
128
|
+
/// database.
|
|
30
129
|
// eslint-disable-next-line no-unused-vars
|
|
31
130
|
_averageLiteralToString(literal, options) {
|
|
32
131
|
throw new Error(`${this.constructor.name}::_averageLiteralToString: This operation is not supported for this connection type.`);
|
|
33
132
|
}
|
|
34
133
|
|
|
134
|
+
/// Convert an <see>CountLiteral</see> into a
|
|
135
|
+
/// string representation for the underlying database.
|
|
136
|
+
///
|
|
137
|
+
/// It is expected that each database driver will implement
|
|
138
|
+
/// this method. By default it will simply throw an
|
|
139
|
+
/// "unsupported" error.
|
|
140
|
+
///
|
|
141
|
+
/// Refer to the specific documentation for your database
|
|
142
|
+
/// driver for more information.
|
|
143
|
+
///
|
|
144
|
+
/// Arguments:
|
|
145
|
+
/// literal: <see>CountLiteral</see>
|
|
146
|
+
/// The literal to stringify for the underlying database.
|
|
147
|
+
/// options?: object
|
|
148
|
+
/// Options for the stringify process. These are often database
|
|
149
|
+
/// driver specific. However, one common option is the `as`
|
|
150
|
+
/// option, which will allow you to give your literal an alias.
|
|
151
|
+
///
|
|
152
|
+
/// Return: string
|
|
153
|
+
/// The literal, converted into the proper string for the underlying
|
|
154
|
+
/// database.
|
|
35
155
|
// eslint-disable-next-line no-unused-vars
|
|
36
156
|
_countLiteralToString(literal, options) {
|
|
37
157
|
throw new Error(`${this.constructor.name}::_countLiteralToString: This operation is not supported for this connection type.`);
|
|
38
158
|
}
|
|
39
159
|
|
|
160
|
+
/// Convert an <see>DistinctLiteral</see> into a
|
|
161
|
+
/// string representation for the underlying database.
|
|
162
|
+
///
|
|
163
|
+
/// It is expected that each database driver will implement
|
|
164
|
+
/// this method. By default it will simply throw an
|
|
165
|
+
/// "unsupported" error.
|
|
166
|
+
///
|
|
167
|
+
/// Refer to the specific documentation for your database
|
|
168
|
+
/// driver for more information.
|
|
169
|
+
///
|
|
170
|
+
/// Arguments:
|
|
171
|
+
/// literal: <see>DistinctLiteral</see>
|
|
172
|
+
/// The literal to stringify for the underlying database.
|
|
173
|
+
/// options?: object
|
|
174
|
+
/// Options for the stringify process. These are often database
|
|
175
|
+
/// driver specific. However, one common option is the `as`
|
|
176
|
+
/// option, which will allow you to give your literal an alias.
|
|
177
|
+
///
|
|
178
|
+
/// Return: string
|
|
179
|
+
/// The literal, converted into the proper string for the underlying
|
|
180
|
+
/// database.
|
|
40
181
|
// eslint-disable-next-line no-unused-vars
|
|
41
182
|
_distinctLiteralToString(literal, options) {
|
|
42
183
|
throw new Error(`${this.constructor.name}::_distinctLiteralToString: This operation is not supported for this connection type.`);
|
|
43
184
|
}
|
|
44
185
|
|
|
186
|
+
/// Convert an <see>FieldLiteral</see> into a
|
|
187
|
+
/// string representation for the underlying database.
|
|
188
|
+
///
|
|
189
|
+
/// It is expected that each database driver will implement
|
|
190
|
+
/// this method. By default it will simply throw an
|
|
191
|
+
/// "unsupported" error.
|
|
192
|
+
///
|
|
193
|
+
/// Refer to the specific documentation for your database
|
|
194
|
+
/// driver for more information.
|
|
195
|
+
///
|
|
196
|
+
/// Arguments:
|
|
197
|
+
/// literal: <see>FieldLiteral</see>
|
|
198
|
+
/// The literal to stringify for the underlying database.
|
|
199
|
+
/// options?: object
|
|
200
|
+
/// Options for the stringify process. These are often database
|
|
201
|
+
/// driver specific. However, one common option is the `as`
|
|
202
|
+
/// option, which will allow you to give your literal an alias.
|
|
203
|
+
///
|
|
204
|
+
/// Return: string
|
|
205
|
+
/// The literal, converted into the proper string for the underlying
|
|
206
|
+
/// database.
|
|
45
207
|
// eslint-disable-next-line no-unused-vars
|
|
46
208
|
_fieldLiteralToString(literal, options) {
|
|
47
209
|
throw new Error(`${this.constructor.name}::_fieldLiteralToString: This operation is not supported for this connection type.`);
|
|
48
210
|
}
|
|
49
211
|
|
|
212
|
+
/// Convert an <see>MaxLiteral</see> into a
|
|
213
|
+
/// string representation for the underlying database.
|
|
214
|
+
///
|
|
215
|
+
/// It is expected that each database driver will implement
|
|
216
|
+
/// this method. By default it will simply throw an
|
|
217
|
+
/// "unsupported" error.
|
|
218
|
+
///
|
|
219
|
+
/// Refer to the specific documentation for your database
|
|
220
|
+
/// driver for more information.
|
|
221
|
+
///
|
|
222
|
+
/// Arguments:
|
|
223
|
+
/// literal: <see>MaxLiteral</see>
|
|
224
|
+
/// The literal to stringify for the underlying database.
|
|
225
|
+
/// options?: object
|
|
226
|
+
/// Options for the stringify process. These are often database
|
|
227
|
+
/// driver specific. However, one common option is the `as`
|
|
228
|
+
/// option, which will allow you to give your literal an alias.
|
|
229
|
+
///
|
|
230
|
+
/// Return: string
|
|
231
|
+
/// The literal, converted into the proper string for the underlying
|
|
232
|
+
/// database.
|
|
50
233
|
// eslint-disable-next-line no-unused-vars
|
|
51
234
|
_maxLiteralToString(literal, options) {
|
|
52
235
|
throw new Error(`${this.constructor.name}::_maxLiteralToString: This operation is not supported for this connection type.`);
|
|
53
236
|
}
|
|
54
237
|
|
|
238
|
+
/// Convert an <see>MinLiteral</see> into a
|
|
239
|
+
/// string representation for the underlying database.
|
|
240
|
+
///
|
|
241
|
+
/// It is expected that each database driver will implement
|
|
242
|
+
/// this method. By default it will simply throw an
|
|
243
|
+
/// "unsupported" error.
|
|
244
|
+
///
|
|
245
|
+
/// Refer to the specific documentation for your database
|
|
246
|
+
/// driver for more information.
|
|
247
|
+
///
|
|
248
|
+
/// Arguments:
|
|
249
|
+
/// literal: <see>MinLiteral</see>
|
|
250
|
+
/// The literal to stringify for the underlying database.
|
|
251
|
+
/// options?: object
|
|
252
|
+
/// Options for the stringify process. These are often database
|
|
253
|
+
/// driver specific. However, one common option is the `as`
|
|
254
|
+
/// option, which will allow you to give your literal an alias.
|
|
255
|
+
///
|
|
256
|
+
/// Return: string
|
|
257
|
+
/// The literal, converted into the proper string for the underlying
|
|
258
|
+
/// database.
|
|
55
259
|
// eslint-disable-next-line no-unused-vars
|
|
56
260
|
_minLiteralToString(literal, options) {
|
|
57
261
|
throw new Error(`${this.constructor.name}::_minLiteralToString: This operation is not supported for this connection type.`);
|
|
58
262
|
}
|
|
59
263
|
|
|
264
|
+
/// Convert an <see>SumLiteral</see> into a
|
|
265
|
+
/// string representation for the underlying database.
|
|
266
|
+
///
|
|
267
|
+
/// It is expected that each database driver will implement
|
|
268
|
+
/// this method. By default it will simply throw an
|
|
269
|
+
/// "unsupported" error.
|
|
270
|
+
///
|
|
271
|
+
/// Refer to the specific documentation for your database
|
|
272
|
+
/// driver for more information.
|
|
273
|
+
///
|
|
274
|
+
/// Arguments:
|
|
275
|
+
/// literal: <see>SumLiteral</see>
|
|
276
|
+
/// The literal to stringify for the underlying database.
|
|
277
|
+
/// options?: object
|
|
278
|
+
/// Options for the stringify process. These are often database
|
|
279
|
+
/// driver specific. However, one common option is the `as`
|
|
280
|
+
/// option, which will allow you to give your literal an alias.
|
|
281
|
+
///
|
|
282
|
+
/// Return: string
|
|
283
|
+
/// The literal, converted into the proper string for the underlying
|
|
284
|
+
/// database.
|
|
60
285
|
// eslint-disable-next-line no-unused-vars
|
|
61
286
|
_sumLiteralToString(literal, options) {
|
|
62
287
|
throw new Error(`${this.constructor.name}::_sumLiteralToString: This operation is not supported for this connection type.`);
|
|
63
288
|
}
|
|
64
289
|
|
|
290
|
+
/// Take a <see>QueryEngine</see> instance and
|
|
291
|
+
/// convert it into a query. For SQL type databases
|
|
292
|
+
/// this would turn a <see>QueryEngine</see> into a
|
|
293
|
+
/// `SELECT` statement. For other types of databases,
|
|
294
|
+
/// this should return a "fetch" query--or string representation
|
|
295
|
+
/// of such a query--in the database's native query language.
|
|
296
|
+
///
|
|
297
|
+
/// Arguments:
|
|
298
|
+
/// queryEngine: <see>QueryEngine</see>
|
|
299
|
+
/// The query engine instance to stringify.
|
|
300
|
+
/// options?: object
|
|
301
|
+
/// Connection and operation specific options. These
|
|
302
|
+
/// generally aren't needed, but are provided in case
|
|
303
|
+
/// the underlying connection needs them.
|
|
304
|
+
///
|
|
305
|
+
/// Return: string
|
|
306
|
+
/// A "fetch" query in the databases native query language,
|
|
307
|
+
/// generated from the provided `queryEngine`.
|
|
65
308
|
// eslint-disable-next-line no-unused-vars
|
|
66
309
|
toConnectionString(queryEngine, options) {
|
|
67
310
|
return '<not supported by connection>';
|
|
68
311
|
}
|
|
312
|
+
|
|
313
|
+
/// Get the "default value" for the given field
|
|
314
|
+
/// for the underlying database. This is used
|
|
315
|
+
/// primarily for "CREATE TABLE" statements.
|
|
316
|
+
///
|
|
317
|
+
/// By default, the implementation of this method
|
|
318
|
+
/// is empty. It is expected that each database driver
|
|
319
|
+
/// will implement their own version of this method.
|
|
320
|
+
///
|
|
321
|
+
/// Arguments:
|
|
322
|
+
/// field: <see>Field</see>
|
|
323
|
+
/// The field instance we are getting a "default value"
|
|
324
|
+
/// from.
|
|
325
|
+
/// fieldName: string
|
|
326
|
+
/// The name of the field that we are getting the "default value"
|
|
327
|
+
/// from. This should always be the same as `field.fieldName`.
|
|
328
|
+
/// options?: object
|
|
329
|
+
/// Options for the operation. These will likely be connection
|
|
330
|
+
/// specific. Please refer to the documentation of your specific
|
|
331
|
+
/// connection for more details.
|
|
332
|
+
///
|
|
333
|
+
/// Return: any
|
|
334
|
+
/// Though in most cases this method will return a string for
|
|
335
|
+
/// most database drivers in most situations, it may return other
|
|
336
|
+
/// types as well, such as literals, or other raw values.
|
|
337
|
+
/// Please refer to the documentation of your specific
|
|
338
|
+
/// connection for more details.
|
|
339
|
+
// eslint-disable-next-line no-unused-vars
|
|
340
|
+
getFieldDefaultValue(field, fieldName, _options) {
|
|
341
|
+
}
|
|
69
342
|
}
|
|
70
343
|
|
|
71
344
|
module.exports = QueryGeneratorBase;
|
package/lib/model.js
CHANGED
|
@@ -1772,8 +1772,22 @@ class Model {
|
|
|
1772
1772
|
return this.getWhereWithConnection(options).all(options);
|
|
1773
1773
|
}
|
|
1774
1774
|
|
|
1775
|
-
static
|
|
1776
|
-
|
|
1775
|
+
/// This method is similar in nature to <see>Model.static all</see>,
|
|
1776
|
+
/// except that instead of collecting all results into an
|
|
1777
|
+
/// array before returning, it will instead "stream" the results
|
|
1778
|
+
/// from the database using an async generator.
|
|
1779
|
+
///
|
|
1780
|
+
/// Arguments:
|
|
1781
|
+
/// options?: object
|
|
1782
|
+
/// Options for the operation. These are generally
|
|
1783
|
+
/// database specific. Like the <see>Model.static all</see>
|
|
1784
|
+
/// method you can supply a `batchSize`.
|
|
1785
|
+
///
|
|
1786
|
+
/// Return: async * iterator
|
|
1787
|
+
/// An async generator iterator that will "stream" the
|
|
1788
|
+
/// results from the database.
|
|
1789
|
+
static cursor(options) {
|
|
1790
|
+
return this.cursor(options);
|
|
1777
1791
|
}
|
|
1778
1792
|
|
|
1779
1793
|
/// Get the first (limit) rows from the database for this model type.
|
|
@@ -4,27 +4,27 @@
|
|
|
4
4
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
-
const APPLY = Symbol.for('@
|
|
8
|
-
const CALLABLE = Symbol.for('@
|
|
9
|
-
const CONSTRUCT = Symbol.for('@
|
|
10
|
-
const DEFINE_PROPERTY = Symbol.for('@
|
|
11
|
-
const DELETE_PROPERTY = Symbol.for('@
|
|
12
|
-
const GET = Symbol.for('@
|
|
13
|
-
const GET_OWN_PROPERTY_DESCRIPTOR = Symbol.for('@
|
|
14
|
-
const GET_PROTOTYPEOF = Symbol.for('@
|
|
15
|
-
const HAS = Symbol.for('@
|
|
16
|
-
const IS_EXTENSIBLE = Symbol.for('@
|
|
17
|
-
const MISSING = Symbol.for('@
|
|
18
|
-
const OWN_KEYS = Symbol.for('@
|
|
19
|
-
const PREVENT_EXTENSIONS = Symbol.for('@
|
|
20
|
-
const SET = Symbol.for('@
|
|
21
|
-
const SET_PROTOTYPEOF = Symbol.for('@
|
|
22
|
-
const PROXY = Symbol.for('@
|
|
23
|
-
const TARGET = Symbol.for('@
|
|
24
|
-
const SELF = Symbol.for('@
|
|
25
|
-
const AUTO_CALL_CALLER = Symbol.for('@
|
|
26
|
-
const AUTO_CALL_CALLED = Symbol.for('@
|
|
27
|
-
const AUTO_CALL = Symbol.for('@
|
|
7
|
+
const APPLY = Symbol.for('@_mythix/orm/ProxyClass/apply');
|
|
8
|
+
const CALLABLE = Symbol.for('@_mythix/orm/ProxyClass/callable');
|
|
9
|
+
const CONSTRUCT = Symbol.for('@_mythix/orm/ProxyClass/construct');
|
|
10
|
+
const DEFINE_PROPERTY = Symbol.for('@_mythix/orm/ProxyClass/defineProperty');
|
|
11
|
+
const DELETE_PROPERTY = Symbol.for('@_mythix/orm/ProxyClass/deleteProperty');
|
|
12
|
+
const GET = Symbol.for('@_mythix/orm/ProxyClass/get');
|
|
13
|
+
const GET_OWN_PROPERTY_DESCRIPTOR = Symbol.for('@_mythix/orm/ProxyClass/getOwnPropertyDescriptor');
|
|
14
|
+
const GET_PROTOTYPEOF = Symbol.for('@_mythix/orm/ProxyClass/getPrototypeOf');
|
|
15
|
+
const HAS = Symbol.for('@_mythix/orm/ProxyClass/has');
|
|
16
|
+
const IS_EXTENSIBLE = Symbol.for('@_mythix/orm/ProxyClass/isExtensible');
|
|
17
|
+
const MISSING = Symbol.for('@_mythix/orm/ProxyClass/missing');
|
|
18
|
+
const OWN_KEYS = Symbol.for('@_mythix/orm/ProxyClass/ownKeys');
|
|
19
|
+
const PREVENT_EXTENSIONS = Symbol.for('@_mythix/orm/ProxyClass/preventExtensions');
|
|
20
|
+
const SET = Symbol.for('@_mythix/orm/ProxyClass/set');
|
|
21
|
+
const SET_PROTOTYPEOF = Symbol.for('@_mythix/orm/ProxyClass/setPrototypeOf');
|
|
22
|
+
const PROXY = Symbol.for('@__mythix/orm/ProxyClass/proxy');
|
|
23
|
+
const TARGET = Symbol.for('@__mythix/orm/ProxyClass/target');
|
|
24
|
+
const SELF = Symbol.for('@__mythix/orm/ProxyClass/rootInstance');
|
|
25
|
+
const AUTO_CALL_CALLER = Symbol.for('@__mythix/orm/ProxyClass/autoCallCaller');
|
|
26
|
+
const AUTO_CALL_CALLED = Symbol.for('@__mythix/orm/ProxyClass/autoCallCalled');
|
|
27
|
+
const AUTO_CALL = Symbol.for('@__mythix/orm/ProxyClass/autoCall');
|
|
28
28
|
|
|
29
29
|
function shouldSkipProxy(prop) {
|
|
30
30
|
if (prop === 'bind' || prop === 'call' || prop === 'apply')
|
|
@@ -39,6 +39,26 @@ function shouldSkipProxy(prop) {
|
|
|
39
39
|
return false;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/// This is essentially a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
|
|
43
|
+
/// converted into class form. What that means is that instead of defining a
|
|
44
|
+
/// proxy by passing it a "handlers" object to it, this instead *is* the handler
|
|
45
|
+
/// for all classes that inherit from it. Just like a `Proxy`, inheriting from
|
|
46
|
+
/// this class will allow the child-class to intercept property gets and sets,
|
|
47
|
+
/// intercept method calls, property deletion, etc...
|
|
48
|
+
///
|
|
49
|
+
/// It works by returning `this` inside the `constructor` wrapped in a
|
|
50
|
+
/// `Proxy`. The `Proxy` it creates is then managed by the class instance itself.
|
|
51
|
+
/// For example, during key access, if a key the user is requesting is not found,
|
|
52
|
+
/// the proxy will call the instance method `MISSING` on the class. This allows
|
|
53
|
+
/// the child class to provide a method for `MISSING`, and then respond to key
|
|
54
|
+
/// access for keys that don't actually exist on the instance.
|
|
55
|
+
///
|
|
56
|
+
/// That is just one example of many. This class provides full `Proxy` support,
|
|
57
|
+
/// and so has methods (or stubs) for every feature available natively to a `Proxy`.
|
|
58
|
+
/// Instance methods are keyed by symbols. This is to try and reduce the chance
|
|
59
|
+
/// of a name collision... keeping this class useful for many scenarios. For example,
|
|
60
|
+
/// the `MISSING` method above is actually `Symbol.for('@_mythix/orm/ProxyClass/missing')`,
|
|
61
|
+
/// that is assigned to the constant <see>ProxyClass.MISSING</see>.
|
|
42
62
|
class ProxyClass {
|
|
43
63
|
static APPLY = APPLY;
|
|
44
64
|
static CALLABLE = CALLABLE;
|
|
@@ -175,6 +195,8 @@ class ProxyClass {
|
|
|
175
195
|
return proxy;
|
|
176
196
|
}
|
|
177
197
|
|
|
198
|
+
/// Construct the class instance, with
|
|
199
|
+
/// `this` returned wrapped in a `Proxy`.
|
|
178
200
|
constructor() {
|
|
179
201
|
Object.defineProperties(this, {
|
|
180
202
|
[AUTO_CALL_CALLER]: {
|
|
@@ -195,6 +217,65 @@ class ProxyClass {
|
|
|
195
217
|
return proxy;
|
|
196
218
|
}
|
|
197
219
|
|
|
220
|
+
/// Any method of the instance wrapped in an
|
|
221
|
+
/// `__autoCall` factory will be automatically
|
|
222
|
+
/// called by the engine if not called by the user.
|
|
223
|
+
///
|
|
224
|
+
/// This works by the `ProxyClass` pushing the auto-call
|
|
225
|
+
/// into a queue when the method key is accessed. If another
|
|
226
|
+
/// key is accessed (any other key), then the `ProxyClass` will
|
|
227
|
+
/// check if the auto-call method has been called yet. If it
|
|
228
|
+
/// hasn't, then the `ProxyClass` will call it, providing no
|
|
229
|
+
/// arguments, and using the return value of the call for the
|
|
230
|
+
/// pending key access. If the auto-call method is simply called,
|
|
231
|
+
/// then the queue is cleared, and the return value simply returned
|
|
232
|
+
/// to the user.
|
|
233
|
+
///
|
|
234
|
+
/// Example:
|
|
235
|
+
/// class Greeter extends ProxyClass {
|
|
236
|
+
/// greet = this.__autoCall((name) => {
|
|
237
|
+
/// if (arguments.length === 0) {
|
|
238
|
+
/// // An auto-call, or the user didn't
|
|
239
|
+
/// // provide any arguments.
|
|
240
|
+
/// console.log('Hello whoever you are!');
|
|
241
|
+
/// } else {
|
|
242
|
+
/// // Was definitely called by the user
|
|
243
|
+
/// console.log(`Hello ${name}!`);
|
|
244
|
+
/// }
|
|
245
|
+
/// });
|
|
246
|
+
///
|
|
247
|
+
/// finish() {
|
|
248
|
+
/// // finish operation
|
|
249
|
+
/// }
|
|
250
|
+
/// }
|
|
251
|
+
///
|
|
252
|
+
/// // Example 1
|
|
253
|
+
/// let greeter = new Greeter();
|
|
254
|
+
/// greeter.greet.finish();
|
|
255
|
+
/// // ^---- Auto call happens here
|
|
256
|
+
/// // output: Hello whoever you are!
|
|
257
|
+
///
|
|
258
|
+
/// // Example 2
|
|
259
|
+
/// greeter.greet('Wyatt Greenway').finish();
|
|
260
|
+
/// // No auto-call happens... this is a manual call.
|
|
261
|
+
/// // output: Hello Wyatt Greenway!
|
|
262
|
+
///
|
|
263
|
+
/// Note:
|
|
264
|
+
/// For an auto-call to work, a key access attempt must happen
|
|
265
|
+
/// after the auto-call method is accessed. This is almost always
|
|
266
|
+
/// the case, because in interacting with the object you are almost
|
|
267
|
+
/// guaranteed to access a key again, i.e. `.toString` if converting
|
|
268
|
+
/// to a string, `.toJSON` if converting to JSON, iterator access,
|
|
269
|
+
/// or even debugging the object.
|
|
270
|
+
///
|
|
271
|
+
/// Arguments:
|
|
272
|
+
/// caller: Function
|
|
273
|
+
/// The method implementation for the class. This method will
|
|
274
|
+
/// be used by the factory to create an auto-call method for
|
|
275
|
+
/// the class.
|
|
276
|
+
///
|
|
277
|
+
/// Return: Function
|
|
278
|
+
/// The `caller` method provided, wrapped into an auto-call factory method.
|
|
198
279
|
__autoCall(caller) {
|
|
199
280
|
this[AUTO_CALL_CALLER] = caller;
|
|
200
281
|
this[AUTO_CALL_CALLED] = false;
|
|
@@ -202,6 +283,60 @@ class ProxyClass {
|
|
|
202
283
|
return this;
|
|
203
284
|
}
|
|
204
285
|
|
|
286
|
+
/// This is a factory much like <see>ProxyClass.__autoCall</see>
|
|
287
|
+
/// for creating instance methods. It differs however in that
|
|
288
|
+
/// the method returned by this factory isn't auto-called, but
|
|
289
|
+
/// instead an *optional* call.
|
|
290
|
+
///
|
|
291
|
+
/// The way it works is that the method provided is returned,
|
|
292
|
+
/// itself wrapped in a `Proxy`. If it is called, then the
|
|
293
|
+
/// `Proxy` will pass the call through to the method, and return
|
|
294
|
+
/// the result. Being a `Proxy`, it passes all key access back
|
|
295
|
+
/// to the original class instance, allowing the method itself
|
|
296
|
+
/// to mimic the class instance. This allows for instance methods
|
|
297
|
+
/// that can *optionally* be called, but if they aren't called,
|
|
298
|
+
/// will act as though you are still interacting with the instance
|
|
299
|
+
/// of the class itself.
|
|
300
|
+
///
|
|
301
|
+
/// Example:
|
|
302
|
+
/// class Greeter extends ProxyClass {
|
|
303
|
+
/// constructor() {
|
|
304
|
+
/// super();
|
|
305
|
+
///
|
|
306
|
+
/// this.greetName = undefined;
|
|
307
|
+
/// }
|
|
308
|
+
///
|
|
309
|
+
/// name = this.__call((name) => {
|
|
310
|
+
/// this.greetName = name;
|
|
311
|
+
/// });
|
|
312
|
+
///
|
|
313
|
+
/// greet() {
|
|
314
|
+
/// if (this.greetName) {
|
|
315
|
+
/// console.log(`Hello ${this.greetName}!`);
|
|
316
|
+
/// } else {
|
|
317
|
+
/// console.log('Hello whoever you are!');
|
|
318
|
+
/// }
|
|
319
|
+
/// }
|
|
320
|
+
/// }
|
|
321
|
+
///
|
|
322
|
+
/// // Example 1
|
|
323
|
+
/// let greeter = new Greeter();
|
|
324
|
+
/// greeter.name.greet();
|
|
325
|
+
/// // ^---- optional call here
|
|
326
|
+
/// // output: Hello whoever you are!
|
|
327
|
+
///
|
|
328
|
+
/// // Example 2
|
|
329
|
+
/// greeter.name('Wyatt Greenway').greet();
|
|
330
|
+
/// // output: Hello Wyatt Greenway!
|
|
331
|
+
///
|
|
332
|
+
/// Arguments:
|
|
333
|
+
/// caller: Function
|
|
334
|
+
/// The method implementation for the class. This method will
|
|
335
|
+
/// be used by the factory to create an optional call method for
|
|
336
|
+
/// the class.
|
|
337
|
+
///
|
|
338
|
+
/// Return: Function
|
|
339
|
+
/// The `caller` method provided, wrapped into an optional call factory method.
|
|
205
340
|
__call(caller) {
|
|
206
341
|
return ProxyClass.createProxy.call(this, caller.bind(this[PROXY]));
|
|
207
342
|
}
|
|
@@ -31,7 +31,7 @@ function applyOrderClause(extraData, ...args) {
|
|
|
31
31
|
}).filter(Boolean);
|
|
32
32
|
|
|
33
33
|
let context = this.getOperationContext();
|
|
34
|
-
let order = this.
|
|
34
|
+
let order = this.mergeFields(
|
|
35
35
|
context.order,
|
|
36
36
|
entities,
|
|
37
37
|
extraData,
|
|
@@ -334,8 +334,8 @@ class ModelScope extends QueryEngineBase {
|
|
|
334
334
|
/// Return: Map<string, { value: Field | Literal | string; direction?: '+' | '-'; ... }>
|
|
335
335
|
/// Return the new field set. A `Map` will always be returned, but it is possible
|
|
336
336
|
/// for the `Map` to be empty.
|
|
337
|
-
|
|
338
|
-
return QueryUtils.
|
|
337
|
+
mergeFields(currentFields, incomingFields, extraData, options) {
|
|
338
|
+
return QueryUtils.mergeFields(this, currentFields, incomingFields, extraData, options);
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
/// Invert the logic of the following operator.
|
|
@@ -487,12 +487,12 @@ class ModelScope extends QueryEngineBase {
|
|
|
487
487
|
/// There are five variants to this method, `ORDER.ASC`,
|
|
488
488
|
/// `ORDER.DESC`, `ORDER.ADD`, `ORDER.REPLACE`, and `ORDER` (which is an alias for `ORDER.ASC`), .
|
|
489
489
|
/// 1) `ORDER` - Alias for `ORDER.ASC`.
|
|
490
|
-
/// 2) `ORDER.ASC` - Follow the rules of <see>ModelScope.
|
|
491
|
-
/// 3) `ORDER.DESC` - Follow the rules of <see>ModelScope.
|
|
492
|
-
/// 4) `ORDER.ADD` - **DO NOT** follow the rules of <see>ModelScope.
|
|
493
|
-
/// 5) `ORDER.REPLACE` - **DO NOT** follow the rules of <see>ModelScope.
|
|
490
|
+
/// 2) `ORDER.ASC` - Follow the rules of <see>ModelScope.mergeFields</see>. Each field/literal added is in `ASC` order.
|
|
491
|
+
/// 3) `ORDER.DESC` - Follow the rules of <see>ModelScope.mergeFields</see>. Each field/literal added is in `DESC` order.
|
|
492
|
+
/// 4) `ORDER.ADD` - **DO NOT** follow the rules of <see>ModelScope.mergeFields</see>, and instead **add** all fields specified, with their sort order being specified instead by the `+` or `-` prefixes on each field.
|
|
493
|
+
/// 5) `ORDER.REPLACE` - **DO NOT** follow the rules of <see>ModelScope.mergeFields</see>, and instead **replace** the operation fields to the fields specified, with their sort order being specified instead by the `+` or `-` prefixes on each field.
|
|
494
494
|
///
|
|
495
|
-
/// See <see>ModelScope.
|
|
495
|
+
/// See <see>ModelScope.mergeFields</see> to better understand how this method works.
|
|
496
496
|
///
|
|
497
497
|
/// SyntaxType: FunctionDeclaration
|
|
498
498
|
///
|
|
@@ -513,7 +513,7 @@ class ModelScope extends QueryEngineBase {
|
|
|
513
513
|
|
|
514
514
|
/// Apply a `GROUP BY` clause to the query.
|
|
515
515
|
///
|
|
516
|
-
/// See <see>ModelScope.
|
|
516
|
+
/// See <see>ModelScope.mergeFields</see> to better understand how this method works.
|
|
517
517
|
///
|
|
518
518
|
/// Note:
|
|
519
519
|
/// This method will flatten all provided arguments into a one dimensional array,
|
|
@@ -548,7 +548,7 @@ class ModelScope extends QueryEngineBase {
|
|
|
548
548
|
}).filter(Boolean);
|
|
549
549
|
|
|
550
550
|
let context = this.getOperationContext();
|
|
551
|
-
let groupBy = this.
|
|
551
|
+
let groupBy = this.mergeFields(
|
|
552
552
|
context.groupBy,
|
|
553
553
|
entities,
|
|
554
554
|
{},
|
|
@@ -643,7 +643,7 @@ class ModelScope extends QueryEngineBase {
|
|
|
643
643
|
|
|
644
644
|
/// Replace, add to, or subtract from the projection of the query.
|
|
645
645
|
///
|
|
646
|
-
/// See <see>ModelScope.
|
|
646
|
+
/// See <see>ModelScope.mergeFields</see> to better understand how this method works.
|
|
647
647
|
///
|
|
648
648
|
/// Note:
|
|
649
649
|
/// This method will flatten all provided arguments into a one dimensional array,
|
|
@@ -691,7 +691,7 @@ class ModelScope extends QueryEngineBase {
|
|
|
691
691
|
}).filter(Boolean);
|
|
692
692
|
|
|
693
693
|
let context = this.getOperationContext();
|
|
694
|
-
let projection = this.
|
|
694
|
+
let projection = this.mergeFields(
|
|
695
695
|
context.projection,
|
|
696
696
|
entities,
|
|
697
697
|
{},
|
package/lib/utils/async-store.js
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
///! import `var { Utils: { AsyncStore } } = require('mythix-orm');`
|
|
2
|
+
///!
|
|
3
|
+
///! AsyncStore utilities provide the only global
|
|
4
|
+
///! used in mythix-orm. The global used here is an
|
|
5
|
+
///! [AsyncLocalStorage](https://nodejs.org/docs/latest-v18.x/api/async_context.html#class-asynclocalstorage) instance used to track
|
|
6
|
+
///! connections (and transactions) through asynchronous
|
|
7
|
+
///! calls in the engine.
|
|
8
|
+
///!
|
|
9
|
+
///! The `node:async_hooks` module is imported inside a
|
|
10
|
+
///! `try/catch` block, so if your Javascript engine doesn't
|
|
11
|
+
///! support `AsyncLocalStorage`, this will fail, and silently
|
|
12
|
+
///! fallback to running the engine with no `AsyncLocalStorage`
|
|
13
|
+
///! support... which simply means that connection instances need
|
|
14
|
+
///! to be manually passed around everywhere.
|
|
15
|
+
///!
|
|
16
|
+
///! **!WARNING!: Never set the `'connection'` key, or a string key
|
|
17
|
+
///! that matches one of your model names to this `AsyncLocalStorage` context
|
|
18
|
+
///! unless you know exactly what you are doing. These keys are reserved
|
|
19
|
+
///! by Mythix ORM to pass connections and transactions through calls.** Any
|
|
20
|
+
///! and all other custom keys are available for use, though it would be
|
|
21
|
+
///! wise for you to prefix your key names, so as to avoid future name collisions
|
|
22
|
+
///! that might occur due to newer versions of Mythix ORM, or name collisions with
|
|
23
|
+
///! other 3rd party plugins or code that might set keys on the context as well.
|
|
24
|
+
///!
|
|
25
|
+
///! DocScope: AsyncStore
|
|
26
|
+
|
|
1
27
|
'use strict';
|
|
2
28
|
|
|
3
29
|
let globalAsyncStore = global._mythixGlobalAsyncLocalStore;
|
|
@@ -14,10 +40,33 @@ if (!globalAsyncStore) {
|
|
|
14
40
|
}
|
|
15
41
|
}
|
|
16
42
|
|
|
43
|
+
/// Fetch the AsyncLocalStorage store.
|
|
44
|
+
/// This calls `.getStore()` on the global
|
|
45
|
+
/// `AsyncLocalStorage` instance.
|
|
46
|
+
///
|
|
47
|
+
/// Return: any
|
|
48
|
+
/// The value from a `.getStore()` call on the global `AsyncLocalStorage` instance.
|
|
49
|
+
/// This will be `undefined` if no `AsyncLocalStorage` context is in scope.
|
|
17
50
|
function getContextStore() {
|
|
18
51
|
return globalAsyncStore.getStore();
|
|
19
52
|
}
|
|
20
53
|
|
|
54
|
+
/// Get a specific value from the global `AsyncLocalStorage` context
|
|
55
|
+
/// by name.
|
|
56
|
+
///
|
|
57
|
+
/// Arguments:
|
|
58
|
+
/// key: any
|
|
59
|
+
/// The name of the property to return. The `AsyncLocalStorage`
|
|
60
|
+
/// context internally uses a `Map` instance, so the `key` provided
|
|
61
|
+
/// can be of any type.
|
|
62
|
+
/// defaultValue: any
|
|
63
|
+
/// The default value to return if the key specified is not found.
|
|
64
|
+
///
|
|
65
|
+
/// Return:
|
|
66
|
+
/// Return the property named by `key` if one is found, otherwise
|
|
67
|
+
/// return the `defaultValue` that was provided. If the global `AsyncLocalStorage` context is not
|
|
68
|
+
/// in scope when this is called, then the `defaultValue` will always be
|
|
69
|
+
/// returned.
|
|
21
70
|
function getContextValue(key, defaultValue) {
|
|
22
71
|
let store = globalAsyncStore.getStore();
|
|
23
72
|
while (store) {
|
|
@@ -33,19 +82,47 @@ function getContextValue(key, defaultValue) {
|
|
|
33
82
|
return defaultValue;
|
|
34
83
|
}
|
|
35
84
|
|
|
85
|
+
/// Set a specific value on the global `AsyncLocalStorage` context
|
|
86
|
+
/// by name. A `Map` instance is used internally, so the `key` can
|
|
87
|
+
/// be of any type.
|
|
88
|
+
///
|
|
89
|
+
/// Note:
|
|
90
|
+
/// The global `AsyncLocalStorage` context must be in scope for this method to work.
|
|
91
|
+
///
|
|
92
|
+
/// Arguments:
|
|
93
|
+
/// key: any
|
|
94
|
+
/// The key you wish to set on the global `AsyncLocalStorage` context.
|
|
95
|
+
/// value: any
|
|
96
|
+
/// The value you wish to set on the global `AsyncLocalStorage` context.
|
|
97
|
+
///
|
|
98
|
+
/// Return: undefined
|
|
99
|
+
/// This method returns nothing.
|
|
36
100
|
function setContextValue(key, value) {
|
|
37
101
|
let store = globalAsyncStore.getStore();
|
|
38
102
|
if (!store || !store.context)
|
|
39
103
|
return;
|
|
40
104
|
|
|
41
|
-
|
|
105
|
+
store.context.set(key, value);
|
|
42
106
|
}
|
|
43
107
|
|
|
108
|
+
/// Run an asynchronous method in the global `AsyncLocalStorage` context.
|
|
109
|
+
///
|
|
110
|
+
/// Running a method this way will provide the method, and all calls within
|
|
111
|
+
/// its scope the global `AsyncLocalStorage` context.
|
|
112
|
+
///
|
|
113
|
+
/// Arguments:
|
|
114
|
+
/// context: Map | null
|
|
115
|
+
/// The context `Map` to use for the operation.
|
|
116
|
+
/// callback: Function
|
|
117
|
+
/// The asynchronous method to call and provide the context to.
|
|
118
|
+
///
|
|
119
|
+
/// Return: any
|
|
120
|
+
/// The return value from the callback.
|
|
44
121
|
function runInContext(context, callback) {
|
|
45
122
|
return globalAsyncStore.run(
|
|
46
123
|
{
|
|
47
|
-
parent:
|
|
48
|
-
context,
|
|
124
|
+
parent: globalAsyncStore.getStore(),
|
|
125
|
+
context: context || new Map(),
|
|
49
126
|
},
|
|
50
127
|
callback,
|
|
51
128
|
);
|
package/lib/utils/index.js
CHANGED
|
@@ -30,7 +30,7 @@ const {
|
|
|
30
30
|
const {
|
|
31
31
|
parseFilterFieldAndOperator,
|
|
32
32
|
generateQueryFromFilter,
|
|
33
|
-
|
|
33
|
+
mergeFields,
|
|
34
34
|
} = QueryUtils;
|
|
35
35
|
|
|
36
36
|
const {
|
|
@@ -69,7 +69,7 @@ module.exports = {
|
|
|
69
69
|
// QueryUtils
|
|
70
70
|
parseFilterFieldAndOperator,
|
|
71
71
|
generateQueryFromFilter,
|
|
72
|
-
|
|
72
|
+
mergeFields,
|
|
73
73
|
|
|
74
74
|
// AsyncStore
|
|
75
75
|
getContextStore,
|
package/lib/utils/misc-utils.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
+
///! import `var { Utils: { MiscUtils } } = require('mythix-orm');`
|
|
2
|
+
///!
|
|
3
|
+
///! MiscUtils utilities provide some miscellaneous utility
|
|
4
|
+
///! functions for assisting with some common operations.
|
|
5
|
+
///!
|
|
6
|
+
///! DocScope: MiscUtils
|
|
7
|
+
|
|
1
8
|
'use strict';
|
|
2
9
|
|
|
3
10
|
const Nife = require('nife');
|
|
4
11
|
const { DateTime } = require('luxon');
|
|
5
12
|
|
|
13
|
+
/// When provided an async iterator,
|
|
14
|
+
/// collect all results from the iterator
|
|
15
|
+
/// until the iterator is exhausted.
|
|
16
|
+
///
|
|
17
|
+
/// Arguments:
|
|
18
|
+
/// iterator: async * iterator
|
|
19
|
+
/// The async generator iterator to collect items from.
|
|
20
|
+
///
|
|
21
|
+
/// Return: Promise<Array<any>>
|
|
22
|
+
/// Return the collected results as an array.
|
|
6
23
|
async function collect(iterator) {
|
|
7
24
|
let items = [];
|
|
8
25
|
|
|
@@ -12,6 +29,27 @@ async function collect(iterator) {
|
|
|
12
29
|
return items;
|
|
13
30
|
}
|
|
14
31
|
|
|
32
|
+
/// Take a timestamp, a string, a Date instance,
|
|
33
|
+
/// or a Luxon [DateTime](https://moment.github.io/luxon/#/) instance
|
|
34
|
+
/// and convert the input to a Luxon [DateTime](https://moment.github.io/luxon/#/) instance.
|
|
35
|
+
///
|
|
36
|
+
/// Arguments:
|
|
37
|
+
/// value: number | string | Date | [DateTime](https://moment.github.io/luxon/#/)
|
|
38
|
+
/// The value to use to create a new Luxon [DateTime](https://moment.github.io/luxon/#/) instance.
|
|
39
|
+
/// If this is a `number` or `bigint`, then it will be assumed this is a timestamp, and
|
|
40
|
+
/// the provided `format` will be ignored. If this is a `string`, the provided `format`
|
|
41
|
+
/// will be used to parse it into a `DateTime` instance. If this is a `Date` instance, then
|
|
42
|
+
/// it will be converted to a Luxon `DateTime` instance. A Luxon `DateTime` instance will
|
|
43
|
+
/// simply be returned.
|
|
44
|
+
/// format?: string
|
|
45
|
+
/// The Luxon [DateTime](https://moment.github.io/luxon/#/) format used to parse
|
|
46
|
+
/// the date/time if the provided `value` is a string. This is only required if
|
|
47
|
+
/// the format is something that Luxon doesn't natively understand (i.e. an ISO format).
|
|
48
|
+
///
|
|
49
|
+
/// Return: [DateTime](https://moment.github.io/luxon/#/)
|
|
50
|
+
/// The newly created Luxon `DateTime` instance. If a Luxon `DateTime`
|
|
51
|
+
/// instance was provided as the `value` argument, then it will simply
|
|
52
|
+
/// be returned.
|
|
15
53
|
function valueToDateTime(value, format) {
|
|
16
54
|
if (DateTime.isDateTime(value)) {
|
|
17
55
|
return value;
|
|
@@ -11,7 +11,7 @@ export declare function generateQueryFromFilter(
|
|
|
11
11
|
filter: Array<GenericObject | Model> | GenericObject | Model,
|
|
12
12
|
): QueryEngine;
|
|
13
13
|
|
|
14
|
-
export declare function
|
|
14
|
+
export declare function mergeFields(
|
|
15
15
|
connection: ConnectionBase,
|
|
16
16
|
currentFields: Map<string, any>,
|
|
17
17
|
incomingFields: Array<any>
|
package/lib/utils/query-utils.js
CHANGED
|
@@ -1,38 +1,15 @@
|
|
|
1
|
+
///! import `var { Utils: { QueryUtils } } = require('mythix-orm');`
|
|
2
|
+
///!
|
|
3
|
+
///! QueryUtils provide utility functions
|
|
4
|
+
///! for creating and interacting with queries
|
|
5
|
+
///! ([QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)).
|
|
6
|
+
///!
|
|
7
|
+
///! DocScope: QueryUtils
|
|
8
|
+
|
|
1
9
|
'use strict';
|
|
2
10
|
|
|
3
11
|
const Nife = require('nife');
|
|
4
12
|
|
|
5
|
-
// The code below will take a "query object"
|
|
6
|
-
// and convert it into Mythix ORM query.
|
|
7
|
-
//
|
|
8
|
-
// "query objects" are objects with a simple
|
|
9
|
-
// structure and convention to build complex queries.
|
|
10
|
-
//
|
|
11
|
-
// Fields inside these objects can have operators,
|
|
12
|
-
// which are postfixed to the field name. For example,
|
|
13
|
-
// you could create a filter to find a user by name
|
|
14
|
-
// with the following query object:
|
|
15
|
-
// { "firstName=": "John", "lastName!=": "Bob" }
|
|
16
|
-
// which would find all users with the first name
|
|
17
|
-
// of "John", and any last name except "Bob".
|
|
18
|
-
//
|
|
19
|
-
// AND and OR conditions are also supported. These
|
|
20
|
-
// work based of the structure of the object itself.
|
|
21
|
-
// If an array is used, then OR is in effect.
|
|
22
|
-
// If an object is used, then AND is in effect.
|
|
23
|
-
// For example, the following query object:
|
|
24
|
-
// [ { firstName: "John", lastName: "Brown" }, { firstName: "Mary", lastName: "Smith" } ]
|
|
25
|
-
// would result in the following query:
|
|
26
|
-
// WHERE ((firstName = 'John' AND lastName = 'Brown') OR (firstName = 'Mary' AND lastName = 'Smith')),
|
|
27
|
-
// finding either user John Brown, or Mary Smith.
|
|
28
|
-
//
|
|
29
|
-
// IN and NOT IN operators are handled automatically
|
|
30
|
-
// when the operator is either "=" or "!=", and the
|
|
31
|
-
// provided value is an array. For example:
|
|
32
|
-
// { firstName: [ 'John', 'Bob', 'Mary' ] }
|
|
33
|
-
// would result in the following query:
|
|
34
|
-
// WHERE firstName IN ('John', 'Bob', 'Mary')
|
|
35
|
-
|
|
36
13
|
const FILTER_OPERATORS = {
|
|
37
14
|
'=': (Model, fieldName, query, value) => {
|
|
38
15
|
return query.AND[fieldName].EQ(value);
|
|
@@ -70,6 +47,24 @@ const FILTER_OPERATORS = {
|
|
|
70
47
|
},
|
|
71
48
|
};
|
|
72
49
|
|
|
50
|
+
/// Take the provided `fieldName`, which might include
|
|
51
|
+
/// an operator as a postfix, and return the operator
|
|
52
|
+
/// and `fieldName` found. If no operator postfix is
|
|
53
|
+
/// present, then the default `=` operator is returned.
|
|
54
|
+
///
|
|
55
|
+
/// Refer to <see>QueryUtils.generateQueryFromFilter</see> for
|
|
56
|
+
/// a better understanding of what this does and why it is needed.
|
|
57
|
+
///
|
|
58
|
+
/// Arguments:
|
|
59
|
+
/// fieldName: string
|
|
60
|
+
/// The field name to parse, with an optional operator postfix added.
|
|
61
|
+
///
|
|
62
|
+
/// Return: { field: string; operator: string; }
|
|
63
|
+
/// Return the parsed `field`, and the parsed `operator`. If no
|
|
64
|
+
/// operator postfix is on the field, then the default is the `=`
|
|
65
|
+
/// operator.
|
|
66
|
+
///
|
|
67
|
+
/// See: QueryUtils.generateQueryFromFilter
|
|
73
68
|
function parseFilterFieldAndOperator(fieldName) {
|
|
74
69
|
let operator = '=';
|
|
75
70
|
let field;
|
|
@@ -90,6 +85,74 @@ function parseFilterFieldAndOperator(fieldName) {
|
|
|
90
85
|
return { field, operator };
|
|
91
86
|
}
|
|
92
87
|
|
|
88
|
+
/// Take a "query object" and convert it into Mythix ORM query.
|
|
89
|
+
///
|
|
90
|
+
/// "query objects" are objects with a simple
|
|
91
|
+
/// structure and convention to build complex queries.
|
|
92
|
+
///
|
|
93
|
+
/// Fields inside these objects can have operators,
|
|
94
|
+
/// which are postfixed to the field name. For example,
|
|
95
|
+
/// you could create a filter to find a user by name
|
|
96
|
+
/// with the following query object:
|
|
97
|
+
/// `{ "firstName=": "John", "lastName!=": "Bob" }`
|
|
98
|
+
/// which would find all users with the first name
|
|
99
|
+
/// of "John", and any last name except "Bob".
|
|
100
|
+
///
|
|
101
|
+
/// `AND` and `OR` conditions are also supported. These
|
|
102
|
+
/// work based of the structure of the object itself.
|
|
103
|
+
/// If an array is used, then `OR` is in effect.
|
|
104
|
+
/// If an object is used, then `AND` is in effect.
|
|
105
|
+
/// For example, the following query object:
|
|
106
|
+
/// `[ { firstName: "John", lastName: "Brown" }, { firstName: "Mary", lastName: "Smith" } ]`
|
|
107
|
+
/// would result in the following SQL query:
|
|
108
|
+
/// `WHERE ((firstName = 'John' AND lastName = 'Brown') OR (firstName = 'Mary' AND lastName = 'Smith'))`,
|
|
109
|
+
/// finding either user John Brown, or Mary Smith.
|
|
110
|
+
///
|
|
111
|
+
/// `IN` and `NOT IN` operators are handled automatically
|
|
112
|
+
/// when the operator is either `=` or `!=`, and the
|
|
113
|
+
/// provided value is an array. For example:
|
|
114
|
+
/// `{ firstName: [ 'John', 'Bob', 'Mary' ] }`
|
|
115
|
+
/// would result in the following SQL query:
|
|
116
|
+
/// `WHERE firstName IN ('John', 'Bob', 'Mary')`.
|
|
117
|
+
///
|
|
118
|
+
/// Operators that can be postfixed to field names
|
|
119
|
+
/// in the provided `filter` object are as follows:
|
|
120
|
+
/// | Operator | Description |
|
|
121
|
+
/// | `=` | Equality operator. If an `Array` of values is provided, then this will turn into a `IN` operation in the underlying database. |
|
|
122
|
+
/// | `!=` | Inverse (not) equality operator. If an `Array` of values is provided, then this will turn into a `NOT IN` operation in the underlying database. |
|
|
123
|
+
/// | `>` | Greater than operator. |
|
|
124
|
+
/// | `>=` | Greater than or equal to operator. |
|
|
125
|
+
/// | `<` | Less than operator. |
|
|
126
|
+
/// | `<=` | Less than or equal to operator. |
|
|
127
|
+
/// | `><` | Between operator. This operator requires that the provided value be an array with exactly two elements: `[ min, max ]`. |
|
|
128
|
+
/// | `<>` | Inverse (not) between operator. This operator requires that the provided value be an array with exactly two elements: `[ min, max ]`. |
|
|
129
|
+
/// | `*` | A `LIKE` wildcard matching operator. The provided value should use `%` for "zero or more" matches, and `_` for "any single character" match. |
|
|
130
|
+
/// | `!*` | A `NOT LIKE` wildcard matching operator. The provided value should use `%` for "zero or more" matches, and `_` for "any single character" match. |
|
|
131
|
+
///
|
|
132
|
+
/// Note:
|
|
133
|
+
/// This is a simple interface to take an "object" and turn it into
|
|
134
|
+
/// a <see>QueryEngine</see>. It doesn't allow multiple models
|
|
135
|
+
/// to be defined at once (table-joins), nor other complex operations.
|
|
136
|
+
/// If you need more complex operations on your query, you will need
|
|
137
|
+
/// to manually create your query... though this method can be used
|
|
138
|
+
/// as a starting point.
|
|
139
|
+
///
|
|
140
|
+
/// Arguments:
|
|
141
|
+
/// connection: <see>Connection</see>
|
|
142
|
+
/// The connection used to create the <see>QueryEngine</see>.
|
|
143
|
+
/// Model: class <see>Model</see>
|
|
144
|
+
/// The model the query is being generated for. The specified
|
|
145
|
+
/// fields provided via the `filter` argument should all be from
|
|
146
|
+
/// this model.
|
|
147
|
+
/// filter: object | Array
|
|
148
|
+
/// An object or an array of objects to build a query from. Any
|
|
149
|
+
/// object will have all its properties `AND`ed together... whereas
|
|
150
|
+
/// any array will have its sub-objects `OR`ed together. i.e.
|
|
151
|
+
/// `[ { prop1 AND prop2 AND prop3 } OR { prop1 AND prop2 AND prop3 } ]`.
|
|
152
|
+
///
|
|
153
|
+
/// Return: <see>QueryEngine</see>
|
|
154
|
+
/// The new query for the `Model` provided, generated from the
|
|
155
|
+
/// provided `filter` argument.
|
|
93
156
|
function generateQueryFromFilter(connection, Model, _filter, _depth) {
|
|
94
157
|
const getOperator = (name) => {
|
|
95
158
|
let func = FILTER_OPERATORS[name];
|
|
@@ -180,7 +243,35 @@ function generateQueryFromFilter(connection, Model, _filter, _depth) {
|
|
|
180
243
|
return query;
|
|
181
244
|
}
|
|
182
245
|
|
|
183
|
-
|
|
246
|
+
/// Merge fields for a `PROJECT`, `ORDER`,
|
|
247
|
+
/// or `GROUP_BY` <see>QueryEngine</see> operation.
|
|
248
|
+
///
|
|
249
|
+
/// See <see>ModelScope.mergeFields</see> for a more detailed description
|
|
250
|
+
/// of what this method does and how it is used.
|
|
251
|
+
///
|
|
252
|
+
/// Arguments:
|
|
253
|
+
/// queryEngine: <see>QueryEngine</see>
|
|
254
|
+
/// The <see>QueryEngine</see> instance that the `PROJECT`,
|
|
255
|
+
/// `ORDER`, or `GROUP_BY` operation is being applied to.
|
|
256
|
+
/// currentFields: Map<string, object>
|
|
257
|
+
/// A map of the current fields that have been applied to the
|
|
258
|
+
/// given operation.
|
|
259
|
+
/// incomingFields: Array<string | Literal | Model | Field>
|
|
260
|
+
/// A list of all the incoming fields that are supplied to the
|
|
261
|
+
/// `PROJECT`, `ORDER`, or `GROUP_BY` operation that is being carried
|
|
262
|
+
/// out. This will either merge will `currentFields`, or replace
|
|
263
|
+
/// the `currentFields`, depending on the content of this argument.
|
|
264
|
+
/// extraData?: object
|
|
265
|
+
/// If supplied, then merge these extra properties into each field being
|
|
266
|
+
/// added to the list of fields. This is used for example by the `ORDER`
|
|
267
|
+
/// operation to define the `direction` property for each field added.
|
|
268
|
+
/// options?: object
|
|
269
|
+
/// Options for the operation. These are only used when stringifying
|
|
270
|
+
/// literals that are being added to the field list. See <see>LiteralBase.toString</see>
|
|
271
|
+
/// for more information.
|
|
272
|
+
///
|
|
273
|
+
/// See: ModelScope.mergeFields
|
|
274
|
+
function mergeFields(queryEngine, currentFields, _incomingFields, extraData, _options) {
|
|
184
275
|
const RESET = 0;
|
|
185
276
|
const ADD = 1;
|
|
186
277
|
const SUB = 2;
|
|
@@ -256,7 +347,7 @@ function margeFields(queryEngine, currentFields, _incomingFields, extraData, _op
|
|
|
256
347
|
|
|
257
348
|
if (typeof incomingField.isLiteral === 'function' && incomingField.isLiteral(incomingField)) {
|
|
258
349
|
if (!connection)
|
|
259
|
-
throw new Error('QueryUtils::
|
|
350
|
+
throw new Error('QueryUtils::mergeFields: "connection" is required, but not found.');
|
|
260
351
|
|
|
261
352
|
let result = incomingField.toString(connection, options);
|
|
262
353
|
addOrRemove(mode, result, result);
|
|
@@ -278,7 +369,7 @@ function margeFields(queryEngine, currentFields, _incomingFields, extraData, _op
|
|
|
278
369
|
continue;
|
|
279
370
|
|
|
280
371
|
if (!connection)
|
|
281
|
-
throw new Error('QueryUtils::
|
|
372
|
+
throw new Error('QueryUtils::mergeFields: "connection" is required, but not found.');
|
|
282
373
|
|
|
283
374
|
if (!incomingField)
|
|
284
375
|
continue;
|
|
@@ -330,7 +421,7 @@ function margeFields(queryEngine, currentFields, _incomingFields, extraData, _op
|
|
|
330
421
|
|
|
331
422
|
let Model = connection.getModel(def.modelName);
|
|
332
423
|
if (!Model)
|
|
333
|
-
throw new Error(`QueryUtils::
|
|
424
|
+
throw new Error(`QueryUtils::mergeFields: Model "${def.modelName}" not found.`);
|
|
334
425
|
|
|
335
426
|
if (Nife.isEmpty(def.fieldNames)) {
|
|
336
427
|
addOrRemoveAllModelFields(currentMode, Model);
|
|
@@ -341,7 +432,7 @@ function margeFields(queryEngine, currentFields, _incomingFields, extraData, _op
|
|
|
341
432
|
let fieldName = def.fieldNames[0];
|
|
342
433
|
let field = connection.getField(fieldName, modelName);
|
|
343
434
|
if (!field)
|
|
344
|
-
throw new Error(`QueryUtils::
|
|
435
|
+
throw new Error(`QueryUtils::mergeFields: Field "${fieldName}" not found.`);
|
|
345
436
|
|
|
346
437
|
let fullFieldName = `${modelName}:${fieldName}`;
|
|
347
438
|
addOrRemove(currentMode, fullFieldName, field);
|
|
@@ -353,5 +444,5 @@ function margeFields(queryEngine, currentFields, _incomingFields, extraData, _op
|
|
|
353
444
|
module.exports = {
|
|
354
445
|
parseFilterFieldAndOperator,
|
|
355
446
|
generateQueryFromFilter,
|
|
356
|
-
|
|
447
|
+
mergeFields,
|
|
357
448
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mythix-orm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.1",
|
|
4
4
|
"description": "ORM for Mythix framework",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -47,7 +47,6 @@
|
|
|
47
47
|
"inflection": "^2.0.0",
|
|
48
48
|
"luxon": "^3.1.0",
|
|
49
49
|
"nife": "^1.12.1",
|
|
50
|
-
"sqlstring": "^2.3.3",
|
|
51
50
|
"uuid": "^9.0.0",
|
|
52
51
|
"xid-js": "^1.0.1"
|
|
53
52
|
},
|