From c4e1e402794e32feaf208b1992582079ef85522c Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Fri, 9 Apr 2021 19:28:00 -0400 Subject: [PATCH] Fix @directus/schema not reading Oracle overview correctly Fixes #4735 --- .../20201105A-add-cascade-system-relations.ts | 33 +---------- packages/schema/package.json | 3 +- packages/schema/src/dialects/oracledb.ts | 55 ++++++++++++++----- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/api/src/database/migrations/20201105A-add-cascade-system-relations.ts b/api/src/database/migrations/20201105A-add-cascade-system-relations.ts index c820335a72..5a7155f844 100644 --- a/api/src/database/migrations/20201105A-add-cascade-system-relations.ts +++ b/api/src/database/migrations/20201105A-add-cascade-system-relations.ts @@ -7,7 +7,6 @@ const updates = [ { column: 'group', references: 'directus_fields.id', - onDelete: 'SET NULL', }, ], }, @@ -17,17 +16,14 @@ const updates = [ { column: 'folder', references: 'directus_folders.id', - onDelete: 'SET NULL', }, { column: 'uploaded_by', references: 'directus_users.id', - onDelete: 'SET NULL', }, { column: 'modified_by', references: 'directus_users.id', - onDelete: 'SET NULL', }, ], }, @@ -37,7 +33,6 @@ const updates = [ { column: 'parent', references: 'directus_folders.id', - onDelete: 'CASCADE', }, ], }, @@ -47,7 +42,6 @@ const updates = [ { column: 'role', references: 'directus_roles.id', - onDelete: 'CASCADE', }, ], }, @@ -57,12 +51,10 @@ const updates = [ { column: 'user', references: 'directus_users.id', - onDelete: 'CASCADE', }, { column: 'role', references: 'directus_roles.id', - onDelete: 'CASCADE', }, ], }, @@ -72,12 +64,10 @@ const updates = [ { column: 'activity', references: 'directus_activity.id', - onDelete: 'CASCADE', }, { column: 'parent', references: 'directus_revisions.id', - onDelete: 'SET NULL', }, ], }, @@ -87,7 +77,6 @@ const updates = [ { column: 'user', references: 'directus_users.id', - onDelete: 'CASCADE', }, ], }, @@ -97,17 +86,14 @@ const updates = [ { column: 'project_logo', references: 'directus_files.id', - onDelete: 'SET NULL', }, { column: 'public_foreground', references: 'directus_files.id', - onDelete: 'SET NULL', }, { column: 'public_background', references: 'directus_files.id', - onDelete: 'SET NULL', }, ], }, @@ -117,7 +103,6 @@ const updates = [ { column: 'role', references: 'directus_roles.id', - onDelete: 'SET NULL', }, ], }, @@ -125,38 +110,26 @@ const updates = [ /** * NOTE: - * MS SQL doesn't support recursive foreign key constraints, nor having multiple foreign key constraints to the same - * related table. This means that about half of the above constraint triggers won't be available in MS SQL. To avoid - * confusion in what's there and what isn't, we'll skip the on-delete / on-update triggers altogether in MS SQL. + * Not all databases allow (or support) recursive onUpdate/onDelete triggers. MS SQL / Oracle flat out deny creating them, + * Postgres behaves erratic on those triggers, not sure if MySQL / Maria plays nice either. */ export async function up(knex: Knex) { - if (knex.client.config.client === 'mssql') return; - for (const update of updates) { await knex.schema.alterTable(update.table, (table) => { for (const constraint of update.constraints) { table.dropForeign([constraint.column]); - - table - .foreign(constraint.column) - .references(constraint.references) - .onUpdate('CASCADE') - .onDelete(constraint.onDelete); + table.foreign(constraint.column).references(constraint.references); } }); } } export async function down(knex: Knex) { - if (knex.client.config.client === 'mssql') return; - for (const update of updates) { await knex.schema.alterTable(update.table, (table) => { for (const constraint of update.constraints) { table.dropForeign([constraint.column]); - - table.foreign(constraint.column).references(constraint.references).onUpdate('NO ACTION').onDelete('NO ACTION'); } }); } diff --git a/packages/schema/package.json b/packages/schema/package.json index 8ee2b83489..e7c0431a0a 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -43,7 +43,8 @@ "typescript": "^4.0.5" }, "dependencies": { - "knex-schema-inspector": "^1.2.0" + "knex-schema-inspector": "^1.2.0", + "lodash": "^4.17.21" }, "gitHead": "71bf628955b5da15ce3070dc09478bc558f243a4" } diff --git a/packages/schema/src/dialects/oracledb.ts b/packages/schema/src/dialects/oracledb.ts index 13b07eaa40..2342d8f7ee 100644 --- a/packages/schema/src/dialects/oracledb.ts +++ b/packages/schema/src/dialects/oracledb.ts @@ -1,19 +1,42 @@ import KnexOracle from 'knex-schema-inspector/dist/dialects/oracledb'; import { SchemaOverview } from '../types/overview'; import { SchemaInspector } from '../types/schema'; +import { mapKeys } from 'lodash'; export default class Oracle extends KnexOracle implements SchemaInspector { async overview() { - const columns = await this.knex.raw(` + type RawColumn = { + TABLE_NAME: string; + COLUMN_NAME: string; + DEFAULT_VALUE: string; + IS_NULLABLE: string; + DATA_TYPE: string; + NUMERIC_PRECISION: number | null; + NUMERIC_SCALE: number | null; + COLUMN_KEY: string; + }; + + type RawColumnLowercase = { + table_name: string; + column_name: string; + default_value: string; + is_nullable: string; + data_type: string; + numeric_precision: number | null; + numeric_scale: number | null; + column_key: string; + }; + + const columns = await this.knex.raw(` SELECT - "USER_TAB_COLUMNS"."TABLE_NAME" AS table_name, - "USER_TAB_COLUMNS"."COLUMN_NAME" AS column_name, - "USER_TAB_COLUMNS"."DATA_DEFAULT" AS default_value, - "USER_TAB_COLUMNS"."NULLABLE" AS is_nullable, - "USER_TAB_COLUMNS"."DATA_TYPE" AS data_type, - "USER_TAB_COLUMNS"."DATA_PRECISION" AS numeric_precision, - "USER_TAB_COLUMNS"."DATA_SCALE" AS numeric_scale, - "USER_CONSTRAINTS"."CONSTRAINT_TYPE" AS column_key + "USER_TAB_COLUMNS"."TABLE_NAME" AS TABLE_NAME, + "USER_TAB_COLUMNS"."COLUMN_NAME" AS COLUMN_NAME, + "USER_TAB_COLUMNS"."DATA_DEFAULT" AS DEFAULT_VALUE, + "USER_TAB_COLUMNS"."NULLABLE" AS IS_NULLABLE, + "USER_TAB_COLUMNS"."DATA_TYPE" AS DATA_TYPE, + "USER_TAB_COLUMNS"."DATA_PRECISION" AS NUMERIC_PRECISION, + "USER_TAB_COLUMNS"."DATA_SCALE" AS NUMERIC_SCALE, + "USER_CONSTRAINTS"."CONSTRAINT_TYPE" AS COLUMN_KEY FROM "USER_TAB_COLUMNS" LEFT JOIN "USER_CONS_COLUMNS" ON "USER_TAB_COLUMNS"."TABLE_NAME" = "USER_CONS_COLUMNS"."TABLE_NAME" @@ -21,14 +44,19 @@ export default class Oracle extends KnexOracle implements SchemaInspector { LEFT JOIN "USER_CONSTRAINTS" ON "USER_CONS_COLUMNS"."CONSTRAINT_NAME" = "USER_CONSTRAINTS"."CONSTRAINT_NAME" `); + const columnsLowercase: RawColumnLowercase[] = columns.map( + (column) => mapKeys(column, (value, key) => key.toLowerCase()) as RawColumnLowercase + ); + const overview: SchemaOverview = {}; - for (const column of columns[0]) { + for (const column of columnsLowercase) { if (column.table_name in overview === false) { overview[column.table_name] = { - primary: columns[0].find((nested: { column_key: string; table_name: string }) => { - return nested.table_name === column.table_name && nested.column_key === 'P'; - })?.column_name, + primary: + columnsLowercase.find((nested: { column_key: string; table_name: string }) => { + return nested.table_name === column.table_name && nested.column_key === 'P'; + })?.column_name || 'id', columns: {}, }; } @@ -38,6 +66,7 @@ export default class Oracle extends KnexOracle implements SchemaInspector { is_nullable: column.is_nullable === 'YES', }; } + return overview; } }