leoric 2.3.0 → 2.4.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/types/index.d.ts CHANGED
@@ -1,8 +1,18 @@
1
1
  import DataType from './data_types';
2
+ import { Hint, IndexHint } from './hint';
2
3
 
3
4
  export { DataType as DataTypes };
4
5
  export * from '../src/decorators';
5
6
 
7
+ export type command = 'select' | 'insert' | 'bulkInsert' | 'update' | 'delete' | 'upsert';
8
+ export type Literal = null | undefined | boolean | number | bigint | string | Date | object | ArrayBuffer;
9
+
10
+ export class Raw {
11
+ value: string;
12
+ type: 'raw';
13
+ }
14
+
15
+
6
16
  type DataTypes<T> = {
7
17
  [Property in keyof T as Exclude<Property, "toSqlString">]: T[Property]
8
18
  }
@@ -37,20 +47,35 @@ interface ExprTernaryOperator {
37
47
  }
38
48
 
39
49
  type ExprOperator = ExprBinaryOperator | ExprTernaryOperator;
50
+ type SpellColumn = ExprIdentifier | Raw;
51
+
52
+ interface Join {
53
+ [key: string]: {
54
+ Model: typeof Bone;
55
+ on: ExprBinaryOperator
56
+ }
57
+ }
40
58
 
41
59
  interface SpellOptions {
42
- command?: string;
43
- columns: Object[];
60
+ command?: command;
61
+ columns: SpellColumn[];
44
62
  table: ExprIdentifier;
45
63
  whereConditions: ExprOperator[];
46
64
  groups: (ExprIdentifier | ExprFunc)[];
47
65
  orders: (ExprIdentifier | ExprFunc)[];
48
66
  havingCondtions: ExprOperator[];
49
- joins: Object;
67
+ joins: Join;
50
68
  skip: number;
51
69
  scopes: Function[];
52
70
  subqueryIndex: number;
53
- rowCount: 0;
71
+ rowCount?: number;
72
+ connection?: Connection;
73
+ sets?: { [key: string]: Literal } | { [key: string]: Literal }[];
74
+ hints?: Array<Hint | IndexHint>;
75
+ }
76
+
77
+ export interface SpellMeta extends SpellOptions {
78
+ Model: typeof Bone;
54
79
  }
55
80
 
56
81
  type OrderOptions = { [name: string]: 'desc' | 'asc' };
@@ -64,7 +89,10 @@ type WithOptions = {
64
89
  export class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<InstanceType<T>> | ResultSet | number | null> extends Promise<U> {
65
90
  constructor(Model: T, opts: SpellOptions);
66
91
 
67
- select(...names: Array<string | RawSql> | Array<(name: string) => boolean>): Spell<T, U>;
92
+ command: string;
93
+ scopes: Function[];
94
+
95
+ select(...names: Array<string | Raw> | Array<(name: string) => boolean>): Spell<T, U>;
68
96
  insert(opts: SetOptions): Spell<T, QueryResult>;
69
97
  update(opts: SetOptions): Spell<T, QueryResult>;
70
98
  upsert(opts: SetOptions): Spell<T, QueryResult>;
@@ -86,7 +114,7 @@ export class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<Insta
86
114
  orWhere(conditions: WhereConditions<T>): Spell<T, U>;
87
115
  orWhere(conditions: string, ...values: Literal[]): Spell<T, U>;
88
116
 
89
- group(...names: Array<string | RawSql>): Spell<T, ResultSet>;
117
+ group(...names: Array<string | Raw>): Spell<T, ResultSet>;
90
118
 
91
119
  having(conditions: string, ...values: Literal[]): Spell<T, ResultSet>;
92
120
  having(conditions: WhereConditions<T>): Spell<T, ResultSet>;
@@ -115,7 +143,6 @@ export class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<Insta
115
143
  toString(): string;
116
144
  }
117
145
 
118
- type Literal = null | undefined | boolean | number | bigint | string | Date | object | ArrayBuffer;
119
146
 
120
147
  type OperatorCondition = {
121
148
  [key in '$eq' | '$ne']?: Literal;
@@ -141,15 +168,21 @@ type InstanceValues<T> = {
141
168
  [Property in keyof Extract<T, Literal>]?: Extract<T, Literal>[Property]
142
169
  }
143
170
 
144
- export interface AttributeMeta {
171
+ export interface ColumnMeta {
145
172
  columnName?: string;
146
173
  columnType?: string;
147
174
  allowNull?: boolean;
148
175
  defaultValue?: Literal;
149
176
  primaryKey?: boolean;
177
+ unique?: boolean;
150
178
  dataType?: string;
179
+ comment?: string;
180
+ datetimePrecision?: string;
181
+ }
182
+ export interface AttributeMeta extends ColumnMeta {
151
183
  jsType?: Literal;
152
184
  type: DataType;
185
+ virtual?: boolean,
153
186
  toSqlString: () => string;
154
187
  }
155
188
 
@@ -187,7 +220,59 @@ declare class Pool {
187
220
  getConnection(): Connection;
188
221
  }
189
222
 
190
- declare class Driver {
223
+ declare class Attribute {
224
+ /**
225
+ * attribute name
226
+ */
227
+ name: string;
228
+ /**
229
+ * primaryKey tag
230
+ */
231
+ primaryKey: boolean;
232
+ allowNull: boolean;
233
+ /**
234
+ * attribute column name in table
235
+ */
236
+ columnName: string;
237
+ columnType: string;
238
+ type: typeof DataType;
239
+ defaultValue: Literal;
240
+ dataType: string;
241
+ jsType: Literal;
242
+ virtual: boolean;
243
+
244
+ euals(columnInfo: ColumnMeta): boolean;
245
+ cast(value: Literal): Literal;
246
+ uncast(value: Literal): Literal;
247
+ }
248
+
249
+ interface SpellBookFormatStandardResult {
250
+ sql?: string;
251
+ values?: Array<Literal> | {
252
+ [key: string]: Literal
253
+ };
254
+ [key: string]: Literal
255
+ }
256
+
257
+ export type SpellBookFormatResult<T> = SpellBookFormatStandardResult | T;
258
+
259
+ declare class Spellbook {
260
+
261
+ format(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
262
+
263
+ formatInsert(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
264
+ formatSelect(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
265
+ formatUpdate(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
266
+ formatDelete(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
267
+ formatUpsert(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
268
+ }
269
+
270
+ declare class AbstractDriver {
271
+
272
+ static Spellbook: typeof Spellbook;
273
+ static DataType: typeof DataType;
274
+ static Attribute: typeof Attribute;
275
+
191
276
  /**
192
277
  * The type of driver, currently there are mysql, sqlite, and postgres
193
278
  */
@@ -203,10 +288,147 @@ declare class Driver {
203
288
  */
204
289
  pool: Pool;
205
290
 
291
+ /**
292
+ * The SQL dialect
293
+ */
294
+ dialect: string;
295
+
296
+ spellbook: Spellbook;
297
+
298
+ DataType: DataType;
299
+
300
+ Attribute: Attribute;
301
+
302
+ constructor(options: ConnectOptions);
303
+
304
+ escape: (v: string) => string;
305
+ escapeId: (v: string) => string;
306
+
206
307
  /**
207
308
  * Grab a connection and query the database
208
309
  */
209
- query(sql: string, values?: Array<Literal | Literal[]>): Promise<QueryResult>;
310
+ query(sql: string | { sql: string, nestTables?: boolean}, values?: Array<Literal | Literal[]>, opts?: SpellMeta): Promise<QueryResult>;
311
+
312
+ /**
313
+ * query with spell
314
+ * @param spell
315
+ */
316
+ cast(spell: Spell<typeof Bone, ResultSet | number | null>): Promise<QueryResult>;
317
+
318
+ /**
319
+ * format spell
320
+ * @param spell SpellMeta
321
+ */
322
+ format(spell: SpellMeta): any;
323
+
324
+ /**
325
+ * create table
326
+ * @param tabe table name
327
+ * @param attributes attributes
328
+ */
329
+ createTable(tabe: string, attributes: { [key: string]: DataTypes<DataType> | AttributeMeta }): Promise<void>;
330
+
331
+ /**
332
+ * alter table
333
+ * @param tabe table name
334
+ * @param attributes alter attributes
335
+ */
336
+ alterTable(tabe: string, attributes: { [key: string]: DataTypes<DataType> | AttributeMeta }): Promise<void>;
337
+
338
+ /**
339
+ * describe table
340
+ * @param table table name
341
+ */
342
+ describeTable(table: string): Promise<{ [key: string]: ColumnMeta }>;
343
+
344
+ /**
345
+ * query table schemas
346
+ * @param database database name
347
+ * @param table table name or table name array
348
+ */
349
+ querySchemaInfo(database: string, table: string | string[]): Promise<{ [key: string] : { [key: string]: ColumnMeta }[]}>;
350
+
351
+ /**
352
+ * add column to table
353
+ * @param table table name
354
+ * @param name column name
355
+ * @param params column meta info
356
+ */
357
+ addColumn(table: string, name: string, params: ColumnMeta): Promise<void>;
358
+
359
+ /**
360
+ * change column meta in table
361
+ * @param table table name
362
+ * @param name column name
363
+ * @param params column meta info
364
+ */
365
+ changeColumn(table: string, name: string, params: ColumnMeta): Promise<void>;
366
+
367
+ /**
368
+ * remove column in table
369
+ * @param table table name
370
+ * @param name column name
371
+ */
372
+ removeColumn(table: string, name: string): Promise<void>;
373
+
374
+ /**
375
+ * rename column in table
376
+ * @param table table name
377
+ * @param name column name
378
+ * @param newName new column name
379
+ */
380
+ renameColumn(table: string, name: string, newName: string): Promise<void>;
381
+
382
+ /**
383
+ * rename table
384
+ * @param table table name
385
+ * @param newTable new table name
386
+ */
387
+ renameTable(table: string, newTable: string): Promise<void>;
388
+
389
+ /**
390
+ * drop table
391
+ * @param table table name
392
+ */
393
+ dropTable(table: string): Promise<void>;
394
+
395
+ /**
396
+ * truncate table
397
+ * @param table table name
398
+ */
399
+ truncateTable(table: string): Promise<void>;
400
+
401
+ /**
402
+ * add index in table
403
+ * @param table table name
404
+ * @param attributes attributes name
405
+ * @param opts
406
+ */
407
+ addIndex(table: string, attributes: string[], opts?: { unique?: boolean, type?: string }): Promise<void>;
408
+
409
+ /**
410
+ * remove index in table
411
+ * @param table string
412
+ * @param attributes attributes name
413
+ * @param opts
414
+ */
415
+ removeIndex(table: string, attributes: string[], opts?: { unique?: boolean, type?: string }): Promise<void>;
416
+
417
+ }
418
+
419
+ export class MysqlDriver extends AbstractDriver {
420
+ type: 'mysql';
421
+ dialect: 'mysql';
422
+ }
423
+
424
+ export class PostgresDriver extends AbstractDriver {
425
+ type: 'postgres';
426
+ dialect: 'postgres';
427
+ }
428
+
429
+ export class SqliteDriver extends AbstractDriver {
430
+ type: 'sqlite';
431
+ dialect: 'sqlite';
210
432
  }
211
433
 
212
434
  type ResultSet = {
@@ -230,7 +452,7 @@ export class Bone {
230
452
  /**
231
453
  * The driver that powers the model
232
454
  */
233
- static driver: Driver;
455
+ static driver: AbstractDriver;
234
456
 
235
457
  /**
236
458
  * The connected models structured as `{ [model.name]: model }`, e.g. `Bone.model.Post => Post`
@@ -303,6 +525,7 @@ export class Bone {
303
525
 
304
526
  static alias(name: string): string;
305
527
  static alias(data: Record<string, Literal>): Record<string, Literal>;
528
+ static unalias(name: string): string;
306
529
 
307
530
  static hasOne(name: string, opts?: RelateOptions): void;
308
531
  static hasMany(name: string, opts?: RelateOptions): void;
@@ -474,7 +697,7 @@ export class Bone {
474
697
 
475
698
  static initialize(): void;
476
699
 
477
- constructor(values: { [key: string]: Literal });
700
+ constructor(values: { [key: string]: Literal }, opts?: { isNewRecord?: boolean });
478
701
 
479
702
  /**
480
703
  * @example
@@ -609,6 +832,7 @@ export interface ConnectOptions {
609
832
  charset?: string;
610
833
  models?: string | (typeof Bone)[];
611
834
  subclass?: boolean;
835
+ driver?: typeof AbstractDriver;
612
836
  }
613
837
 
614
838
  interface InitOptions {
@@ -626,12 +850,6 @@ interface SyncOptions {
626
850
  alter?: boolean;
627
851
  }
628
852
 
629
- type RawSql = {
630
- __raw: true,
631
- value: string,
632
- type: 'raw',
633
- };
634
-
635
853
  interface RawQueryOptions {
636
854
  replacements?: { [key:string]: Literal | Literal[] };
637
855
  model: Bone;
@@ -641,11 +859,14 @@ interface RawQueryOptions {
641
859
  export default class Realm {
642
860
  Bone: typeof Bone;
643
861
  DataTypes: typeof DataType;
644
- driver: Driver;
862
+ driver: AbstractDriver;
645
863
  models: Record<string, Bone>;
864
+ connected?: boolean;
646
865
 
647
866
  constructor(options: ConnectOptions);
648
867
 
868
+ connect(): Promise<Bone>;
869
+
649
870
  define(
650
871
  name: string,
651
872
  attributes: Record<string, DataTypes<DataType> | AttributeMeta>,
@@ -653,7 +874,7 @@ export default class Realm {
653
874
  descriptors?: Record<string, Function>,
654
875
  ): typeof Bone;
655
876
 
656
- raw(sql: string): RawSql;
877
+ raw(sql: string): Raw;
657
878
 
658
879
  escape(value: Literal): string;
659
880
 
@@ -676,3 +897,8 @@ export default class Realm {
676
897
  * })
677
898
  */
678
899
  export function connect(opts: ConnectOptions): Promise<Realm>;
900
+
901
+ export {
902
+ Hint,
903
+ IndexHint,
904
+ }
@@ -1,140 +0,0 @@
1
- 'use strict';
2
-
3
- const { heresql } = require('../../utils/string');
4
-
5
- module.exports = {
6
- async createTable(table, attributes) {
7
- const { escapeId, Attribute } = this;
8
- const chunks = [ `CREATE TABLE ${escapeId(table)}` ];
9
- const columns = Object.keys(attributes).map(name => {
10
- const attribute = new Attribute(name, attributes[name]);
11
- return attribute.toSqlString();
12
- });
13
- chunks.push(`(${columns.join(', ')})`);
14
- await this.query(chunks.join(' '));
15
- },
16
-
17
- async alterTable(table, attributes) {
18
- const { escapeId, Attribute } = this;
19
- const chunks = [ `ALTER TABLE ${escapeId(table)}` ];
20
-
21
- const actions = Object.keys(attributes).map(name => {
22
- const attribute = new Attribute(name, attributes[name]);
23
- return [
24
- attribute.modify ? 'MODIFY COLUMN' : 'ADD COLUMN',
25
- attribute.toSqlString(),
26
- ].join(' ');
27
- });
28
- chunks.push(actions.join(', '));
29
- await this.query(chunks.join(' '));
30
- },
31
-
32
- async describeTable(table) {
33
- const { database } = this.options;
34
- const schemaInfo = await this.querySchemaInfo(database, table);
35
- return schemaInfo[table].reduce(function(result, column) {
36
- result[column.columnName] = column;
37
- return result;
38
- }, {});
39
- },
40
-
41
- async addColumn(table, name, params) {
42
- const { escapeId, Attribute } = this;
43
- const attribute = new Attribute(name, params);
44
- const sql = heresql(`
45
- ALTER TABLE ${escapeId(table)}
46
- ADD COLUMN ${attribute.toSqlString()}
47
- `);
48
- await this.query(sql);
49
- },
50
-
51
- async changeColumn(table, name, params) {
52
- const { escapeId, Attribute } = this;
53
- const attribute = new Attribute(name, params);
54
- const sql = heresql(`
55
- ALTER TABLE ${escapeId(table)}
56
- MODIFY COLUMN ${attribute.toSqlString()}
57
- `);
58
- await this.query(sql);
59
- },
60
-
61
- async removeColumn(table, name) {
62
- const { escapeId, Attribute } = this;
63
- const { columnName } = new Attribute(name);
64
- const sql = heresql(`
65
- ALTER TABLE ${escapeId(table)} DROP COLUMN ${escapeId(columnName)}
66
- `);
67
- await this.query(sql);
68
- },
69
-
70
- async renameColumn(table, name, newName) {
71
- const { escapeId, Attribute } = this;
72
- const { columnName } = new Attribute(name);
73
- const attribute = new Attribute(newName);
74
- const sql = heresql(`
75
- ALTER TABLE ${escapeId(table)}
76
- RENAME COLUMN ${escapeId(columnName)} TO ${escapeId(attribute.columnName)}
77
- `);
78
- await this.query(sql);
79
- },
80
-
81
- async renameTable(table, newTable) {
82
- const { escapeId } = this;
83
- const sql = heresql(`
84
- ALTER TABLE ${escapeId(table)} RENAME TO ${escapeId(newTable)}
85
- `);
86
- await this.query(sql);
87
- },
88
-
89
- async dropTable(table) {
90
- const { escapeId } = this;
91
- await this.query(`DROP TABLE IF EXISTS ${escapeId(table)}`);
92
- },
93
-
94
- async truncateTable(table) {
95
- const { escapeId } = this;
96
- await this.query(`TRUNCATE TABLE ${escapeId(table)}`);
97
- },
98
-
99
- async addIndex(table, attributes, opts = {}) {
100
- const { escapeId, Attribute } = this;
101
- const columns = attributes.map(name => new Attribute(name).columnName);
102
- const type = opts.unique ? 'UNIQUE' : opts.type;
103
- const prefix = type === 'UNIQUE' ? 'uk' : 'idx';
104
- const { name } = {
105
- name: [ prefix, table ].concat(columns).join('_'),
106
- ...opts,
107
- };
108
-
109
- if (type != null && ![ 'UNIQUE', 'FULLTEXT', 'SPATIAL' ].includes(type)) {
110
- throw new Error(`Unexpected index type: ${type}`);
111
- }
112
-
113
- const sql = heresql(`
114
- CREATE ${type ? `${type} INDEX` : 'INDEX'} ${escapeId(name)}
115
- ON ${escapeId(table)} (${columns.map(escapeId).join(', ')})
116
- `);
117
- await this.query(sql);
118
- },
119
-
120
- async removeIndex(table, attributes, opts = {}) {
121
- const { escapeId, Attribute } = this;
122
- let name;
123
- if (Array.isArray(attributes)) {
124
- const columns = attributes.map(entry => new Attribute(entry).columnName);
125
- const type = opts.unique ? 'UNIQUE' : opts.type;
126
- const prefix = type === 'UNIQUE' ? 'uk' : 'idx';
127
- name = [ prefix, table ].concat(columns).join('_');
128
- } else if (typeof attributes === 'string') {
129
- name = attributes;
130
- } else {
131
- throw new Error(`Unexpected index name: ${attributes}`);
132
- }
133
-
134
- const sql = this.type === 'mysql'
135
- ? `DROP INDEX ${escapeId(name)} ON ${escapeId(table)}`
136
- : `DROP INDEX IF EXISTS ${escapeId(name)}`;
137
- await this.query(sql);
138
- },
139
-
140
- };
@@ -1,98 +0,0 @@
1
- 'use strict';
2
-
3
- const Attribute = require('./attribute');
4
- const schema = require('../abstract/schema');
5
- const { heresql } = require('../../utils/string');
6
-
7
- module.exports = {
8
- ...schema,
9
-
10
- /**
11
- * Fetch columns of give tables from database
12
- * - https://dev.mysql.com/doc/mysql-infoschema-excerpt/5.6/en/columns-table.html
13
- * @param {string} database
14
- * @param {string|string[]} tables
15
- */
16
- async querySchemaInfo(database, tables) {
17
- tables = [].concat(tables);
18
- const sql = heresql(`
19
- SELECT table_name, column_name, column_type, data_type, is_nullable,
20
- column_default, column_key, column_comment,
21
- datetime_precision
22
- FROM information_schema.columns
23
- WHERE table_schema = ? AND table_name in (?)
24
- ORDER BY table_name, column_name
25
- `);
26
-
27
- const { rows } = await this.query(sql, [ database, tables ]);
28
- const schemaInfo = {};
29
-
30
- for (const entry of rows) {
31
- // make sure the column names are in lower case
32
- const row = Object.keys(entry).reduce((obj, name) => {
33
- obj[name.toLowerCase()] = entry[name];
34
- return obj;
35
- }, {});
36
- const tabelName = row.table_name;
37
- const columns = schemaInfo[tabelName] || (schemaInfo[tabelName] = []);
38
- columns.push({
39
- columnName: row.column_name,
40
- columnType: row.column_type,
41
- columnComment: row.column_comment,
42
- defaultValue: row.column_default,
43
- dataType: row.data_type,
44
- allowNull: row.is_nullable === 'YES',
45
- primaryKey: row.column_key == 'PRI',
46
- unique: row.column_key == 'PRI' || row.column_key == 'UNI',
47
- datetimePrecision: row.datetime_precision,
48
- });
49
- }
50
-
51
- return schemaInfo;
52
- },
53
-
54
- /**
55
- * Rename column with SQL that works on older versions of MySQL
56
- * - https://dev.mysql.com/doc/refman/5.7/en/alter-table.html
57
- * - https://dev.mysql.com/doc/refman/8.0/en/alter-table.html
58
- * @param {string} table
59
- * @param {string} column the old column name
60
- * @param {string} newColumn the new column name
61
- */
62
- async renameColumn(table, name, newName) {
63
- const { escapeId } = this;
64
- const { database } = this.options;
65
- const { columnName } = new Attribute(name);
66
- const schemaInfo = await this.querySchemaInfo(database, table);
67
- const { columnName: _, ...columnInfo } = schemaInfo[table].find(entry => {
68
- return entry.columnName == columnName;
69
- });
70
-
71
- if (!columnInfo) {
72
- throw new Error(`Unable to find column ${table}.${columnName}`);
73
- }
74
-
75
- const attribute = new Attribute(newName, columnInfo);
76
- const sql = heresql(`
77
- ALTER TABLE ${escapeId(table)}
78
- CHANGE COLUMN ${escapeId(columnName)} ${attribute.toSqlString()}
79
- `);
80
- await this.query(sql);
81
- },
82
-
83
- async describeTable(table) {
84
- const { escapeId } = this;
85
- const { rows } = await this.query(`DESCRIBE ${escapeId(table)}`);
86
- const result = {};
87
- for (const row of rows) {
88
- result[row.Field] = {
89
- columnName: row.Field,
90
- columnType: row.Type,
91
- allowNull: row.Null === 'YES',
92
- defaultValue: row.Default,
93
- autoIncrement: row.Extra === 'auto_increment',
94
- };
95
- }
96
- return result;
97
- },
98
- };