@jskit-ai/database-runtime-mysql 0.1.18 → 0.1.19
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/package.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/database-runtime-mysql",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.19",
|
|
5
5
|
kind: "runtime",
|
|
6
6
|
options: {
|
|
7
7
|
"db-host": {
|
|
@@ -91,7 +91,7 @@ export default Object.freeze({
|
|
|
91
91
|
mutations: {
|
|
92
92
|
dependencies: {
|
|
93
93
|
runtime: {
|
|
94
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
94
|
+
"@jskit-ai/database-runtime": "0.1.20",
|
|
95
95
|
"mysql2": "^3.11.2"
|
|
96
96
|
},
|
|
97
97
|
dev: {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/database-runtime-mysql",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
"./shared/dialect": "./src/shared/dialect.js"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
15
|
+
"@jskit-ai/database-runtime": "0.1.20"
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -257,6 +257,61 @@ function normalizeIndexes(rows = []) {
|
|
|
257
257
|
);
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
function normalizeForeignKeys(rows = []) {
|
|
261
|
+
const grouped = new Map();
|
|
262
|
+
|
|
263
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
264
|
+
const name = normalizeText(row.constraintName || row.constraint_name);
|
|
265
|
+
const columnName = normalizeText(row.columnName || row.column_name);
|
|
266
|
+
const referencedTableName = normalizeText(row.referencedTableName || row.referenced_table_name);
|
|
267
|
+
const referencedColumnName = normalizeText(row.referencedColumnName || row.referenced_column_name);
|
|
268
|
+
if (!name || !columnName || !referencedTableName || !referencedColumnName) {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const ordinalPosition = toNullableNumber(row.ordinalPosition ?? row.ordinal_position) || 0;
|
|
273
|
+
const updateRule = normalizeText(row.updateRule || row.update_rule).toUpperCase();
|
|
274
|
+
const deleteRule = normalizeText(row.deleteRule || row.delete_rule).toUpperCase();
|
|
275
|
+
const existing = grouped.get(name) || {
|
|
276
|
+
name,
|
|
277
|
+
referencedTableName,
|
|
278
|
+
updateRule,
|
|
279
|
+
deleteRule,
|
|
280
|
+
columns: []
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
existing.columns.push({
|
|
284
|
+
name: columnName,
|
|
285
|
+
referencedName: referencedColumnName,
|
|
286
|
+
order: ordinalPosition
|
|
287
|
+
});
|
|
288
|
+
grouped.set(name, existing);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return Object.freeze(
|
|
292
|
+
[...grouped.values()]
|
|
293
|
+
.map((foreignKey) =>
|
|
294
|
+
Object.freeze({
|
|
295
|
+
name: foreignKey.name,
|
|
296
|
+
referencedTableName: foreignKey.referencedTableName,
|
|
297
|
+
updateRule: foreignKey.updateRule,
|
|
298
|
+
deleteRule: foreignKey.deleteRule,
|
|
299
|
+
columns: Object.freeze(
|
|
300
|
+
foreignKey.columns
|
|
301
|
+
.sort((left, right) => left.order - right.order)
|
|
302
|
+
.map((column) =>
|
|
303
|
+
Object.freeze({
|
|
304
|
+
name: column.name,
|
|
305
|
+
referencedName: column.referencedName
|
|
306
|
+
})
|
|
307
|
+
)
|
|
308
|
+
)
|
|
309
|
+
})
|
|
310
|
+
)
|
|
311
|
+
.sort((left, right) => left.name.localeCompare(right.name))
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
260
315
|
function requireIdColumn(columns, idColumn) {
|
|
261
316
|
const normalizedIdColumn = normalizeText(idColumn) || "id";
|
|
262
317
|
const idSpec = columns.find((column) => column.name === normalizedIdColumn) || null;
|
|
@@ -361,6 +416,30 @@ async function introspectCrudTableSnapshot(knex, { tableName = "", idColumn = "i
|
|
|
361
416
|
)
|
|
362
417
|
);
|
|
363
418
|
|
|
419
|
+
const foreignKeyRows = normalizeRows(
|
|
420
|
+
await knex.raw(
|
|
421
|
+
`
|
|
422
|
+
SELECT
|
|
423
|
+
rc.constraint_name AS constraintName,
|
|
424
|
+
k.column_name AS columnName,
|
|
425
|
+
k.referenced_table_name AS referencedTableName,
|
|
426
|
+
k.referenced_column_name AS referencedColumnName,
|
|
427
|
+
k.ordinal_position AS ordinalPosition,
|
|
428
|
+
rc.update_rule AS updateRule,
|
|
429
|
+
rc.delete_rule AS deleteRule
|
|
430
|
+
FROM information_schema.referential_constraints rc
|
|
431
|
+
JOIN information_schema.key_column_usage k
|
|
432
|
+
ON k.constraint_name = rc.constraint_name
|
|
433
|
+
AND k.constraint_schema = rc.constraint_schema
|
|
434
|
+
AND k.table_name = rc.table_name
|
|
435
|
+
WHERE rc.constraint_schema = ?
|
|
436
|
+
AND rc.table_name = ?
|
|
437
|
+
ORDER BY rc.constraint_name ASC, k.ordinal_position ASC
|
|
438
|
+
`,
|
|
439
|
+
[schemaName, resolvedTableName]
|
|
440
|
+
)
|
|
441
|
+
);
|
|
442
|
+
|
|
364
443
|
const columns = Object.freeze(columnRows.map((row) => normalizeColumn(row)));
|
|
365
444
|
const resolvedIdColumn = requireIdColumn(columns, idColumn);
|
|
366
445
|
const primaryKeyColumns = normalizePrimaryKeyColumns(primaryRows);
|
|
@@ -375,7 +454,8 @@ async function introspectCrudTableSnapshot(knex, { tableName = "", idColumn = "i
|
|
|
375
454
|
hasWorkspaceOwnerColumn: columns.some((column) => column.name === "workspace_owner_id"),
|
|
376
455
|
hasUserOwnerColumn: columns.some((column) => column.name === "user_owner_id"),
|
|
377
456
|
columns,
|
|
378
|
-
indexes: normalizeIndexes(indexRows)
|
|
457
|
+
indexes: normalizeIndexes(indexRows),
|
|
458
|
+
foreignKeys: normalizeForeignKeys(foreignKeyRows)
|
|
379
459
|
});
|
|
380
460
|
|
|
381
461
|
return snapshot;
|
|
@@ -7,7 +7,8 @@ function createKnexRawDouble({
|
|
|
7
7
|
schemaName = "appdb",
|
|
8
8
|
columns = [],
|
|
9
9
|
primaryKeyColumns = [],
|
|
10
|
-
indexes = []
|
|
10
|
+
indexes = [],
|
|
11
|
+
foreignKeys = []
|
|
11
12
|
} = {}) {
|
|
12
13
|
const calls = [];
|
|
13
14
|
|
|
@@ -31,6 +32,9 @@ function createKnexRawDouble({
|
|
|
31
32
|
if (normalizedSql.includes("from information_schema.statistics")) {
|
|
32
33
|
return [[...indexes], []];
|
|
33
34
|
}
|
|
35
|
+
if (normalizedSql.includes("from information_schema.referential_constraints")) {
|
|
36
|
+
return [[...foreignKeys], []];
|
|
37
|
+
}
|
|
34
38
|
|
|
35
39
|
throw new Error(`Unexpected SQL in test double: ${normalizedSql}`);
|
|
36
40
|
}
|
|
@@ -151,6 +155,17 @@ test("introspectCrudTableSnapshot maps MySQL table metadata to normalized snapsh
|
|
|
151
155
|
columnName: "vip",
|
|
152
156
|
seqInIndex: 1
|
|
153
157
|
}
|
|
158
|
+
],
|
|
159
|
+
foreignKeys: [
|
|
160
|
+
{
|
|
161
|
+
constraintName: "contacts_workspace_owner_id_foreign",
|
|
162
|
+
columnName: "workspace_owner_id",
|
|
163
|
+
referencedTableName: "workspaces",
|
|
164
|
+
referencedColumnName: "id",
|
|
165
|
+
ordinalPosition: 1,
|
|
166
|
+
updateRule: "CASCADE",
|
|
167
|
+
deleteRule: "SET NULL"
|
|
168
|
+
}
|
|
154
169
|
]
|
|
155
170
|
});
|
|
156
171
|
|
|
@@ -197,6 +212,20 @@ test("introspectCrudTableSnapshot maps MySQL table metadata to normalized snapsh
|
|
|
197
212
|
columns: ["vip"]
|
|
198
213
|
}
|
|
199
214
|
]);
|
|
215
|
+
assert.deepEqual(snapshot.foreignKeys, [
|
|
216
|
+
{
|
|
217
|
+
name: "contacts_workspace_owner_id_foreign",
|
|
218
|
+
referencedTableName: "workspaces",
|
|
219
|
+
updateRule: "CASCADE",
|
|
220
|
+
deleteRule: "SET NULL",
|
|
221
|
+
columns: [
|
|
222
|
+
{
|
|
223
|
+
name: "workspace_owner_id",
|
|
224
|
+
referencedName: "id"
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
]);
|
|
200
229
|
});
|
|
201
230
|
|
|
202
231
|
test("introspectCrudTableSnapshot rejects unsupported column types", async () => {
|