mythix-orm 1.5.0 → 1.5.3
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 +1 -1
- package/lib/field.js +217 -0
- package/lib/model.js +40 -40
- package/lib/query-engine/query-engine.js +24 -6
- package/lib/types/concrete/bigint-type.js +123 -0
- package/lib/types/concrete/blob-type.js +85 -0
- package/lib/types/concrete/boolean-type.js +75 -2
- package/lib/types/concrete/char-type.js +72 -0
- package/lib/types/concrete/date-type.js +168 -0
- package/lib/types/concrete/datetime-type.js +172 -3
- package/lib/types/concrete/integer-type.js +100 -0
- package/lib/types/concrete/numeric-type.js +106 -0
- package/lib/types/helpers/default-helpers.js +6 -6
- package/lib/types/type.js +23 -0
- package/package.json +1 -1
|
@@ -100,7 +100,7 @@ class ConnectionBase extends EventEmitter {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
getDefaultOrder(rootModel, options) {
|
|
103
|
-
return rootModel.
|
|
103
|
+
return rootModel.defaultOrder.call(rootModel, options);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
_getFromModelCache(Model, key, defaultValue) {
|
package/lib/field.js
CHANGED
|
@@ -1,8 +1,183 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
/// Field class, that holds the properties
|
|
4
|
+
/// of all field descriptors that define
|
|
5
|
+
/// the model's fields.
|
|
6
|
+
///
|
|
7
|
+
/// Example:
|
|
8
|
+
/// class User extends Model {
|
|
9
|
+
/// // Each field below is termed a "field descriptor"
|
|
10
|
+
/// // and will eventually be turned into a Field.
|
|
11
|
+
/// static fields = {
|
|
12
|
+
/// id: {
|
|
13
|
+
/// type: Types.BIGINT,
|
|
14
|
+
/// defaultValue: Types.BIGINT.Default.AUTO_INCREMENT,
|
|
15
|
+
/// allowNull: false,
|
|
16
|
+
/// primaryKey: true,
|
|
17
|
+
/// },
|
|
18
|
+
/// email: {
|
|
19
|
+
/// type: Types.STRING(64),
|
|
20
|
+
/// allowNull: false,
|
|
21
|
+
/// index: true,
|
|
22
|
+
/// unique: true,
|
|
23
|
+
/// valiate: (value) => {
|
|
24
|
+
/// if (('' + value).indexOf('@') < 0)
|
|
25
|
+
/// throw new Error(`Invalid email address: "${value}"`);
|
|
26
|
+
/// },
|
|
27
|
+
/// },
|
|
28
|
+
/// gender: {
|
|
29
|
+
/// type: Types.STRING(32),
|
|
30
|
+
/// allowNull: false,
|
|
31
|
+
/// index: true,
|
|
32
|
+
/// defaultValue: 'other',
|
|
33
|
+
/// valiate: (value) => {
|
|
34
|
+
/// if (!(/^(male|female|other)$/).test(value))
|
|
35
|
+
/// throw new Error(`Invalid gender: "${value}"`);
|
|
36
|
+
/// },
|
|
37
|
+
/// },
|
|
38
|
+
/// prefix: {
|
|
39
|
+
/// type: Types.STRING(10),
|
|
40
|
+
/// allowNull: true,
|
|
41
|
+
/// index: true,
|
|
42
|
+
/// get: ({ self, value }) => {
|
|
43
|
+
/// if (self.gender === 'male')
|
|
44
|
+
/// return 'Mr.';
|
|
45
|
+
/// else if (self.gender === 'female')
|
|
46
|
+
/// return 'Ms.';
|
|
47
|
+
/// else
|
|
48
|
+
/// return value;
|
|
49
|
+
/// },
|
|
50
|
+
/// set: ({ set, value }) => {
|
|
51
|
+
/// set(value);
|
|
52
|
+
/// },
|
|
53
|
+
/// },
|
|
54
|
+
/// firstName: {
|
|
55
|
+
/// type: Types.STRING(32),
|
|
56
|
+
/// allowNull: false,
|
|
57
|
+
/// index: true,
|
|
58
|
+
/// },
|
|
59
|
+
/// lastName: {
|
|
60
|
+
/// type: Types.STRING(32),
|
|
61
|
+
/// allowNull: false,
|
|
62
|
+
/// index: true,
|
|
63
|
+
/// },
|
|
64
|
+
/// };
|
|
65
|
+
/// }
|
|
66
|
+
///
|
|
67
|
+
/// Interface:
|
|
68
|
+
/// interface DefaultValueContext {
|
|
69
|
+
/// _initial: boolean; // If `true`, then this is the initial set of the field's value.
|
|
70
|
+
/// connection: Connection; // The connection from the model.
|
|
71
|
+
/// data: object | undefined; // All attributes provided to the model upon instantiation.
|
|
72
|
+
/// field: Field; // The field descriptor where this `defaultValue` is defined.
|
|
73
|
+
/// fieldName: string; // The name of this field where this `defaultValue` is defined.
|
|
74
|
+
/// fieldValue: any; // The field value as provided to the model instance upon instantiation.
|
|
75
|
+
/// self: Model; // The model instance.
|
|
76
|
+
/// }
|
|
77
|
+
///
|
|
78
|
+
/// Interface:
|
|
79
|
+
/// interface GetSetContext {
|
|
80
|
+
/// field: Field; // The field descriptor of this field.
|
|
81
|
+
/// fieldName: string; // The field name of this field.
|
|
82
|
+
/// get: Function; // A method to fetch the current value of this field.
|
|
83
|
+
/// self: Model; // The model instance of this field value.
|
|
84
|
+
/// set: Function; // A method to set the current value of this field.
|
|
85
|
+
/// value: any; // The current value of this field.
|
|
86
|
+
/// }
|
|
87
|
+
///
|
|
88
|
+
/// Properties:
|
|
89
|
+
/// type: Type
|
|
90
|
+
/// The type of the field. Can be either a virtual or concrete type.
|
|
91
|
+
/// You can supply either a `Type` instance (`type: new Types.BigIntType()`),
|
|
92
|
+
/// a `Type` class (`type: Types.BigIntType`), a type wrapper
|
|
93
|
+
/// (`type: Types.BIGINT`), or a `Type` instance created through a type
|
|
94
|
+
/// wrapper (`type: Types.BIGINT(8)`).
|
|
95
|
+
/// primaryKey: boolean = false
|
|
96
|
+
/// If `true`, then this field will be the primary key of the model.
|
|
97
|
+
/// It will also be marked as the primary key in the underlying database.
|
|
98
|
+
/// fieldName: string
|
|
99
|
+
/// The name of this field. If not provided, this will
|
|
100
|
+
/// be the key that defined the field. If your model
|
|
101
|
+
/// fields are defined as an `Array` or `Set`, then this
|
|
102
|
+
/// attribute is required, and must be supplied. If
|
|
103
|
+
/// your fields are defined as an `Object`, or a `Map`,
|
|
104
|
+
/// then if this attribute is not supplied, the key
|
|
105
|
+
/// will be used as the `fieldName` instead. The
|
|
106
|
+
/// `fieldName` always takes priority, so if you
|
|
107
|
+
/// have a key and a `fieldName`, then the field name
|
|
108
|
+
/// will take precedence over the key name.
|
|
109
|
+
/// allowNull: boolean = true
|
|
110
|
+
/// If `true`, then this field is allowed to have a `NULL`
|
|
111
|
+
/// value in the underlying database. If `false`, then this
|
|
112
|
+
/// field must not have a `NULL` value in the underlying database.
|
|
113
|
+
/// This has no effect client-side in JavaScript. Even if `allowNull`
|
|
114
|
+
/// is `false`, the field property on your model may still have a
|
|
115
|
+
/// `null` value in JavaScript.
|
|
116
|
+
/// index: boolean = false
|
|
117
|
+
/// If `true`, then this field will be indexed in the database.
|
|
118
|
+
/// unique: boolean = false
|
|
119
|
+
/// If `true`, then add a unique constraint to this field in
|
|
120
|
+
/// the underlying database.
|
|
121
|
+
/// defaultValue: any | Function(context: DefaultValueContext)
|
|
122
|
+
/// Provide a default value for this field. `defaultValue` in
|
|
123
|
+
/// Mythix ORM can be either a literal value, such as a `string`
|
|
124
|
+
/// or a `number`, it can be `null`, or it can be a function. If
|
|
125
|
+
/// it is a function, it will be called when the model is initialized
|
|
126
|
+
/// if no value for the field was provided to the model during instantiation.
|
|
127
|
+
/// As a method, it can have numerous different "flags" set on it, via
|
|
128
|
+
/// the <see>DefaultHelpers.defaultValueFlags</see> factory. Reference this
|
|
129
|
+
/// methods documentation for a better understanding of what default value
|
|
130
|
+
/// flags are, and what they do.
|
|
131
|
+
/// get: Function(context: GetSetContext)
|
|
132
|
+
/// A "getter" for this field. If defined, this will be called any time
|
|
133
|
+
/// the field is accessed. The return value will be the value of the field.
|
|
134
|
+
/// Use the `get` method provided by the `context` argument to get the underlying
|
|
135
|
+
/// field value, or use <see>Model.getDataValue</see> to get the underlying value.<br>
|
|
136
|
+
/// *Note: The provided `get` method, and <see>Model.getDataValue</see> will bypass this method.*<br>
|
|
137
|
+
/// *Note: Do NOT get the field property directly on the model inside this method, or you will enter an infinite recursive loop.*
|
|
138
|
+
/// set: Function(context: GetSetContext)
|
|
139
|
+
/// A "setter" for this field. If defined, this will be called any time
|
|
140
|
+
/// the field is set. This field must call the `set` method provided by
|
|
141
|
+
/// the `context` argument, or it must call <see>Model.setDataValue</see>
|
|
142
|
+
/// on the `self` model instance provided by the `context`.<br>
|
|
143
|
+
/// *Note: The provided `set` method, and <see>Model.setDataValue</see> will bypass this method.*<br>
|
|
144
|
+
/// *Note: Do NOT set the field name directly on the model inside this method, or you will enter an infinite recursive loop.*
|
|
145
|
+
/// validate: async Function(value: any, context: { connection, Model, options })
|
|
146
|
+
/// If this method is provided, then it will be called from <see>Model.onValidate</see>
|
|
147
|
+
/// immediately before an insert or update operation. The return value of this method
|
|
148
|
+
/// is ignored by Mythix ORM (though if you want, you can do something with it if you
|
|
149
|
+
/// overload the `onValidate` method of the model). If validation fails, it is expected
|
|
150
|
+
/// that this method will throw an error. Notice that RegExp or pattern values are not
|
|
151
|
+
/// supported. `validate` MUST be a method. How you implement it is up to you.
|
|
152
|
+
/// The `value` argument is the current value of the field. The `context` argument
|
|
153
|
+
/// is provided by the underlying connection. The `Model` inside the context is the
|
|
154
|
+
/// model class of the current model that is being validated. The `options` inside
|
|
155
|
+
/// the context is simply an object containing the current options for the underlying
|
|
156
|
+
/// connection operation.
|
|
3
157
|
class Field {
|
|
158
|
+
/// This helps with type checking
|
|
4
159
|
static _isMythixField = true;
|
|
5
160
|
|
|
161
|
+
/// Check if the provided `value` is
|
|
162
|
+
/// a <see>Field</see> class.
|
|
163
|
+
///
|
|
164
|
+
/// This will check if the provided value's
|
|
165
|
+
/// `prototype` is an instance of <see>Field</see>
|
|
166
|
+
/// if it is, this method will return `true`.
|
|
167
|
+
/// If that check fails, then it will see if
|
|
168
|
+
/// the provided value has a `_isMythixField`
|
|
169
|
+
/// property that is `true`. If this is the
|
|
170
|
+
/// case, then this method will return `true`.
|
|
171
|
+
/// Finally, if all checks have failed, this
|
|
172
|
+
/// method will return false.
|
|
173
|
+
///
|
|
174
|
+
/// Return: boolean
|
|
175
|
+
/// `true` if the provided value is a <see>Field</see>
|
|
176
|
+
/// class, or inherits from <see>Field</see>. `false`
|
|
177
|
+
/// otherwise.
|
|
178
|
+
/// Arguments:
|
|
179
|
+
/// value: any
|
|
180
|
+
/// The value to check.
|
|
6
181
|
static isFieldClass(value) {
|
|
7
182
|
if (!value)
|
|
8
183
|
return false;
|
|
@@ -16,6 +191,26 @@ class Field {
|
|
|
16
191
|
return false;
|
|
17
192
|
}
|
|
18
193
|
|
|
194
|
+
/// Check if the provided `value` is
|
|
195
|
+
/// a <see>Field</see> instance.
|
|
196
|
+
///
|
|
197
|
+
/// This will check if the provided value
|
|
198
|
+
/// is an `instanceof` <see>Field</see>,
|
|
199
|
+
/// if it is this method will return `true`.
|
|
200
|
+
/// If that check fails, then it will see if
|
|
201
|
+
/// the provided value has a `value.constructor_isMythixField`
|
|
202
|
+
/// property that is `true`. If this is the
|
|
203
|
+
/// case, then this method will return `true`.
|
|
204
|
+
/// Finally, if all checks have failed, this
|
|
205
|
+
/// method will return false.
|
|
206
|
+
///
|
|
207
|
+
/// Return: boolean
|
|
208
|
+
/// `true` if the provided value is a <see>Field</see>
|
|
209
|
+
/// instance, or inherits from <see>Field</see>. `false`
|
|
210
|
+
/// otherwise.
|
|
211
|
+
/// Arguments:
|
|
212
|
+
/// value: any
|
|
213
|
+
/// The value to check.
|
|
19
214
|
static isField(value) {
|
|
20
215
|
if (!value)
|
|
21
216
|
return false;
|
|
@@ -29,15 +224,37 @@ class Field {
|
|
|
29
224
|
return false;
|
|
30
225
|
}
|
|
31
226
|
|
|
227
|
+
/// Construct a Field.
|
|
228
|
+
///
|
|
229
|
+
/// This method will create a new instance of <see>Field</see>.
|
|
230
|
+
/// The provided `fieldDefinition` argument is expected to
|
|
231
|
+
/// be another <see>Field</see>, or an iterable object containing
|
|
232
|
+
/// the field attributes.
|
|
233
|
+
///
|
|
234
|
+
/// Return: <see>Field</see>
|
|
235
|
+
/// Arguments:
|
|
236
|
+
/// fieldDescription: object | <see>Field</see>
|
|
237
|
+
/// The attributes to provide to this field.
|
|
32
238
|
constructor(fieldDefinition) {
|
|
33
239
|
Object.assign(this, fieldDefinition || {});
|
|
34
240
|
}
|
|
35
241
|
|
|
242
|
+
/// Clone this field instance.
|
|
243
|
+
///
|
|
244
|
+
/// Return: <see>Field</see>
|
|
245
|
+
/// This field, cloned into a new instance.
|
|
36
246
|
clone() {
|
|
37
247
|
const FieldClass = this.constructor;
|
|
38
248
|
return new FieldClass(this);
|
|
39
249
|
}
|
|
40
250
|
|
|
251
|
+
/// Set the parent <see>Model</see> class
|
|
252
|
+
/// for this field.
|
|
253
|
+
///
|
|
254
|
+
/// Return: undefined
|
|
255
|
+
/// Arguments:
|
|
256
|
+
/// Model: class <see>Model</see>
|
|
257
|
+
/// The parent model class of this field.
|
|
41
258
|
setModel(Model) {
|
|
42
259
|
this.Model = Model;
|
|
43
260
|
}
|
package/lib/model.js
CHANGED
|
@@ -432,7 +432,7 @@ class Model {
|
|
|
432
432
|
|
|
433
433
|
/// One can apply a "default scope" to any model simply
|
|
434
434
|
/// by providing this static method on the model. By
|
|
435
|
-
/// default it will simply return the <see>QueryEngine</see>
|
|
435
|
+
/// default it will simply return the <see name="derp">QueryEngine</see>
|
|
436
436
|
/// instance (a query) that it was provided.
|
|
437
437
|
///
|
|
438
438
|
/// The way this works is simple. The caller provides the
|
|
@@ -1112,33 +1112,28 @@ class Model {
|
|
|
1112
1112
|
/// value from the provided `callback` will be pushed into an array
|
|
1113
1113
|
/// just like `Array.prototype.map`. The `callback` provided, when called,
|
|
1114
1114
|
/// will be provided a `context` object, as the single argument to
|
|
1115
|
-
/// the callback.
|
|
1116
|
-
/// ```javascript
|
|
1117
|
-
/// IterationContext = {
|
|
1118
|
-
/// // The Field instance itself.
|
|
1119
|
-
/// field,
|
|
1120
|
-
/// // The name of the field.
|
|
1121
|
-
/// fieldName,
|
|
1122
|
-
/// // All the model's fields.
|
|
1123
|
-
/// fields,
|
|
1124
|
-
/// // The current index into the list of fields.
|
|
1125
|
-
/// // This will be set even if the fields are
|
|
1126
|
-
/// // `object` or `Map` types.
|
|
1127
|
-
/// index,
|
|
1128
|
-
/// // A method that when called will halt
|
|
1129
|
-
/// // iteration and immediately return.
|
|
1130
|
-
/// stop,
|
|
1131
|
-
/// // A method that you can call to see
|
|
1132
|
-
/// // if `stop` has been called... meaning the
|
|
1133
|
-
/// // iteration process is about to halt.
|
|
1134
|
-
/// isStopped,
|
|
1135
|
-
/// }
|
|
1136
|
-
/// ```
|
|
1115
|
+
/// the callback.
|
|
1137
1116
|
///
|
|
1138
1117
|
/// At any time you can call the `stop` method provided via the context.
|
|
1139
1118
|
/// When called, `iterateFields` will stop iterating, and immediately
|
|
1140
1119
|
/// return an array of results returned by all calls to `callback`.
|
|
1141
1120
|
///
|
|
1121
|
+
/// The provided `context` object has the following shape:
|
|
1122
|
+
///
|
|
1123
|
+
/// Interface:
|
|
1124
|
+
/// interface IterationContext {
|
|
1125
|
+
/// field: Field; // The Field instance itself.
|
|
1126
|
+
/// fieldName: string; // The name of the field.
|
|
1127
|
+
/// fields: // All the model's fields.
|
|
1128
|
+
/// Array<Field> |
|
|
1129
|
+
/// Set<Field> |
|
|
1130
|
+
/// Object<string, Field> |
|
|
1131
|
+
// Map<string, Field>;
|
|
1132
|
+
/// index: string | number; // The current index into the list of fields.
|
|
1133
|
+
/// stop: Function; // A method that when called will halt iteration.
|
|
1134
|
+
/// isStopped: Function; // Call this method to see if iteration is about to be halted.
|
|
1135
|
+
/// }
|
|
1136
|
+
///
|
|
1142
1137
|
/// Return: Array<any>
|
|
1143
1138
|
/// Arguments:
|
|
1144
1139
|
/// callback: Function(context: IterationContext)
|
|
@@ -1348,7 +1343,7 @@ class Model {
|
|
|
1348
1343
|
/// query being operated on.
|
|
1349
1344
|
///
|
|
1350
1345
|
/// Note:
|
|
1351
|
-
/// Internally, Mythix ORM will call `this.connection.
|
|
1346
|
+
/// Internally, Mythix ORM will call `this.connection.defaultOrder(options)`,
|
|
1352
1347
|
/// which--if not overloaded--will simply call this method from the
|
|
1353
1348
|
/// model itself.
|
|
1354
1349
|
/// Note:
|
|
@@ -1365,7 +1360,7 @@ class Model {
|
|
|
1365
1360
|
/// Prefix a field name with `+` to specify ASCending order, i.e.
|
|
1366
1361
|
/// `[ "+User:id" ]`. Prefix the field name with `-` to specify
|
|
1367
1362
|
/// DESCending order, i.e. `[ "-User:id" ]`.
|
|
1368
|
-
static
|
|
1363
|
+
static defaultOrder(options) {
|
|
1369
1364
|
}
|
|
1370
1365
|
|
|
1371
1366
|
/// This method is called anytime a `Model.where` or `Model.$`
|
|
@@ -1902,6 +1897,7 @@ class Model {
|
|
|
1902
1897
|
if (shouldRunDefaultValueOnInitialize()) {
|
|
1903
1898
|
defaultValue = defaultValue({
|
|
1904
1899
|
model: this,
|
|
1900
|
+
self: this,
|
|
1905
1901
|
connection: this.getConnection(),
|
|
1906
1902
|
_initial: true,
|
|
1907
1903
|
field,
|
|
@@ -1942,16 +1938,7 @@ class Model {
|
|
|
1942
1938
|
/// fields for the model instance. Unlike
|
|
1943
1939
|
/// `Model.changes`, which is a getter, you can
|
|
1944
1940
|
/// pass `options` to this method, which can change
|
|
1945
|
-
/// its behavior.
|
|
1946
|
-
/// following shape:
|
|
1947
|
-
/// ```javascript
|
|
1948
|
-
/// {
|
|
1949
|
-
/// connection: <see>Connection</see>,
|
|
1950
|
-
/// update: boolean,
|
|
1951
|
-
/// insert: boolean,
|
|
1952
|
-
/// // ... any options you wish to pass to `connection.dirtyFieldHelper`
|
|
1953
|
-
/// }
|
|
1954
|
-
/// ```
|
|
1941
|
+
/// its behavior.
|
|
1955
1942
|
///
|
|
1956
1943
|
/// If this method is provided a <see>Connection</see> via the
|
|
1957
1944
|
/// `connection` options value, then it will assume it is being
|
|
@@ -2001,6 +1988,17 @@ class Model {
|
|
|
2001
1988
|
/// or since the last time the <see>Model.clearDirty</see> method was
|
|
2002
1989
|
/// called.
|
|
2003
1990
|
///
|
|
1991
|
+
/// The `options` argument has the
|
|
1992
|
+
/// following shape:
|
|
1993
|
+
///
|
|
1994
|
+
/// Interface:
|
|
1995
|
+
/// interface DirtyFieldOptions {
|
|
1996
|
+
/// connection: Connection; // The connection for this operation.
|
|
1997
|
+
/// update: boolean; // If `true`, then this is an update operation.
|
|
1998
|
+
/// insert: boolean; // If `true`, then this is an insert operation.
|
|
1999
|
+
/// // ... any options you wish to pass to `connection.dirtyFieldHelper`
|
|
2000
|
+
/// }
|
|
2001
|
+
///
|
|
2004
2002
|
/// Note:
|
|
2005
2003
|
/// If this is an "update" or "insert" operation, as defined by
|
|
2006
2004
|
/// the `update` or `insert` "options", then the default value
|
|
@@ -2008,7 +2006,7 @@ class Model {
|
|
|
2008
2006
|
/// method through the provided `connection`.
|
|
2009
2007
|
/// Return: DirtyFieldChangeList
|
|
2010
2008
|
/// Arguments:
|
|
2011
|
-
/// options?:
|
|
2009
|
+
/// options?: DirtyFieldOptions
|
|
2012
2010
|
/// Options to provide to the method.
|
|
2013
2011
|
_getDirtyFields(_options) {
|
|
2014
2012
|
let options = _options || {};
|
|
@@ -2120,13 +2118,14 @@ class Model {
|
|
|
2120
2118
|
/// The name of the field whose value we wish to get.
|
|
2121
2119
|
/// field: <see>Field</see>
|
|
2122
2120
|
/// The field definition itself for the value we wish to get.
|
|
2123
|
-
/// See: Field
|
|
2121
|
+
/// See: Field
|
|
2124
2122
|
_getFieldValue(fieldName, field) {
|
|
2125
2123
|
let value = this.getDataValue(fieldName);
|
|
2126
2124
|
|
|
2127
2125
|
if (typeof field.get === 'function') {
|
|
2128
2126
|
return field.get.call(this, {
|
|
2129
2127
|
model: this,
|
|
2128
|
+
self: this,
|
|
2130
2129
|
set: this.setDataValue.bind(this, fieldName),
|
|
2131
2130
|
get: this.getDataValue.bind(this, fieldName),
|
|
2132
2131
|
value,
|
|
@@ -2163,11 +2162,12 @@ class Model {
|
|
|
2163
2162
|
/// The name of the field whose value we wish to get.
|
|
2164
2163
|
/// field: <see>Field</see>
|
|
2165
2164
|
/// The field definition itself for the value we wish to get.
|
|
2166
|
-
/// See: Field
|
|
2165
|
+
/// See: Field
|
|
2167
2166
|
_setFieldValue(fieldName, field, value) {
|
|
2168
2167
|
if (typeof field.set === 'function') {
|
|
2169
2168
|
field.set.call(this, {
|
|
2170
2169
|
model: this,
|
|
2170
|
+
self: this,
|
|
2171
2171
|
set: this.setDataValue.bind(this, fieldName),
|
|
2172
2172
|
get: this.getDataValue.bind(this, fieldName),
|
|
2173
2173
|
value,
|
|
@@ -2949,8 +2949,8 @@ class Model {
|
|
|
2949
2949
|
}
|
|
2950
2950
|
|
|
2951
2951
|
// eslint-disable-next-line no-unused-vars
|
|
2952
|
-
[Symbol.for('nodejs.util.inspect.custom')](
|
|
2953
|
-
return
|
|
2952
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
2953
|
+
return this.toJSON();
|
|
2954
2954
|
}
|
|
2955
2955
|
}
|
|
2956
2956
|
|
|
@@ -68,8 +68,9 @@ class QueryEngine extends QueryEngineBase {
|
|
|
68
68
|
if (!QueryEngine.isQuery(queryEngine) && Nife.instanceOf(queryEngine, 'array', 'object', 'map', 'set'))
|
|
69
69
|
queryEngine = Utils.generateQueryFromFilter(this.getConnection(), thisQueryContext.rootModel, queryEngine);
|
|
70
70
|
|
|
71
|
-
let sourceQuery
|
|
72
|
-
let currentModel
|
|
71
|
+
let sourceQuery = queryEngine._getRawQuery();
|
|
72
|
+
let currentModel = thisQueryContext.Model;
|
|
73
|
+
let skipLogicalOperators = true;
|
|
73
74
|
|
|
74
75
|
for (let i = 0, il = sourceQuery.length; i < il; i++) {
|
|
75
76
|
let queryPart = sourceQuery[i];
|
|
@@ -88,12 +89,29 @@ class QueryEngine extends QueryEngineBase {
|
|
|
88
89
|
'rootModelName',
|
|
89
90
|
]);
|
|
90
91
|
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
// For merges, we want to skip the first logical operators
|
|
93
|
+
// found before any other operation.
|
|
94
|
+
// This is because one might do a: Model.where.OR.MERGE(Model.AND.field.EQ()).
|
|
95
|
+
// This query, once merged, would be: Model.where.OR.Model.AND.field.EQ(),
|
|
96
|
+
// which is not what we want... instead we want: Model.where.OR.Model.field.EQ().
|
|
97
|
+
// Since the result we want here is OR merge, not AND merge
|
|
98
|
+
// we skip the first "AND" we encounter, leaving the "OR" as
|
|
99
|
+
// the current logical operator.
|
|
100
|
+
if (skipLogicalOperators && Object.prototype.hasOwnProperty.call(mergeContext, 'logical') && mergeContext.logical) {
|
|
101
|
+
if (mergeContext.value == null && (mergeContext.operator === 'AND' || mergeContext.operator === 'OR'))
|
|
94
102
|
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (Object.prototype.hasOwnProperty.call(mergeContext, 'operator')) {
|
|
106
|
+
// Skip unneeded duplicate model entries
|
|
107
|
+
if (mergeContext.operator === 'MODEL') {
|
|
108
|
+
if (mergeContext.Model === currentModel)
|
|
109
|
+
continue;
|
|
95
110
|
|
|
96
|
-
|
|
111
|
+
currentModel = mergeContext.Model;
|
|
112
|
+
} else if (mergeContext.operator !== 'FIELD') {
|
|
113
|
+
skipLogicalOperators = false;
|
|
114
|
+
}
|
|
97
115
|
}
|
|
98
116
|
|
|
99
117
|
this._addToQuery(Object.assign({
|
|
@@ -4,11 +4,61 @@ const Nife = require('nife');
|
|
|
4
4
|
const Type = require('../type');
|
|
5
5
|
const { AUTO_INCREMENT } = require('../helpers/default-helpers');
|
|
6
6
|
|
|
7
|
+
/// `BIGINT` type.
|
|
8
|
+
///
|
|
9
|
+
/// This represents a "big integer", or a 64+ bit integer
|
|
10
|
+
/// in any underlying database.
|
|
11
|
+
///
|
|
12
|
+
/// By default, `BIGINT` will use the `number` primitive
|
|
13
|
+
/// to store values in JavaScript client-side. This
|
|
14
|
+
/// choice was made because the `number` primitive is
|
|
15
|
+
/// more commonly dealt with, and its max storage
|
|
16
|
+
/// capacity is the number `9,007,199,254,740,991`, which
|
|
17
|
+
/// is generally far above and beyond what most databases
|
|
18
|
+
/// will ever reach. However, you can pass the
|
|
19
|
+
/// `{ strict: true }` argument to the constructor when
|
|
20
|
+
/// defining the type, and in this case it will instead
|
|
21
|
+
/// use JavaScript's [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
|
22
|
+
/// type to store this value client-side.
|
|
23
|
+
///
|
|
24
|
+
/// Example:
|
|
25
|
+
/// class Numbers extends Model {
|
|
26
|
+
/// static fields = {
|
|
27
|
+
/// number1: Types.BIGINT(8, { strict: true }),
|
|
28
|
+
/// number2: new Types.BigIntType(8, { strict: true }),
|
|
29
|
+
/// autoIncrementing: {
|
|
30
|
+
/// type: Types.BIGINT,
|
|
31
|
+
/// defaultValue: Types.BIGINT.Default.AUTO_INCREMENT,
|
|
32
|
+
/// },
|
|
33
|
+
/// };
|
|
34
|
+
/// }
|
|
35
|
+
///
|
|
36
|
+
/// Note:
|
|
37
|
+
/// SQLite currently doesn't support 64bit auto-incrementing
|
|
38
|
+
/// IDs (except on the primary key itself). For this reason,
|
|
39
|
+
/// Mythix ORM supports emulation of BIGINT auto-incrementing
|
|
40
|
+
/// IDs in its [mythix-orm-sqlite](https://www.npmjs.com/package/mythix-orm-sqlite)
|
|
41
|
+
/// driver. You can read more about it in the documentation.
|
|
42
|
+
/// Properties:
|
|
43
|
+
/// Default: object = { AUTO_INCREMENT }
|
|
44
|
+
/// `AUTO_INCREMENT` is a method that can be used as the `defaultValue` of a <see>Field</see>
|
|
45
|
+
/// to have this field auto-increment in the underlying database.
|
|
46
|
+
/// See: Type
|
|
7
47
|
class BigIntType extends Type {
|
|
8
48
|
static Default = {
|
|
9
49
|
AUTO_INCREMENT,
|
|
10
50
|
};
|
|
11
51
|
|
|
52
|
+
/// Get the "display" name for this type.
|
|
53
|
+
///
|
|
54
|
+
/// This method is called from <see>Model.toString</see>
|
|
55
|
+
/// when stringifying the model for representation.
|
|
56
|
+
///
|
|
57
|
+
/// Note:
|
|
58
|
+
/// This is also an instance method that can be called from
|
|
59
|
+
/// an instance of the type.
|
|
60
|
+
/// Return: string
|
|
61
|
+
/// Return the string value `'BIGINT'`
|
|
12
62
|
static getDisplayName() {
|
|
13
63
|
return 'BIGINT';
|
|
14
64
|
}
|
|
@@ -17,6 +67,31 @@ class BigIntType extends Type {
|
|
|
17
67
|
return this.constructor.getDisplayName();
|
|
18
68
|
}
|
|
19
69
|
|
|
70
|
+
/// Construct a new `BIGINT` type.
|
|
71
|
+
///
|
|
72
|
+
/// The `length` argument--as on all
|
|
73
|
+
/// integer types in Mythix ORM--specifies
|
|
74
|
+
/// the number of bytes to use for this type
|
|
75
|
+
/// in the database. Each underlying database
|
|
76
|
+
/// driver will interpret this value in a way that
|
|
77
|
+
/// makes sense to the database.
|
|
78
|
+
///
|
|
79
|
+
/// The "options" argument can be used to specify
|
|
80
|
+
/// if this BIGINT type should be in "strict" mode.
|
|
81
|
+
/// "strict" mode simply means that the client-side
|
|
82
|
+
/// storage for the field's value (in JavaScript)
|
|
83
|
+
/// will actually be a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) type.
|
|
84
|
+
/// By default, the underlying field value is stored
|
|
85
|
+
/// as a `number` primitive.
|
|
86
|
+
///
|
|
87
|
+
/// Return: BigIntType
|
|
88
|
+
/// Arguments:
|
|
89
|
+
/// length?: number = 8
|
|
90
|
+
/// How many bytes to use in the underlying database to store the value.
|
|
91
|
+
/// options?: object
|
|
92
|
+
/// Only possible option is `{ strict: true }`, which will change the
|
|
93
|
+
/// underlying field to use [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
|
94
|
+
/// for value storage.
|
|
20
95
|
constructor(length, _options) {
|
|
21
96
|
let options = _options || {};
|
|
22
97
|
|
|
@@ -34,6 +109,23 @@ class BigIntType extends Type {
|
|
|
34
109
|
});
|
|
35
110
|
}
|
|
36
111
|
|
|
112
|
+
/// Cast provided value to underlying type.
|
|
113
|
+
///
|
|
114
|
+
/// This will cast the incoming value to the
|
|
115
|
+
/// underlying type of this field, either a
|
|
116
|
+
/// `number` primitive, or a `BigInt` if in
|
|
117
|
+
/// "strict" mode. A `null` or `undefined`
|
|
118
|
+
/// value will simply be returned.
|
|
119
|
+
///
|
|
120
|
+
/// See <see>Type.castToType</see> for a more
|
|
121
|
+
/// detailed description.
|
|
122
|
+
///
|
|
123
|
+
/// Return: number | BigInt | null | undefined
|
|
124
|
+
/// Return the incoming `value`, cast to this
|
|
125
|
+
/// type. `null` and `undefined` are simply
|
|
126
|
+
/// returned without casting.
|
|
127
|
+
/// Arguments:
|
|
128
|
+
/// context: <see name="CastToTypeContext">Type.castToType</see>
|
|
37
129
|
castToType({ value }) {
|
|
38
130
|
if (value == null)
|
|
39
131
|
return value;
|
|
@@ -45,10 +137,41 @@ class BigIntType extends Type {
|
|
|
45
137
|
return Number(castValue).valueOf();
|
|
46
138
|
}
|
|
47
139
|
|
|
140
|
+
/// Check if the provided value is valid.
|
|
141
|
+
///
|
|
142
|
+
/// This will check if the provided value is
|
|
143
|
+
/// a `number` or a BigInt instance, and if
|
|
144
|
+
/// it is finite. If both conditions are true,
|
|
145
|
+
/// then it will return `true`.
|
|
146
|
+
///
|
|
147
|
+
/// Return: boolean
|
|
148
|
+
/// Arguments:
|
|
149
|
+
/// value: any
|
|
150
|
+
/// The value to check.
|
|
48
151
|
isValidValue(value) {
|
|
49
152
|
return (Nife.instanceOf(value, 'number', 'bigint') && isFinite(value));
|
|
50
153
|
}
|
|
51
154
|
|
|
155
|
+
/// Stringify the type itself.
|
|
156
|
+
///
|
|
157
|
+
/// If a `connection` argument is provided, then this
|
|
158
|
+
/// will go through the connection to generate the type
|
|
159
|
+
/// for the underlying database. If no connection is
|
|
160
|
+
/// provided, then a "standard" SQL type will be returned
|
|
161
|
+
/// for this type instead. The "standard" type returned
|
|
162
|
+
/// when no `connection` is provided is `'BIGINT'` or
|
|
163
|
+
/// `'BIGINT(${this.length})'` if a `length` is provided to
|
|
164
|
+
/// the type.
|
|
165
|
+
///
|
|
166
|
+
/// Return: string
|
|
167
|
+
/// Arguments:
|
|
168
|
+
/// connection?: <see>Connection</see>
|
|
169
|
+
/// An optional connection. If provided, send this
|
|
170
|
+
/// type through <see>Type.toConnectionType</see>
|
|
171
|
+
/// to have the connection itself generate the underlying
|
|
172
|
+
/// type for the database. If `connection` is not provided,
|
|
173
|
+
/// then this will simply return a "standard" generic matching
|
|
174
|
+
/// SQL type.
|
|
52
175
|
toString(connection) {
|
|
53
176
|
return (connection)
|
|
54
177
|
? this.toConnectionType(connection)
|