@mikro-orm/sql 7.0.0-dev.100
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/AbstractSqlConnection.d.ts +57 -0
- package/AbstractSqlConnection.js +239 -0
- package/AbstractSqlDriver.d.ts +94 -0
- package/AbstractSqlDriver.js +1387 -0
- package/AbstractSqlPlatform.d.ts +37 -0
- package/AbstractSqlPlatform.js +100 -0
- package/LICENSE +21 -0
- package/PivotCollectionPersister.d.ts +22 -0
- package/PivotCollectionPersister.js +159 -0
- package/README.md +390 -0
- package/SqlEntityManager.d.ts +33 -0
- package/SqlEntityManager.js +44 -0
- package/SqlEntityRepository.d.ts +19 -0
- package/SqlEntityRepository.js +26 -0
- package/dialects/index.d.ts +4 -0
- package/dialects/index.js +4 -0
- package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +14 -0
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +200 -0
- package/dialects/mssql/index.d.ts +1 -0
- package/dialects/mssql/index.js +1 -0
- package/dialects/mysql/MySqlExceptionConverter.d.ts +9 -0
- package/dialects/mysql/MySqlExceptionConverter.js +80 -0
- package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +7 -0
- package/dialects/mysql/MySqlNativeQueryBuilder.js +77 -0
- package/dialects/mysql/MySqlPlatform.d.ts +46 -0
- package/dialects/mysql/MySqlPlatform.js +120 -0
- package/dialects/mysql/MySqlSchemaHelper.d.ts +36 -0
- package/dialects/mysql/MySqlSchemaHelper.js +269 -0
- package/dialects/mysql/index.d.ts +4 -0
- package/dialects/mysql/index.js +4 -0
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +5 -0
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +8 -0
- package/dialects/postgresql/PostgreSqlTableCompiler.d.ts +1 -0
- package/dialects/postgresql/PostgreSqlTableCompiler.js +1 -0
- package/dialects/postgresql/index.d.ts +1 -0
- package/dialects/postgresql/index.js +1 -0
- package/dialects/sqlite/BaseSqliteConnection.d.ts +6 -0
- package/dialects/sqlite/BaseSqliteConnection.js +8 -0
- package/dialects/sqlite/BaseSqlitePlatform.d.ts +70 -0
- package/dialects/sqlite/BaseSqlitePlatform.js +104 -0
- package/dialects/sqlite/SqliteExceptionConverter.d.ts +9 -0
- package/dialects/sqlite/SqliteExceptionConverter.js +54 -0
- package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +6 -0
- package/dialects/sqlite/SqliteNativeQueryBuilder.js +11 -0
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +38 -0
- package/dialects/sqlite/SqliteSchemaHelper.js +379 -0
- package/dialects/sqlite/index.d.ts +5 -0
- package/dialects/sqlite/index.js +5 -0
- package/index.d.ts +19 -0
- package/index.js +19 -0
- package/package.json +61 -0
- package/plugin/index.d.ts +53 -0
- package/plugin/index.js +42 -0
- package/plugin/transformer.d.ts +115 -0
- package/plugin/transformer.js +883 -0
- package/query/ArrayCriteriaNode.d.ts +11 -0
- package/query/ArrayCriteriaNode.js +24 -0
- package/query/CriteriaNode.d.ts +29 -0
- package/query/CriteriaNode.js +121 -0
- package/query/CriteriaNodeFactory.d.ts +12 -0
- package/query/CriteriaNodeFactory.js +90 -0
- package/query/NativeQueryBuilder.d.ts +108 -0
- package/query/NativeQueryBuilder.js +425 -0
- package/query/ObjectCriteriaNode.d.ts +19 -0
- package/query/ObjectCriteriaNode.js +249 -0
- package/query/QueryBuilder.d.ts +389 -0
- package/query/QueryBuilder.js +1558 -0
- package/query/QueryBuilderHelper.d.ts +73 -0
- package/query/QueryBuilderHelper.js +756 -0
- package/query/ScalarCriteriaNode.d.ts +10 -0
- package/query/ScalarCriteriaNode.js +49 -0
- package/query/enums.d.ts +18 -0
- package/query/enums.js +20 -0
- package/query/index.d.ts +10 -0
- package/query/index.js +10 -0
- package/query/raw.d.ts +59 -0
- package/query/raw.js +68 -0
- package/schema/DatabaseSchema.d.ts +45 -0
- package/schema/DatabaseSchema.js +185 -0
- package/schema/DatabaseTable.d.ts +68 -0
- package/schema/DatabaseTable.js +793 -0
- package/schema/SchemaComparator.d.ts +58 -0
- package/schema/SchemaComparator.js +577 -0
- package/schema/SchemaHelper.d.ts +76 -0
- package/schema/SchemaHelper.js +545 -0
- package/schema/SqlSchemaGenerator.d.ts +65 -0
- package/schema/SqlSchemaGenerator.js +375 -0
- package/schema/index.d.ts +5 -0
- package/schema/index.js +5 -0
- package/typings.d.ts +272 -0
- package/typings.js +1 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { Utils } from '@mikro-orm/core';
|
|
2
|
+
import { SchemaHelper } from '../../schema/SchemaHelper.js';
|
|
3
|
+
export class SqliteSchemaHelper extends SchemaHelper {
|
|
4
|
+
disableForeignKeysSQL() {
|
|
5
|
+
return 'pragma foreign_keys = off;';
|
|
6
|
+
}
|
|
7
|
+
enableForeignKeysSQL() {
|
|
8
|
+
return 'pragma foreign_keys = on;';
|
|
9
|
+
}
|
|
10
|
+
supportsSchemaConstraints() {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
getListTablesSQL() {
|
|
14
|
+
return `select name as table_name from sqlite_master where type = 'table' and name != 'sqlite_sequence' and name != 'geometry_columns' and name != 'spatial_ref_sys' `
|
|
15
|
+
+ `union all select name as table_name from sqlite_temp_master where type = 'table' order by name`;
|
|
16
|
+
}
|
|
17
|
+
getDropDatabaseSQL(name) {
|
|
18
|
+
if (name === ':memory:') {
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
/* v8 ignore next */
|
|
22
|
+
return `drop database if exists ${this.quote(name)}`;
|
|
23
|
+
}
|
|
24
|
+
async loadInformationSchema(schema, connection, tables, schemas) {
|
|
25
|
+
for (const t of tables) {
|
|
26
|
+
const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
|
|
27
|
+
const cols = await this.getColumns(connection, table.name, table.schema);
|
|
28
|
+
const indexes = await this.getIndexes(connection, table.name, table.schema);
|
|
29
|
+
const checks = await this.getChecks(connection, table.name, table.schema);
|
|
30
|
+
const pks = await this.getPrimaryKeys(connection, indexes, table.name, table.schema);
|
|
31
|
+
const fks = await this.getForeignKeys(connection, table.name, table.schema);
|
|
32
|
+
const enums = await this.getEnumDefinitions(connection, table.name);
|
|
33
|
+
table.init(cols, indexes, checks, pks, fks, enums);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
createTable(table, alter) {
|
|
37
|
+
let sql = `create table ${table.getQuotedName()} (`;
|
|
38
|
+
const columns = table.getColumns();
|
|
39
|
+
const lastColumn = columns[columns.length - 1].name;
|
|
40
|
+
for (const column of columns) {
|
|
41
|
+
const col = this.createTableColumn(column, table);
|
|
42
|
+
if (col) {
|
|
43
|
+
const comma = column.name === lastColumn ? '' : ', ';
|
|
44
|
+
sql += col + comma;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const primaryKey = table.getPrimaryKey();
|
|
48
|
+
const createPrimary = primaryKey?.composite;
|
|
49
|
+
if (createPrimary && primaryKey) {
|
|
50
|
+
sql += `, primary key (${primaryKey.columnNames.map(c => this.quote(c)).join(', ')})`;
|
|
51
|
+
}
|
|
52
|
+
const parts = [];
|
|
53
|
+
for (const fk of Object.values(table.getForeignKeys())) {
|
|
54
|
+
parts.push(this.createForeignKey(table, fk, false));
|
|
55
|
+
}
|
|
56
|
+
for (const check of table.getChecks()) {
|
|
57
|
+
const sql = `constraint ${this.quote(check.name)} check (${check.expression})`;
|
|
58
|
+
parts.push(sql);
|
|
59
|
+
}
|
|
60
|
+
if (parts.length > 0) {
|
|
61
|
+
sql += ', ' + parts.join(', ');
|
|
62
|
+
}
|
|
63
|
+
sql += ')';
|
|
64
|
+
const ret = [];
|
|
65
|
+
this.append(ret, sql);
|
|
66
|
+
for (const index of table.getIndexes()) {
|
|
67
|
+
this.append(ret, this.createIndex(index, table));
|
|
68
|
+
}
|
|
69
|
+
return ret;
|
|
70
|
+
}
|
|
71
|
+
createTableColumn(column, table, _changedProperties) {
|
|
72
|
+
const col = [this.quote(column.name)];
|
|
73
|
+
const checks = table.getChecks();
|
|
74
|
+
const check = checks.findIndex(check => check.columnName === column.name);
|
|
75
|
+
const useDefault = column.default != null && column.default !== 'null';
|
|
76
|
+
let columnType = column.type;
|
|
77
|
+
if (column.autoincrement) {
|
|
78
|
+
columnType = 'integer';
|
|
79
|
+
}
|
|
80
|
+
if (column.generated) {
|
|
81
|
+
columnType += ` generated always as ${column.generated}`;
|
|
82
|
+
}
|
|
83
|
+
col.push(columnType);
|
|
84
|
+
if (check !== -1) {
|
|
85
|
+
col.push(`check (${checks[check].expression})`);
|
|
86
|
+
checks.splice(check, 1);
|
|
87
|
+
}
|
|
88
|
+
Utils.runIfNotEmpty(() => col.push('null'), column.nullable);
|
|
89
|
+
Utils.runIfNotEmpty(() => col.push('not null'), !column.nullable && !column.generated);
|
|
90
|
+
Utils.runIfNotEmpty(() => col.push('primary key'), column.primary);
|
|
91
|
+
Utils.runIfNotEmpty(() => col.push('autoincrement'), column.autoincrement);
|
|
92
|
+
Utils.runIfNotEmpty(() => col.push(`default ${column.default}`), useDefault);
|
|
93
|
+
return col.join(' ');
|
|
94
|
+
}
|
|
95
|
+
getAddColumnsSQL(table, columns, diff) {
|
|
96
|
+
return columns.map(column => {
|
|
97
|
+
let sql = `alter table ${table.getQuotedName()} add column ${this.createTableColumn(column, table)}`;
|
|
98
|
+
const foreignKey = Object.values(diff.addedForeignKeys).find(fk => fk.columnNames.length === 1 && fk.columnNames[0] === column.name);
|
|
99
|
+
if (foreignKey && this.options.createForeignKeyConstraints) {
|
|
100
|
+
delete diff.addedForeignKeys[foreignKey.constraintName];
|
|
101
|
+
sql += ' ' + this.createForeignKey(diff.toTable, foreignKey, false, true);
|
|
102
|
+
}
|
|
103
|
+
return sql;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
dropForeignKey(tableName, constraintName) {
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
getDropColumnsSQL(tableName, columns, schemaName) {
|
|
110
|
+
/* v8 ignore next */
|
|
111
|
+
const name = this.quote((schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName);
|
|
112
|
+
return columns.map(column => {
|
|
113
|
+
return `alter table ${name} drop column ${this.quote(column.name)}`;
|
|
114
|
+
}).join(';\n');
|
|
115
|
+
}
|
|
116
|
+
getCreateIndexSQL(tableName, index) {
|
|
117
|
+
/* v8 ignore next */
|
|
118
|
+
if (index.expression) {
|
|
119
|
+
return index.expression;
|
|
120
|
+
}
|
|
121
|
+
tableName = this.quote(tableName);
|
|
122
|
+
const keyName = this.quote(index.keyName);
|
|
123
|
+
const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} `;
|
|
124
|
+
if (index.columnNames.some(column => column.includes('.'))) {
|
|
125
|
+
// JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
|
|
126
|
+
const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} `;
|
|
127
|
+
const columns = this.platform.getJsonIndexDefinition(index);
|
|
128
|
+
return `${sql}(${columns.join(', ')})`;
|
|
129
|
+
}
|
|
130
|
+
return `${sql}(${index.columnNames.map(c => this.quote(c)).join(', ')})`;
|
|
131
|
+
}
|
|
132
|
+
parseTableDefinition(sql, cols) {
|
|
133
|
+
const columns = {};
|
|
134
|
+
const constraints = [];
|
|
135
|
+
// extract all columns definitions
|
|
136
|
+
let columnsDef = sql.replaceAll('\n', '').match(new RegExp(`create table [\`"']?.*?[\`"']? \\((.*)\\)`, 'i'))?.[1];
|
|
137
|
+
/* v8 ignore next */
|
|
138
|
+
if (columnsDef) {
|
|
139
|
+
if (columnsDef.includes(', constraint ')) {
|
|
140
|
+
constraints.push(...columnsDef.substring(columnsDef.indexOf(', constraint') + 2).split(', '));
|
|
141
|
+
columnsDef = columnsDef.substring(0, columnsDef.indexOf(', constraint'));
|
|
142
|
+
}
|
|
143
|
+
for (let i = cols.length - 1; i >= 0; i--) {
|
|
144
|
+
const col = cols[i];
|
|
145
|
+
const re = ` *, *[\`"']?${col.name}[\`"']? (.*)`;
|
|
146
|
+
const columnDef = columnsDef.match(new RegExp(re, 'i'));
|
|
147
|
+
if (columnDef) {
|
|
148
|
+
columns[col.name] = { name: col.name, definition: columnDef[1] };
|
|
149
|
+
columnsDef = columnsDef.substring(0, columnDef.index);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { columns, constraints };
|
|
154
|
+
}
|
|
155
|
+
async getColumns(connection, tableName, schemaName) {
|
|
156
|
+
const columns = await connection.execute(`pragma table_xinfo('${tableName}')`);
|
|
157
|
+
const sql = `select sql from sqlite_master where type = ? and name = ?`;
|
|
158
|
+
const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
|
|
159
|
+
const composite = columns.reduce((count, col) => count + (col.pk ? 1 : 0), 0) > 1;
|
|
160
|
+
// there can be only one, so naive check like this should be enough
|
|
161
|
+
const hasAutoincrement = tableDefinition.sql.toLowerCase().includes('autoincrement');
|
|
162
|
+
const { columns: columnDefinitions } = this.parseTableDefinition(tableDefinition.sql, columns);
|
|
163
|
+
return columns.map(col => {
|
|
164
|
+
const mappedType = connection.getPlatform().getMappedType(col.type);
|
|
165
|
+
let generated;
|
|
166
|
+
if (col.hidden > 1) {
|
|
167
|
+
/* v8 ignore next */
|
|
168
|
+
const storage = col.hidden === 2 ? 'virtual' : 'stored';
|
|
169
|
+
const re = new RegExp(`(generated always)? as \\((.*)\\)( ${storage})?$`, 'i');
|
|
170
|
+
const match = columnDefinitions[col.name].definition.match(re);
|
|
171
|
+
if (match) {
|
|
172
|
+
generated = `${match[2]} ${storage}`;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
name: col.name,
|
|
177
|
+
type: col.type,
|
|
178
|
+
default: col.dflt_value,
|
|
179
|
+
nullable: !col.notnull,
|
|
180
|
+
primary: !!col.pk,
|
|
181
|
+
mappedType,
|
|
182
|
+
unsigned: false,
|
|
183
|
+
autoincrement: !composite && col.pk && this.platform.isNumericColumn(mappedType) && hasAutoincrement,
|
|
184
|
+
generated,
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
async getEnumDefinitions(connection, tableName) {
|
|
189
|
+
const sql = `select sql from sqlite_master where type = ? and name = ?`;
|
|
190
|
+
const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
|
|
191
|
+
const checkConstraints = [...(tableDefinition.sql.match(/[`["'][^`\]"']+[`\]"'] text check \(.*?\)/gi) ?? [])];
|
|
192
|
+
return checkConstraints.reduce((o, item) => {
|
|
193
|
+
// check constraints are defined as (note that last closing paren is missing):
|
|
194
|
+
// `type` text check (`type` in ('local', 'global')
|
|
195
|
+
const match = item.match(/[`["']([^`\]"']+)[`\]"'] text check \(.* \((.*)\)/i);
|
|
196
|
+
/* v8 ignore next */
|
|
197
|
+
if (match) {
|
|
198
|
+
o[match[1]] = match[2].split(',').map((item) => item.trim().match(/^\(?'(.*)'/)[1]);
|
|
199
|
+
}
|
|
200
|
+
return o;
|
|
201
|
+
}, {});
|
|
202
|
+
}
|
|
203
|
+
async getPrimaryKeys(connection, indexes, tableName, schemaName) {
|
|
204
|
+
const sql = `pragma table_info(\`${tableName}\`)`;
|
|
205
|
+
const cols = await connection.execute(sql);
|
|
206
|
+
return cols.filter(col => !!col.pk).map(col => col.name);
|
|
207
|
+
}
|
|
208
|
+
async getIndexes(connection, tableName, schemaName) {
|
|
209
|
+
const sql = `pragma table_info(\`${tableName}\`)`;
|
|
210
|
+
const cols = await connection.execute(sql);
|
|
211
|
+
const indexes = await connection.execute(`pragma index_list(\`${tableName}\`)`);
|
|
212
|
+
const ret = [];
|
|
213
|
+
for (const col of cols.filter(c => c.pk)) {
|
|
214
|
+
ret.push({
|
|
215
|
+
columnNames: [col.name],
|
|
216
|
+
keyName: 'primary',
|
|
217
|
+
constraint: true,
|
|
218
|
+
unique: true,
|
|
219
|
+
primary: true,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
for (const index of indexes.filter(index => !this.isImplicitIndex(index.name))) {
|
|
223
|
+
const res = await connection.execute(`pragma index_info(\`${index.name}\`)`);
|
|
224
|
+
ret.push(...res.map(row => ({
|
|
225
|
+
columnNames: [row.name],
|
|
226
|
+
keyName: index.name,
|
|
227
|
+
unique: !!index.unique,
|
|
228
|
+
constraint: !!index.unique,
|
|
229
|
+
primary: false,
|
|
230
|
+
})));
|
|
231
|
+
}
|
|
232
|
+
return this.mapIndexes(ret);
|
|
233
|
+
}
|
|
234
|
+
async getChecks(connection, tableName, schemaName) {
|
|
235
|
+
const { columns, constraints } = await this.getColumnDefinitions(connection, tableName, schemaName);
|
|
236
|
+
const checks = [];
|
|
237
|
+
for (const key of Object.keys(columns)) {
|
|
238
|
+
const column = columns[key];
|
|
239
|
+
const expression = column.definition.match(/ (check \((.*)\))/i);
|
|
240
|
+
if (expression) {
|
|
241
|
+
checks.push({
|
|
242
|
+
name: this.platform.getConfig().getNamingStrategy().indexName(tableName, [column.name], 'check'),
|
|
243
|
+
definition: expression[1],
|
|
244
|
+
expression: expression[2],
|
|
245
|
+
columnName: column.name,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
for (const constraint of constraints) {
|
|
250
|
+
const expression = constraint.match(/constraint *[`"']?(.*?)[`"']? * (check \((.*)\))/i);
|
|
251
|
+
if (expression) {
|
|
252
|
+
checks.push({
|
|
253
|
+
name: expression[1],
|
|
254
|
+
definition: expression[2],
|
|
255
|
+
expression: expression[3],
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return checks;
|
|
260
|
+
}
|
|
261
|
+
async getColumnDefinitions(connection, tableName, schemaName) {
|
|
262
|
+
const columns = await connection.execute(`pragma table_xinfo('${tableName}')`);
|
|
263
|
+
const sql = `select sql from sqlite_master where type = ? and name = ?`;
|
|
264
|
+
const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
|
|
265
|
+
return this.parseTableDefinition(tableDefinition.sql, columns);
|
|
266
|
+
}
|
|
267
|
+
async getForeignKeys(connection, tableName, schemaName) {
|
|
268
|
+
const { constraints } = await this.getColumnDefinitions(connection, tableName, schemaName);
|
|
269
|
+
const fks = await connection.execute(`pragma foreign_key_list(\`${tableName}\`)`);
|
|
270
|
+
return fks.reduce((ret, fk) => {
|
|
271
|
+
const constraintName = this.platform.getIndexName(tableName, [fk.from], 'foreign');
|
|
272
|
+
const constraint = constraints?.find(c => c.includes(constraintName));
|
|
273
|
+
ret[constraintName] = {
|
|
274
|
+
constraintName,
|
|
275
|
+
columnName: fk.from,
|
|
276
|
+
columnNames: [fk.from],
|
|
277
|
+
localTableName: tableName,
|
|
278
|
+
referencedTableName: fk.table,
|
|
279
|
+
referencedColumnName: fk.to,
|
|
280
|
+
referencedColumnNames: [fk.to],
|
|
281
|
+
updateRule: fk.on_update.toLowerCase(),
|
|
282
|
+
deleteRule: fk.on_delete.toLowerCase(),
|
|
283
|
+
deferMode: constraint?.match(/ deferrable initially (deferred|immediate)/i)?.[1].toLowerCase(),
|
|
284
|
+
};
|
|
285
|
+
return ret;
|
|
286
|
+
}, {});
|
|
287
|
+
}
|
|
288
|
+
getManagementDbName() {
|
|
289
|
+
return '';
|
|
290
|
+
}
|
|
291
|
+
getCreateDatabaseSQL(name) {
|
|
292
|
+
return '';
|
|
293
|
+
}
|
|
294
|
+
async databaseExists(connection, name) {
|
|
295
|
+
const tables = await connection.execute(this.getListTablesSQL());
|
|
296
|
+
return tables.length > 0;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Implicit indexes will be ignored when diffing
|
|
300
|
+
*/
|
|
301
|
+
isImplicitIndex(name) {
|
|
302
|
+
// Ignore indexes with reserved names, e.g. autoindexes
|
|
303
|
+
return name.startsWith('sqlite_');
|
|
304
|
+
}
|
|
305
|
+
dropIndex(table, index, oldIndexName = index.keyName) {
|
|
306
|
+
return `drop index ${this.quote(oldIndexName)}`;
|
|
307
|
+
}
|
|
308
|
+
alterTable(diff, safe) {
|
|
309
|
+
const ret = [];
|
|
310
|
+
const [schemaName, tableName] = this.splitTableName(diff.name);
|
|
311
|
+
if (Utils.hasObjectKeys(diff.removedChecks)
|
|
312
|
+
|| Utils.hasObjectKeys(diff.changedChecks)
|
|
313
|
+
|| Utils.hasObjectKeys(diff.changedForeignKeys)
|
|
314
|
+
|| Utils.hasObjectKeys(diff.changedColumns)) {
|
|
315
|
+
return this.getAlterTempTableSQL(diff);
|
|
316
|
+
}
|
|
317
|
+
for (const index of Object.values(diff.removedIndexes)) {
|
|
318
|
+
this.append(ret, this.dropIndex(diff.name, index));
|
|
319
|
+
}
|
|
320
|
+
for (const index of Object.values(diff.changedIndexes)) {
|
|
321
|
+
this.append(ret, this.dropIndex(diff.name, index));
|
|
322
|
+
}
|
|
323
|
+
/* v8 ignore next */
|
|
324
|
+
if (!safe && Object.values(diff.removedColumns).length > 0) {
|
|
325
|
+
this.append(ret, this.getDropColumnsSQL(tableName, Object.values(diff.removedColumns), schemaName));
|
|
326
|
+
}
|
|
327
|
+
if (Object.values(diff.addedColumns).length > 0) {
|
|
328
|
+
this.append(ret, this.getAddColumnsSQL(diff.toTable, Object.values(diff.addedColumns), diff));
|
|
329
|
+
}
|
|
330
|
+
if (Utils.hasObjectKeys(diff.addedForeignKeys) || Utils.hasObjectKeys(diff.addedChecks)) {
|
|
331
|
+
return this.getAlterTempTableSQL(diff);
|
|
332
|
+
}
|
|
333
|
+
for (const [oldColumnName, column] of Object.entries(diff.renamedColumns)) {
|
|
334
|
+
this.append(ret, this.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
|
|
335
|
+
}
|
|
336
|
+
for (const index of Object.values(diff.addedIndexes)) {
|
|
337
|
+
ret.push(this.createIndex(index, diff.toTable));
|
|
338
|
+
}
|
|
339
|
+
for (const index of Object.values(diff.changedIndexes)) {
|
|
340
|
+
ret.push(this.createIndex(index, diff.toTable, true));
|
|
341
|
+
}
|
|
342
|
+
for (const [oldIndexName, index] of Object.entries(diff.renamedIndexes)) {
|
|
343
|
+
if (index.unique) {
|
|
344
|
+
this.append(ret, this.dropIndex(diff.name, index, oldIndexName));
|
|
345
|
+
this.append(ret, this.createIndex(index, diff.toTable));
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
this.append(ret, this.getRenameIndexSQL(diff.name, index, oldIndexName));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return ret;
|
|
352
|
+
}
|
|
353
|
+
getAlterTempTableSQL(changedTable) {
|
|
354
|
+
const tempName = `${(changedTable.toTable.name)}__temp_alter`;
|
|
355
|
+
const quotedName = this.quote(changedTable.toTable.name);
|
|
356
|
+
const quotedTempName = this.quote(tempName);
|
|
357
|
+
const [first, ...rest] = this.createTable(changedTable.toTable);
|
|
358
|
+
const sql = [
|
|
359
|
+
'pragma foreign_keys = off;',
|
|
360
|
+
first.replace(`create table ${quotedName}`, `create table ${quotedTempName}`),
|
|
361
|
+
];
|
|
362
|
+
const columns = [];
|
|
363
|
+
for (const column of changedTable.toTable.getColumns()) {
|
|
364
|
+
const fromColumn = changedTable.fromTable.getColumn(column.name);
|
|
365
|
+
if (fromColumn) {
|
|
366
|
+
columns.push(this.quote(column.name));
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
columns.push(`null as ${this.quote(column.name)}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
sql.push(`insert into ${quotedTempName} select ${columns.join(', ')} from ${quotedName};`);
|
|
373
|
+
sql.push(`drop table ${quotedName};`);
|
|
374
|
+
sql.push(`alter table ${quotedTempName} rename to ${quotedName};`);
|
|
375
|
+
sql.push(...rest);
|
|
376
|
+
sql.push('pragma foreign_keys = on;');
|
|
377
|
+
return sql;
|
|
378
|
+
}
|
|
379
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* @module sql
|
|
4
|
+
*/
|
|
5
|
+
export { Kysely } from 'kysely';
|
|
6
|
+
export * from '@mikro-orm/core';
|
|
7
|
+
export * from './AbstractSqlConnection.js';
|
|
8
|
+
export * from './AbstractSqlDriver.js';
|
|
9
|
+
export * from './AbstractSqlPlatform.js';
|
|
10
|
+
export * from './SqlEntityManager.js';
|
|
11
|
+
export * from './SqlEntityRepository.js';
|
|
12
|
+
export * from './query/index.js';
|
|
13
|
+
export { raw } from './query/index.js';
|
|
14
|
+
export * from './schema/index.js';
|
|
15
|
+
export * from './dialects/index.js';
|
|
16
|
+
export * from './typings.js';
|
|
17
|
+
export * from './plugin/index.js';
|
|
18
|
+
export { SqlEntityManager as EntityManager } from './SqlEntityManager.js';
|
|
19
|
+
export { SqlEntityRepository as EntityRepository } from './SqlEntityRepository.js';
|
package/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* @module sql
|
|
4
|
+
*/
|
|
5
|
+
export { Kysely } from 'kysely';
|
|
6
|
+
export * from '@mikro-orm/core';
|
|
7
|
+
export * from './AbstractSqlConnection.js';
|
|
8
|
+
export * from './AbstractSqlDriver.js';
|
|
9
|
+
export * from './AbstractSqlPlatform.js';
|
|
10
|
+
export * from './SqlEntityManager.js';
|
|
11
|
+
export * from './SqlEntityRepository.js';
|
|
12
|
+
export * from './query/index.js';
|
|
13
|
+
export { raw } from './query/index.js';
|
|
14
|
+
export * from './schema/index.js';
|
|
15
|
+
export * from './dialects/index.js';
|
|
16
|
+
export * from './typings.js';
|
|
17
|
+
export * from './plugin/index.js';
|
|
18
|
+
export { SqlEntityManager as EntityManager } from './SqlEntityManager.js';
|
|
19
|
+
export { SqlEntityRepository as EntityRepository } from './SqlEntityRepository.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mikro-orm/sql",
|
|
3
|
+
"version": "7.0.0-dev.100",
|
|
4
|
+
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./package.json": "./package.json",
|
|
8
|
+
".": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+ssh://git@github.com/mikro-orm/mikro-orm.git"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"orm",
|
|
16
|
+
"mongo",
|
|
17
|
+
"mongodb",
|
|
18
|
+
"mysql",
|
|
19
|
+
"mariadb",
|
|
20
|
+
"postgresql",
|
|
21
|
+
"sqlite",
|
|
22
|
+
"sqlite3",
|
|
23
|
+
"ts",
|
|
24
|
+
"typescript",
|
|
25
|
+
"js",
|
|
26
|
+
"javascript",
|
|
27
|
+
"entity",
|
|
28
|
+
"ddd",
|
|
29
|
+
"mikro-orm",
|
|
30
|
+
"unit-of-work",
|
|
31
|
+
"data-mapper",
|
|
32
|
+
"identity-map"
|
|
33
|
+
],
|
|
34
|
+
"author": "Martin Adámek",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/mikro-orm/mikro-orm/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://mikro-orm.io",
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">= 22.17.0"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "yarn clean && yarn compile && yarn copy",
|
|
45
|
+
"clean": "yarn run -T rimraf ./dist",
|
|
46
|
+
"compile": "yarn run -T tsc -p tsconfig.build.json",
|
|
47
|
+
"copy": "node ../../scripts/copy.mjs"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"kysely": "0.28.9"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@mikro-orm/core": "^6.6.2"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@mikro-orm/core": "7.0.0-dev.100"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type KyselyPlugin, type PluginTransformQueryArgs, type PluginTransformResultArgs, type QueryResult, type RootOperationNode, type UnknownRow } from 'kysely';
|
|
2
|
+
import { MikroTransformer } from './transformer.js';
|
|
3
|
+
import type { SqlEntityManager } from '../SqlEntityManager.js';
|
|
4
|
+
import type { EntityMetadata } from '@mikro-orm/core';
|
|
5
|
+
/**
|
|
6
|
+
* Cache for query transformation data
|
|
7
|
+
* Stores the query node and metadata about tables/aliases
|
|
8
|
+
*/
|
|
9
|
+
interface QueryTransformCache {
|
|
10
|
+
entityMap: Map<string, EntityMetadata>;
|
|
11
|
+
}
|
|
12
|
+
export interface MikroKyselyPluginOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Use database table names ('table') or entity names ('entity') in queries.
|
|
15
|
+
*
|
|
16
|
+
* @default 'table'
|
|
17
|
+
*/
|
|
18
|
+
tableNamingStrategy?: 'table' | 'entity';
|
|
19
|
+
/**
|
|
20
|
+
* Use database column names ('column') or property names ('property') in queries.
|
|
21
|
+
*
|
|
22
|
+
* @default 'column'
|
|
23
|
+
*/
|
|
24
|
+
columnNamingStrategy?: 'column' | 'property';
|
|
25
|
+
/**
|
|
26
|
+
* Automatically process entity `onCreate` hooks in INSERT queries.
|
|
27
|
+
*
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
processOnCreateHooks?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Automatically process entity `onUpdate` hooks in UPDATE queries.
|
|
33
|
+
*
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
processOnUpdateHooks?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Convert JavaScript values to database-compatible values (e.g., Date to timestamp, custom types).
|
|
39
|
+
*
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
convertValues?: boolean;
|
|
43
|
+
}
|
|
44
|
+
export declare class MikroKyselyPlugin implements KyselyPlugin {
|
|
45
|
+
protected readonly em: SqlEntityManager;
|
|
46
|
+
protected readonly options: MikroKyselyPluginOptions;
|
|
47
|
+
protected static queryNodeCache: WeakMap<any, QueryTransformCache>;
|
|
48
|
+
protected readonly transformer: MikroTransformer;
|
|
49
|
+
constructor(em: SqlEntityManager, options?: MikroKyselyPluginOptions);
|
|
50
|
+
transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
|
|
51
|
+
transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>>;
|
|
52
|
+
}
|
|
53
|
+
export {};
|
package/plugin/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SelectQueryNode as SelectQueryNodeClass, InsertQueryNode as InsertQueryNodeClass, UpdateQueryNode as UpdateQueryNodeClass, DeleteQueryNode as DeleteQueryNodeClass, } from 'kysely';
|
|
2
|
+
import { MikroTransformer } from './transformer.js';
|
|
3
|
+
export class MikroKyselyPlugin {
|
|
4
|
+
em;
|
|
5
|
+
options;
|
|
6
|
+
static queryNodeCache = new WeakMap();
|
|
7
|
+
transformer;
|
|
8
|
+
constructor(em, options = {}) {
|
|
9
|
+
this.em = em;
|
|
10
|
+
this.options = options;
|
|
11
|
+
this.transformer = new MikroTransformer(em, options);
|
|
12
|
+
}
|
|
13
|
+
transformQuery(args) {
|
|
14
|
+
this.transformer.reset();
|
|
15
|
+
const result = this.transformer.transformNode(args.node, args.queryId);
|
|
16
|
+
// Cache the entity map if it is one we can process (for use in transformResult)
|
|
17
|
+
if (SelectQueryNodeClass.is(args.node) ||
|
|
18
|
+
InsertQueryNodeClass.is(args.node) ||
|
|
19
|
+
UpdateQueryNodeClass.is(args.node) ||
|
|
20
|
+
DeleteQueryNodeClass.is(args.node)) {
|
|
21
|
+
MikroKyselyPlugin.queryNodeCache.set(args.queryId, { entityMap: this.transformer.getOutputEntityMap() });
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
async transformResult(args) {
|
|
26
|
+
// Only transform results if columnNamingStrategy is 'property' or convertValues is true
|
|
27
|
+
if (this.options.columnNamingStrategy !== 'property' && !this.options.convertValues) {
|
|
28
|
+
return args.result;
|
|
29
|
+
}
|
|
30
|
+
// Retrieve the cached query node and metadata
|
|
31
|
+
const cache = MikroKyselyPlugin.queryNodeCache.get(args.queryId);
|
|
32
|
+
if (!cache) {
|
|
33
|
+
return args.result;
|
|
34
|
+
}
|
|
35
|
+
// Transform the result rows using the transformer
|
|
36
|
+
const transformedRows = this.transformer.transformResult(args.result.rows ?? [], cache.entityMap);
|
|
37
|
+
return {
|
|
38
|
+
...args.result,
|
|
39
|
+
rows: transformedRows ?? [],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|