mythix-orm 1.4.6 → 1.5.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/docs/Associations.md +2 -2
- package/docs/Certifications.md +22 -0
- package/docs/Home.md +25 -22
- package/lib/connection/connection-base.js +92 -3
- package/lib/connection/query-generator-base.js +5 -3
- package/lib/model.js +1515 -35
- package/lib/query-engine/query-engine.js +24 -6
- package/lib/types/concrete/date-type.js +4 -3
- package/lib/types/concrete/datetime-type.js +4 -3
- package/lib/types/concrete/index.js +9 -3
- package/lib/types/concrete/{float-type.js → numeric-type.js} +12 -9
- package/lib/types/concrete/real-type.js +47 -0
- package/lib/types/concrete/serialized-type.js +134 -0
- package/lib/types/index.js +12 -4
- package/lib/types/type.js +6 -0
- package/lib/utils/model-utils.js +39 -19
- package/lib/utils/query-utils.js +4 -4
- package/package.json +1 -1
|
@@ -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({
|
|
@@ -26,11 +26,11 @@ class DateType extends Type {
|
|
|
26
26
|
this.format = format || 'YYYY-MM-DD';
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
castToType({ value }) {
|
|
29
|
+
castToType({ value, connection }) {
|
|
30
30
|
if (value == null)
|
|
31
31
|
return value;
|
|
32
32
|
|
|
33
|
-
let dateTime = this.deserialize(value);
|
|
33
|
+
let dateTime = this.deserialize(value, connection);
|
|
34
34
|
if (!dateTime.isValid())
|
|
35
35
|
throw new TypeError(`DateType::castToType: Value provided ("${value}") can not be cast into a date.`);
|
|
36
36
|
|
|
@@ -60,7 +60,8 @@ class DateType extends Type {
|
|
|
60
60
|
return value.toISOString();
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
// eslint-disable-next-line no-unused-vars
|
|
64
|
+
deserialize(_value, connection) {
|
|
64
65
|
let value = _value;
|
|
65
66
|
if (value == null)
|
|
66
67
|
return value;
|
|
@@ -27,11 +27,11 @@ class DateTimeType extends Type {
|
|
|
27
27
|
this.format = format;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
castToType({ value }) {
|
|
30
|
+
castToType({ value, connection }) {
|
|
31
31
|
if (value == null)
|
|
32
32
|
return value;
|
|
33
33
|
|
|
34
|
-
let dateTime = this.deserialize(value);
|
|
34
|
+
let dateTime = this.deserialize(value, connection);
|
|
35
35
|
if (!dateTime.isValid())
|
|
36
36
|
throw new TypeError(`DateTimeType::castToType: Value provided ("${value}") can not be cast into a date.`);
|
|
37
37
|
|
|
@@ -65,7 +65,8 @@ class DateTimeType extends Type {
|
|
|
65
65
|
return value.toISOString();
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
// eslint-disable-next-line no-unused-vars
|
|
69
|
+
deserialize(_value, connection) {
|
|
69
70
|
let value = _value;
|
|
70
71
|
if (value == null)
|
|
71
72
|
return value;
|
|
@@ -6,9 +6,11 @@ const { BOOLEAN, BooleanType } = require('./boolean-type');
|
|
|
6
6
|
const { CHAR, CharType } = require('./char-type');
|
|
7
7
|
const { DATE, DateType } = require('./date-type');
|
|
8
8
|
const { DATETIME, DateTimeType } = require('./datetime-type');
|
|
9
|
-
const { FLOAT, FloatType } = require('./float-type');
|
|
10
9
|
const { FOREIGN_KEY, ForeignKeyType } = require('./foreign-key-type');
|
|
11
10
|
const { INTEGER, IntegerType } = require('./integer-type');
|
|
11
|
+
const { NUMERIC, NumericType } = require('./numeric-type');
|
|
12
|
+
const { REAL, RealType } = require('./real-type');
|
|
13
|
+
const { SERIALIZED, SerializedType } = require('./serialized-type');
|
|
12
14
|
const { STRING, StringType } = require('./string-type');
|
|
13
15
|
const { TEXT, TextType } = require('./text-type');
|
|
14
16
|
const { UUIDV1, UUIDV1Type } = require('./uuid-v1-type');
|
|
@@ -24,9 +26,11 @@ module.exports = {
|
|
|
24
26
|
CharType,
|
|
25
27
|
DateTimeType,
|
|
26
28
|
DateType,
|
|
27
|
-
|
|
29
|
+
NumericType,
|
|
30
|
+
RealType,
|
|
28
31
|
ForeignKeyType,
|
|
29
32
|
IntegerType,
|
|
33
|
+
SerializedType,
|
|
30
34
|
StringType,
|
|
31
35
|
TextType,
|
|
32
36
|
UUIDV1Type,
|
|
@@ -40,9 +44,11 @@ module.exports = {
|
|
|
40
44
|
CHAR,
|
|
41
45
|
DATE,
|
|
42
46
|
DATETIME,
|
|
43
|
-
|
|
47
|
+
NUMERIC,
|
|
48
|
+
REAL,
|
|
44
49
|
FOREIGN_KEY,
|
|
45
50
|
INTEGER,
|
|
51
|
+
SERIALIZED,
|
|
46
52
|
STRING,
|
|
47
53
|
TEXT,
|
|
48
54
|
UUIDV1,
|
|
@@ -3,20 +3,23 @@
|
|
|
3
3
|
const Nife = require('nife');
|
|
4
4
|
const Type = require('../type');
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
const DEFAULT_TOTAL_DIGITS = 20;
|
|
7
|
+
const DEFAULT_DECIMAL_PLACES = 6;
|
|
8
|
+
|
|
9
|
+
class NumericType extends Type {
|
|
7
10
|
static getDisplayName() {
|
|
8
|
-
return '
|
|
11
|
+
return 'NUMERIC';
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
getDisplayName() {
|
|
12
15
|
return this.constructor.getDisplayName();
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
constructor(
|
|
16
|
-
super(
|
|
18
|
+
constructor(precision, scale) {
|
|
19
|
+
super(precision, scale);
|
|
17
20
|
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
21
|
+
this.precision = precision || DEFAULT_TOTAL_DIGITS;
|
|
22
|
+
this.scale = scale || DEFAULT_DECIMAL_PLACES;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
castToType({ value }) {
|
|
@@ -37,11 +40,11 @@ class FloatType extends Type {
|
|
|
37
40
|
toString(connection) {
|
|
38
41
|
return (connection)
|
|
39
42
|
? this.toConnectionType(connection)
|
|
40
|
-
: '
|
|
43
|
+
: 'NUMERIC';
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
module.exports = {
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
NUMERIC: Type.wrapConstructor(NumericType),
|
|
49
|
+
NumericType,
|
|
47
50
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Nife = require('nife');
|
|
4
|
+
const Type = require('../type');
|
|
5
|
+
|
|
6
|
+
class RealType extends Type {
|
|
7
|
+
static getDisplayName() {
|
|
8
|
+
return 'REAL';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
getDisplayName() {
|
|
12
|
+
return this.constructor.getDisplayName();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
constructor(length, scale) {
|
|
16
|
+
super(length, scale);
|
|
17
|
+
|
|
18
|
+
this.length = length;
|
|
19
|
+
this.scale = scale;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
castToType({ value }) {
|
|
23
|
+
if (value == null)
|
|
24
|
+
return value;
|
|
25
|
+
|
|
26
|
+
let number = parseFloat(('' + value));
|
|
27
|
+
if (!isFinite(number))
|
|
28
|
+
throw new TypeError(`RealType::castToType: Value provided ("${value}") can not be cast into an floating point number.`);
|
|
29
|
+
|
|
30
|
+
return number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
isValidValue(value) {
|
|
34
|
+
return (Nife.instanceOf(value, 'number') && isFinite(value));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
toString(connection) {
|
|
38
|
+
return (connection)
|
|
39
|
+
? this.toConnectionType(connection)
|
|
40
|
+
: 'FLOAT';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
REAL: Type.wrapConstructor(RealType),
|
|
46
|
+
RealType,
|
|
47
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Type = require('../type');
|
|
4
|
+
|
|
5
|
+
class SerializedType extends Type {
|
|
6
|
+
static getDisplayName() {
|
|
7
|
+
return 'SERIALIZED';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
getDisplayName() {
|
|
11
|
+
return this.constructor.getDisplayName();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
constructor(_options) {
|
|
15
|
+
let options = _options;
|
|
16
|
+
if (Type.isTypeClass(options) || Type.isType(options))
|
|
17
|
+
options = { type: options };
|
|
18
|
+
|
|
19
|
+
options = {
|
|
20
|
+
serialize: ({ value }) => {
|
|
21
|
+
if (value == null)
|
|
22
|
+
return value;
|
|
23
|
+
|
|
24
|
+
return JSON.stringify(value);
|
|
25
|
+
},
|
|
26
|
+
deserialize: ({ value }) => {
|
|
27
|
+
if (value == null)
|
|
28
|
+
return value;
|
|
29
|
+
|
|
30
|
+
return JSON.parse(value);
|
|
31
|
+
},
|
|
32
|
+
...(options || {}),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (!options.type)
|
|
36
|
+
throw new TypeError('SerializedType::constructor: "type" must be specified on the "options" for this type. "type" defines the storage type for this field. i.e. Types.SERIALIZED({ type: Types.STRING(1024) })');
|
|
37
|
+
|
|
38
|
+
super(options);
|
|
39
|
+
|
|
40
|
+
options.type = Type.instantiateType(options.type);
|
|
41
|
+
|
|
42
|
+
Object.defineProperties(this, {
|
|
43
|
+
'options': {
|
|
44
|
+
writable: true,
|
|
45
|
+
enumberable: false,
|
|
46
|
+
configurable: true,
|
|
47
|
+
value: options,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getOptions() {
|
|
53
|
+
return this.options;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
initialize(connection, self) {
|
|
57
|
+
let options = this.getOptions();
|
|
58
|
+
options.type.initialize(connection, self);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
castToType({ value, connection }) {
|
|
62
|
+
return this.deserialize(value, connection);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
onSetFieldValue({ value, fieldName, self }) {
|
|
66
|
+
// we make a copy here
|
|
67
|
+
// so that when the value is modified
|
|
68
|
+
// we can detect the changes later
|
|
69
|
+
let clonedValue = this.deserialize(this.serialize(value, self.getConnection() || {}));
|
|
70
|
+
self._typeData[fieldName] = clonedValue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
isDirty(context) {
|
|
74
|
+
let options = this.getOptions();
|
|
75
|
+
if (typeof options.isDirty === 'function')
|
|
76
|
+
return options.isDirty.call(this, context);
|
|
77
|
+
|
|
78
|
+
let { value, fieldName, self, connection } = context;
|
|
79
|
+
let currentValue = self._typeData[fieldName];
|
|
80
|
+
if (value == null && currentValue == null)
|
|
81
|
+
return;
|
|
82
|
+
|
|
83
|
+
if (this.serialize(value, connection) !== this.serialize(currentValue, connection))
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
isValidValue() {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
serialize(value, connection) {
|
|
92
|
+
if (!connection)
|
|
93
|
+
return value;
|
|
94
|
+
|
|
95
|
+
let options = this.getOptions();
|
|
96
|
+
let innerType = options.type;
|
|
97
|
+
|
|
98
|
+
if (value != null && innerType.isValidValue(value))
|
|
99
|
+
return value;
|
|
100
|
+
|
|
101
|
+
return options.serialize({ value, connection });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
deserialize(value, connection) {
|
|
105
|
+
let options = this.getOptions();
|
|
106
|
+
let innerType = options.type;
|
|
107
|
+
|
|
108
|
+
if (value != null && !innerType.isValidValue(value))
|
|
109
|
+
return value;
|
|
110
|
+
|
|
111
|
+
return options.deserialize({ value, connection });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
toString(connection) {
|
|
115
|
+
let options = this.getOptions();
|
|
116
|
+
let innerType = options.type;
|
|
117
|
+
return innerType.toString(connection);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
toConnectionType(connection, options) {
|
|
121
|
+
let typeOptions = this.getOptions();
|
|
122
|
+
let innerType = typeOptions.type;
|
|
123
|
+
|
|
124
|
+
if (!connection)
|
|
125
|
+
return innerType.toString();
|
|
126
|
+
|
|
127
|
+
return connection.typeToString(innerType, options);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = {
|
|
132
|
+
SERIALIZED: Type.wrapConstructor(SerializedType),
|
|
133
|
+
SerializedType,
|
|
134
|
+
};
|
package/lib/types/index.js
CHANGED
|
@@ -12,9 +12,11 @@ const {
|
|
|
12
12
|
CharType,
|
|
13
13
|
DateTimeType,
|
|
14
14
|
DateType,
|
|
15
|
-
|
|
15
|
+
NumericType,
|
|
16
|
+
RealType,
|
|
16
17
|
ForeignKeyType,
|
|
17
18
|
IntegerType,
|
|
19
|
+
SerializedType,
|
|
18
20
|
StringType,
|
|
19
21
|
TextType,
|
|
20
22
|
UUIDV1Type,
|
|
@@ -28,9 +30,11 @@ const {
|
|
|
28
30
|
CHAR,
|
|
29
31
|
DATE,
|
|
30
32
|
DATETIME,
|
|
31
|
-
|
|
33
|
+
NUMERIC,
|
|
34
|
+
REAL,
|
|
32
35
|
FOREIGN_KEY,
|
|
33
36
|
INTEGER,
|
|
37
|
+
SERIALIZED,
|
|
34
38
|
STRING,
|
|
35
39
|
TEXT,
|
|
36
40
|
UUIDV1,
|
|
@@ -59,9 +63,11 @@ module.exports = {
|
|
|
59
63
|
CharType,
|
|
60
64
|
DateTimeType,
|
|
61
65
|
DateType,
|
|
62
|
-
|
|
66
|
+
NumericType,
|
|
67
|
+
RealType,
|
|
63
68
|
ForeignKeyType,
|
|
64
69
|
IntegerType,
|
|
70
|
+
SerializedType,
|
|
65
71
|
StringType,
|
|
66
72
|
TextType,
|
|
67
73
|
UUIDV1Type,
|
|
@@ -75,9 +81,11 @@ module.exports = {
|
|
|
75
81
|
CHAR,
|
|
76
82
|
DATE,
|
|
77
83
|
DATETIME,
|
|
78
|
-
|
|
84
|
+
NUMERIC,
|
|
85
|
+
REAL,
|
|
79
86
|
FOREIGN_KEY,
|
|
80
87
|
INTEGER,
|
|
88
|
+
SERIALIZED,
|
|
81
89
|
STRING,
|
|
82
90
|
TEXT,
|
|
83
91
|
UUIDV1,
|
package/lib/types/type.js
CHANGED
package/lib/utils/model-utils.js
CHANGED
|
@@ -81,32 +81,52 @@ function fieldToFullyQualifiedName(field, Model) {
|
|
|
81
81
|
return `${def.modelName}:${def.fieldNames[0]}`;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
function sortModelNamesByDependencyOrder(connection,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
let Model = connection.getModel(modelName);
|
|
89
|
-
let dependentModelNames = dependencyHelper(Model, modelName);
|
|
84
|
+
function sortModelNamesByDependencyOrder(connection, _modelNames, dependencyHelper) {
|
|
85
|
+
const recursiveAdd = (modelName, _depth) => {
|
|
86
|
+
if (modelNames.indexOf(modelName) < 0)
|
|
87
|
+
return;
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
}
|
|
89
|
+
let depth = _depth || 0;
|
|
93
90
|
|
|
94
|
-
|
|
95
|
-
if (
|
|
96
|
-
|
|
91
|
+
// eslint-disable-next-line no-magic-numbers
|
|
92
|
+
if (depth > 10)
|
|
93
|
+
throw new Error(`ModelUtils::sortModelNamesByDependencyOrder: Cyclic dependency detected with model "${modelName}".`);
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
if (finalOrder.has(modelName))
|
|
96
|
+
return;
|
|
100
97
|
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
let dependentModelNames = modelOrderMap[modelName];
|
|
99
|
+
if (dependentModelNames == null) {
|
|
100
|
+
let Model = connection.getModel(modelName);
|
|
101
|
+
dependentModelNames = modelOrderMap[modelName] = (dependencyHelper(Model, modelName) || []);
|
|
102
|
+
}
|
|
103
103
|
|
|
104
|
-
if (
|
|
105
|
-
|
|
104
|
+
if (dependentModelNames.length === 0) {
|
|
105
|
+
finalOrder.set(modelName, dependentModelNames);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
for (let j = 0, jl = dependentModelNames.length; j < jl; j++) {
|
|
110
|
+
let dependentModelName = dependentModelNames[j];
|
|
111
|
+
recursiveAdd(dependentModelName, depth + 1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
finalOrder.set(modelName, dependentModelNames);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
let modelOrderMap = {};
|
|
118
|
+
let modelNames = Nife.toArray(_modelNames).slice().sort();
|
|
119
|
+
let finalOrder = new Map();
|
|
120
|
+
|
|
121
|
+
for (let i = 0, il = modelNames.length; i < il; i++) {
|
|
122
|
+
let modelName = modelNames[i];
|
|
123
|
+
if (!modelName)
|
|
124
|
+
continue;
|
|
125
|
+
|
|
126
|
+
recursiveAdd(modelName);
|
|
127
|
+
}
|
|
109
128
|
|
|
129
|
+
let sortedModelNames = Array.from(finalOrder.keys());
|
|
110
130
|
return sortedModelNames;
|
|
111
131
|
}
|
|
112
132
|
|
package/lib/utils/query-utils.js
CHANGED
|
@@ -60,13 +60,13 @@ const FILTER_OPERATORS = {
|
|
|
60
60
|
'<>': (Model, fieldName, query, value) => {
|
|
61
61
|
return query.AND(Model.where[fieldName].LT(value[0]).OR[fieldName].GT(value[1]));
|
|
62
62
|
},
|
|
63
|
-
// Like
|
|
63
|
+
// Like
|
|
64
64
|
'*': (Model, fieldName, query, value) => {
|
|
65
|
-
return query.
|
|
65
|
+
return query.LIKE(value);
|
|
66
66
|
},
|
|
67
|
-
// NOT Like
|
|
67
|
+
// NOT Like
|
|
68
68
|
'!*': (Model, fieldName, query, value) => {
|
|
69
|
-
return query.
|
|
69
|
+
return query.NOT_LIKE(value);
|
|
70
70
|
},
|
|
71
71
|
};
|
|
72
72
|
|