mythix-orm 1.11.6 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -9
- package/lib/connection/connection-base.js +173 -39
- package/lib/connection/literals/average-literal.js +67 -0
- package/lib/connection/literals/count-literal.js +80 -0
- package/lib/connection/literals/distinct-literal.js +71 -0
- package/lib/connection/literals/field-literal.js +54 -0
- package/lib/connection/literals/literal-base.d.ts +1 -0
- package/lib/connection/literals/literal-base.js +137 -2
- package/lib/connection/literals/literal-field-base.js +50 -0
- package/lib/connection/literals/literal.js +15 -0
- package/lib/connection/literals/max-literal.js +67 -0
- package/lib/connection/literals/min-literal.js +67 -0
- package/lib/connection/literals/sum-literal.js +67 -0
- package/lib/connection/query-generator-base.js +273 -0
- package/lib/field.js +1 -1
- package/lib/model.js +54 -2
- package/lib/proxy-class/proxy-class.js +156 -21
- package/lib/query-engine/field-scope.js +401 -9
- package/lib/query-engine/model-scope.js +572 -13
- package/lib/query-engine/query-engine-base.js +590 -30
- package/lib/query-engine/query-engine.d.ts +13 -2
- package/lib/query-engine/query-engine.js +525 -18
- package/lib/types/helpers/default-helpers.js +124 -0
- package/lib/types/type.js +297 -3
- package/lib/utils/async-store.js +80 -3
- package/package.json +1 -2
|
@@ -1,3 +1,60 @@
|
|
|
1
|
+
///! Import `const { Types: { Helpers } } = require('mythix-orm');`
|
|
2
|
+
///!
|
|
3
|
+
///! Helpers are a set of utilities used to assist with
|
|
4
|
+
///! `defaultValue` attributes on model fields.
|
|
5
|
+
///!
|
|
6
|
+
///! Default values for fields in Mythix ORM are generally used in
|
|
7
|
+
///! two different places: As column values directly, or as `DEFAULT VALUE`
|
|
8
|
+
///! for columns when defining tables in the database. When creating tables
|
|
9
|
+
///! the `defaultValue` of a field will generally only ever be used if it
|
|
10
|
+
///! has the `remote` flag set. Otherwise, Mythix ORM simply provides the
|
|
11
|
+
///! `defaultValue` to the database directly during `INSERT` and `UPDATE`
|
|
12
|
+
///! operations.
|
|
13
|
+
///!
|
|
14
|
+
///! ```javascript
|
|
15
|
+
///! const { Model, Types } = require('mythix-orm');
|
|
16
|
+
///!
|
|
17
|
+
///! class TestModel extends Model {
|
|
18
|
+
///! static fields = {
|
|
19
|
+
///! myCustomDate: {
|
|
20
|
+
///! type: Types.STRING(32),
|
|
21
|
+
///! // Inform Mythix ORM that our `defaultValue` should be
|
|
22
|
+
///! // applied on every `UPDATE` operation... even if the
|
|
23
|
+
///! // field already has a value.
|
|
24
|
+
///! defaultValue: Types.Helpers.defaultValueFlags(() => {
|
|
25
|
+
///! return (new Date()).toISOString();
|
|
26
|
+
///! }, { onUpdate: true }),
|
|
27
|
+
///! allowNull: false,
|
|
28
|
+
///! index: true,
|
|
29
|
+
///! }
|
|
30
|
+
///! };
|
|
31
|
+
///! }
|
|
32
|
+
///! ```
|
|
33
|
+
///!
|
|
34
|
+
///! Properties:
|
|
35
|
+
///! FLAG_ON_INITIALIZE: number = 0x01
|
|
36
|
+
///! This flag informs Mythix ORM that the `defaultValue` should
|
|
37
|
+
///! be fetched and used as soon as a model instance is first
|
|
38
|
+
///! initialized.
|
|
39
|
+
///! FLAG_ON_INSERT: number = 0x02
|
|
40
|
+
///! This flag informs Mythix ORM that the `defaultValue` should
|
|
41
|
+
///! only be used on `INSERT` operations.
|
|
42
|
+
///! FLAG_ON_UPDATE: number = 0x04
|
|
43
|
+
///! This flag informs Mythix ORM that the `defaultValue` should
|
|
44
|
+
///! only be used on `UPDATE` operations. This is used for example
|
|
45
|
+
///! by `Types.DATE.Defaults.NOW.UPDATE`.
|
|
46
|
+
///! FLAG_ON_STORE: number = 0x06
|
|
47
|
+
///! This flag informs Mythix ORM that the `defaultValue` should
|
|
48
|
+
///! only be used on `INSERT` and `UPDATE` operations.
|
|
49
|
+
///! FLAG_LITERAL: number = 0x08
|
|
50
|
+
///! This flag informs Mythix ORM that the `defaultValue` is intended
|
|
51
|
+
///! to be a literal value, and should not be escaped.
|
|
52
|
+
///! FLAG_REMOTE: number = 0x10
|
|
53
|
+
///! This flag informs Mythix ORM that the `defaultValue` is provided
|
|
54
|
+
///! by the database itself. For example the `Types.BIGINT.Defaults.AUTO_INCREMENT`
|
|
55
|
+
///! type uses this flag.
|
|
56
|
+
///!
|
|
57
|
+
///! DocScope: Helpers
|
|
1
58
|
'use strict';
|
|
2
59
|
|
|
3
60
|
const FLAG_ON_INITIALIZE = 0x01;
|
|
@@ -7,6 +64,46 @@ const FLAG_ON_STORE = FLAG_ON_INSERT | FLAG_ON_UPDATE;
|
|
|
7
64
|
const FLAG_LITERAL = 0x08;
|
|
8
65
|
const FLAG_REMOTE = 0x10;
|
|
9
66
|
|
|
67
|
+
/// Give a `defaultValue` method certain flags to
|
|
68
|
+
/// assist Mythix ORM in working with a field's
|
|
69
|
+
/// `defaultValue`.
|
|
70
|
+
///
|
|
71
|
+
/// `defaultValue` flags change the way a `defaultValue`
|
|
72
|
+
/// for a field behaves. For example, if the `FLAG_LITERAL`
|
|
73
|
+
/// is set, then the database will not escape the default value.
|
|
74
|
+
///
|
|
75
|
+
/// By default, all `defaultValue` attributes on fields (that
|
|
76
|
+
/// are methods) have the flags `FLAG_ON_INITIALIZE`, which
|
|
77
|
+
/// simply tells Mythix ORM to call the `defaultValue` method
|
|
78
|
+
/// and assign the result to the field as soon as the model is
|
|
79
|
+
/// instantiated. This is the default behavior of all `defaultValue`
|
|
80
|
+
/// attributes... unless the defined flags change that default
|
|
81
|
+
/// behavior. As soon as any flag is set on a `defaultValue` method,
|
|
82
|
+
/// the `FLAG_ON_INITIALIZE` value will be cleared.
|
|
83
|
+
///
|
|
84
|
+
/// This adds an attribute named `mythixFlags` to
|
|
85
|
+
/// the provided method. This attribute is then
|
|
86
|
+
/// used by Mythix ORM to know what to do with the
|
|
87
|
+
/// `defaultValue` method provided on a field.
|
|
88
|
+
///
|
|
89
|
+
/// Arguments:
|
|
90
|
+
/// func: Function
|
|
91
|
+
/// The `defaultValue` function to apply flags to.
|
|
92
|
+
/// flags: object
|
|
93
|
+
/// An object, specifying which flags to enable
|
|
94
|
+
/// or disable. The allowed properties are listed in
|
|
95
|
+
/// the table below.
|
|
96
|
+
/// | Option | Type | Default Value | Description |
|
|
97
|
+
/// | ------------- | ---- | ------------- | ----------- |
|
|
98
|
+
/// | `onInitialize` | `boolean` | `true` | If `true`, then assign the `defaultValue` as soon as a model is instantiated. |
|
|
99
|
+
/// | `onInsert` | `boolean` | `false` | If `true`, then only assign the `defaultValue` when an `INSERT` operation is being executed. |
|
|
100
|
+
/// | `onUpdate` | `boolean` | `false` | If `true`, then only assign the `defaultValue` when an `UPDATE` operation is being executed. |
|
|
101
|
+
/// | `onStore` | `boolean` | `false` | If `true`, then only assign the `defaultValue` when an `INSERT` or `UPDATE` operation is being executed. |
|
|
102
|
+
/// | `literal` | `boolean` | `false` | If `true`, then inform Mythix ORM that the value is a literal, and not to escape it. |
|
|
103
|
+
/// | `remote` | `boolean` | `false` | If `true`, then inform Mythix ORM that the value is provided by the database itself. |
|
|
104
|
+
///
|
|
105
|
+
/// Return: Function
|
|
106
|
+
/// The method provided, with a new `mythixFlags` assigned to it.
|
|
10
107
|
function defaultValueFlags(func, _flagsObj) {
|
|
11
108
|
let flags = FLAG_ON_INITIALIZE;
|
|
12
109
|
let flagsObj = _flagsObj || {};
|
|
@@ -36,6 +133,15 @@ function defaultValueFlags(func, _flagsObj) {
|
|
|
36
133
|
return func;
|
|
37
134
|
}
|
|
38
135
|
|
|
136
|
+
/// Fetch the `mythixFlags` attribute on the provided
|
|
137
|
+
/// function. If none is found, or no method is provided,
|
|
138
|
+
/// then the value `0` will be returned instead.
|
|
139
|
+
///
|
|
140
|
+
/// Return: number
|
|
141
|
+
/// The `defaultValue` flags as a bitmask. If none is found, or no
|
|
142
|
+
/// method is provided, then `0` will be returned instead.
|
|
143
|
+
///
|
|
144
|
+
/// See: Helpers.defaultValueFlags
|
|
39
145
|
function getDefaultValueFlags(func) {
|
|
40
146
|
if (!func)
|
|
41
147
|
return 0;
|
|
@@ -43,6 +149,24 @@ function getDefaultValueFlags(func) {
|
|
|
43
149
|
return func.mythixFlags || 0;
|
|
44
150
|
}
|
|
45
151
|
|
|
152
|
+
/// Check if the provided `defaultValue` method has
|
|
153
|
+
/// specific flags set. The flags are provided via
|
|
154
|
+
/// their name.
|
|
155
|
+
///
|
|
156
|
+
/// Arguments:
|
|
157
|
+
/// func: Function
|
|
158
|
+
/// The `defaultValue` function to check.
|
|
159
|
+
/// checkFlags: Array<string>
|
|
160
|
+
/// The flags to check. Acceptable values are:
|
|
161
|
+
/// `[ 'onInitialize', 'onInsert', 'onUpdate', 'onStore', 'literal', 'remote' ]`
|
|
162
|
+
///
|
|
163
|
+
/// Return: boolean
|
|
164
|
+
/// Return `true` if all provided `checkFlags` are `true`. If any
|
|
165
|
+
/// provided flag results in `false`, then the method will return
|
|
166
|
+
/// `false`. In short, all provided flags must be `true`, otherwise
|
|
167
|
+
/// `false` is returned.
|
|
168
|
+
///
|
|
169
|
+
/// See: Helpers.defaultValueFlags
|
|
46
170
|
function checkDefaultValueFlags(func, checkFlags) {
|
|
47
171
|
if (!checkFlags || !checkFlags.length || !func)
|
|
48
172
|
return false;
|
package/lib/types/type.js
CHANGED
|
@@ -8,6 +8,20 @@ class Type {
|
|
|
8
8
|
return '<UNKNOWN>';
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/// Get the "display name" for this type instance.
|
|
12
|
+
///
|
|
13
|
+
/// This will return a "human friendly" name for the type,
|
|
14
|
+
/// generally used for logging or debugging. It will change
|
|
15
|
+
/// based on the type it is called upon. For example, a
|
|
16
|
+
/// <see>BooleanType</see> will return the string value `'BOOLEAN'`.
|
|
17
|
+
///
|
|
18
|
+
/// Note:
|
|
19
|
+
/// This method is also a static method on the type class.
|
|
20
|
+
///
|
|
21
|
+
/// Return: string
|
|
22
|
+
/// A string representing the type. This is not the same as
|
|
23
|
+
/// the database equivalent type. Rather, it is simply used
|
|
24
|
+
/// to represent the type for logging or debugging.
|
|
11
25
|
getDisplayName() {
|
|
12
26
|
return this.constructor.getDisplayName();
|
|
13
27
|
}
|
|
@@ -18,6 +32,18 @@ class Type {
|
|
|
18
32
|
return this;
|
|
19
33
|
};
|
|
20
34
|
|
|
35
|
+
/// Use this method to check if a class
|
|
36
|
+
/// is a Mythix ORM field type. It will return
|
|
37
|
+
/// `true` if the provided value is a class
|
|
38
|
+
/// that inherits from <see>Type</see>, or
|
|
39
|
+
/// if the provided value has an attribute
|
|
40
|
+
/// named `_isMythixFieldType` that is truthy.
|
|
41
|
+
///
|
|
42
|
+
/// Return: boolean
|
|
43
|
+
///
|
|
44
|
+
/// Arguments:
|
|
45
|
+
/// value: Function
|
|
46
|
+
/// Value to check.
|
|
21
47
|
static isTypeClass(value) {
|
|
22
48
|
if (!value)
|
|
23
49
|
return false;
|
|
@@ -31,6 +57,22 @@ class Type {
|
|
|
31
57
|
return false;
|
|
32
58
|
}
|
|
33
59
|
|
|
60
|
+
/// Check to see if the provided value is
|
|
61
|
+
/// an *instance* of a Mythix ORM <see>Type</see>.
|
|
62
|
+
/// Unlike <see>Type.static isTypeClass</see>, which
|
|
63
|
+
/// checks if a *class* is a <see>Type</see>, this will check
|
|
64
|
+
/// to see if an *instance* is an instance of a
|
|
65
|
+
/// Mythix ORM <see>Type</see>. It will return
|
|
66
|
+
/// `true` if the provided value is an `instanceof`
|
|
67
|
+
/// <see>Type</see>, or if the value's `constructor`
|
|
68
|
+
/// property has a truthy `_isMythixFieldType` property
|
|
69
|
+
/// (`value.constructor._isMythixFieldType`)
|
|
70
|
+
///
|
|
71
|
+
/// Return: boolean
|
|
72
|
+
///
|
|
73
|
+
/// Arguments:
|
|
74
|
+
/// value: any
|
|
75
|
+
/// Value to check
|
|
34
76
|
static isType(value) {
|
|
35
77
|
if (!value)
|
|
36
78
|
return false;
|
|
@@ -44,10 +86,42 @@ class Type {
|
|
|
44
86
|
return false;
|
|
45
87
|
}
|
|
46
88
|
|
|
89
|
+
/// Check to see if the provided type is the same as this type.
|
|
90
|
+
///
|
|
91
|
+
/// This checks if the two types are the same type by comparing
|
|
92
|
+
/// the type names. For example, a `Types.BooleanType.isSameType(new BooleanType())`
|
|
93
|
+
/// would return `true`.
|
|
94
|
+
///
|
|
95
|
+
/// Arguments:
|
|
96
|
+
/// value: <see>Type</see>
|
|
97
|
+
/// A type instance to check. This must be a type instance, not a type class.
|
|
98
|
+
///
|
|
99
|
+
/// Return: boolean
|
|
100
|
+
/// Return `true` if the provided `value` is the same type instance as this type class.
|
|
101
|
+
/// Return `false` otherwise. Similarity is based on the name of the types. If the class
|
|
102
|
+
/// names between the two match, then the types are considered the same type.
|
|
47
103
|
static isSameType(value) {
|
|
48
104
|
return (this.isType(value) && value.constructor && value.constructor.name === this.name);
|
|
49
105
|
}
|
|
50
106
|
|
|
107
|
+
/// Instantiate this field type.
|
|
108
|
+
///
|
|
109
|
+
/// This method will instantiate the type class it
|
|
110
|
+
/// is called from. It won't instantiate the type if
|
|
111
|
+
/// it is already instantiated, and it will call the
|
|
112
|
+
/// type wrapper if one was provided (see <see>Type.static wrapConstructor</see>).
|
|
113
|
+
/// It may not need to instantiate the type if the user already
|
|
114
|
+
/// did so (for example `type: new Types.StringType()`,
|
|
115
|
+
/// or `type: Types.STRING()`). It may need to instantiate
|
|
116
|
+
/// however if the user didn't do so, for example `type: Types.StringType`,
|
|
117
|
+
/// or `type: Types.STRING`.
|
|
118
|
+
///
|
|
119
|
+
/// Note:
|
|
120
|
+
/// If the type is already instantiated, then it will be
|
|
121
|
+
/// cloned instead using <see>Type.clone</see>.
|
|
122
|
+
///
|
|
123
|
+
/// Return: <see>Type</see>
|
|
124
|
+
/// The instantiated type instance.
|
|
51
125
|
static instantiateType(_type) {
|
|
52
126
|
let type = _type;
|
|
53
127
|
if (!type)
|
|
@@ -77,6 +151,28 @@ class Type {
|
|
|
77
151
|
return true;
|
|
78
152
|
}
|
|
79
153
|
|
|
154
|
+
/// This method is used to create the "shortcut" types
|
|
155
|
+
/// for Mythix ORM. For example, a "string" type can be
|
|
156
|
+
/// created either via `new Types.StringType()`, or via `Types.STRING()`.
|
|
157
|
+
/// Both are equivalent. `Types.STRING` was created by calling
|
|
158
|
+
/// `Types.STRING = Type.wrapConstructor(Types.StringType)`.
|
|
159
|
+
///
|
|
160
|
+
/// This method "wraps" a type constructor, providing a more
|
|
161
|
+
/// convenient way to create and use field types. It works
|
|
162
|
+
/// by wrapping the provided class's constructor in a callable
|
|
163
|
+
/// method. If the method **is not** called (i.e. `type: Types.STRING`)
|
|
164
|
+
/// then the type system still knows what to do, because the wrapping
|
|
165
|
+
/// method will be called by Mythix ORM to instantiate the type
|
|
166
|
+
/// when the model's fields are first fetched.
|
|
167
|
+
///
|
|
168
|
+
/// Arguments:
|
|
169
|
+
/// TypeKlass: class <see>Type</see>
|
|
170
|
+
/// A `Type` class to wrap.
|
|
171
|
+
///
|
|
172
|
+
/// Return: Function
|
|
173
|
+
/// A callable function to instantiate the type class. If not called
|
|
174
|
+
/// by the user, then Mythix ORM will call the method when the type
|
|
175
|
+
/// is being created to fetch the type instance.
|
|
80
176
|
static wrapConstructor(TypeKlass) {
|
|
81
177
|
let TypeWrapper = function(...args) {
|
|
82
178
|
return new TypeKlass(...args);
|
|
@@ -116,6 +212,15 @@ class Type {
|
|
|
116
212
|
return TypeWrapper;
|
|
117
213
|
}
|
|
118
214
|
|
|
215
|
+
/// Instantiate a new field Type.
|
|
216
|
+
///
|
|
217
|
+
/// Arguments:
|
|
218
|
+
/// ...args: Array<any>
|
|
219
|
+
/// All field types "record" their constructor arguments, always.
|
|
220
|
+
/// Mythix ORM requires that all field types, when calling `super` in
|
|
221
|
+
/// their constructor, provide the base `Type` class all arguments
|
|
222
|
+
/// provided to their constructor.
|
|
223
|
+
/// This is so that the field type can later be cloned or serialized.
|
|
119
224
|
constructor(...args) {
|
|
120
225
|
Object.defineProperties(this, {
|
|
121
226
|
'_args': {
|
|
@@ -139,6 +244,10 @@ class Type {
|
|
|
139
244
|
});
|
|
140
245
|
}
|
|
141
246
|
|
|
247
|
+
/// Clone this field type.
|
|
248
|
+
///
|
|
249
|
+
/// Return: Type
|
|
250
|
+
/// This field type, cloned to a new instance.
|
|
142
251
|
clone() {
|
|
143
252
|
let Type = this.constructor;
|
|
144
253
|
let newInstance = new Type(...this._args);
|
|
@@ -149,22 +258,86 @@ class Type {
|
|
|
149
258
|
return newInstance;
|
|
150
259
|
}
|
|
151
260
|
|
|
261
|
+
/// Check if this field type is a virtual field type.
|
|
262
|
+
///
|
|
263
|
+
/// Note:
|
|
264
|
+
/// This method is also a static method on the type class.
|
|
265
|
+
///
|
|
266
|
+
/// Return: boolean
|
|
267
|
+
/// Return `true` if this field type is a virtual field
|
|
268
|
+
/// type. Virtual fields are fields that don't *directly*
|
|
269
|
+
/// store a concrete value themselves. They often pull
|
|
270
|
+
/// and combine values from other fields, or other models.
|
|
271
|
+
/// Currently the only virtual fields in Mythix ORM are
|
|
272
|
+
/// <see>ModelType</see> and <see>ModelsType</see>.
|
|
152
273
|
isVirtual() {
|
|
153
274
|
return this.constructor.isVirtual.call(this.constructor);
|
|
154
275
|
}
|
|
155
276
|
|
|
277
|
+
/// Check if this field type is a relational field type.
|
|
278
|
+
///
|
|
279
|
+
/// Note:
|
|
280
|
+
/// This method is also a static method on the type class.
|
|
281
|
+
///
|
|
282
|
+
/// Return: boolean
|
|
283
|
+
/// Return `true` if this field type defines a relation,
|
|
284
|
+
/// instead of a direct value. Field types such as
|
|
285
|
+
/// <see>ModelType</see> and <see>ModelsType</see> are
|
|
286
|
+
/// examples of relational field types. <see>ForeignKeyType</see>
|
|
287
|
+
/// **is not** a relational type, but is instead considered
|
|
288
|
+
/// a "concrete" type. Even though it does technically define
|
|
289
|
+
/// a relationship, it is also a direct field, that actually
|
|
290
|
+
/// has a concrete value, backed by database storage.
|
|
156
291
|
isRelational() {
|
|
157
292
|
return this.constructor.isRelational.call(this.constructor);
|
|
158
293
|
}
|
|
159
294
|
|
|
295
|
+
/// Check if this field type is a foreign key type.
|
|
296
|
+
///
|
|
297
|
+
/// Note:
|
|
298
|
+
/// This method is also a static method on the type class.
|
|
299
|
+
///
|
|
300
|
+
/// Return: boolean
|
|
301
|
+
/// Return `true` if this field type defines a foreign key,
|
|
302
|
+
/// or `false` otherwise.
|
|
160
303
|
isForeignKey() {
|
|
161
304
|
return this.constructor.isForeignKey.call(this.constructor);
|
|
162
305
|
}
|
|
163
306
|
|
|
307
|
+
/// Used to decide if a field should be exposed on the model
|
|
308
|
+
/// or not.
|
|
309
|
+
///
|
|
310
|
+
/// Some fields, such as types like <see>ModelType</see> and
|
|
311
|
+
/// <see>ModelsType</see> do not expose themselves on the model
|
|
312
|
+
/// as model fields. Instead they only expose themselves via the
|
|
313
|
+
/// relationship methods they inject onto the model instance.
|
|
314
|
+
/// Most fields **do** expose themselves on the model, but any
|
|
315
|
+
/// field that overrides this method and returns `false` will
|
|
316
|
+
/// not be exposed on the model instance.
|
|
317
|
+
///
|
|
318
|
+
/// Note:
|
|
319
|
+
/// This method is also a static method on the type class.
|
|
320
|
+
///
|
|
321
|
+
/// Return: boolean
|
|
322
|
+
/// If `true` is returned, then the field owning this type
|
|
323
|
+
/// will be added to the model instance, and accessible by
|
|
324
|
+
/// the user. If `false` is returned, then the field will
|
|
325
|
+
/// be "hidden", and not exposed to the user on model instances.
|
|
164
326
|
exposeToModel() {
|
|
165
327
|
return this.constructor.exposeToModel.call(this.constructor);
|
|
166
328
|
}
|
|
167
329
|
|
|
330
|
+
/// Check if this field's value is driven by the database.
|
|
331
|
+
///
|
|
332
|
+
/// For example, given an AUTOINCREMENTING id field, this
|
|
333
|
+
/// would return `true`, because the value of the field is
|
|
334
|
+
/// provided by the database itself. This can be true for
|
|
335
|
+
/// nearly any field type, but is generally only true for
|
|
336
|
+
/// auto-incrementing ids, and date/time types.
|
|
337
|
+
///
|
|
338
|
+
/// Return: boolean
|
|
339
|
+
/// Return `true` for any field type that has a value provided
|
|
340
|
+
/// directly by the underlying database, or `false` otherwise.
|
|
168
341
|
isRemote() {
|
|
169
342
|
let field = this.getField();
|
|
170
343
|
if (!field)
|
|
@@ -176,19 +349,41 @@ class Type {
|
|
|
176
349
|
return checkDefaultValueFlags(field.defaultValue, [ 'remote' ]);
|
|
177
350
|
}
|
|
178
351
|
|
|
352
|
+
/// Check if the value provided is a valid value for this field type.
|
|
353
|
+
///
|
|
354
|
+
/// This is used to check if any value *would* be a valid value for
|
|
355
|
+
/// this type. For example, if this type happens to be a <see>BooleanType</see>,
|
|
356
|
+
/// then `isValidValue` would only return `true` if the provided `value`
|
|
357
|
+
/// was either `true` or `false`. All field types have their own custom
|
|
358
|
+
/// `isValidValue` implementation, to verify values against their type.
|
|
359
|
+
///
|
|
360
|
+
/// Arguments:
|
|
361
|
+
/// value: any
|
|
362
|
+
/// Any value to check.
|
|
363
|
+
///
|
|
364
|
+
/// Return: boolean
|
|
365
|
+
/// Return `true` if the provided `value` is a valid value for the field
|
|
366
|
+
/// type this was called upon, or `false` otherwise.
|
|
179
367
|
// eslint-disable-next-line no-unused-vars
|
|
180
368
|
isValidValue(value) {
|
|
181
369
|
return true;
|
|
182
370
|
}
|
|
183
371
|
|
|
372
|
+
/// Get the field that owns this type.
|
|
184
373
|
getField() {
|
|
185
374
|
return this._field;
|
|
186
375
|
}
|
|
187
376
|
|
|
377
|
+
/// Set the field that owns this type.
|
|
378
|
+
///
|
|
379
|
+
/// Arguments:
|
|
380
|
+
/// field: <see>Field</see>
|
|
381
|
+
/// The field that owns this type.
|
|
188
382
|
setField(field) {
|
|
189
383
|
this._field = field;
|
|
190
384
|
}
|
|
191
385
|
|
|
386
|
+
/// Get the model class that owns this field type.
|
|
192
387
|
getModel() {
|
|
193
388
|
let Model = this._Model;
|
|
194
389
|
if (!Model) {
|
|
@@ -206,6 +401,11 @@ class Type {
|
|
|
206
401
|
return Model;
|
|
207
402
|
}
|
|
208
403
|
|
|
404
|
+
/// Set the model class that this type belongs to.
|
|
405
|
+
///
|
|
406
|
+
/// Arguments:
|
|
407
|
+
/// Model: class <see>Model</see>
|
|
408
|
+
/// The model class that owns this field type.
|
|
209
409
|
setModel(Model) {
|
|
210
410
|
this._Model = Model;
|
|
211
411
|
}
|
|
@@ -258,17 +458,111 @@ class Type {
|
|
|
258
458
|
initialize(connection, self) {
|
|
259
459
|
}
|
|
260
460
|
|
|
261
|
-
|
|
461
|
+
/// Check if the field value is dirty.
|
|
462
|
+
///
|
|
463
|
+
/// This is only used by some field types, such as <see>SerializedType</see>.
|
|
464
|
+
/// It will respond with `true` if the field is dirty, or `false` if it isn't.
|
|
465
|
+
///
|
|
466
|
+
/// Interface:
|
|
467
|
+
/// interface CheckDirtyContext {
|
|
468
|
+
/// value: any; // The field's current value
|
|
469
|
+
/// field: Field; // The field that is being checked
|
|
470
|
+
/// fieldName: string; // The fieldName of the field that is being checked
|
|
471
|
+
/// self: Model; // The model instance the field is from
|
|
472
|
+
/// connection: ConnectionBase; // The current connection
|
|
473
|
+
/// }
|
|
474
|
+
///
|
|
475
|
+
/// Arguments:
|
|
476
|
+
/// context: CheckDirtyContext
|
|
477
|
+
/// The context provided to the call.
|
|
478
|
+
///
|
|
479
|
+
/// Return: boolean
|
|
480
|
+
/// Returns `true` if the field is dirty, or `false` otherwise.
|
|
481
|
+
// eslint-disable-next-line no-unused-vars
|
|
482
|
+
isDirty(context) {
|
|
262
483
|
}
|
|
263
484
|
|
|
485
|
+
/// This method is called any time a field's value is set on a model.
|
|
486
|
+
///
|
|
487
|
+
/// It is only used by the <see>SerializedType</see> to update its internal
|
|
488
|
+
/// "dirty" cache. It can be used by any field type however to detect when
|
|
489
|
+
/// a model's field's value changes.
|
|
490
|
+
///
|
|
491
|
+
/// Interface:
|
|
492
|
+
/// interface SetFieldValueContext {
|
|
493
|
+
/// value: any;
|
|
494
|
+
/// field: Field;
|
|
495
|
+
/// fieldName: string;
|
|
496
|
+
/// self: Model;
|
|
497
|
+
/// }
|
|
498
|
+
///
|
|
499
|
+
/// Arguments:
|
|
500
|
+
/// context: SetFieldValueContext
|
|
501
|
+
/// The context provided to the call.
|
|
502
|
+
///
|
|
503
|
+
/// Return: undefined
|
|
504
|
+
/// This method returns nothing.
|
|
264
505
|
onSetFieldValue() {
|
|
265
506
|
}
|
|
266
507
|
|
|
267
|
-
|
|
508
|
+
/// Serialize the field's value. This is the opposite of
|
|
509
|
+
/// <see>Type.deserialize</see>.
|
|
510
|
+
///
|
|
511
|
+
/// This is used mostly by the <see>Model.toJSON</see> method
|
|
512
|
+
/// to serialize values for JSON format. However, it is also used
|
|
513
|
+
/// in some other cases, such as formatting for <see>DateType</see>
|
|
514
|
+
/// and <see>DateTimeType</see>, and for checking dirtiness in the
|
|
515
|
+
/// <see>SerializedType</see>.
|
|
516
|
+
///
|
|
517
|
+
/// The job of this method is to serialize the field's value for any serialize operation,
|
|
518
|
+
/// generally to JSON. If a `connection` is provided as the second argument,
|
|
519
|
+
/// then it is assumed by the field type that it is being serialized for the
|
|
520
|
+
/// database. In this case the connection generally assists with the serializing
|
|
521
|
+
/// of the value. This is used for example with <see>DateType</see>
|
|
522
|
+
/// and <see>DateTimeType</see> types, when they need to be serialized to or from
|
|
523
|
+
/// a database operation.
|
|
524
|
+
///
|
|
525
|
+
/// Arguments:
|
|
526
|
+
/// value: any
|
|
527
|
+
/// The field's value to serialize.
|
|
528
|
+
/// connection?: <see>Connection</see>
|
|
529
|
+
/// An optional connection, which if provided will likely change
|
|
530
|
+
/// how the value is serialized.
|
|
531
|
+
///
|
|
532
|
+
/// Return: any | string
|
|
533
|
+
/// Though the return value will generally be a string, it isn't required
|
|
534
|
+
/// to be.
|
|
535
|
+
///
|
|
536
|
+
/// See: Type.deserialize
|
|
537
|
+
// eslint-disable-next-line no-unused-vars
|
|
538
|
+
serialize(value, connection) {
|
|
268
539
|
return value;
|
|
269
540
|
}
|
|
270
541
|
|
|
271
|
-
|
|
542
|
+
/// Deserialize the field's value. This is the opposite of
|
|
543
|
+
/// <see>Type.serialize</see>.
|
|
544
|
+
///
|
|
545
|
+
/// The job of this method to serialize the field's value for any serialize operation,
|
|
546
|
+
/// generally to JSON. If a `connection` is provided as the second argument,
|
|
547
|
+
/// then it is assumed by the field type that it is being serialized for the
|
|
548
|
+
/// database. In this case the connection generally assists with the serializing
|
|
549
|
+
/// of the value. This is used for example with <see>DateType</see>
|
|
550
|
+
/// and <see>DateTimeType</see> types, when they need to be serialized to or from
|
|
551
|
+
/// a database operation.
|
|
552
|
+
///
|
|
553
|
+
/// Arguments:
|
|
554
|
+
/// value: any
|
|
555
|
+
/// The field's value to deserialize.
|
|
556
|
+
/// connection?: <see>Connection</see>
|
|
557
|
+
/// An optional connection, which if provided will likely change
|
|
558
|
+
/// how the value is deserialized.
|
|
559
|
+
///
|
|
560
|
+
/// Return: any
|
|
561
|
+
/// The deserialized value for the field.
|
|
562
|
+
///
|
|
563
|
+
/// See: Type.serialize
|
|
564
|
+
// eslint-disable-next-line no-unused-vars
|
|
565
|
+
deserialize(value, connection) {
|
|
272
566
|
return value;
|
|
273
567
|
}
|
|
274
568
|
|
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
|
);
|