leoric 1.13.5 → 1.14.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/History.md CHANGED
@@ -1,3 +1,67 @@
1
+ 1.14.3 / 2021-11-12
2
+ ===================
3
+
4
+ ## What's Changed
5
+ * fix: logger.logQuery should be guarded in case of error by @SmartOrange in https://github.com/cyjake/leoric/pull/222
6
+ * fix: findOne without result should return null by @JimmyDaddy in https://github.com/cyjake/leoric/pull/225
7
+ * fix: Literal should support bigint type by @fengmk2 in https://github.com/cyjake/leoric/pull/226
8
+ * fix: select((name: string) => boolean) by @cyjake in https://github.com/cyjake/leoric/pull/227
9
+
10
+ **Full Changelog**: https://github.com/cyjake/leoric/compare/v1.14.2...v1.14.3
11
+
12
+ 1.14.2 / 2021-11-01
13
+ ===================
14
+
15
+ ## What's Changed
16
+ * fix: accept timestamps in snake case by @cyjake in https://github.com/cyjake/leoric/pull/221
17
+
18
+
19
+ **Full Changelog**: https://github.com/cyjake/leoric/compare/v1.14.1...v1.14.2
20
+
21
+ 1.14.1 / 2021-11-01
22
+ ===================
23
+
24
+ ## What's Changed
25
+ * docs: export { Collection } by @cyjake in https://github.com/cyjake/leoric/pull/220
26
+
27
+
28
+ **Full Changelog**: https://github.com/cyjake/leoric/compare/v1.14.0...v1.14.1
29
+
30
+ 1.14.0 / 2021-11-01
31
+ ===================
32
+
33
+ Two options regarding `Model.init()` were added in this release:
34
+
35
+ ```js
36
+ class User extends Bone {}
37
+ User.init({ name: STRING }, {
38
+ timestamps: true, // which is the default
39
+ paranoid: true, // which default to `false`
40
+ });
41
+ assert.deepEqual(Object.keys(User.attributes), [
42
+ 'id',
43
+ 'name',
44
+ 'createdAt',
45
+ 'updatedAt',
46
+ 'deletedAt',
47
+ ]);
48
+ ```
49
+
50
+ ## What's Changed
51
+ * docs: update 'primayKey' typos by @freshgum-bubbles in https://github.com/cyjake/leoric/pull/211
52
+ * docs: DataTypes definitions in d.ts by @cyjake in https://github.com/cyjake/leoric/pull/210
53
+ * fix: fix#209 sequelize mode should update all changed fields in instance update method by @JimmyDaddy in https://github.com/cyjake/leoric/pull/212
54
+ * fix: fix #213 findAndCountAll should ignore attributes by @JimmyDaddy in https://github.com/cyjake/leoric/pull/214
55
+ * fix: opts.connectTimeout by @cyjake in https://github.com/cyjake/leoric/pull/216
56
+ * fix: reload instance with sharding key should not throw by @cyjake in https://github.com/cyjake/leoric/pull/217
57
+ * feat: timestamps should be defined by default by @cyjake in https://github.com/cyjake/leoric/pull/218
58
+ * fix: instance.reload() should not rely on `static findOne()` by @cyjake in https://github.com/cyjake/leoric/pull/219
59
+
60
+ ## New Contributors
61
+ * @freshgum-bubbles made their first contribution in https://github.com/cyjake/leoric/pull/211
62
+
63
+ **Full Changelog**: https://github.com/cyjake/leoric/compare/v1.13.5...v1.14.0
64
+
1
65
  1.13.5 / 2021-10-26
2
66
  ===================
3
67
 
package/Readme.md CHANGED
@@ -48,7 +48,7 @@ If table structures were intended to be maintained in the models, Leoric can be
48
48
  const { BIGINT, STRING } = Bone.DataTypes;
49
49
  class Post extends Bone {
50
50
  static attributes = {
51
- id: { type: BIGINT, primayKey: true },
51
+ id: { type: BIGINT, primaryKey: true },
52
52
  email: { type: STRING, allowNull: false },
53
53
  nickname: { type: STRING, allowNull: false },
54
54
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leoric",
3
- "version": "1.13.5",
3
+ "version": "1.14.3",
4
4
  "description": "JavaScript Object-relational mapping alchemy",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -331,6 +331,7 @@ module.exports = Bone => {
331
331
  let spell = this._find({}, filterOptions(options));
332
332
  translateOptions(spell, options);
333
333
  let spellCount = this._find({}, filterOptions(options));
334
+ delete options.attributes;
334
335
  translateOptions(spellCount, options);
335
336
  delete spellCount.rowCount;
336
337
  delete spellCount.skip;
@@ -378,7 +379,7 @@ module.exports = Bone => {
378
379
  // findAll maybe override by developer, that will make it return a non-Spell object
379
380
  spell = this._find({}, filterOptions(options));
380
381
  translateOptions(spell, { ...options, limit: 1 });
381
- spell = spell.later(result => result[0]);
382
+ spell = spell.later(result => result[0] != null? result[0]: null);
382
383
  }
383
384
  if (options && options.paranoid === false) return spell.unparanoid;
384
385
  return spell;
@@ -496,29 +497,46 @@ module.exports = Bone => {
496
497
  async update(values = {}, options = {}) {
497
498
  const { fields } = options;
498
499
  const changeValues = {};
500
+ const originalValues = Object.assign({}, this.getRaw());
501
+ for (const name in values) {
502
+ if (values[name] !== undefined && this.hasAttribute(name)) {
503
+ // exec custom setters in case it exist
504
+ this[name] = values[name];
505
+ changeValues[name] = this.attribute(name);
506
+ }
507
+ }
508
+
499
509
  const changedKeys = this.changed();
500
510
  if (changedKeys) {
501
511
  for (const name of changedKeys) {
502
512
  // custom getter should be executed in case there is a custom setter
503
- changeValues[name] = this[name];
513
+ if (!(name in changeValues)) changeValues[name] = this[name];
504
514
  }
505
515
  }
506
516
 
507
517
  let changes = {};
508
518
  if (fields && fields.length) {
509
519
  fields.map(key => {
510
- if (values[key] !== undefined) changes[key] = values[key];
511
- else changes[key] = changeValues[key] || this.attribute(key);
520
+ if (changeValues[key] !== undefined) changes[key] = changeValues[key];
521
+ else if (values[key] !== undefined) changes[key] = values[key];
522
+ else changes[key] = this.attribute(key);
512
523
  });
513
524
  } else {
514
525
  changes = {
515
- ...changeValues,
516
526
  ...values,
527
+ ...changeValues,
517
528
  };
518
529
  }
519
- const spell = super._update(changes, options);
520
530
  // instance update don't need to be paranoid
521
- return spell.unparanoid;
531
+ options.paranoid = false;
532
+ try {
533
+ const res = await super._update(changes, options);
534
+ return res;
535
+ } catch (err) {
536
+ // revert value in case update failed
537
+ this._setRaw(originalValues);
538
+ throw err;
539
+ }
522
540
  }
523
541
 
524
542
  // EXISTS
package/src/bone.js CHANGED
@@ -15,12 +15,6 @@ const { capitalize, camelCase, snakeCase } = require('./utils/string');
15
15
  const { hookNames, setupSingleHook } = require('./setup_hooks');
16
16
  const { logger } = require('./utils/index');
17
17
 
18
- const LEGACY_TIMESTAMP_MAP = {
19
- gmtCreate: 'createdAt',
20
- gmtModified: 'updatedAt',
21
- gmtDeleted: 'deletedAt',
22
- };
23
-
24
18
  function looseReadonly(props) {
25
19
  return Object.keys(props).reduce((result, name) => {
26
20
  result[name] = {
@@ -243,8 +237,13 @@ class Bone {
243
237
  }
244
238
 
245
239
  // protected
246
- _setRaw(key, value) {
247
- this.#raw[key] = value;
240
+ _setRaw(...args) {
241
+ const [ name, value ] = args;
242
+ if (args.length > 1) {
243
+ this.#raw[name] = value;
244
+ } else if (args.length === 1 && name !== undefined && typeof name === 'object') {
245
+ this.#raw = name;
246
+ }
248
247
  }
249
248
 
250
249
  // protected
@@ -626,13 +625,31 @@ class Bone {
626
625
  /**
627
626
  * Persist changes on current instance back to database with `UPDATE`.
628
627
  * @public
629
- * @param {Object} changes
628
+ * @param {Object} values
630
629
  * @param {Object?} options
631
630
  * @returns {number} affected rows
632
631
  * @memberof Bone
633
632
  */
634
- update(changes, options = {}) {
635
- return this._update(changes, options);
633
+ async update(values, options = {}) {
634
+ const changes = {};
635
+ const originalValues = Object.assign({}, this.#raw);
636
+ if (typeof values === 'object') {
637
+ for (const name in values) {
638
+ if (values[name] !== undefined && this.hasAttribute(name)) {
639
+ // exec custom setters in case it exist
640
+ this[name] = values[name];
641
+ changes[name] = this.attribute(name);
642
+ }
643
+ }
644
+ }
645
+ try {
646
+ const res = await this._update(Object.keys(changes).length? changes : values, options);
647
+ return res;
648
+ } catch (error) {
649
+ // revert value in case update failed
650
+ this._setRaw(originalValues);
651
+ throw error;
652
+ }
636
653
  }
637
654
 
638
655
  /**
@@ -640,23 +657,19 @@ class Bone {
640
657
  * @private
641
658
  * @return {number}
642
659
  */
643
- _update(values, options = {}) {
644
- const changes = {};
660
+ async _update(values, options = {}) {
645
661
  const Model = this.constructor;
646
662
  const { attributes, primaryKey, shardingKey } = Model;
647
-
663
+ let changes = {};
648
664
  if (values == null) {
649
665
  for (const name in attributes) {
650
666
  if (this.changed(name)) changes[name] = this.attribute(name);
651
667
  }
652
- } else if (typeof values === 'object') {
653
- for (const name in values) {
654
- const originValue = this.attribute(name);
655
- // exec custom setters in case it exist
656
- this[name] = values[name];
657
- changes[name] = this.attribute(name);
658
- // revert value in case update failed
659
- this.attribute(name, originValue);
668
+ } else {
669
+ for (const key in values) {
670
+ if (values[key] !== undefined && this.hasAttribute(key)) {
671
+ changes[key] = values[key];
672
+ }
660
673
  }
661
674
  }
662
675
 
@@ -676,7 +689,7 @@ class Bone {
676
689
  this._validateAttributes(changes);
677
690
  }
678
691
  const spell = new Spell(Model, options).$where(where).$update(changes);
679
- return spell.later(result => {
692
+ return await spell.later(result => {
680
693
  // sync changes (changes has been formatted by custom setters, use this.attribute(name, value) directly)
681
694
  for (const key in changes) {
682
695
  this.attribute(key, changes[key]);
@@ -737,11 +750,13 @@ class Bone {
737
750
  }
738
751
 
739
752
  async reload() {
740
- const { primaryKey } = this.constructor;
741
- const instance = await this.constructor.findOne(this[primaryKey]).unscoped;
742
- if (instance) {
743
- this._clone(instance);
744
- }
753
+ const { primaryKey, shardingKey } = this.constructor;
754
+ const conditions = { [primaryKey]: this[primaryKey] };
755
+ if (shardingKey) conditions[shardingKey] = this[shardingKey];
756
+ const spell = this.constructor._find(conditions).$get(0);
757
+ spell.scopes = [];
758
+ const instance = await spell;
759
+ if (instance) this._clone(instance);
745
760
  return instance;
746
761
  }
747
762
 
@@ -894,27 +909,6 @@ class Bone {
894
909
  Object.assign(attribute, { jsType });
895
910
  }
896
911
 
897
- static normalize(attributes) {
898
- for (const name in LEGACY_TIMESTAMP_MAP) {
899
- const newName = LEGACY_TIMESTAMP_MAP[name];
900
- if (attributes.hasOwnProperty(name) && !attributes.hasOwnProperty(newName)) {
901
- attributes[newName] = attributes[name];
902
- delete attributes[name];
903
- }
904
- }
905
-
906
- // if there is no primaryKey added, add it to attributes automatically
907
- if (Object.values(attributes).every(attribute => !attribute.primaryKey)) {
908
- attributes[this.primaryKey] = {
909
- type: new DataTypes.BIGINT(),
910
- allowNull: false,
911
- autoIncrement: true,
912
- primaryKey: true,
913
- columnName: snakeCase(this.primaryKey),
914
- };
915
- }
916
- }
917
-
918
912
  /**
919
913
  * Generate attributes from column definitions.
920
914
  * @private
@@ -927,7 +921,18 @@ class Bone {
927
921
  const table = this.table || snakeCase(pluralize(this.name));
928
922
  const tableAlias = camelCase(pluralize(this.name || table));
929
923
 
930
- this.normalize(attributes);
924
+ // if there is no primaryKey added, add it to attributes automatically
925
+ if (Object.values(attributes).every(attribute => !attribute.primaryKey)) {
926
+ attributes[this.primaryKey] = {
927
+ type: new DataTypes.BIGINT(),
928
+ allowNull: false,
929
+ autoIncrement: true,
930
+ columnName: snakeCase(this.primaryKey),
931
+ ...attributes[this.primaryKey],
932
+ primaryKey: true,
933
+ };
934
+ }
935
+
931
936
  for (const name of Object.keys(attributes)) {
932
937
  const attribute = new Attribute(name, attributes[name], options.define);
933
938
  attributeMap[attribute.columnName] = attribute;
@@ -936,13 +941,15 @@ class Bone {
936
941
 
937
942
  const primaryKey = Object.keys(attributes).find(key => attributes[key].primaryKey);
938
943
  const timestamps = {};
939
- for (const name of [ 'createdAt', 'updatedAt', 'deletedAt' ]) {
940
- if (attributes.hasOwnProperty(name)) timestamps[name] = name;
941
- if (attributes.hasOwnProperty(snakeCase(name))) {
942
- timestamps[name] = snakeCase(name);
944
+ for (const key of [ 'createdAt', 'updatedAt', 'deletedAt' ]) {
945
+ const name = attributes.hasOwnProperty(key) ? key : snakeCase(key);
946
+ const attribute = attributes[name];
947
+
948
+ if (!attribute) continue;
949
+ if (columns.some(column => column.columnName === attribute.columnName)) {
950
+ timestamps[key] = name;
943
951
  }
944
952
  }
945
-
946
953
  for (const name in attributes) this.loadAttribute(name);
947
954
 
948
955
  Object.defineProperties(this, looseReadonly({
@@ -1498,14 +1505,25 @@ class Bone {
1498
1505
  }
1499
1506
 
1500
1507
  static init(attributes = {}, opts = {}, overrides = {}) {
1501
- const { hooks, tableName: table } = {
1508
+ const { hooks, paranoid, tableName: table, timestamps } = {
1502
1509
  underscored: true,
1510
+ timestamps: true,
1503
1511
  tableName: this.table,
1504
1512
  hooks: {},
1505
1513
  ...(this.options && this.options.define),
1506
1514
  ...opts,
1507
1515
  };
1508
1516
 
1517
+ if (timestamps) {
1518
+ const names = [ 'createdAt', 'updatedAt' ];
1519
+ if (paranoid) names.push('deletedAt');
1520
+ for (const name of names) {
1521
+ if (!attributes[name] && !attributes[snakeCase(name)]) {
1522
+ attributes[name] = DataTypes.DATE;
1523
+ }
1524
+ }
1525
+ }
1526
+
1509
1527
  const customDescriptors = Object.getOwnPropertyDescriptors(overrides);
1510
1528
  Object.defineProperties(this.prototype, customDescriptors);
1511
1529
 
@@ -1514,6 +1532,7 @@ class Bone {
1514
1532
  if (typeof method === 'function') result[key] = method;
1515
1533
  return result;
1516
1534
  }, {});
1535
+
1517
1536
  Object.defineProperties(this, looseReadonly({ ...hookMethods, attributes, table }));
1518
1537
  }
1519
1538
 
@@ -105,17 +105,17 @@ class Attribute {
105
105
  });
106
106
  }
107
107
 
108
- equals(targetAttribute) {
109
- if (!targetAttribute) return false;
110
- const props = [ 'dataType', 'allowNull', 'primaryKey' ];
108
+ equals(columnInfo) {
109
+ if (!columnInfo) return false;
110
+ const props = [ 'allowNull', 'dataType', 'primaryKey' ];
111
111
  for (const prop of props) {
112
112
  // SQLite has default value as string even if data type is integer
113
- if (this[prop] != targetAttribute[prop]) {
113
+ if (this[prop] != columnInfo[prop]) {
114
114
  debug('[attribute] [%s] %s not equal (defined: %s, actual: %s)',
115
115
  this.columnName,
116
116
  prop,
117
117
  this[prop],
118
- targetAttribute[prop]);
118
+ columnInfo[prop]);
119
119
  return false;
120
120
  }
121
121
  }
@@ -24,6 +24,14 @@ class Logger {
24
24
  return SqlString.format(query.sql || query, values);
25
25
  }
26
26
 
27
+ tryLogQuery() {
28
+ try {
29
+ this.logQuery(...arguments);
30
+ } catch (error) {
31
+ console.error(error);
32
+ }
33
+ }
34
+
27
35
  logQuery(sql, duration, opts) {
28
36
  debug('[query] [%s] %s', duration, sql);
29
37
  }
@@ -18,6 +18,8 @@ class MysqlDriver extends AbstractDriver {
18
18
  * @param {string} opts.appName - In some RDMS, appName is used as the actual name of the database
19
19
  * @param {string} opts.database
20
20
  * @param {string} opts.connectionLimit
21
+ * @param {number} opts.connectTimeout - The milliseconds before a timeout occurs during the initial connection to the MySQL server. (Default: `10000`)
22
+ * @param {string} opts.charset
21
23
  * @param {boolean} opts.stringifyObjects - stringify object value in dataValues
22
24
  */
23
25
  constructor(opts = {}) {
@@ -37,7 +39,7 @@ class MysqlDriver extends AbstractDriver {
37
39
  const client = opts.client || 'mysql';
38
40
  const {
39
41
  host, port, user, password,
40
- connectionLimit, charset, stringifyObjects = false,
42
+ connectTimeout, connectionLimit, charset, stringifyObjects = true,
41
43
  } = opts;
42
44
 
43
45
  if (client !== 'mysql' && client !== 'mysql2') {
@@ -46,6 +48,7 @@ class MysqlDriver extends AbstractDriver {
46
48
 
47
49
  return require(client).createPool({
48
50
  connectionLimit,
51
+ connectTimeout,
49
52
  host,
50
53
  port,
51
54
  user,
@@ -93,7 +96,7 @@ class MysqlDriver extends AbstractDriver {
93
96
  if (!opts.connection) connection.release();
94
97
  }
95
98
 
96
- logger.logQuery(sql, Date.now() - start, opts);
99
+ logger.tryLogQuery(sql, Date.now() - start, opts);
97
100
  const [ results, fields ] = result;
98
101
  if (fields) return { rows: results, fields };
99
102
  return results;
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const debug = require('debug')('leoric');
4
+
3
5
  const Attribute = require('../abstract/attribute');
4
6
  const DataTypes = require('./data_types');
5
7
  const { escape, escapeId } = require('./sqlstring');
@@ -32,6 +34,30 @@ class PostgresAttribute extends Attribute {
32
34
  }
33
35
  return chunks.join(' ');
34
36
  }
37
+
38
+
39
+ equals(columnInfo) {
40
+ if (!columnInfo) return false;
41
+ if (this.type.toSqlString() !== columnInfo.columnType.toUpperCase()) {
42
+ debug('[attribute] [%s] columnType not equal (defined: %s, actual: %s)',
43
+ this.columnName,
44
+ this.type.toSqlString(),
45
+ columnInfo.columnType.toUpperCase());
46
+ return false;
47
+ }
48
+ const props = [ 'allowNull', 'defaultValue', 'primaryKey' ];
49
+ for (const prop of props) {
50
+ if (this[prop] != columnInfo[prop]) {
51
+ debug('[attribute] [%s] %s not equal (defined: %s, actual: %s)',
52
+ this.columnName,
53
+ prop,
54
+ this[prop],
55
+ columnInfo[prop]);
56
+ return false;
57
+ }
58
+ }
59
+ return true;
60
+ }
35
61
  }
36
62
 
37
63
  module.exports = PostgresAttribute;
@@ -141,7 +141,7 @@ class PostgresDriver extends AbstractDriver {
141
141
  if (!spell.connection) connection.release();
142
142
  }
143
143
 
144
- logger.logQuery(formatted, Date.now() - start, spell);
144
+ logger.tryLogQuery(formatted, Date.now() - start, spell);
145
145
  return result;
146
146
  }
147
147
 
@@ -53,7 +53,7 @@ module.exports = {
53
53
  for (const row of rows) {
54
54
  const tableName = row.table_name;
55
55
  const columns = schemaInfo[tableName] || (schemaInfo[tableName] = []);
56
- let { data_type: dataType, character_octet_length: length } = row;
56
+ let { data_type: dataType, character_maximum_length: length } = row;
57
57
 
58
58
  if (dataType === 'character varying') dataType = 'varchar';
59
59
  if (dataType === 'timestamp without time zone') dataType = 'timestamp';
@@ -52,7 +52,7 @@ class SqliteDriver extends AbstractDriver {
52
52
  if (!opts.connection) connection.release();
53
53
  }
54
54
 
55
- logger.logQuery(sql, Date.now() - start, opts);
55
+ logger.tryLogQuery(sql, Date.now() - start, opts);
56
56
  return result;
57
57
  }
58
58
 
@@ -11,7 +11,7 @@ const { precedes, walkExpr } = require('./expr');
11
11
  * @param {Spell} spell
12
12
  * @param {string[]} qualifiers
13
13
  */
14
- function findModel(spell, qualifiers) {
14
+ function findModel(spell, qualifiers) {
15
15
  const qualifier = qualifiers && qualifiers[0];
16
16
  const Model = qualifier && qualifier != spell.Model.tableAlias
17
17
  ? (spell.joins.hasOwnProperty(qualifier) ? spell.joins[qualifier].Model : null)
package/src/realm.js CHANGED
@@ -38,6 +38,17 @@ async function findModels(dir) {
38
38
  return models;
39
39
  }
40
40
 
41
+ const LEGACY_TIMESTAMP_MAP = {
42
+ gmtCreate: 'createdAt',
43
+ gmtModified: 'updatedAt',
44
+ gmtDeleted: 'deletedAt',
45
+ };
46
+
47
+ /**
48
+ * construct model attributes entirely from column definitions
49
+ * @param {Bone} model
50
+ * @param {Array<string, Object>} columns column definitions
51
+ */
41
52
  function initAttributes(model, columns) {
42
53
  const attributes = {};
43
54
 
@@ -52,7 +63,15 @@ function initAttributes(model, columns) {
52
63
  };
53
64
  }
54
65
 
55
- model.init(attributes);
66
+ for (const name in LEGACY_TIMESTAMP_MAP) {
67
+ const newName = LEGACY_TIMESTAMP_MAP[name];
68
+ if (attributes.hasOwnProperty(name) && !attributes.hasOwnProperty(newName)) {
69
+ attributes[newName] = attributes[name];
70
+ delete attributes[name];
71
+ }
72
+ }
73
+
74
+ model.init(attributes, { timestamps: false });
56
75
  }
57
76
 
58
77
  async function loadModels(Spine, models, opts) {
@@ -0,0 +1,88 @@
1
+ type LENGTH_VARIANTS = 'tiny' | '' | 'medium' | 'long';
2
+
3
+ interface INVOKABLE<T> {
4
+ (length: LENGTH_VARIANTS): T;
5
+ (length: number): T;
6
+ }
7
+
8
+ export default class DataType {
9
+ toSqlString(): string;
10
+
11
+ static STRING: typeof STRING & INVOKABLE<STRING>;
12
+ static INTEGER: typeof INTEGER & INVOKABLE<INTEGER>;
13
+ static BIGINT: typeof BIGINT & INVOKABLE<BIGINT>;
14
+ static TEXT: typeof TEXT & INVOKABLE<TEXT>;
15
+ static BLOB: typeof BLOB & INVOKABLE<BLOB>;
16
+ static JSON: typeof JSON & INVOKABLE<JSON>;
17
+ static JSONB: typeof JSONB & INVOKABLE<JSONB>;
18
+ static BINARY: typeof BINARY & INVOKABLE<BINARY>;
19
+ static VARBINARY: typeof VARBINARY & INVOKABLE<VARBINARY>;
20
+ static DATE: typeof DATE & INVOKABLE<DATE>;
21
+ static DATEONLY: typeof DATEONLY & INVOKABLE<DATEONLY>;
22
+ static BOOLEAN: typeof BOOLEAN & INVOKABLE<BOOLEAN>;
23
+ }
24
+
25
+ declare class STRING extends DataType {
26
+ dataType: 'varchar';
27
+ length: number;
28
+ constructor(length: number);
29
+ }
30
+
31
+ declare class INTEGER extends DataType {
32
+ dataType: 'integer' | 'bigint';
33
+ length: number;
34
+ constructor(length: number);
35
+ get UNSIGNED(): this;
36
+ get ZEROFILL(): this;
37
+ }
38
+
39
+ declare class BIGINT extends INTEGER {
40
+ dataType: 'bigint';
41
+ }
42
+
43
+ declare class TEXT extends DataType {
44
+ dataType: 'text';
45
+ length: LENGTH_VARIANTS;
46
+ constructor(length: LENGTH_VARIANTS);
47
+ }
48
+
49
+ declare class BLOB extends DataType {
50
+ dataType: 'blob';
51
+ length: LENGTH_VARIANTS;
52
+ constructor(length: LENGTH_VARIANTS)
53
+ }
54
+
55
+ declare class JSON extends DataType {
56
+ dataType: 'text' | 'json';
57
+ }
58
+
59
+ declare class JSONB extends JSON {
60
+ dataType: 'json';
61
+ }
62
+
63
+ declare class BINARY extends DataType {
64
+ dataType: 'binary';
65
+ length: number;
66
+ constructor(length: number);
67
+ }
68
+
69
+ declare class VARBINARY extends DataType {
70
+ dataType: 'varbinary';
71
+ length: number;
72
+ constructor(length: number);
73
+ }
74
+
75
+ declare class DATE extends DataType {
76
+ dataType: 'date';
77
+ precision: number;
78
+ timezone: boolean;
79
+ constructor(precision: number, timezone?: boolean)
80
+ }
81
+
82
+ declare class DATEONLY extends DataType {
83
+ dataType: 'dateonly';
84
+ }
85
+
86
+ declare class BOOLEAN extends DataType {
87
+ dataType: 'boolean'
88
+ }
package/types/index.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ import DataType from './data_types';
2
+
3
+ export { DataType as DataTypes };
4
+
5
+ type DataTypes<T> = {
6
+ [Property in keyof T as Exclude<Property, "toSqlString">]: T[Property]
7
+ }
8
+
1
9
  interface ExprIdentifier {
2
10
  type: 'id';
3
11
  value: string;
@@ -52,10 +60,10 @@ type WithOptions = {
52
60
  [qualifier: string]: { select: string | string[], throughRelation?: string }
53
61
  }
54
62
 
55
- declare class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<InstanceType<T>> | ResultSet | number | null> extends Promise<U> {
63
+ export class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<InstanceType<T>> | ResultSet | number | null> extends Promise<U> {
56
64
  constructor(Model: T, opts: SpellOptions);
57
65
 
58
- select(...names: Array<string | RawSql>): Spell<T, U>;
66
+ select(...names: Array<string | RawSql> | Array<(name: string) => boolean>): Spell<T, U>;
59
67
  insert(opts: SetOptions): Spell<T, number>;
60
68
  update(opts: SetOptions): Spell<T, number>;
61
69
  upsert(opts: SetOptions): Spell<T, number>;
@@ -103,7 +111,7 @@ declare class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<Inst
103
111
  toString(): string;
104
112
  }
105
113
 
106
- type Literal = null | undefined | boolean | number | string | Date | object | ArrayBuffer;
114
+ type Literal = null | undefined | boolean | number | bigint | string | Date | object | ArrayBuffer;
107
115
 
108
116
  type OperatorCondition = {
109
117
  [key in '$eq' | '$ne']?: Literal;
@@ -129,21 +137,15 @@ type InstanceValues<T> = {
129
137
  [Property in keyof Extract<T, Literal>]?: Extract<T, Literal>[Property]
130
138
  }
131
139
 
132
- declare class DataType {}
133
-
134
- export const DataTypes: {
135
- [key in 'STRING' | 'INTEGER' | 'BIGINT' | 'DATE' | 'BOOLEAN' | 'TEXT' | 'BLOB' | 'JSON' | 'JSONB' | 'BINARY' | 'VARBINARY' ]: DataType;
136
- };
137
-
138
140
  interface AttributeMeta {
139
- column: string;
140
- columnType: string;
141
- allowNull: boolean;
142
- defaultValue: Literal;
143
- primaryKey: boolean;
144
- dataType: string;
145
- jsType: Literal;
146
- type: DataType;
141
+ column?: string;
142
+ columnType?: string;
143
+ allowNull?: boolean;
144
+ defaultValue?: Literal;
145
+ primaryKey?: boolean;
146
+ dataType?: string;
147
+ jsType?: Literal;
148
+ type: DataTypes<DataType>;
147
149
  }
148
150
 
149
151
  interface RelateOptions {
@@ -205,15 +207,17 @@ type ResultSet = {
205
207
  [key: string]: Literal
206
208
  };
207
209
 
208
- declare class Collection<T extends Bone> extends Array<T> {
210
+ export class Collection<T extends Bone> extends Array<T> {
209
211
  save(): Promise<void>;
210
212
  toJSON(): Object[];
211
213
  toObject(): Object[];
212
214
  }
213
215
 
214
216
  export class Bone {
217
+ static DataTypes: DataType;
218
+
215
219
  /**
216
- * The connection pool of the specified client, with few `Leoric_` prefixed methods extended to eliminate client differences.
220
+ * get the connection pool of the driver
217
221
  */
218
222
  static pool: Pool;
219
223
 
@@ -250,7 +254,7 @@ export class Bone {
250
254
  /**
251
255
  * The attribute definitions of the model.
252
256
  */
253
- static attributes: { [key: string]: DataType | AttributeMeta };
257
+ static attributes: { [key: string]: DataTypes<DataType> | AttributeMeta };
254
258
 
255
259
  /**
256
260
  * The schema info of current model.
@@ -617,7 +621,7 @@ interface RawQueryOptions {
617
621
  }
618
622
 
619
623
  export default class Realm {
620
- Bone: Bone;
624
+ Bone: typeof Bone;
621
625
  driver: Driver;
622
626
  models: Record<string, Bone>;
623
627