@remix-run/data-table-mysql 0.1.0 → 0.2.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/README.md +9 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/adapter.d.ts +98 -35
- package/dist/lib/adapter.d.ts.map +1 -1
- package/dist/lib/adapter.js +547 -17
- package/dist/lib/sql-compiler.d.ts +2 -7
- package/dist/lib/sql-compiler.d.ts.map +1 -1
- package/dist/lib/sql-compiler.js +47 -77
- package/package.json +6 -7
- package/src/index.ts +1 -8
- package/src/lib/adapter.ts +680 -68
- package/src/lib/sql-compiler.ts +60 -99
package/dist/lib/adapter.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { getTablePrimaryKey } from '@remix-run/data-table';
|
|
2
|
-
import {
|
|
2
|
+
import { isDataManipulationOperation as isDataManipulationOperationHelper, quoteLiteral as quoteLiteralHelper, quoteTableRef as quoteTableRefHelper, } from '@remix-run/data-table/sql-helpers';
|
|
3
|
+
import { compileMysqlOperation } from "./sql-compiler.js";
|
|
3
4
|
/**
|
|
4
5
|
* `DatabaseAdapter` implementation for mysql-compatible clients.
|
|
5
6
|
*/
|
|
6
7
|
export class MysqlDatabaseAdapter {
|
|
8
|
+
/**
|
|
9
|
+
* The SQL dialect identifier reported by this adapter.
|
|
10
|
+
*/
|
|
7
11
|
dialect = 'mysql';
|
|
12
|
+
/**
|
|
13
|
+
* Feature flags describing the mysql behaviors supported by this adapter.
|
|
14
|
+
*/
|
|
8
15
|
capabilities;
|
|
9
16
|
#client;
|
|
10
17
|
#transactions = new Map();
|
|
@@ -15,22 +22,42 @@ export class MysqlDatabaseAdapter {
|
|
|
15
22
|
returning: options?.capabilities?.returning ?? false,
|
|
16
23
|
savepoints: options?.capabilities?.savepoints ?? true,
|
|
17
24
|
upsert: options?.capabilities?.upsert ?? true,
|
|
25
|
+
transactionalDdl: options?.capabilities?.transactionalDdl ?? false,
|
|
26
|
+
migrationLock: options?.capabilities?.migrationLock ?? true,
|
|
18
27
|
};
|
|
19
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Compiles a data or migration operation to mysql SQL statements.
|
|
31
|
+
* @param operation Operation to compile.
|
|
32
|
+
* @returns Compiled SQL statements.
|
|
33
|
+
*/
|
|
34
|
+
compileSql(operation) {
|
|
35
|
+
if (isDataManipulationOperation(operation)) {
|
|
36
|
+
let compiled = compileMysqlOperation(operation);
|
|
37
|
+
return [{ text: compiled.text, values: compiled.values }];
|
|
38
|
+
}
|
|
39
|
+
return compileMysqlMigrationOperations(operation);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Executes a mysql data-manipulation request.
|
|
43
|
+
* @param request Request to execute.
|
|
44
|
+
* @returns Execution result.
|
|
45
|
+
*/
|
|
20
46
|
async execute(request) {
|
|
21
|
-
if (request.
|
|
47
|
+
if (request.operation.kind === 'insertMany' && request.operation.values.length === 0) {
|
|
22
48
|
return {
|
|
23
49
|
affectedRows: 0,
|
|
24
50
|
insertId: undefined,
|
|
25
|
-
rows: request.
|
|
51
|
+
rows: request.operation.returning ? [] : undefined,
|
|
26
52
|
};
|
|
27
53
|
}
|
|
28
|
-
let
|
|
54
|
+
let statements = this.compileSql(request.operation);
|
|
55
|
+
let statement = statements[0];
|
|
29
56
|
let client = this.#resolveClient(request.transaction);
|
|
30
57
|
let [result] = await client.query(statement.text, statement.values);
|
|
31
58
|
if (isRowsResult(result)) {
|
|
32
59
|
let rows = normalizeRows(result);
|
|
33
|
-
if (request.
|
|
60
|
+
if (request.operation.kind === 'count' || request.operation.kind === 'exists') {
|
|
34
61
|
rows = normalizeCountRows(rows);
|
|
35
62
|
}
|
|
36
63
|
return { rows };
|
|
@@ -38,9 +65,68 @@ export class MysqlDatabaseAdapter {
|
|
|
38
65
|
let header = normalizeHeader(result);
|
|
39
66
|
return {
|
|
40
67
|
affectedRows: header.affectedRows,
|
|
41
|
-
insertId: normalizeInsertId(request.
|
|
68
|
+
insertId: normalizeInsertId(request.operation.kind, request.operation, header),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Executes mysql migration operations.
|
|
73
|
+
* @param request Migration request to execute.
|
|
74
|
+
* @returns Migration result.
|
|
75
|
+
*/
|
|
76
|
+
async migrate(request) {
|
|
77
|
+
let statements = this.compileSql(request.operation);
|
|
78
|
+
let client = this.#resolveClient(request.transaction);
|
|
79
|
+
for (let statement of statements) {
|
|
80
|
+
await client.query(statement.text, statement.values);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
affectedOperations: statements.length,
|
|
42
84
|
};
|
|
43
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Checks whether a table exists in mysql.
|
|
88
|
+
* @param table Table reference to inspect.
|
|
89
|
+
* @param transaction Optional transaction token.
|
|
90
|
+
* @returns `true` when the table exists.
|
|
91
|
+
*/
|
|
92
|
+
async hasTable(table, transaction) {
|
|
93
|
+
let schema = table.schema;
|
|
94
|
+
let sql = schema
|
|
95
|
+
? 'select exists(select 1 from information_schema.tables where table_schema = ? and table_name = ?) as `exists`'
|
|
96
|
+
: 'select exists(select 1 from information_schema.tables where table_schema = database() and table_name = ?) as `exists`';
|
|
97
|
+
let values = schema ? [schema, table.name] : [table.name];
|
|
98
|
+
let client = this.#resolveClient(transaction);
|
|
99
|
+
let [result] = await client.query(sql, values);
|
|
100
|
+
if (!isRowsResult(result)) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
return toBooleanExists(result[0]?.exists);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Checks whether a column exists in mysql.
|
|
107
|
+
* @param table Table reference to inspect.
|
|
108
|
+
* @param column Column name to look up.
|
|
109
|
+
* @param transaction Optional transaction token.
|
|
110
|
+
* @returns `true` when the column exists.
|
|
111
|
+
*/
|
|
112
|
+
async hasColumn(table, column, transaction) {
|
|
113
|
+
let schema = table.schema;
|
|
114
|
+
let sql = schema
|
|
115
|
+
? 'select exists(select 1 from information_schema.columns where table_schema = ? and table_name = ? and column_name = ?) as `exists`'
|
|
116
|
+
: 'select exists(select 1 from information_schema.columns where table_schema = database() and table_name = ? and column_name = ?) as `exists`';
|
|
117
|
+
let values = schema ? [schema, table.name, column] : [table.name, column];
|
|
118
|
+
let client = this.#resolveClient(transaction);
|
|
119
|
+
let [result] = await client.query(sql, values);
|
|
120
|
+
if (!isRowsResult(result)) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return toBooleanExists(result[0]?.exists);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Starts a mysql transaction.
|
|
127
|
+
* @param options Transaction options.
|
|
128
|
+
* @returns Transaction token.
|
|
129
|
+
*/
|
|
44
130
|
async beginTransaction(options) {
|
|
45
131
|
let releaseOnClose = false;
|
|
46
132
|
let connection;
|
|
@@ -66,6 +152,11 @@ export class MysqlDatabaseAdapter {
|
|
|
66
152
|
});
|
|
67
153
|
return token;
|
|
68
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Commits an open mysql transaction.
|
|
157
|
+
* @param token Transaction token to commit.
|
|
158
|
+
* @returns A promise that resolves when the transaction is committed.
|
|
159
|
+
*/
|
|
69
160
|
async commitTransaction(token) {
|
|
70
161
|
let transaction = this.#transactions.get(token.id);
|
|
71
162
|
if (!transaction) {
|
|
@@ -76,11 +167,16 @@ export class MysqlDatabaseAdapter {
|
|
|
76
167
|
}
|
|
77
168
|
finally {
|
|
78
169
|
this.#transactions.delete(token.id);
|
|
79
|
-
if (transaction.releaseOnClose) {
|
|
80
|
-
transaction.connection.release
|
|
170
|
+
if (transaction.releaseOnClose && isMysqlPoolConnection(transaction.connection)) {
|
|
171
|
+
transaction.connection.release();
|
|
81
172
|
}
|
|
82
173
|
}
|
|
83
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Rolls back an open mysql transaction.
|
|
177
|
+
* @param token Transaction token to roll back.
|
|
178
|
+
* @returns A promise that resolves when the transaction is rolled back.
|
|
179
|
+
*/
|
|
84
180
|
async rollbackTransaction(token) {
|
|
85
181
|
let transaction = this.#transactions.get(token.id);
|
|
86
182
|
if (!transaction) {
|
|
@@ -91,23 +187,55 @@ export class MysqlDatabaseAdapter {
|
|
|
91
187
|
}
|
|
92
188
|
finally {
|
|
93
189
|
this.#transactions.delete(token.id);
|
|
94
|
-
if (transaction.releaseOnClose) {
|
|
95
|
-
transaction.connection.release
|
|
190
|
+
if (transaction.releaseOnClose && isMysqlPoolConnection(transaction.connection)) {
|
|
191
|
+
transaction.connection.release();
|
|
96
192
|
}
|
|
97
193
|
}
|
|
98
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Creates a savepoint in an open mysql transaction.
|
|
197
|
+
* @param token Transaction token to use.
|
|
198
|
+
* @param name Savepoint name.
|
|
199
|
+
* @returns A promise that resolves when the savepoint is created.
|
|
200
|
+
*/
|
|
99
201
|
async createSavepoint(token, name) {
|
|
100
202
|
let connection = this.#transactionConnection(token);
|
|
101
203
|
await connection.query('savepoint ' + quoteIdentifier(name));
|
|
102
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Rolls back to a savepoint in an open mysql transaction.
|
|
207
|
+
* @param token Transaction token to use.
|
|
208
|
+
* @param name Savepoint name.
|
|
209
|
+
* @returns A promise that resolves when the rollback completes.
|
|
210
|
+
*/
|
|
103
211
|
async rollbackToSavepoint(token, name) {
|
|
104
212
|
let connection = this.#transactionConnection(token);
|
|
105
213
|
await connection.query('rollback to savepoint ' + quoteIdentifier(name));
|
|
106
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Releases a savepoint in an open mysql transaction.
|
|
217
|
+
* @param token Transaction token to use.
|
|
218
|
+
* @param name Savepoint name.
|
|
219
|
+
* @returns A promise that resolves when the savepoint is released.
|
|
220
|
+
*/
|
|
107
221
|
async releaseSavepoint(token, name) {
|
|
108
222
|
let connection = this.#transactionConnection(token);
|
|
109
223
|
await connection.query('release savepoint ' + quoteIdentifier(name));
|
|
110
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Acquires the mysql migration lock.
|
|
227
|
+
* @returns A promise that resolves when the lock is acquired.
|
|
228
|
+
*/
|
|
229
|
+
async acquireMigrationLock() {
|
|
230
|
+
await this.#client.query('select get_lock(?, 60)', ['data_table_migrations']);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Releases the mysql migration lock.
|
|
234
|
+
* @returns A promise that resolves when the lock is released.
|
|
235
|
+
*/
|
|
236
|
+
async releaseMigrationLock() {
|
|
237
|
+
await this.#client.query('select release_lock(?)', ['data_table_migrations']);
|
|
238
|
+
}
|
|
111
239
|
#resolveClient(token) {
|
|
112
240
|
if (!token) {
|
|
113
241
|
return this.#client;
|
|
@@ -127,16 +255,44 @@ export class MysqlDatabaseAdapter {
|
|
|
127
255
|
* @param client Mysql pool or connection.
|
|
128
256
|
* @param options Optional adapter capability overrides.
|
|
129
257
|
* @returns A configured mysql adapter.
|
|
258
|
+
* @example
|
|
259
|
+
* ```ts
|
|
260
|
+
* import { createPool } from 'mysql2/promise'
|
|
261
|
+
* import { createDatabase } from 'remix/data-table'
|
|
262
|
+
* import { createMysqlDatabaseAdapter } from 'remix/data-table-mysql'
|
|
263
|
+
*
|
|
264
|
+
* let pool = createPool({ uri: process.env.DATABASE_URL })
|
|
265
|
+
* let adapter = createMysqlDatabaseAdapter(pool)
|
|
266
|
+
* let db = createDatabase(adapter)
|
|
267
|
+
* ```
|
|
130
268
|
*/
|
|
131
269
|
export function createMysqlDatabaseAdapter(client, options) {
|
|
132
270
|
return new MysqlDatabaseAdapter(client, options);
|
|
133
271
|
}
|
|
134
272
|
function isMysqlPool(client) {
|
|
135
|
-
return typeof client.getConnection === 'function';
|
|
273
|
+
return 'getConnection' in client && typeof client.getConnection === 'function';
|
|
274
|
+
}
|
|
275
|
+
function isMysqlPoolConnection(connection) {
|
|
276
|
+
return 'release' in connection && typeof connection.release === 'function';
|
|
136
277
|
}
|
|
137
278
|
function isRowsResult(result) {
|
|
138
279
|
return Array.isArray(result) && (result.length === 0 || !Array.isArray(result[0]));
|
|
139
280
|
}
|
|
281
|
+
function toBooleanExists(value) {
|
|
282
|
+
if (typeof value === 'boolean') {
|
|
283
|
+
return value;
|
|
284
|
+
}
|
|
285
|
+
if (typeof value === 'number') {
|
|
286
|
+
return value > 0;
|
|
287
|
+
}
|
|
288
|
+
if (typeof value === 'bigint') {
|
|
289
|
+
return value > 0n;
|
|
290
|
+
}
|
|
291
|
+
if (typeof value === 'string') {
|
|
292
|
+
return value === '1' || value.toLowerCase() === 'true';
|
|
293
|
+
}
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
140
296
|
function normalizeRows(rows) {
|
|
141
297
|
return rows.map((row) => ({ ...row }));
|
|
142
298
|
}
|
|
@@ -174,11 +330,11 @@ function normalizeCountRows(rows) {
|
|
|
174
330
|
return row;
|
|
175
331
|
});
|
|
176
332
|
}
|
|
177
|
-
function normalizeInsertId(kind,
|
|
178
|
-
if (!
|
|
333
|
+
function normalizeInsertId(kind, operation, header) {
|
|
334
|
+
if (!isInsertOperationKind(kind) || !isInsertOperation(operation)) {
|
|
179
335
|
return undefined;
|
|
180
336
|
}
|
|
181
|
-
if (getTablePrimaryKey(
|
|
337
|
+
if (getTablePrimaryKey(operation.table).length !== 1) {
|
|
182
338
|
return undefined;
|
|
183
339
|
}
|
|
184
340
|
return header.insertId;
|
|
@@ -186,9 +342,383 @@ function normalizeInsertId(kind, statement, header) {
|
|
|
186
342
|
function quoteIdentifier(value) {
|
|
187
343
|
return '`' + value.replace(/`/g, '``') + '`';
|
|
188
344
|
}
|
|
189
|
-
function
|
|
345
|
+
function quoteTableRef(table) {
|
|
346
|
+
return quoteTableRefHelper(table, quoteIdentifier);
|
|
347
|
+
}
|
|
348
|
+
function quoteLiteral(value) {
|
|
349
|
+
return quoteLiteralHelper(value);
|
|
350
|
+
}
|
|
351
|
+
function isInsertOperationKind(kind) {
|
|
190
352
|
return kind === 'insert' || kind === 'insertMany' || kind === 'upsert';
|
|
191
353
|
}
|
|
192
|
-
function
|
|
193
|
-
return (
|
|
354
|
+
function isInsertOperation(operation) {
|
|
355
|
+
return (operation.kind === 'insert' || operation.kind === 'insertMany' || operation.kind === 'upsert');
|
|
356
|
+
}
|
|
357
|
+
function isDataManipulationOperation(operation) {
|
|
358
|
+
return isDataManipulationOperationHelper(operation);
|
|
359
|
+
}
|
|
360
|
+
function compileMysqlMigrationOperations(operation) {
|
|
361
|
+
if (operation.kind === 'raw') {
|
|
362
|
+
return [{ text: operation.sql.text, values: [...operation.sql.values] }];
|
|
363
|
+
}
|
|
364
|
+
if (operation.kind === 'createTable') {
|
|
365
|
+
let columns = Object.keys(operation.columns).map((columnName) => quoteIdentifier(columnName) + ' ' + compileMysqlColumn(operation.columns[columnName]));
|
|
366
|
+
let constraints = [];
|
|
367
|
+
if (operation.primaryKey) {
|
|
368
|
+
constraints.push('constraint ' +
|
|
369
|
+
quoteIdentifier(operation.primaryKey.name) +
|
|
370
|
+
' primary key (' +
|
|
371
|
+
operation.primaryKey.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
372
|
+
')');
|
|
373
|
+
}
|
|
374
|
+
for (let unique of operation.uniques ?? []) {
|
|
375
|
+
constraints.push('constraint ' +
|
|
376
|
+
quoteIdentifier(unique.name) +
|
|
377
|
+
' ' +
|
|
378
|
+
'unique (' +
|
|
379
|
+
unique.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
380
|
+
')');
|
|
381
|
+
}
|
|
382
|
+
for (let check of operation.checks ?? []) {
|
|
383
|
+
constraints.push('constraint ' + quoteIdentifier(check.name) + ' ' + 'check (' + check.expression + ')');
|
|
384
|
+
}
|
|
385
|
+
for (let foreignKey of operation.foreignKeys ?? []) {
|
|
386
|
+
let clause = 'constraint ' +
|
|
387
|
+
quoteIdentifier(foreignKey.name) +
|
|
388
|
+
' ' +
|
|
389
|
+
'foreign key (' +
|
|
390
|
+
foreignKey.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
391
|
+
') references ' +
|
|
392
|
+
quoteTableRef(foreignKey.references.table) +
|
|
393
|
+
' (' +
|
|
394
|
+
foreignKey.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
395
|
+
')';
|
|
396
|
+
if (foreignKey.onDelete) {
|
|
397
|
+
clause += ' on delete ' + foreignKey.onDelete;
|
|
398
|
+
}
|
|
399
|
+
if (foreignKey.onUpdate) {
|
|
400
|
+
clause += ' on update ' + foreignKey.onUpdate;
|
|
401
|
+
}
|
|
402
|
+
constraints.push(clause);
|
|
403
|
+
}
|
|
404
|
+
let sql = 'create table ' +
|
|
405
|
+
(operation.ifNotExists ? 'if not exists ' : '') +
|
|
406
|
+
quoteTableRef(operation.table) +
|
|
407
|
+
' (' +
|
|
408
|
+
[...columns, ...constraints].join(', ') +
|
|
409
|
+
')';
|
|
410
|
+
let statements = [{ text: sql, values: [] }];
|
|
411
|
+
if (operation.comment) {
|
|
412
|
+
statements.push({
|
|
413
|
+
text: 'alter table ' +
|
|
414
|
+
quoteTableRef(operation.table) +
|
|
415
|
+
' comment = ' +
|
|
416
|
+
quoteLiteral(operation.comment),
|
|
417
|
+
values: [],
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
return statements;
|
|
421
|
+
}
|
|
422
|
+
if (operation.kind === 'alterTable') {
|
|
423
|
+
let statements = [];
|
|
424
|
+
for (let change of operation.changes) {
|
|
425
|
+
let sql = 'alter table ' + quoteTableRef(operation.table) + ' ';
|
|
426
|
+
if (change.kind === 'addColumn') {
|
|
427
|
+
sql +=
|
|
428
|
+
'add column ' +
|
|
429
|
+
quoteIdentifier(change.column) +
|
|
430
|
+
' ' +
|
|
431
|
+
compileMysqlColumn(change.definition);
|
|
432
|
+
}
|
|
433
|
+
else if (change.kind === 'changeColumn') {
|
|
434
|
+
sql +=
|
|
435
|
+
'modify column ' +
|
|
436
|
+
quoteIdentifier(change.column) +
|
|
437
|
+
' ' +
|
|
438
|
+
compileMysqlColumn(change.definition);
|
|
439
|
+
}
|
|
440
|
+
else if (change.kind === 'renameColumn') {
|
|
441
|
+
sql += 'rename column ' + quoteIdentifier(change.from) + ' to ' + quoteIdentifier(change.to);
|
|
442
|
+
}
|
|
443
|
+
else if (change.kind === 'dropColumn') {
|
|
444
|
+
sql += 'drop column ' + quoteIdentifier(change.column);
|
|
445
|
+
}
|
|
446
|
+
else if (change.kind === 'addPrimaryKey') {
|
|
447
|
+
sql +=
|
|
448
|
+
'add primary key (' +
|
|
449
|
+
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
450
|
+
')';
|
|
451
|
+
}
|
|
452
|
+
else if (change.kind === 'dropPrimaryKey') {
|
|
453
|
+
sql += 'drop primary key';
|
|
454
|
+
}
|
|
455
|
+
else if (change.kind === 'addUnique') {
|
|
456
|
+
sql +=
|
|
457
|
+
'add ' +
|
|
458
|
+
'constraint ' +
|
|
459
|
+
quoteIdentifier(change.constraint.name) +
|
|
460
|
+
' ' +
|
|
461
|
+
'unique (' +
|
|
462
|
+
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
463
|
+
')';
|
|
464
|
+
}
|
|
465
|
+
else if (change.kind === 'dropUnique') {
|
|
466
|
+
sql += 'drop index ' + quoteIdentifier(change.name);
|
|
467
|
+
}
|
|
468
|
+
else if (change.kind === 'addForeignKey') {
|
|
469
|
+
sql +=
|
|
470
|
+
'add ' +
|
|
471
|
+
'constraint ' +
|
|
472
|
+
quoteIdentifier(change.constraint.name) +
|
|
473
|
+
' ' +
|
|
474
|
+
'foreign key (' +
|
|
475
|
+
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
476
|
+
') references ' +
|
|
477
|
+
quoteTableRef(change.constraint.references.table) +
|
|
478
|
+
' (' +
|
|
479
|
+
change.constraint.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
480
|
+
')';
|
|
481
|
+
}
|
|
482
|
+
else if (change.kind === 'dropForeignKey') {
|
|
483
|
+
sql += 'drop foreign key ' + quoteIdentifier(change.name);
|
|
484
|
+
}
|
|
485
|
+
else if (change.kind === 'addCheck') {
|
|
486
|
+
sql +=
|
|
487
|
+
'add ' +
|
|
488
|
+
'constraint ' +
|
|
489
|
+
quoteIdentifier(change.constraint.name) +
|
|
490
|
+
' ' +
|
|
491
|
+
'check (' +
|
|
492
|
+
change.constraint.expression +
|
|
493
|
+
')';
|
|
494
|
+
}
|
|
495
|
+
else if (change.kind === 'dropCheck') {
|
|
496
|
+
sql += 'drop check ' + quoteIdentifier(change.name);
|
|
497
|
+
}
|
|
498
|
+
else if (change.kind === 'setTableComment') {
|
|
499
|
+
sql += 'comment = ' + quoteLiteral(change.comment);
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
statements.push({ text: sql, values: [] });
|
|
505
|
+
}
|
|
506
|
+
return statements;
|
|
507
|
+
}
|
|
508
|
+
if (operation.kind === 'renameTable') {
|
|
509
|
+
return [
|
|
510
|
+
{
|
|
511
|
+
text: 'rename table ' + quoteTableRef(operation.from) + ' to ' + quoteTableRef(operation.to),
|
|
512
|
+
values: [],
|
|
513
|
+
},
|
|
514
|
+
];
|
|
515
|
+
}
|
|
516
|
+
if (operation.kind === 'dropTable') {
|
|
517
|
+
return [
|
|
518
|
+
{
|
|
519
|
+
text: 'drop table ' + (operation.ifExists ? 'if exists ' : '') + quoteTableRef(operation.table),
|
|
520
|
+
values: [],
|
|
521
|
+
},
|
|
522
|
+
];
|
|
523
|
+
}
|
|
524
|
+
if (operation.kind === 'createIndex') {
|
|
525
|
+
return [
|
|
526
|
+
{
|
|
527
|
+
text: 'create ' +
|
|
528
|
+
(operation.index.unique ? 'unique ' : '') +
|
|
529
|
+
'index ' +
|
|
530
|
+
quoteIdentifier(operation.index.name) +
|
|
531
|
+
' on ' +
|
|
532
|
+
quoteTableRef(operation.index.table) +
|
|
533
|
+
(operation.index.using ? ' using ' + operation.index.using : '') +
|
|
534
|
+
' (' +
|
|
535
|
+
operation.index.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
536
|
+
')' +
|
|
537
|
+
(operation.index.where ? ' where ' + operation.index.where : ''),
|
|
538
|
+
values: [],
|
|
539
|
+
},
|
|
540
|
+
];
|
|
541
|
+
}
|
|
542
|
+
if (operation.kind === 'dropIndex') {
|
|
543
|
+
return [
|
|
544
|
+
{
|
|
545
|
+
text: 'drop index ' + quoteIdentifier(operation.name) + ' on ' + quoteTableRef(operation.table),
|
|
546
|
+
values: [],
|
|
547
|
+
},
|
|
548
|
+
];
|
|
549
|
+
}
|
|
550
|
+
if (operation.kind === 'renameIndex') {
|
|
551
|
+
return [
|
|
552
|
+
{
|
|
553
|
+
text: 'alter table ' +
|
|
554
|
+
quoteTableRef(operation.table) +
|
|
555
|
+
' rename index ' +
|
|
556
|
+
quoteIdentifier(operation.from) +
|
|
557
|
+
' to ' +
|
|
558
|
+
quoteIdentifier(operation.to),
|
|
559
|
+
values: [],
|
|
560
|
+
},
|
|
561
|
+
];
|
|
562
|
+
}
|
|
563
|
+
if (operation.kind === 'addForeignKey') {
|
|
564
|
+
return [
|
|
565
|
+
{
|
|
566
|
+
text: 'alter table ' +
|
|
567
|
+
quoteTableRef(operation.table) +
|
|
568
|
+
' add ' +
|
|
569
|
+
'constraint ' +
|
|
570
|
+
quoteIdentifier(operation.constraint.name) +
|
|
571
|
+
' ' +
|
|
572
|
+
'foreign key (' +
|
|
573
|
+
operation.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
574
|
+
') references ' +
|
|
575
|
+
quoteTableRef(operation.constraint.references.table) +
|
|
576
|
+
' (' +
|
|
577
|
+
operation.constraint.references.columns
|
|
578
|
+
.map((column) => quoteIdentifier(column))
|
|
579
|
+
.join(', ') +
|
|
580
|
+
')' +
|
|
581
|
+
(operation.constraint.onDelete ? ' on delete ' + operation.constraint.onDelete : '') +
|
|
582
|
+
(operation.constraint.onUpdate ? ' on update ' + operation.constraint.onUpdate : ''),
|
|
583
|
+
values: [],
|
|
584
|
+
},
|
|
585
|
+
];
|
|
586
|
+
}
|
|
587
|
+
if (operation.kind === 'dropForeignKey') {
|
|
588
|
+
return [
|
|
589
|
+
{
|
|
590
|
+
text: 'alter table ' +
|
|
591
|
+
quoteTableRef(operation.table) +
|
|
592
|
+
' drop foreign key ' +
|
|
593
|
+
quoteIdentifier(operation.name),
|
|
594
|
+
values: [],
|
|
595
|
+
},
|
|
596
|
+
];
|
|
597
|
+
}
|
|
598
|
+
if (operation.kind === 'addCheck') {
|
|
599
|
+
return [
|
|
600
|
+
{
|
|
601
|
+
text: 'alter table ' +
|
|
602
|
+
quoteTableRef(operation.table) +
|
|
603
|
+
' add ' +
|
|
604
|
+
'constraint ' +
|
|
605
|
+
quoteIdentifier(operation.constraint.name) +
|
|
606
|
+
' ' +
|
|
607
|
+
'check (' +
|
|
608
|
+
operation.constraint.expression +
|
|
609
|
+
')',
|
|
610
|
+
values: [],
|
|
611
|
+
},
|
|
612
|
+
];
|
|
613
|
+
}
|
|
614
|
+
if (operation.kind === 'dropCheck') {
|
|
615
|
+
return [
|
|
616
|
+
{
|
|
617
|
+
text: 'alter table ' +
|
|
618
|
+
quoteTableRef(operation.table) +
|
|
619
|
+
' drop check ' +
|
|
620
|
+
quoteIdentifier(operation.name),
|
|
621
|
+
values: [],
|
|
622
|
+
},
|
|
623
|
+
];
|
|
624
|
+
}
|
|
625
|
+
throw new Error('Unsupported data migration operation kind');
|
|
626
|
+
}
|
|
627
|
+
function compileMysqlColumn(definition) {
|
|
628
|
+
let parts = [compileMysqlColumnType(definition)];
|
|
629
|
+
if (definition.nullable === false) {
|
|
630
|
+
parts.push('not null');
|
|
631
|
+
}
|
|
632
|
+
if (definition.default) {
|
|
633
|
+
if (definition.default.kind === 'now') {
|
|
634
|
+
parts.push('default current_timestamp');
|
|
635
|
+
}
|
|
636
|
+
else if (definition.default.kind === 'sql') {
|
|
637
|
+
parts.push('default ' + definition.default.expression);
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
parts.push('default ' + quoteLiteral(definition.default.value));
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (definition.autoIncrement) {
|
|
644
|
+
parts.push('auto_increment');
|
|
645
|
+
}
|
|
646
|
+
if (definition.primaryKey) {
|
|
647
|
+
parts.push('primary key');
|
|
648
|
+
}
|
|
649
|
+
if (definition.unique) {
|
|
650
|
+
parts.push('unique');
|
|
651
|
+
}
|
|
652
|
+
if (definition.computed) {
|
|
653
|
+
parts.push('generated always as (' + definition.computed.expression + ')');
|
|
654
|
+
parts.push(definition.computed.stored ? 'stored' : 'virtual');
|
|
655
|
+
}
|
|
656
|
+
if (definition.references) {
|
|
657
|
+
let clause = 'references ' +
|
|
658
|
+
quoteTableRef(definition.references.table) +
|
|
659
|
+
' (' +
|
|
660
|
+
definition.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
661
|
+
')';
|
|
662
|
+
if (definition.references.onDelete) {
|
|
663
|
+
clause += ' on delete ' + definition.references.onDelete;
|
|
664
|
+
}
|
|
665
|
+
if (definition.references.onUpdate) {
|
|
666
|
+
clause += ' on update ' + definition.references.onUpdate;
|
|
667
|
+
}
|
|
668
|
+
parts.push(clause);
|
|
669
|
+
}
|
|
670
|
+
if (definition.checks && definition.checks.length > 0) {
|
|
671
|
+
for (let check of definition.checks) {
|
|
672
|
+
parts.push('check (' + check.expression + ')');
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return parts.join(' ');
|
|
676
|
+
}
|
|
677
|
+
function compileMysqlColumnType(definition) {
|
|
678
|
+
if (definition.type === 'varchar') {
|
|
679
|
+
return 'varchar(' + String(definition.length ?? 255) + ')';
|
|
680
|
+
}
|
|
681
|
+
if (definition.type === 'text') {
|
|
682
|
+
return 'text';
|
|
683
|
+
}
|
|
684
|
+
if (definition.type === 'integer') {
|
|
685
|
+
return definition.unsigned ? 'int unsigned' : 'int';
|
|
686
|
+
}
|
|
687
|
+
if (definition.type === 'bigint') {
|
|
688
|
+
return definition.unsigned ? 'bigint unsigned' : 'bigint';
|
|
689
|
+
}
|
|
690
|
+
if (definition.type === 'decimal') {
|
|
691
|
+
if (definition.precision !== undefined && definition.scale !== undefined) {
|
|
692
|
+
return 'decimal(' + String(definition.precision) + ', ' + String(definition.scale) + ')';
|
|
693
|
+
}
|
|
694
|
+
return 'decimal';
|
|
695
|
+
}
|
|
696
|
+
if (definition.type === 'boolean') {
|
|
697
|
+
return 'boolean';
|
|
698
|
+
}
|
|
699
|
+
if (definition.type === 'uuid') {
|
|
700
|
+
return 'char(36)';
|
|
701
|
+
}
|
|
702
|
+
if (definition.type === 'date') {
|
|
703
|
+
return 'date';
|
|
704
|
+
}
|
|
705
|
+
if (definition.type === 'time') {
|
|
706
|
+
return 'time';
|
|
707
|
+
}
|
|
708
|
+
if (definition.type === 'timestamp') {
|
|
709
|
+
return 'timestamp';
|
|
710
|
+
}
|
|
711
|
+
if (definition.type === 'json') {
|
|
712
|
+
return 'json';
|
|
713
|
+
}
|
|
714
|
+
if (definition.type === 'binary') {
|
|
715
|
+
return 'blob';
|
|
716
|
+
}
|
|
717
|
+
if (definition.type === 'enum') {
|
|
718
|
+
if (definition.enumValues && definition.enumValues.length > 0) {
|
|
719
|
+
return 'enum(' + definition.enumValues.map((value) => quoteLiteral(value)).join(', ') + ')';
|
|
720
|
+
}
|
|
721
|
+
return 'text';
|
|
722
|
+
}
|
|
723
|
+
return 'text';
|
|
194
724
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
text: string;
|
|
4
|
-
values: unknown[];
|
|
5
|
-
};
|
|
6
|
-
export declare function compileMysqlStatement(statement: AdapterStatement): CompiledSql;
|
|
7
|
-
export {};
|
|
1
|
+
import type { DataManipulationOperation, SqlStatement } from '@remix-run/data-table';
|
|
2
|
+
export declare function compileMysqlOperation(operation: DataManipulationOperation): SqlStatement;
|
|
8
3
|
//# sourceMappingURL=sql-compiler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql-compiler.d.ts","sourceRoot":"","sources":["../../src/lib/sql-compiler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"sql-compiler.d.ts","sourceRoot":"","sources":["../../src/lib/sql-compiler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAa,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAe/F,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,yBAAyB,GAAG,YAAY,CAgGxF"}
|