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/History.md +40 -0
- package/Readme.md +29 -3
- package/index.js +7 -0
- package/package.json +3 -1
- package/src/adapters/sequelize.js +11 -4
- package/src/bone.js +28 -13
- package/src/data_types.js +52 -12
- package/src/drivers/abstract/attribute.js +4 -0
- package/src/drivers/abstract/index.js +192 -1
- package/src/drivers/abstract/spellbook.js +403 -412
- package/src/drivers/index.js +15 -4
- package/src/drivers/mysql/attribute.js +11 -2
- package/src/drivers/mysql/index.js +101 -10
- package/src/drivers/mysql/spellbook.js +13 -11
- package/src/drivers/postgres/index.js +103 -109
- package/src/drivers/postgres/spellbook.js +9 -9
- package/src/drivers/postgres/sqlstring.js +124 -0
- package/src/drivers/sqlite/index.js +124 -13
- package/src/drivers/sqlite/spellbook.js +6 -6
- package/src/drivers/sqlite/sqlstring.js +88 -0
- package/src/hint.js +2 -1
- package/src/realm.js +8 -6
- package/src/spell.js +2 -4
- package/types/data_types.d.ts +9 -1
- package/types/hint.d.ts +96 -0
- package/types/index.d.ts +246 -20
- package/src/drivers/abstract/schema.js +0 -140
- package/src/drivers/mysql/schema.js +0 -98
- package/src/drivers/postgres/schema.js +0 -119
- package/src/drivers/sqlite/schema.js +0 -203
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?:
|
|
43
|
-
columns:
|
|
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:
|
|
67
|
+
joins: Join;
|
|
50
68
|
skip: number;
|
|
51
69
|
scopes: Function[];
|
|
52
70
|
subqueryIndex: number;
|
|
53
|
-
rowCount
|
|
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
|
-
|
|
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 |
|
|
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
|
|
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
|
|
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[]
|
|
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:
|
|
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:
|
|
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):
|
|
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
|
-
};
|