leoric 2.0.1 → 2.0.2
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/History.md +17 -0
- package/package.json +1 -1
- package/src/adapters/sequelize.js +3 -3
- package/src/bone.js +44 -43
- package/src/collection.js +1 -1
- package/src/constants.js +30 -0
- package/src/data_types.js +17 -9
- package/src/drivers/abstract/attribute.js +3 -3
- package/src/drivers/abstract/spellbook.js +4 -2
- package/src/drivers/mysql/spellbook.js +17 -0
- package/src/drivers/postgres/data_types.js +26 -0
- package/src/drivers/sqlite/data_types.js +42 -0
- package/src/expr_formatter.js +1 -1
- package/src/realm.js +1 -6
- package/src/spell.js +1 -1
- package/src/contants.js +0 -13
package/History.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
2.0.2 / 2021-02-10
|
|
2
|
+
==================
|
|
3
|
+
|
|
4
|
+
## What's Changed
|
|
5
|
+
* fix: order by alias should not throw by @cyjake in https://github.com/cyjake/leoric/pull/255
|
|
6
|
+
* fix: fix #257 DataType.uncast should skip Raw type at type checking by @JimmyDaddy in https://github.com/cyjake/leoric/pull/258
|
|
7
|
+
* docs: async function in transaction by @cyjake in https://github.com/cyjake/leoric/pull/259
|
|
8
|
+
* fix: fixed #256 static create instance should check all default attri… by @JimmyDaddy in https://github.com/cyjake/leoric/pull/262
|
|
9
|
+
* fix: fix #260 UPDATE with LIMIT and ORDER should be formatted(mysql only) by @JimmyDaddy in https://github.com/cyjake/leoric/pull/261
|
|
10
|
+
* refactor: keep the UPDATE ... ORDER BY ... LIMIT to mysql driver by @cyjake in https://github.com/cyjake/leoric/pull/264
|
|
11
|
+
* fix: fix #263 upsert attributes should use defaultValue while there i… by @JimmyDaddy in https://github.com/cyjake/leoric/pull/265
|
|
12
|
+
* fix: fix restore Error `Undefined attribute "deletedAt"` by @JimmyDaddy in https://github.com/cyjake/leoric/pull/267
|
|
13
|
+
* fix: type checking adaption by @JimmyDaddy in https://github.com/cyjake/leoric/pull/266
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
**Full Changelog**: https://github.com/cyjake/leoric/compare/v2.0.1...v2.0.2
|
|
17
|
+
|
|
1
18
|
2.0.1 / 2022-01-05
|
|
2
19
|
==================
|
|
3
20
|
|
package/package.json
CHANGED
|
@@ -238,9 +238,6 @@ module.exports = Bone => {
|
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
static build(values, options = {}) {
|
|
241
|
-
if (options.validate !== false) {
|
|
242
|
-
this._validateAttributes(values);
|
|
243
|
-
}
|
|
244
241
|
const { raw } = Object.assign({ raw: false, isNewRecord: true }, options);
|
|
245
242
|
const { attributes } = this;
|
|
246
243
|
|
|
@@ -256,6 +253,7 @@ module.exports = Bone => {
|
|
|
256
253
|
} else {
|
|
257
254
|
instance = new this(values, options);
|
|
258
255
|
}
|
|
256
|
+
|
|
259
257
|
return instance;
|
|
260
258
|
}
|
|
261
259
|
|
|
@@ -469,6 +467,7 @@ module.exports = Bone => {
|
|
|
469
467
|
const { where, paranoid, individualHooks } = options;
|
|
470
468
|
if (individualHooks) {
|
|
471
469
|
let findSpell = this._find(where, options);
|
|
470
|
+
translateOptions(findSpell, options);
|
|
472
471
|
if (paranoid === false) findSpell = findSpell.unparanoid;
|
|
473
472
|
const instances = await findSpell;
|
|
474
473
|
if (instances.length) {
|
|
@@ -484,6 +483,7 @@ module.exports = Bone => {
|
|
|
484
483
|
const { where, paranoid = false, validate } = options;
|
|
485
484
|
const whereConditions = where || {};
|
|
486
485
|
const spell = super.update(whereConditions, values, { validate, hooks: false, ...options });
|
|
486
|
+
translateOptions(spell, options);
|
|
487
487
|
if (!paranoid) return spell.unparanoid;
|
|
488
488
|
return spell;
|
|
489
489
|
}
|
package/src/bone.js
CHANGED
|
@@ -15,6 +15,7 @@ const Raw = require('./raw');
|
|
|
15
15
|
const { capitalize, camelCase, snakeCase } = require('./utils/string');
|
|
16
16
|
const { hookNames, setupSingleHook } = require('./setup_hooks');
|
|
17
17
|
const { logger } = require('./utils/index');
|
|
18
|
+
const { TIMESTAMP_NAMES, LEGACY_TIMESTAMP_COLUMN_MAP } = require('./constants');
|
|
18
19
|
|
|
19
20
|
function looseReadonly(props) {
|
|
20
21
|
return Object.keys(props).reduce((result, name) => {
|
|
@@ -76,6 +77,23 @@ function copyValues(values) {
|
|
|
76
77
|
return copyValue;
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
function valuesValidate(values, attributes, ctx) {
|
|
81
|
+
for (const valueKey in values) {
|
|
82
|
+
const attribute = attributes[valueKey];
|
|
83
|
+
if (!attribute) continue;
|
|
84
|
+
const { validate = {}, name, allowNull, defaultValue } = attribute;
|
|
85
|
+
const value = values[valueKey];
|
|
86
|
+
if (value == null && defaultValue == null) {
|
|
87
|
+
if (allowNull === false) throw new LeoricValidateError('notNull', name);
|
|
88
|
+
if ((allowNull === true || allowNull === undefined) && validate.notNull === undefined ) continue;
|
|
89
|
+
}
|
|
90
|
+
if (!validate) continue;
|
|
91
|
+
for (const key in validate) {
|
|
92
|
+
if (validate.hasOwnProperty(key)) executeValidator(ctx, key, attribute, value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
79
97
|
/**
|
|
80
98
|
* The base class that provides Object-relational mapping. This class is never intended to be used directly. We need to create models that extends from Bone. Most of the query features of Bone is implemented by {@link Spell} such as {@link Spell#$group} and {@link Spell#$join}. With Bone, you can create models like this:
|
|
81
99
|
*
|
|
@@ -280,21 +298,7 @@ class Bone {
|
|
|
280
298
|
|
|
281
299
|
// merge all changed values
|
|
282
300
|
changedValues = Object.assign(changedValues, values);
|
|
283
|
-
|
|
284
|
-
for (const valueKey in changedValues) {
|
|
285
|
-
const attribute = attributes[valueKey];
|
|
286
|
-
if (!attribute) continue;
|
|
287
|
-
const { validate = {}, name, allowNull, defaultValue } = attribute;
|
|
288
|
-
const value = changedValues[valueKey];
|
|
289
|
-
if (value == null && defaultValue == null) {
|
|
290
|
-
if (allowNull === false) throw new LeoricValidateError('notNull', name);
|
|
291
|
-
if ((allowNull === true || allowNull === undefined) && validate.notNull === undefined ) return;
|
|
292
|
-
}
|
|
293
|
-
if (!validate) return;
|
|
294
|
-
for (const key in validate) {
|
|
295
|
-
if (validate.hasOwnProperty(key)) executeValidator(this, key, attribute, value);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
301
|
+
valuesValidate(changedValues, attributes, this);
|
|
298
302
|
}
|
|
299
303
|
|
|
300
304
|
/**
|
|
@@ -306,22 +310,7 @@ class Bone {
|
|
|
306
310
|
*/
|
|
307
311
|
static _validateAttributes(values = {}) {
|
|
308
312
|
const { attributes } = this;
|
|
309
|
-
|
|
310
|
-
const attribute = attributes[valueKey];
|
|
311
|
-
// If valueKey is not an attribute of the Model, go to the next loop instead of throw 'No Such Attribute' Error,
|
|
312
|
-
// in case it is a custom property of the Model which defined by custom setters/getters.
|
|
313
|
-
if (!attribute) return;
|
|
314
|
-
const { validate = {}, name, allowNull, defaultValue } = attribute;
|
|
315
|
-
const value = values[valueKey];
|
|
316
|
-
if (value == null && defaultValue == null) {
|
|
317
|
-
if (allowNull === false) throw new LeoricValidateError('notNull', name);
|
|
318
|
-
if ((allowNull === true || allowNull === undefined) && validate.notNull === undefined) return;
|
|
319
|
-
}
|
|
320
|
-
if (!validate) return;
|
|
321
|
-
for (const key in validate) {
|
|
322
|
-
if (validate.hasOwnProperty(key)) executeValidator(this, key, attribute, value);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
313
|
+
valuesValidate(values, attributes, this);
|
|
325
314
|
}
|
|
326
315
|
|
|
327
316
|
/**
|
|
@@ -725,6 +714,7 @@ class Bone {
|
|
|
725
714
|
this[updatedAt] = this[createdAt];
|
|
726
715
|
}
|
|
727
716
|
|
|
717
|
+
const validateValues = {};
|
|
728
718
|
for (const name in attributes) {
|
|
729
719
|
const value = this.attribute(name);
|
|
730
720
|
const { defaultValue } = attributes[name];
|
|
@@ -733,10 +723,12 @@ class Bone {
|
|
|
733
723
|
} else if (value === undefined && defaultValue != null) {
|
|
734
724
|
data[name] = defaultValue;
|
|
735
725
|
}
|
|
726
|
+
if (attributes[name].primaryKey) continue;
|
|
727
|
+
validateValues[name] = data[name];
|
|
736
728
|
}
|
|
737
729
|
|
|
738
730
|
if (opts.validate !== false) {
|
|
739
|
-
this._validateAttributes();
|
|
731
|
+
this._validateAttributes(validateValues);
|
|
740
732
|
}
|
|
741
733
|
|
|
742
734
|
const spell = new Spell(Model, opts).$insert(data);
|
|
@@ -822,10 +814,10 @@ class Bone {
|
|
|
822
814
|
|
|
823
815
|
const conditions = {
|
|
824
816
|
[primaryKey]: this[primaryKey],
|
|
825
|
-
deletedAt: { $ne: null },
|
|
817
|
+
[deletedAt]: { $ne: null },
|
|
826
818
|
};
|
|
827
819
|
if (shardingKey) conditions[shardingKey] = this[shardingKey];
|
|
828
|
-
await this.update({ deletedAt: null }, { ...opts, paranoid: false });
|
|
820
|
+
await this.update({ [deletedAt]: null }, { ...opts, paranoid: false });
|
|
829
821
|
return this;
|
|
830
822
|
}
|
|
831
823
|
|
|
@@ -840,7 +832,7 @@ class Bone {
|
|
|
840
832
|
if (deletedAt == null) {
|
|
841
833
|
throw new Error('Model is not paranoid');
|
|
842
834
|
}
|
|
843
|
-
return Bone.update.call(this, conditions, { deletedAt: null }, { ...opts, paranoid: false });
|
|
835
|
+
return Bone.update.call(this, conditions, { [deletedAt]: null }, { ...opts, paranoid: false });
|
|
844
836
|
}
|
|
845
837
|
|
|
846
838
|
/**
|
|
@@ -855,9 +847,13 @@ class Bone {
|
|
|
855
847
|
const data = {};
|
|
856
848
|
const Model = this;
|
|
857
849
|
const { attributes } = Model;
|
|
858
|
-
for (const
|
|
859
|
-
|
|
860
|
-
|
|
850
|
+
for (const key in attributes) {
|
|
851
|
+
const attribute = attributes[key];
|
|
852
|
+
if (attribute.primaryKey) continue;
|
|
853
|
+
if (values[key] == null && attribute.defaultValue != null) {
|
|
854
|
+
data[key] = attribute.defaultValue;
|
|
855
|
+
} else if (values[key] !== undefined){
|
|
856
|
+
data[key] = values[key];
|
|
861
857
|
}
|
|
862
858
|
}
|
|
863
859
|
|
|
@@ -940,6 +936,15 @@ class Bone {
|
|
|
940
936
|
const attribute = new Attribute(name, attributes[name], options.define);
|
|
941
937
|
attributeMap[attribute.columnName] = attribute;
|
|
942
938
|
attributes[name] = attribute;
|
|
939
|
+
if (TIMESTAMP_NAMES.includes(name)) {
|
|
940
|
+
const { columnName } = attribute;
|
|
941
|
+
const legacyColumnName = LEGACY_TIMESTAMP_COLUMN_MAP[columnName];
|
|
942
|
+
if (!columnMap[columnName] && legacyColumnName && columnMap[legacyColumnName]) {
|
|
943
|
+
// correct columname
|
|
944
|
+
attribute.columnName = legacyColumnName;
|
|
945
|
+
attributeMap[attribute.columnName] = attribute;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
943
948
|
const columnInfo = columnMap[attribute.columnName];
|
|
944
949
|
// if datetime or timestamp precision not defined, default to column info
|
|
945
950
|
if (columnInfo && attribute.type instanceof DataTypes.DATE && attribute.type.precision == null) {
|
|
@@ -949,7 +954,7 @@ class Bone {
|
|
|
949
954
|
|
|
950
955
|
const primaryKey = Object.keys(attributes).find(key => attributes[key].primaryKey);
|
|
951
956
|
const timestamps = {};
|
|
952
|
-
for (const key of
|
|
957
|
+
for (const key of TIMESTAMP_NAMES) {
|
|
953
958
|
const name = attributes.hasOwnProperty(key) ? key : snakeCase(key);
|
|
954
959
|
const attribute = attributes[name];
|
|
955
960
|
|
|
@@ -1318,13 +1323,9 @@ class Bone {
|
|
|
1318
1323
|
static create(values, opts = {}) {
|
|
1319
1324
|
const data = Object.assign({}, values);
|
|
1320
1325
|
const instance = new this(data);
|
|
1321
|
-
if (opts.validate !== false) {
|
|
1322
|
-
instance._validateAttributes(data); // call instance._validateAttributes manually to validate the raw value
|
|
1323
|
-
}
|
|
1324
1326
|
// static create proxy to instance.create
|
|
1325
1327
|
return instance.create({
|
|
1326
1328
|
...opts,
|
|
1327
|
-
validate: false, // should not validate again
|
|
1328
1329
|
});
|
|
1329
1330
|
}
|
|
1330
1331
|
|
package/src/collection.js
CHANGED
package/src/constants.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const AGGREGATOR_MAP = {
|
|
4
|
+
count: 'count',
|
|
5
|
+
average: 'avg',
|
|
6
|
+
minimum: 'min',
|
|
7
|
+
maximum: 'max',
|
|
8
|
+
sum: 'sum'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const LEGACY_TIMESTAMP_MAP = {
|
|
12
|
+
gmtCreate: 'createdAt',
|
|
13
|
+
gmtModified: 'updatedAt',
|
|
14
|
+
gmtDeleted: 'deletedAt',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const LEGACY_TIMESTAMP_COLUMN_MAP = {
|
|
18
|
+
created_at: 'gmt_create',
|
|
19
|
+
updated_at: 'gmt_modified',
|
|
20
|
+
deleted_at: 'gmt_deleted',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const TIMESTAMP_NAMES = [ 'createdAt', 'updatedAt', 'deletedAt' ];
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
AGGREGATOR_MAP,
|
|
27
|
+
LEGACY_TIMESTAMP_MAP,
|
|
28
|
+
TIMESTAMP_NAMES,
|
|
29
|
+
LEGACY_TIMESTAMP_COLUMN_MAP
|
|
30
|
+
};
|
package/src/data_types.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const util = require('util');
|
|
4
4
|
const invokable = require('./utils/invokable');
|
|
5
|
+
const Raw = require('./raw');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @example
|
|
@@ -114,7 +115,7 @@ class STRING extends DataType {
|
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
uncast(value) {
|
|
117
|
-
if (value == null) return value;
|
|
118
|
+
if (value == null || value instanceof Raw) return value;
|
|
118
119
|
return '' + value;
|
|
119
120
|
}
|
|
120
121
|
}
|
|
@@ -186,15 +187,18 @@ class INTEGER extends DataType {
|
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
cast(value) {
|
|
189
|
-
if (value == null) return value;
|
|
190
|
+
if (value == null || isNaN(value)) return value;
|
|
190
191
|
return Number(value);
|
|
191
192
|
}
|
|
192
193
|
|
|
193
|
-
uncast(value) {
|
|
194
|
+
uncast(value, strict = true) {
|
|
194
195
|
const originValue = value;
|
|
195
|
-
if (value == null) return value;
|
|
196
|
+
if (value == null || value instanceof Raw) return value;
|
|
196
197
|
if (typeof value === 'string') value = parseInt(value, 10);
|
|
197
|
-
if (isNaN(value))
|
|
198
|
+
if (isNaN(value)) {
|
|
199
|
+
if (strict) throw new Error(util.format('invalid integer: %s', originValue));
|
|
200
|
+
return originValue;
|
|
201
|
+
}
|
|
198
202
|
return value;
|
|
199
203
|
}
|
|
200
204
|
}
|
|
@@ -243,15 +247,17 @@ class DATE extends DataType {
|
|
|
243
247
|
}
|
|
244
248
|
|
|
245
249
|
cast(value) {
|
|
250
|
+
const original = value;
|
|
246
251
|
if (value == null) return value;
|
|
247
252
|
if (!(value instanceof Date)) value = new Date(value);
|
|
253
|
+
if (isNaN(value.getTime())) return original;
|
|
248
254
|
return this._round(value);
|
|
249
255
|
}
|
|
250
256
|
|
|
251
257
|
uncast(value) {
|
|
252
258
|
const originValue = value;
|
|
253
259
|
|
|
254
|
-
if (value == null) return value;
|
|
260
|
+
if (value == null || value instanceof Raw) return value;
|
|
255
261
|
if (typeof value.toDate === 'function') {
|
|
256
262
|
value = value.toDate();
|
|
257
263
|
}
|
|
@@ -289,15 +295,17 @@ class DATEONLY extends DataType {
|
|
|
289
295
|
}
|
|
290
296
|
|
|
291
297
|
cast(value) {
|
|
298
|
+
const original = value;
|
|
292
299
|
if (value == null) return value;
|
|
293
300
|
if (!(value instanceof Date)) value = new Date(value);
|
|
301
|
+
if (isNaN(value.getTime())) return original;
|
|
294
302
|
return this._round(value);
|
|
295
303
|
}
|
|
296
304
|
|
|
297
305
|
uncast(value) {
|
|
298
306
|
const originValue = value;
|
|
299
307
|
|
|
300
|
-
if (value == null) return value;
|
|
308
|
+
if (value == null || value instanceof Raw) return value;
|
|
301
309
|
if (typeof value.toDate === 'function') {
|
|
302
310
|
value = value.toDate();
|
|
303
311
|
}
|
|
@@ -309,7 +317,7 @@ class DATEONLY extends DataType {
|
|
|
309
317
|
}
|
|
310
318
|
|
|
311
319
|
if (!(value instanceof Date)) value = new Date(value);
|
|
312
|
-
if (isNaN(value)) throw new Error(util.format('invalid date: %s', originValue))
|
|
320
|
+
if (isNaN(value)) throw new Error(util.format('invalid date: %s', originValue));
|
|
313
321
|
|
|
314
322
|
return this._round(value);
|
|
315
323
|
}
|
|
@@ -393,7 +401,7 @@ class JSON extends DataType {
|
|
|
393
401
|
}
|
|
394
402
|
|
|
395
403
|
uncast(value) {
|
|
396
|
-
if (value == null) return value;
|
|
404
|
+
if (value == null || value instanceof Raw) return value;
|
|
397
405
|
return global.JSON.stringify(value);
|
|
398
406
|
}
|
|
399
407
|
}
|
|
@@ -126,11 +126,11 @@ class Attribute {
|
|
|
126
126
|
return this.type.cast(value);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
uncast(value) {
|
|
129
|
+
uncast(value, strict = true) {
|
|
130
130
|
if (Array.isArray(value) && this.jsType !== JSON) {
|
|
131
|
-
return value.map(entry => this.type.uncast(entry));
|
|
131
|
+
return value.map(entry => this.type.uncast(entry, strict));
|
|
132
132
|
}
|
|
133
|
-
return this.type.uncast(value);
|
|
133
|
+
return this.type.uncast(value, strict);
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -129,7 +129,7 @@ function createSubspell(spell) {
|
|
|
129
129
|
subspell.orders = [];
|
|
130
130
|
for (const order of orders) {
|
|
131
131
|
const [token, direction] = order;
|
|
132
|
-
const { type, qualifiers, value } = token;
|
|
132
|
+
const { type, qualifiers = [], value } = token;
|
|
133
133
|
if (type == 'id' && qualifiers[0] == baseName) {
|
|
134
134
|
subspell.orders.push([{ type, value }, direction]);
|
|
135
135
|
}
|
|
@@ -220,7 +220,7 @@ function formatSelectWithJoin(spell) {
|
|
|
220
220
|
|
|
221
221
|
let hoistable = skip > 0 || rowCount > 0;
|
|
222
222
|
if (hoistable) {
|
|
223
|
-
function checkQualifier({ type, qualifiers }) {
|
|
223
|
+
function checkQualifier({ type, qualifiers = [] }) {
|
|
224
224
|
if (type === 'id' && qualifiers.length> 0 && !qualifiers.includes(baseName)) {
|
|
225
225
|
hoistable = false;
|
|
226
226
|
}
|
|
@@ -476,6 +476,7 @@ function formatUpdate(spell) {
|
|
|
476
476
|
for (const condition of whereConditions) collectLiteral(spell, condition, values);
|
|
477
477
|
chunks.push(`WHERE ${formatConditions(spell, whereConditions)}`);
|
|
478
478
|
}
|
|
479
|
+
|
|
479
480
|
return {
|
|
480
481
|
sql: chunks.join(' '),
|
|
481
482
|
values,
|
|
@@ -606,4 +607,5 @@ module.exports = {
|
|
|
606
607
|
formatSelectWithoutJoin,
|
|
607
608
|
formatUpdateOnDuplicate,
|
|
608
609
|
formatReturning,
|
|
610
|
+
formatOrders
|
|
609
611
|
};
|
|
@@ -58,4 +58,21 @@ module.exports = {
|
|
|
58
58
|
formatReturning() {
|
|
59
59
|
return '';
|
|
60
60
|
},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* UPDATE ... ORDER BY ... LIMIT ${rowCount}
|
|
64
|
+
* - https://dev.mysql.com/doc/refman/8.0/en/update.html
|
|
65
|
+
* @param {Spell} spell
|
|
66
|
+
*/
|
|
67
|
+
formatUpdate(spell) {
|
|
68
|
+
const result = spellbook.formatUpdate.call(this, spell);
|
|
69
|
+
const { rowCount, orders } = spell;
|
|
70
|
+
const chunks = [];
|
|
71
|
+
|
|
72
|
+
if (orders.length > 0) chunks.push(`ORDER BY ${this.formatOrders(spell, orders).join(', ')}`);
|
|
73
|
+
if (rowCount > 0) chunks.push(`LIMIT ${rowCount}`);
|
|
74
|
+
if (chunks.length > 0) result.sql += ` ${chunks.join(' ')}`;
|
|
75
|
+
|
|
76
|
+
return result;
|
|
77
|
+
},
|
|
61
78
|
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const DataTypes = require('../../data_types');
|
|
4
|
+
const util = require('util');
|
|
5
|
+
const Raw = require('../../raw');
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
class Postgres_DATE extends DataTypes.DATE {
|
|
6
9
|
constructor(precision, timezone = true) {
|
|
@@ -37,12 +40,35 @@ class Postgres_BINARY extends DataTypes {
|
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
class Postgres_INTEGER extends DataTypes.INTEGER {
|
|
44
|
+
constructor(length) {
|
|
45
|
+
super(length);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
uncast(value) {
|
|
49
|
+
const originValue = value;
|
|
50
|
+
if (value == null || value instanceof Raw) return value;
|
|
51
|
+
if (typeof value === 'string') value = parseInt(value, 10);
|
|
52
|
+
if (isNaN(value)) throw new Error(util.format('invalid integer: %s', originValue));
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class Postgres_BIGINT extends Postgres_INTEGER {
|
|
58
|
+
constructor() {
|
|
59
|
+
super();
|
|
60
|
+
this.dataType = 'bigint';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
40
64
|
class Postgres_DataTypes extends DataTypes {
|
|
41
65
|
static DATE = Postgres_DATE;
|
|
42
66
|
static JSONB = Postgres_JSONB;
|
|
43
67
|
static BINARY = Postgres_BINARY;
|
|
44
68
|
static VARBINARY = Postgres_BINARY;
|
|
45
69
|
static BLOB = Postgres_BINARY;
|
|
70
|
+
static INTEGER = Postgres_INTEGER;
|
|
71
|
+
static BIGINT = Postgres_BIGINT;
|
|
46
72
|
}
|
|
47
73
|
|
|
48
74
|
module.exports = Postgres_DataTypes;
|
|
@@ -7,8 +7,42 @@ class Sqlite_DATE extends DataTypes.DATE {
|
|
|
7
7
|
super(precision, timezone);
|
|
8
8
|
this.dataType = 'datetime';
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
uncast(value) {
|
|
12
|
+
try {
|
|
13
|
+
return super.uncast(value);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
console.error(new Error(`unable to cast ${value} to DATE`));
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class Sqlite_DATEONLY extends DataTypes.DATEONLY {
|
|
22
|
+
constructor() {
|
|
23
|
+
super();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
uncast(value) {
|
|
27
|
+
try {
|
|
28
|
+
return super.uncast(value);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error(new Error(`unable to cast ${value} to DATEONLY`));
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
10
34
|
}
|
|
11
35
|
|
|
36
|
+
class Sqlite_INTEGER extends DataTypes.INTEGER {
|
|
37
|
+
constructor(length) {
|
|
38
|
+
super(length);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
uncast(value) {
|
|
42
|
+
return super.uncast(value, false);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
12
46
|
class Sqlite_BIGINT extends DataTypes.BIGINT {
|
|
13
47
|
constructor() {
|
|
14
48
|
super();
|
|
@@ -58,6 +92,14 @@ class Sqlite_DataTypes extends DataTypes {
|
|
|
58
92
|
static get VARBINARY() {
|
|
59
93
|
return Sqlite_VARBINARY;
|
|
60
94
|
}
|
|
95
|
+
|
|
96
|
+
static get DATEONLY() {
|
|
97
|
+
return Sqlite_DATEONLY;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static get INTEGER() {
|
|
101
|
+
return Sqlite_INTEGER;
|
|
102
|
+
}
|
|
61
103
|
}
|
|
62
104
|
|
|
63
105
|
module.exports = Sqlite_DataTypes;
|
package/src/expr_formatter.js
CHANGED
|
@@ -208,7 +208,7 @@ function coerceLiteral(spell, ast) {
|
|
|
208
208
|
if (arg.type === 'literal') {
|
|
209
209
|
// { params: { $like: '%foo%' } }
|
|
210
210
|
if (attribute.jsType === JSON && typeof arg.value === 'string') continue;
|
|
211
|
-
arg.value = attribute.uncast(arg.value);
|
|
211
|
+
arg.value = attribute.uncast(arg.value, false);
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
}
|
package/src/realm.js
CHANGED
|
@@ -8,6 +8,7 @@ const { findDriver } = require('./drivers');
|
|
|
8
8
|
const { camelCase } = require('./utils/string');
|
|
9
9
|
const sequelize = require('./adapters/sequelize');
|
|
10
10
|
const Raw = require('./raw');
|
|
11
|
+
const { LEGACY_TIMESTAMP_MAP } = require('./constants');
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
*
|
|
@@ -39,12 +40,6 @@ async function findModels(dir) {
|
|
|
39
40
|
return models;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
const LEGACY_TIMESTAMP_MAP = {
|
|
43
|
-
gmtCreate: 'createdAt',
|
|
44
|
-
gmtModified: 'updatedAt',
|
|
45
|
-
gmtDeleted: 'deletedAt',
|
|
46
|
-
};
|
|
47
|
-
|
|
48
43
|
/**
|
|
49
44
|
* construct model attributes entirely from column definitions
|
|
50
45
|
* @param {Bone} model
|
package/src/spell.js
CHANGED
|
@@ -11,7 +11,7 @@ const { isPlainObject } = require('./utils');
|
|
|
11
11
|
const { IndexHint, INDEX_HINT_TYPE, Hint } = require('./hint');
|
|
12
12
|
const { parseObject } = require('./query_object');
|
|
13
13
|
const Raw = require('./raw');
|
|
14
|
-
const { AGGREGATOR_MAP } = require('./
|
|
14
|
+
const { AGGREGATOR_MAP } = require('./constants');
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Parse condition expressions
|