leoric 2.3.2 → 2.5.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 +31 -0
- package/Readme.md +1 -1
- package/index.js +14 -0
- package/package.json +3 -1
- package/src/bone.js +11 -11
- package/src/constants.js +8 -1
- package/src/data_types.js +32 -32
- package/src/drivers/abstract/attribute.js +1 -1
- package/src/drivers/abstract/index.js +201 -1
- package/src/drivers/abstract/spellbook.js +403 -412
- package/src/drivers/index.js +15 -4
- package/src/drivers/mysql/index.js +101 -10
- package/src/drivers/mysql/spellbook.js +13 -11
- package/src/drivers/postgres/data_types.js +2 -2
- 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/data_types.js +9 -9
- 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 +13 -5
- package/src/spell.js +2 -4
- package/src/utils/invokable.js +3 -0
- package/types/data_types.d.ts +35 -32
- package/types/hint.d.ts +96 -0
- package/types/index.d.ts +266 -26
- package/src/drivers/abstract/schema.js +0 -143
- package/src/drivers/mysql/schema.js +0 -98
- package/src/drivers/postgres/schema.js +0 -125
- package/src/drivers/sqlite/schema.js +0 -211
package/types/index.d.ts
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
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
|
}
|
|
9
19
|
|
|
20
|
+
type RawQueryResult = typeof Bone | ResultSet | boolean | number;
|
|
21
|
+
|
|
10
22
|
interface ExprIdentifier {
|
|
11
23
|
type: 'id';
|
|
12
24
|
value: string;
|
|
@@ -37,20 +49,35 @@ interface ExprTernaryOperator {
|
|
|
37
49
|
}
|
|
38
50
|
|
|
39
51
|
type ExprOperator = ExprBinaryOperator | ExprTernaryOperator;
|
|
52
|
+
type SpellColumn = ExprIdentifier | Raw;
|
|
53
|
+
|
|
54
|
+
interface Join {
|
|
55
|
+
[key: string]: {
|
|
56
|
+
Model: typeof Bone;
|
|
57
|
+
on: ExprBinaryOperator
|
|
58
|
+
}
|
|
59
|
+
}
|
|
40
60
|
|
|
41
61
|
interface SpellOptions {
|
|
42
|
-
command?:
|
|
43
|
-
columns:
|
|
62
|
+
command?: command;
|
|
63
|
+
columns: SpellColumn[];
|
|
44
64
|
table: ExprIdentifier;
|
|
45
65
|
whereConditions: ExprOperator[];
|
|
46
66
|
groups: (ExprIdentifier | ExprFunc)[];
|
|
47
67
|
orders: (ExprIdentifier | ExprFunc)[];
|
|
48
68
|
havingCondtions: ExprOperator[];
|
|
49
|
-
joins:
|
|
69
|
+
joins: Join;
|
|
50
70
|
skip: number;
|
|
51
71
|
scopes: Function[];
|
|
52
72
|
subqueryIndex: number;
|
|
53
|
-
rowCount
|
|
73
|
+
rowCount?: number;
|
|
74
|
+
connection?: Connection;
|
|
75
|
+
sets?: { [key: string]: Literal } | { [key: string]: Literal }[];
|
|
76
|
+
hints?: Array<Hint | IndexHint>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface SpellMeta extends SpellOptions {
|
|
80
|
+
Model: typeof Bone;
|
|
54
81
|
}
|
|
55
82
|
|
|
56
83
|
type OrderOptions = { [name: string]: 'desc' | 'asc' };
|
|
@@ -64,7 +91,10 @@ type WithOptions = {
|
|
|
64
91
|
export class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<InstanceType<T>> | ResultSet | number | null> extends Promise<U> {
|
|
65
92
|
constructor(Model: T, opts: SpellOptions);
|
|
66
93
|
|
|
67
|
-
|
|
94
|
+
command: string;
|
|
95
|
+
scopes: Function[];
|
|
96
|
+
|
|
97
|
+
select(...names: Array<string | Raw> | Array<(name: string) => boolean>): Spell<T, U>;
|
|
68
98
|
insert(opts: SetOptions): Spell<T, QueryResult>;
|
|
69
99
|
update(opts: SetOptions): Spell<T, QueryResult>;
|
|
70
100
|
upsert(opts: SetOptions): Spell<T, QueryResult>;
|
|
@@ -86,7 +116,7 @@ export class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<Insta
|
|
|
86
116
|
orWhere(conditions: WhereConditions<T>): Spell<T, U>;
|
|
87
117
|
orWhere(conditions: string, ...values: Literal[]): Spell<T, U>;
|
|
88
118
|
|
|
89
|
-
group(...names: Array<string |
|
|
119
|
+
group(...names: Array<string | Raw>): Spell<T, ResultSet>;
|
|
90
120
|
|
|
91
121
|
having(conditions: string, ...values: Literal[]): Spell<T, ResultSet>;
|
|
92
122
|
having(conditions: WhereConditions<T>): Spell<T, ResultSet>;
|
|
@@ -115,7 +145,6 @@ export class Spell<T extends typeof Bone, U = InstanceType<T> | Collection<Insta
|
|
|
115
145
|
toString(): string;
|
|
116
146
|
}
|
|
117
147
|
|
|
118
|
-
type Literal = null | undefined | boolean | number | bigint | string | Date | object | ArrayBuffer;
|
|
119
148
|
|
|
120
149
|
type OperatorCondition = {
|
|
121
150
|
[key in '$eq' | '$ne']?: Literal;
|
|
@@ -141,16 +170,28 @@ type InstanceValues<T> = {
|
|
|
141
170
|
[Property in keyof Extract<T, Literal>]?: Extract<T, Literal>[Property]
|
|
142
171
|
}
|
|
143
172
|
|
|
144
|
-
export interface
|
|
173
|
+
export interface ColumnMeta {
|
|
145
174
|
columnName?: string;
|
|
146
175
|
columnType?: string;
|
|
147
176
|
allowNull?: boolean;
|
|
148
177
|
defaultValue?: Literal;
|
|
149
178
|
primaryKey?: boolean;
|
|
179
|
+
unique?: boolean;
|
|
150
180
|
dataType?: string;
|
|
181
|
+
comment?: string;
|
|
182
|
+
datetimePrecision?: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
declare type validator = Literal | Function | Array<Literal | Literal[]>;
|
|
186
|
+
|
|
187
|
+
export interface AttributeMeta extends ColumnMeta {
|
|
151
188
|
jsType?: Literal;
|
|
152
189
|
type: DataType;
|
|
190
|
+
virtual?: boolean,
|
|
153
191
|
toSqlString: () => string;
|
|
192
|
+
validate: {
|
|
193
|
+
[key: string]: validator;
|
|
194
|
+
}
|
|
154
195
|
}
|
|
155
196
|
|
|
156
197
|
interface RelateOptions {
|
|
@@ -187,7 +228,59 @@ declare class Pool {
|
|
|
187
228
|
getConnection(): Connection;
|
|
188
229
|
}
|
|
189
230
|
|
|
190
|
-
declare class
|
|
231
|
+
declare class Attribute {
|
|
232
|
+
/**
|
|
233
|
+
* attribute name
|
|
234
|
+
*/
|
|
235
|
+
name: string;
|
|
236
|
+
/**
|
|
237
|
+
* primaryKey tag
|
|
238
|
+
*/
|
|
239
|
+
primaryKey: boolean;
|
|
240
|
+
allowNull: boolean;
|
|
241
|
+
/**
|
|
242
|
+
* attribute column name in table
|
|
243
|
+
*/
|
|
244
|
+
columnName: string;
|
|
245
|
+
columnType: string;
|
|
246
|
+
type: typeof DataType;
|
|
247
|
+
defaultValue: Literal;
|
|
248
|
+
dataType: string;
|
|
249
|
+
jsType: Literal;
|
|
250
|
+
virtual: boolean;
|
|
251
|
+
|
|
252
|
+
euals(columnInfo: ColumnMeta): boolean;
|
|
253
|
+
cast(value: Literal): Literal;
|
|
254
|
+
uncast(value: Literal): Literal;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
interface SpellBookFormatStandardResult {
|
|
258
|
+
sql?: string;
|
|
259
|
+
values?: Array<Literal> | {
|
|
260
|
+
[key: string]: Literal
|
|
261
|
+
};
|
|
262
|
+
[key: string]: Literal
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export type SpellBookFormatResult<T> = SpellBookFormatStandardResult | T;
|
|
266
|
+
|
|
267
|
+
declare class Spellbook {
|
|
268
|
+
|
|
269
|
+
format(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
270
|
+
|
|
271
|
+
formatInsert(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
272
|
+
formatSelect(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
273
|
+
formatUpdate(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
274
|
+
formatDelete(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
275
|
+
formatUpsert(spell: SpellMeta): SpellBookFormatResult<SpellBookFormatStandardResult>;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
declare class AbstractDriver {
|
|
279
|
+
|
|
280
|
+
static Spellbook: typeof Spellbook;
|
|
281
|
+
static DataType: typeof DataType;
|
|
282
|
+
static Attribute: typeof Attribute;
|
|
283
|
+
|
|
191
284
|
/**
|
|
192
285
|
* The type of driver, currently there are mysql, sqlite, and postgres
|
|
193
286
|
*/
|
|
@@ -203,10 +296,153 @@ declare class Driver {
|
|
|
203
296
|
*/
|
|
204
297
|
pool: Pool;
|
|
205
298
|
|
|
299
|
+
/**
|
|
300
|
+
* The SQL dialect
|
|
301
|
+
*/
|
|
302
|
+
dialect: string;
|
|
303
|
+
|
|
304
|
+
spellbook: Spellbook;
|
|
305
|
+
|
|
306
|
+
DataType: DataType;
|
|
307
|
+
|
|
308
|
+
Attribute: Attribute;
|
|
309
|
+
|
|
310
|
+
constructor(options: ConnectOptions);
|
|
311
|
+
|
|
312
|
+
escape: (v: string) => string;
|
|
313
|
+
escapeId: (v: string) => string;
|
|
314
|
+
|
|
206
315
|
/**
|
|
207
316
|
* Grab a connection and query the database
|
|
208
317
|
*/
|
|
209
|
-
query(sql: string, values?: Array<Literal | Literal[]
|
|
318
|
+
query(sql: string | { sql: string, nestTables?: boolean}, values?: Array<Literal | Literal[]>, opts?: SpellMeta): Promise<QueryResult>;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* disconnect manually
|
|
322
|
+
* @param callback
|
|
323
|
+
*/
|
|
324
|
+
disconnect(callback?: Function): Promise<boolean | void>;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* query with spell
|
|
328
|
+
* @param spell
|
|
329
|
+
*/
|
|
330
|
+
cast(spell: Spell<typeof Bone, ResultSet | number | null>): Promise<QueryResult>;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* format spell
|
|
334
|
+
* @param spell SpellMeta
|
|
335
|
+
*/
|
|
336
|
+
format(spell: SpellMeta): any;
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* create table
|
|
340
|
+
* @param tabe table name
|
|
341
|
+
* @param attributes attributes
|
|
342
|
+
*/
|
|
343
|
+
createTable(tabe: string, attributes: { [key: string]: DataTypes<DataType> | AttributeMeta }): Promise<void>;
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* alter table
|
|
347
|
+
* @param tabe table name
|
|
348
|
+
* @param attributes alter attributes
|
|
349
|
+
*/
|
|
350
|
+
alterTable(tabe: string, attributes: { [key: string]: DataTypes<DataType> | AttributeMeta }): Promise<void>;
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* describe table
|
|
354
|
+
* @param table table name
|
|
355
|
+
*/
|
|
356
|
+
describeTable(table: string): Promise<{ [key: string]: ColumnMeta }>;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* query table schemas
|
|
360
|
+
* @param database database name
|
|
361
|
+
* @param table table name or table name array
|
|
362
|
+
*/
|
|
363
|
+
querySchemaInfo(database: string, table: string | string[]): Promise<{ [key: string] : { [key: string]: ColumnMeta }[]}>;
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* add column to table
|
|
367
|
+
* @param table table name
|
|
368
|
+
* @param name column name
|
|
369
|
+
* @param params column meta info
|
|
370
|
+
*/
|
|
371
|
+
addColumn(table: string, name: string, params: ColumnMeta): Promise<void>;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* change column meta in table
|
|
375
|
+
* @param table table name
|
|
376
|
+
* @param name column name
|
|
377
|
+
* @param params column meta info
|
|
378
|
+
*/
|
|
379
|
+
changeColumn(table: string, name: string, params: ColumnMeta): Promise<void>;
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* remove column in table
|
|
383
|
+
* @param table table name
|
|
384
|
+
* @param name column name
|
|
385
|
+
*/
|
|
386
|
+
removeColumn(table: string, name: string): Promise<void>;
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* rename column in table
|
|
390
|
+
* @param table table name
|
|
391
|
+
* @param name column name
|
|
392
|
+
* @param newName new column name
|
|
393
|
+
*/
|
|
394
|
+
renameColumn(table: string, name: string, newName: string): Promise<void>;
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* rename table
|
|
398
|
+
* @param table table name
|
|
399
|
+
* @param newTable new table name
|
|
400
|
+
*/
|
|
401
|
+
renameTable(table: string, newTable: string): Promise<void>;
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* drop table
|
|
405
|
+
* @param table table name
|
|
406
|
+
*/
|
|
407
|
+
dropTable(table: string): Promise<void>;
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* truncate table
|
|
411
|
+
* @param table table name
|
|
412
|
+
*/
|
|
413
|
+
truncateTable(table: string): Promise<void>;
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* add index in table
|
|
417
|
+
* @param table table name
|
|
418
|
+
* @param attributes attributes name
|
|
419
|
+
* @param opts
|
|
420
|
+
*/
|
|
421
|
+
addIndex(table: string, attributes: string[], opts?: { unique?: boolean, type?: string }): Promise<void>;
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* remove index in table
|
|
425
|
+
* @param table string
|
|
426
|
+
* @param attributes attributes name
|
|
427
|
+
* @param opts
|
|
428
|
+
*/
|
|
429
|
+
removeIndex(table: string, attributes: string[], opts?: { unique?: boolean, type?: string }): Promise<void>;
|
|
430
|
+
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export class MysqlDriver extends AbstractDriver {
|
|
434
|
+
type: 'mysql';
|
|
435
|
+
dialect: 'mysql';
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
export class PostgresDriver extends AbstractDriver {
|
|
439
|
+
type: 'postgres';
|
|
440
|
+
dialect: 'postgres';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export class SqliteDriver extends AbstractDriver {
|
|
444
|
+
type: 'sqlite';
|
|
445
|
+
dialect: 'sqlite';
|
|
210
446
|
}
|
|
211
447
|
|
|
212
448
|
type ResultSet = {
|
|
@@ -220,7 +456,7 @@ export class Collection<T extends Bone> extends Array<T> {
|
|
|
220
456
|
}
|
|
221
457
|
|
|
222
458
|
export class Bone {
|
|
223
|
-
static DataTypes: DataType;
|
|
459
|
+
static DataTypes: typeof DataType;
|
|
224
460
|
|
|
225
461
|
/**
|
|
226
462
|
* get the connection pool of the driver
|
|
@@ -230,7 +466,7 @@ export class Bone {
|
|
|
230
466
|
/**
|
|
231
467
|
* The driver that powers the model
|
|
232
468
|
*/
|
|
233
|
-
static driver:
|
|
469
|
+
static driver: AbstractDriver;
|
|
234
470
|
|
|
235
471
|
/**
|
|
236
472
|
* The connected models structured as `{ [model.name]: model }`, e.g. `Bone.model.Post => Post`
|
|
@@ -303,6 +539,7 @@ export class Bone {
|
|
|
303
539
|
|
|
304
540
|
static alias(name: string): string;
|
|
305
541
|
static alias(data: Record<string, Literal>): Record<string, Literal>;
|
|
542
|
+
static unalias(name: string): string;
|
|
306
543
|
|
|
307
544
|
static hasOne(name: string, opts?: RelateOptions): void;
|
|
308
545
|
static hasMany(name: string, opts?: RelateOptions): void;
|
|
@@ -457,8 +694,8 @@ export class Bone {
|
|
|
457
694
|
* yield Muscle.create({ boneId: bone.id, bar: 1 })
|
|
458
695
|
* });
|
|
459
696
|
*/
|
|
460
|
-
static transaction(callback: GeneratorFunction): Promise<
|
|
461
|
-
static transaction(callback: (connection: Connection) => Promise<
|
|
697
|
+
static transaction(callback: GeneratorFunction): Promise<RawQueryResult>;
|
|
698
|
+
static transaction(callback: (connection: Connection) => Promise<RawQueryResult>): Promise<RawQueryResult>;
|
|
462
699
|
|
|
463
700
|
/**
|
|
464
701
|
* DROP the table
|
|
@@ -474,7 +711,7 @@ export class Bone {
|
|
|
474
711
|
|
|
475
712
|
static initialize(): void;
|
|
476
713
|
|
|
477
|
-
constructor(values: { [key: string]: Literal });
|
|
714
|
+
constructor(values: { [key: string]: Literal }, opts?: { isNewRecord?: boolean });
|
|
478
715
|
|
|
479
716
|
/**
|
|
480
717
|
* @example
|
|
@@ -609,6 +846,7 @@ export interface ConnectOptions {
|
|
|
609
846
|
charset?: string;
|
|
610
847
|
models?: string | (typeof Bone)[];
|
|
611
848
|
subclass?: boolean;
|
|
849
|
+
driver?: typeof AbstractDriver;
|
|
612
850
|
}
|
|
613
851
|
|
|
614
852
|
interface InitOptions {
|
|
@@ -626,12 +864,6 @@ interface SyncOptions {
|
|
|
626
864
|
alter?: boolean;
|
|
627
865
|
}
|
|
628
866
|
|
|
629
|
-
type RawSql = {
|
|
630
|
-
__raw: true,
|
|
631
|
-
value: string,
|
|
632
|
-
type: 'raw',
|
|
633
|
-
};
|
|
634
|
-
|
|
635
867
|
interface RawQueryOptions {
|
|
636
868
|
replacements?: { [key:string]: Literal | Literal[] };
|
|
637
869
|
model: Bone;
|
|
@@ -641,11 +873,14 @@ interface RawQueryOptions {
|
|
|
641
873
|
export default class Realm {
|
|
642
874
|
Bone: typeof Bone;
|
|
643
875
|
DataTypes: typeof DataType;
|
|
644
|
-
driver:
|
|
876
|
+
driver: AbstractDriver;
|
|
645
877
|
models: Record<string, Bone>;
|
|
878
|
+
connected?: boolean;
|
|
646
879
|
|
|
647
880
|
constructor(options: ConnectOptions);
|
|
648
881
|
|
|
882
|
+
connect(): Promise<Bone>;
|
|
883
|
+
|
|
649
884
|
define(
|
|
650
885
|
name: string,
|
|
651
886
|
attributes: Record<string, DataTypes<DataType> | AttributeMeta>,
|
|
@@ -653,14 +888,14 @@ export default class Realm {
|
|
|
653
888
|
descriptors?: Record<string, Function>,
|
|
654
889
|
): typeof Bone;
|
|
655
890
|
|
|
656
|
-
raw(sql: string):
|
|
891
|
+
raw(sql: string): Raw;
|
|
657
892
|
|
|
658
893
|
escape(value: Literal): string;
|
|
659
894
|
|
|
660
|
-
query(sql: string, values?: Array<Literal>, options?: RawQueryOptions):
|
|
895
|
+
query(sql: string, values?: Array<Literal>, options?: RawQueryOptions): RawQueryResult;
|
|
661
896
|
|
|
662
|
-
transaction(callback: GeneratorFunction): Promise<
|
|
663
|
-
transaction(callback: (connection: Connection) => Promise<
|
|
897
|
+
transaction(callback: GeneratorFunction): Promise<RawQueryResult>;
|
|
898
|
+
transaction(callback: (connection: Connection) => Promise<RawQueryResult>): Promise<RawQueryResult>;
|
|
664
899
|
|
|
665
900
|
sync(options?: SyncOptions): Promise<void>;
|
|
666
901
|
}
|
|
@@ -676,3 +911,8 @@ export default class Realm {
|
|
|
676
911
|
* })
|
|
677
912
|
*/
|
|
678
913
|
export function connect(opts: ConnectOptions): Promise<Realm>;
|
|
914
|
+
export function disconnect(realm: Realm, callback?: Function): Promise<boolean | void>;
|
|
915
|
+
export {
|
|
916
|
+
Hint,
|
|
917
|
+
IndexHint,
|
|
918
|
+
}
|
|
@@ -1,143 +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 options = attributes[name];
|
|
23
|
-
// { [columnName]: { remove: true } }
|
|
24
|
-
if (options.remove) return `DROP COLUMN ${escapeId(name)}`;
|
|
25
|
-
const attribute = new Attribute(name, options);
|
|
26
|
-
return [
|
|
27
|
-
options.modify ? 'MODIFY COLUMN' : 'ADD COLUMN',
|
|
28
|
-
attribute.toSqlString(),
|
|
29
|
-
].join(' ');
|
|
30
|
-
});
|
|
31
|
-
chunks.push(actions.join(', '));
|
|
32
|
-
await this.query(chunks.join(' '));
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
async describeTable(table) {
|
|
36
|
-
const { database } = this.options;
|
|
37
|
-
const schemaInfo = await this.querySchemaInfo(database, table);
|
|
38
|
-
return schemaInfo[table].reduce(function(result, column) {
|
|
39
|
-
result[column.columnName] = column;
|
|
40
|
-
return result;
|
|
41
|
-
}, {});
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
async addColumn(table, name, params) {
|
|
45
|
-
const { escapeId, Attribute } = this;
|
|
46
|
-
const attribute = new Attribute(name, params);
|
|
47
|
-
const sql = heresql(`
|
|
48
|
-
ALTER TABLE ${escapeId(table)}
|
|
49
|
-
ADD COLUMN ${attribute.toSqlString()}
|
|
50
|
-
`);
|
|
51
|
-
await this.query(sql);
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
async changeColumn(table, name, params) {
|
|
55
|
-
const { escapeId, Attribute } = this;
|
|
56
|
-
const attribute = new Attribute(name, params);
|
|
57
|
-
const sql = heresql(`
|
|
58
|
-
ALTER TABLE ${escapeId(table)}
|
|
59
|
-
MODIFY COLUMN ${attribute.toSqlString()}
|
|
60
|
-
`);
|
|
61
|
-
await this.query(sql);
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
async removeColumn(table, name) {
|
|
65
|
-
const { escapeId, Attribute } = this;
|
|
66
|
-
const { columnName } = new Attribute(name);
|
|
67
|
-
const sql = heresql(`
|
|
68
|
-
ALTER TABLE ${escapeId(table)} DROP COLUMN ${escapeId(columnName)}
|
|
69
|
-
`);
|
|
70
|
-
await this.query(sql);
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
async renameColumn(table, name, newName) {
|
|
74
|
-
const { escapeId, Attribute } = this;
|
|
75
|
-
const { columnName } = new Attribute(name);
|
|
76
|
-
const attribute = new Attribute(newName);
|
|
77
|
-
const sql = heresql(`
|
|
78
|
-
ALTER TABLE ${escapeId(table)}
|
|
79
|
-
RENAME COLUMN ${escapeId(columnName)} TO ${escapeId(attribute.columnName)}
|
|
80
|
-
`);
|
|
81
|
-
await this.query(sql);
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
async renameTable(table, newTable) {
|
|
85
|
-
const { escapeId } = this;
|
|
86
|
-
const sql = heresql(`
|
|
87
|
-
ALTER TABLE ${escapeId(table)} RENAME TO ${escapeId(newTable)}
|
|
88
|
-
`);
|
|
89
|
-
await this.query(sql);
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
async dropTable(table) {
|
|
93
|
-
const { escapeId } = this;
|
|
94
|
-
await this.query(`DROP TABLE IF EXISTS ${escapeId(table)}`);
|
|
95
|
-
},
|
|
96
|
-
|
|
97
|
-
async truncateTable(table) {
|
|
98
|
-
const { escapeId } = this;
|
|
99
|
-
await this.query(`TRUNCATE TABLE ${escapeId(table)}`);
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
async addIndex(table, attributes, opts = {}) {
|
|
103
|
-
const { escapeId, Attribute } = this;
|
|
104
|
-
const columns = attributes.map(name => new Attribute(name).columnName);
|
|
105
|
-
const type = opts.unique ? 'UNIQUE' : opts.type;
|
|
106
|
-
const prefix = type === 'UNIQUE' ? 'uk' : 'idx';
|
|
107
|
-
const { name } = {
|
|
108
|
-
name: [ prefix, table ].concat(columns).join('_'),
|
|
109
|
-
...opts,
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
if (type != null && ![ 'UNIQUE', 'FULLTEXT', 'SPATIAL' ].includes(type)) {
|
|
113
|
-
throw new Error(`Unexpected index type: ${type}`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const sql = heresql(`
|
|
117
|
-
CREATE ${type ? `${type} INDEX` : 'INDEX'} ${escapeId(name)}
|
|
118
|
-
ON ${escapeId(table)} (${columns.map(escapeId).join(', ')})
|
|
119
|
-
`);
|
|
120
|
-
await this.query(sql);
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
async removeIndex(table, attributes, opts = {}) {
|
|
124
|
-
const { escapeId, Attribute } = this;
|
|
125
|
-
let name;
|
|
126
|
-
if (Array.isArray(attributes)) {
|
|
127
|
-
const columns = attributes.map(entry => new Attribute(entry).columnName);
|
|
128
|
-
const type = opts.unique ? 'UNIQUE' : opts.type;
|
|
129
|
-
const prefix = type === 'UNIQUE' ? 'uk' : 'idx';
|
|
130
|
-
name = [ prefix, table ].concat(columns).join('_');
|
|
131
|
-
} else if (typeof attributes === 'string') {
|
|
132
|
-
name = attributes;
|
|
133
|
-
} else {
|
|
134
|
-
throw new Error(`Unexpected index name: ${attributes}`);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const sql = this.type === 'mysql'
|
|
138
|
-
? `DROP INDEX ${escapeId(name)} ON ${escapeId(table)}`
|
|
139
|
-
: `DROP INDEX IF EXISTS ${escapeId(name)}`;
|
|
140
|
-
await this.query(sql);
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
};
|
|
@@ -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
|
-
comment: 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
|
-
};
|