leoric 2.6.2 → 2.7.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/src/decorators.ts CHANGED
@@ -1,17 +1,24 @@
1
1
  import Bone from './bone';
2
- import DataType from './data_types';
2
+ import DataTypes, { DataType, AbstractDataType } from './data_types';
3
3
  import { ASSOCIATE_METADATA_MAP } from './constants';
4
4
  import 'reflect-metadata';
5
5
 
6
- type DataTypes<T> = {
7
- [Property in keyof T as Exclude<Property, "toSqlString">]: T[Property];
8
- }
6
+ type Literal = null | undefined | boolean | number | bigint | string | Date | object | ArrayBuffer;
7
+ type BaseValidateArgs = boolean | RegExp | Function | Array<Array<Literal>> | string;
9
8
 
10
9
  interface ColumnOption {
11
- type?: DataTypes<DataType>;
10
+ type?: AbstractDataType<DataType>;
12
11
  name?: string;
13
- defaultValue?: null | boolean | number | string | Date | JSON;
12
+ defaultValue?: Literal;
14
13
  allowNull?: boolean;
14
+ primaryKey?: boolean;
15
+ columnName?: string;
16
+ validate?: {
17
+ [key: string]: BaseValidateArgs | {
18
+ args: BaseValidateArgs;
19
+ msg: string;
20
+ };
21
+ }
15
22
  }
16
23
 
17
24
  function findType(tsType) {
@@ -20,7 +27,7 @@ function findType(tsType) {
20
27
  DATE,
21
28
  STRING,
22
29
  BOOLEAN,
23
- } = DataType;
30
+ } = DataTypes;
24
31
 
25
32
  switch (tsType) {
26
33
  case BigInt:
@@ -38,9 +45,13 @@ function findType(tsType) {
38
45
  }
39
46
  }
40
47
 
41
- export function Column(options: ColumnOption | DataTypes<DataType> = {}) {
48
+ export function Column(options?: ColumnOption | AbstractDataType<DataType>) {
42
49
  return function(target: Bone, propertyKey: string) {
43
- if (options['prototype'] instanceof DataType) options = { type: options };
50
+ if (options == null) {
51
+ options = {};
52
+ }
53
+ // target refers to model prototype, an internal instance of `Bone {}`
54
+ if (options['prototype'] instanceof DataType) options = { type: options as AbstractDataType<DataType> };
44
55
 
45
56
  if (!('type' in options)) {
46
57
  const tsType = Reflect.getMetadata('design:type', target, propertyKey);
@@ -36,8 +36,8 @@ class AbstractDriver {
36
36
 
37
37
  /**
38
38
  * query with spell
39
- * @param {Spell} spell
40
- * @returns
39
+ * @param {Spell} spell
40
+ * @returns
41
41
  */
42
42
  async cast(spell) {
43
43
  const { sql, values } = this.format(spell);
@@ -47,9 +47,9 @@ class AbstractDriver {
47
47
 
48
48
  /**
49
49
  * raw query
50
- * @param {object|string} query
51
- * @param {object | array} values
52
- * @param {object} opts
50
+ * @param {object|string} query
51
+ * @param {object | array} values
52
+ * @param {object} opts
53
53
  */
54
54
  async query(query, values, opts) {
55
55
  throw new Error('unimplemented!');
@@ -57,7 +57,7 @@ class AbstractDriver {
57
57
 
58
58
  /**
59
59
  * disconnect manually
60
- * @param {Function} callback
60
+ * @param {Function} callback
61
61
  */
62
62
  async disconnect(callback) {
63
63
  debug('[disconnect] called');
@@ -69,8 +69,8 @@ class AbstractDriver {
69
69
 
70
70
  /**
71
71
  * use spellbook to format spell
72
- * @param {Spell} spell
73
- * @returns
72
+ * @param {Spell} spell
73
+ * @returns
74
74
  */
75
75
  format(spell) {
76
76
  return this.spellbook.format(spell);
@@ -163,11 +163,11 @@ class SpellBook {
163
163
  const { shardingKey } = Model;
164
164
  const { createdAt } = Model.timestamps;
165
165
  const { escapeId } = Model.driver;
166
- let columns = [];
167
- let updateOnDuplicateColumns = [];
166
+ const columns = [];
167
+ const updateOnDuplicateColumns = [];
168
168
 
169
- let values = [];
170
- let placeholders = [];
169
+ const values = [];
170
+ const placeholders = [];
171
171
  if (Array.isArray(sets)) {
172
172
  // merge records to get the big picture of involved columnAttributes
173
173
  const involved = sets.reduce((result, entry) => {
@@ -318,7 +318,7 @@ class SpellBook {
318
318
  spell.updateOnDuplicate = true;
319
319
  }
320
320
 
321
- let { sql, values } = this.formatInsert(spell);
321
+ const { sql, values } = this.formatInsert(spell);
322
322
  return {
323
323
  sql,
324
324
  values,
@@ -347,7 +347,7 @@ class SpellBook {
347
347
  * @param {Array} columns columns for value set
348
348
  */
349
349
  formatUpdateOnDuplicate(spell, columns) {
350
- const { updateOnDuplicate, uniqueKeys, Model } = spell;
350
+ const { updateOnDuplicate, uniqueKeys, Model, sets } = spell;
351
351
  if (!updateOnDuplicate) return '';
352
352
  const { columnAttributes, primaryColumn } = Model;
353
353
  const { escapeId } = Model.driver;
@@ -358,25 +358,27 @@ class SpellBook {
358
358
  actualUniqueKeys.push(escapeId(field));
359
359
  }
360
360
  } else {
361
+ const setFields = Object.keys(sets);
361
362
  // conflict_target must be unique
362
363
  // get all unique keys
363
364
  if (columnAttributes) {
364
365
  for (const key in columnAttributes) {
365
366
  const att = columnAttributes[key];
366
367
  // use the first unique key
367
- if (att.unique) {
368
+ if (att.unique || (att.primaryKey && setFields.includes(att.name))) {
368
369
  actualUniqueKeys.push(escapeId(att.columnName));
369
370
  break;
370
371
  }
371
372
  }
372
373
  }
374
+
373
375
  if (!actualUniqueKeys.length) actualUniqueKeys.push(escapeId(primaryColumn));
374
376
  // default use id as primary key
375
377
  if (!actualUniqueKeys.length) actualUniqueKeys.push(escapeId('id'));
376
378
  }
377
379
 
378
380
  if (Array.isArray(updateOnDuplicate) && updateOnDuplicate.length) {
379
- columns = updateOnDuplicate.map(column => (columnAttributes[column] && columnAttributes[column].columnName )|| column);
381
+ columns = updateOnDuplicate.map(column => (columnAttributes[column] && columnAttributes[column].columnName)|| column);
380
382
  } else if (!columns.length) {
381
383
  columns = Object.values(columnAttributes).map(({ columnName }) => columnName);
382
384
  }
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const DataTypes = require('../../data_types');
3
+ const { default: DataTypes } = require('../../data_types');
4
4
 
5
5
  class Mysql_BOOLEAN extends DataTypes.BOOLEAN {
6
6
  constructor() {
@@ -18,7 +18,6 @@ class MysqlDriver extends AbstractDriver {
18
18
 
19
19
  /**
20
20
  * Create a connection pool
21
- * @param {string} clientName
22
21
  * @param {Object} opts
23
22
  * @param {string} opts.host
24
23
  * @param {string} opts.port
@@ -30,6 +29,7 @@ class MysqlDriver extends AbstractDriver {
30
29
  * @param {number} opts.connectTimeout - The milliseconds before a timeout occurs during the initial connection to the MySQL server. (Default: `10000`)
31
30
  * @param {string} opts.charset
32
31
  * @param {boolean} opts.stringifyObjects - stringify object value in dataValues
32
+ * @param {string} opts.client
33
33
  */
34
34
  constructor(opts = {}) {
35
35
  super(opts);
@@ -50,10 +50,11 @@ class MysqlDriver extends AbstractDriver {
50
50
  const {
51
51
  host, port, user, password,
52
52
  connectTimeout, connectionLimit, charset, stringifyObjects = true,
53
+ decimalNumbers = true,
53
54
  } = opts;
54
55
 
55
56
  if (client !== 'mysql' && client !== 'mysql2') {
56
- throw new Error(`Unsupported mysql client ${client}`);
57
+ console.warn(`[leoric] mysql client "${client}" not tested`);
57
58
  }
58
59
 
59
60
  return require(client).createPool({
@@ -66,6 +67,7 @@ class MysqlDriver extends AbstractDriver {
66
67
  database,
67
68
  charset,
68
69
  stringifyObjects,
70
+ decimalNumbers,
69
71
  });
70
72
  }
71
73
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const DataTypes = require('../../data_types');
3
+ const { default: DataTypes } = require('../../data_types');
4
4
  const util = require('util');
5
5
  const Raw = require('../../raw');
6
6
 
@@ -29,7 +29,7 @@ class Postgres_JSONB extends DataTypes.JSONB {
29
29
  }
30
30
  }
31
31
 
32
- class Postgres_BINARY extends DataTypes {
32
+ class Postgres_BINARY extends DataTypes.BINARY {
33
33
  constructor() {
34
34
  super();
35
35
  this.dataType = 'bytea';
@@ -5,7 +5,7 @@ const { performance } = require('perf_hooks');
5
5
  const AbstractDriver = require('../abstract');
6
6
  const Attribute = require('./attribute');
7
7
  const DataTypes = require('./data_types');
8
- const {
8
+ const {
9
9
  escape, escapeId, formatAddColumn,
10
10
  formatAlterColumns, formatDropColumn,
11
11
  cast, nest, parameterize,
@@ -36,6 +36,9 @@ class PostgresDriver extends AbstractDriver {
36
36
 
37
37
  createPool(opts) {
38
38
  const { host, port, user, password, database } = opts;
39
+ // dynamic require pg type parse
40
+ // if not use pg, pg-types may not exits
41
+ require('./type_parser');
39
42
  return new (require('pg')).Pool({ host, port, user, password, database });
40
43
  }
41
44
 
@@ -124,7 +127,8 @@ class PostgresDriver extends AbstractDriver {
124
127
  for (const row of rows) {
125
128
  const tableName = row.table_name;
126
129
  const columns = schemaInfo[tableName] || (schemaInfo[tableName] = []);
127
- let { data_type: dataType, character_maximum_length: length } = row;
130
+ const { character_maximum_length: length } = row;
131
+ let { data_type: dataType } = row;
128
132
 
129
133
  if (dataType === 'character varying') dataType = 'varchar';
130
134
  if (dataType === 'timestamp without time zone') dataType = 'timestamp';
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ const pgTypes = require('pg-types');
4
+
5
+ pgTypes.setTypeParser(1700, 'text', function (val) {
6
+ return Number(val);
7
+ });
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const DataTypes = require('../../data_types');
3
+ const { default: DataTypes } = require('../../data_types');
4
4
 
5
5
  class Sqlite_DATE extends DataTypes.DATE {
6
6
  constructor(precision, timezone) {
@@ -53,7 +53,7 @@ class Sqlite_BIGINT extends DataTypes.BIGINT {
53
53
  return this.dataType.toUpperCase();
54
54
  }
55
55
  }
56
- class Sqlite_BINARY extends DataTypes {
56
+ class Sqlite_BINARY extends DataTypes.BINARY {
57
57
  constructor(dataLength = 255) {
58
58
  super(dataLength);
59
59
  this.dataLength = dataLength;
package/src/realm.js CHANGED
@@ -6,6 +6,7 @@ const path = require('path');
6
6
  const Bone = require('./bone');
7
7
  const { findDriver, AbstractDriver } = require('./drivers');
8
8
  const { camelCase } = require('./utils/string');
9
+ const { isBone } = require('./utils');
9
10
  const sequelize = require('./adapters/sequelize');
10
11
  const Raw = require('./raw');
11
12
  const { LEGACY_TIMESTAMP_MAP } = require('./constants');
@@ -33,7 +34,7 @@ async function findModels(dir) {
33
34
  const extname = path.extname(entry.name);
34
35
  if (entry.isFile() && ['.js', '.mjs'].includes(extname)) {
35
36
  const model = require(path.join(dir, entry.name));
36
- if (model.prototype instanceof Bone) models.push(model);
37
+ if (isBone(model)) models.push(model);
37
38
  }
38
39
  }
39
40
 
@@ -101,11 +102,14 @@ const rReplacementKey = /\s:(\w+)\b/g;
101
102
 
102
103
  class Realm {
103
104
  constructor(opts = {}) {
104
- let { client, dialect, database, driver: CustomDriver, ...restOpts } = {
105
- dialect: 'mysql',
106
- database: opts.db || opts.storage,
107
- ...opts
108
- };
105
+ const {
106
+ dialect = 'mysql',
107
+ dialectModulePath,
108
+ client = dialectModulePath,
109
+ database = opts.db || opts.storage,
110
+ driver: CustomDriver,
111
+ ...restOpts
112
+ } = opts;
109
113
  const Spine = createSpine(opts);
110
114
  const models = {};
111
115
 
@@ -213,7 +217,7 @@ class Realm {
213
217
  const { rows, ...restRes } = await this.driver.query(query, values, opts);
214
218
  const results = [];
215
219
 
216
- if (rows && rows.length && opts.model && opts.model.prototype instanceof this.Bone) {
220
+ if (rows && rows.length && opts.model && isBone(opts.model)) {
217
221
  const { attributeMap } = opts.model;
218
222
 
219
223
  for (const data of rows) {
package/src/spell.js CHANGED
@@ -15,8 +15,8 @@ const { AGGREGATOR_MAP } = require('./constants');
15
15
 
16
16
  /**
17
17
  * check condition to avoid use virtual fields as where condtions
18
- * @param {Bone} Model
19
- * @param {Array<Object>} conds
18
+ * @param {Bone} Model
19
+ * @param {Array<Object>} conds
20
20
  */
21
21
  function checkCond(Model, conds) {
22
22
  if (Array.isArray(conds)) {
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { performance } = require('perf_hooks');
4
+ const { IS_LEORIC_BONE } = require('../constants');
4
5
 
5
6
  function isPlainObject(value) {
6
7
  return Object.prototype.toString.call(value) === '[object Object]';
@@ -43,10 +44,17 @@ const logger = {};
43
44
  };
44
45
  });
45
46
 
47
+ function isBone(bone) {
48
+ if (!bone || (typeof bone !== 'object' && typeof bone !== 'function')) return false;
49
+ const metaValue = Reflect.getMetadata(IS_LEORIC_BONE, bone);
50
+ return metaValue === true;
51
+ }
52
+
46
53
  module.exports = {
47
54
  isPlainObject,
48
55
  compose,
49
56
  getPropertyNames,
50
57
  calculateDuration,
51
58
  logger,
59
+ isBone,
52
60
  };
package/types/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import DataType from './data_types';
1
+ import DataTypes, { DataType, AbstractDataType, LENGTH_VARIANTS } from '../src/data_types';
2
2
  import { Hint, IndexHint } from './hint';
3
3
 
4
- export { DataType as DataTypes };
4
+ export { DataTypes };
5
+ export { LENGTH_VARIANTS as LENGTH_VARIANTS };
5
6
  export * from '../src/decorators';
6
7
 
7
8
  export type command = 'select' | 'insert' | 'bulkInsert' | 'update' | 'delete' | 'upsert';
@@ -12,11 +13,6 @@ export class Raw {
12
13
  type: 'raw';
13
14
  }
14
15
 
15
-
16
- type DataTypes<T> = {
17
- [Property in keyof T as Exclude<Property, "toSqlString">]: T[Property]
18
- }
19
-
20
16
  type RawQueryResult = typeof Bone | ResultSet | boolean | number;
21
17
 
22
18
  interface ExprIdentifier {
@@ -160,6 +156,8 @@ type OperatorCondition = {
160
156
 
161
157
  type WhereConditions<T extends typeof Bone> = {
162
158
  [Property in keyof Extract<InstanceType<T>, Literal>]?: Literal | Literal[] | OperatorCondition;
159
+ } | {
160
+ [key in '$and' | '$or']?: WhereConditions<T>[];
163
161
  }
164
162
 
165
163
  type Values<T extends typeof Bone> = {
@@ -186,10 +184,10 @@ declare type validator = Literal | Function | Array<Literal | Literal[]>;
186
184
 
187
185
  export interface AttributeMeta extends ColumnMeta {
188
186
  jsType?: Literal;
189
- type: DataType;
187
+ type: AbstractDataType<DataType>;
190
188
  virtual?: boolean,
191
- toSqlString: () => string;
192
- validate: {
189
+ toSqlString?: () => string;
190
+ validate?: {
193
191
  [key: string]: validator;
194
192
  }
195
193
  }
@@ -345,14 +343,14 @@ declare class AbstractDriver {
345
343
  * @param tabe table name
346
344
  * @param attributes attributes
347
345
  */
348
- createTable(tabe: string, attributes: { [key: string]: DataTypes<DataType> | AttributeMeta }): Promise<void>;
346
+ createTable(tabe: string, attributes: { [key: string]: AbstractDataType<DataType> | AttributeMeta }): Promise<void>;
349
347
 
350
348
  /**
351
349
  * alter table
352
350
  * @param tabe table name
353
351
  * @param attributes alter attributes
354
352
  */
355
- alterTable(tabe: string, attributes: { [key: string]: DataTypes<DataType> | AttributeMeta }): Promise<void>;
353
+ alterTable(tabe: string, attributes: { [key: string]: AbstractDataType<DataType> | AttributeMeta }): Promise<void>;
356
354
 
357
355
  /**
358
356
  * describe table
@@ -461,7 +459,7 @@ export class Collection<T extends Bone> extends Array<T> {
461
459
  }
462
460
 
463
461
  export class Bone {
464
- static DataTypes: typeof DataType;
462
+ static DataTypes: typeof DataTypes;
465
463
 
466
464
  /**
467
465
  * get the connection pool of the driver
@@ -501,7 +499,7 @@ export class Bone {
501
499
  /**
502
500
  * The attribute definitions of the model.
503
501
  */
504
- static attributes: { [key: string]: DataTypes<DataType> | AttributeMeta };
502
+ static attributes: { [key: string]: AbstractDataType<DataType> | AttributeMeta };
505
503
 
506
504
  /**
507
505
  * The schema info of current model.
@@ -579,6 +577,7 @@ export class Bone {
579
577
  */
580
578
  static find<T extends typeof Bone>(this: T, whereConditions: WhereConditions<T>): Spell<T, Collection<InstanceType<T>>>;
581
579
  static find<T extends typeof Bone>(this: T, whereConditions: string, ...values: Literal[]): Spell<T, Collection<InstanceType<T>>>;
580
+ static find<T extends typeof Bone>(this: T, primaryKey: number | number[]): Spell<T, Collection<InstanceType<T>>>;
582
581
  static find<T extends typeof Bone>(this: T, ): Spell<T, Collection<InstanceType<T>>>;
583
582
 
584
583
  /**
@@ -601,6 +600,7 @@ export class Bone {
601
600
  */
602
601
  static findOne<T extends typeof Bone>(this: T, whereConditions: WhereConditions<T>): Spell<T, InstanceType<T> | null>;
603
602
  static findOne<T extends typeof Bone>(this: T, whereConditions: string, ...values: Literal[]): Spell<T, InstanceType<T> | null>;
603
+ static findOne<T extends typeof Bone>(this: T, primaryKey: number | number[]): Spell<T, InstanceType<T> | null>;
604
604
  static findOne<T extends typeof Bone>(this: T, ): Spell<T, InstanceType<T> | null>;
605
605
 
606
606
  /**
@@ -877,7 +877,7 @@ interface RawQueryOptions {
877
877
 
878
878
  export default class Realm {
879
879
  Bone: typeof Bone;
880
- DataTypes: typeof DataType;
880
+ DataTypes: typeof DataTypes;
881
881
  driver: AbstractDriver;
882
882
  models: Record<string, Bone>;
883
883
  connected?: boolean;
@@ -894,7 +894,7 @@ export default class Realm {
894
894
 
895
895
  define(
896
896
  name: string,
897
- attributes: Record<string, DataTypes<DataType> | AttributeMeta>,
897
+ attributes: Record<string, AbstractDataType<DataType> | AttributeMeta>,
898
898
  options?: InitOptions,
899
899
  descriptors?: Record<string, Function>,
900
900
  ): typeof Bone;
@@ -1,105 +0,0 @@
1
- type LENGTH_VARIANTS = 'tiny' | '' | 'medium' | 'long';
2
-
3
- interface INVOKABLE<T> extends DataType {
4
- (dataLength?: LENGTH_VARIANTS): T;
5
- (dataLength?: number): T;
6
- }
7
-
8
- export default class DataType {
9
- toSqlString(): string;
10
-
11
- static STRING: INVOKABLE<STRING>;
12
- static INTEGER: INTEGER & INVOKABLE<INTEGER>;
13
- static BIGINT: BIGINT & INVOKABLE<BIGINT>;
14
- static DECIMAL: DECIMAL & INVOKABLE<DECIMAL>;
15
- static TEXT: INVOKABLE<TEXT>;
16
- static BLOB: INVOKABLE<BLOB>;
17
- static JSON: JSON;
18
- static JSONB: JSONB;
19
- static BINARY: BINARY & INVOKABLE<BINARY>;
20
- static VARBINARY: VARBINARY & INVOKABLE<VARBINARY>;
21
- static DATE: DATE & INVOKABLE<DATE>;
22
- static DATEONLY: DATEONLY;
23
- static BOOLEAN: BOOLEAN;
24
- static VIRTUAL: VIRTUAL;
25
-
26
- }
27
-
28
- declare class STRING extends DataType {
29
- dataType: 'varchar';
30
- dataLength: number;
31
- constructor(dataLength: number);
32
- }
33
-
34
- declare class INTEGER extends DataType {
35
- dataType: 'integer' | 'bigint' | 'decimal';
36
- dataLength: number;
37
- constructor(dataLength: number);
38
- // avoid INTEGER.UNSIGNED.ZEROFILL.UNSIGNED.UNSIGNED
39
- get UNSIGNED(): Omit<this, 'UNSIGNED' | 'ZEROFILL'>;
40
- get ZEROFILL(): Omit<this, 'UNSIGNED' | 'ZEROFILL'>;
41
- }
42
-
43
- declare class BIGINT extends INTEGER {
44
- dataType: 'bigint';
45
- }
46
-
47
- declare class DECIMAL_INNER extends INTEGER {
48
- dataType: 'decimal';
49
- precision: number;
50
- scale: number;
51
- constructor(precision: number, scale: number);
52
- }
53
-
54
- declare type DECIMAL = Omit<DECIMAL_INNER, 'dataLength'>;
55
-
56
- declare class TEXT extends DataType {
57
- dataType: 'text';
58
- dataLength: LENGTH_VARIANTS;
59
- constructor(dataLength: LENGTH_VARIANTS);
60
- }
61
-
62
- declare class BLOB extends DataType {
63
- dataType: 'blob';
64
- dataLength: LENGTH_VARIANTS;
65
- constructor(dataLength: LENGTH_VARIANTS)
66
- }
67
-
68
- declare class JSON extends DataType {
69
- dataType: 'text' | 'json';
70
- }
71
-
72
- declare class JSONB extends JSON {
73
- dataType: 'json';
74
- }
75
-
76
- declare class BINARY extends DataType {
77
- dataType: 'binary';
78
- dataLength: number;
79
- constructor(dataLength: number);
80
- }
81
-
82
- declare class VARBINARY extends DataType {
83
- dataType: 'varbinary';
84
- dataLength: number;
85
- constructor(dataLength: number);
86
- }
87
-
88
- declare class DATE extends DataType {
89
- dataType: 'date';
90
- precision: number;
91
- timezone: boolean;
92
- constructor(precision: number, timezone?: boolean)
93
- }
94
-
95
- declare class DATEONLY extends DataType {
96
- dataType: 'dateonly';
97
- }
98
-
99
- declare class BOOLEAN extends DataType {
100
- dataType: 'boolean'
101
- }
102
-
103
- declare class VIRTUAL extends DataType {
104
- dataType: 'virtual'
105
- }