From 5d665d8fbb3e4e025779db1156722eacea45ef54 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 13 Sep 2022 22:58:37 +0530 Subject: [PATCH 01/20] fix(api): apply column changes in order to avoid foreign key constraint error Signed-off-by: Pranav C --- packages/nocodb/src/lib/meta/api/metaDiffApis.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/nocodb/src/lib/meta/api/metaDiffApis.ts b/packages/nocodb/src/lib/meta/api/metaDiffApis.ts index 3f84613bfa..eee915bb2e 100644 --- a/packages/nocodb/src/lib/meta/api/metaDiffApis.ts +++ b/packages/nocodb/src/lib/meta/api/metaDiffApis.ts @@ -34,6 +34,11 @@ export enum MetaDiffType { TABLE_VIRTUAL_M2M_REMOVE = 'TABLE_VIRTUAL_M2M_REMOVE', } +const applyChangesPriorityOrder = [ + MetaDiffType.VIEW_COLUMN_REMOVE, + MetaDiffType.TABLE_RELATION_REMOVE, +]; + type MetaDiff = { title?: string; table_name: string; @@ -549,6 +554,15 @@ export async function metaDiffSync(req, res) { // const relations = (await sqlClient.relationListAll())?.data?.list; for (const { table_name, detectedChanges } of changes) { + // reorder changes to apply relation remove changes + // before column remove to avoid foreign key constraint error + detectedChanges.sort((a, b) => { + return ( + applyChangesPriorityOrder.indexOf(b.type) - + applyChangesPriorityOrder.indexOf(a.type) + ); + }); + for (const change of detectedChanges) { switch (change.type) { case MetaDiffType.TABLE_NEW: From 10e406e345320be6e5a8de033cdc8937a1530324 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 14 Sep 2022 11:30:51 +0530 Subject: [PATCH 02/20] fix(api): on deleting a column check for LTAR which referring it Signed-off-by: Pranav C --- packages/nocodb/src/lib/models/Column.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/nocodb/src/lib/models/Column.ts b/packages/nocodb/src/lib/models/Column.ts index 82cc863b23..a235bbedcc 100644 --- a/packages/nocodb/src/lib/models/Column.ts +++ b/packages/nocodb/src/lib/models/Column.ts @@ -772,6 +772,28 @@ export default class Column implements ColumnType { await NocoCache.del(`${CacheScope.GALLERY_VIEW_COLUMN}:${col.id}`); } + // Get LTAR columns in which current column is referenced as foreign key + const ltarColumns = await ncMeta.metaList2( + null, + null, + MetaTable.COL_RELATIONS, + { + xcCondition: { + _or: [ + { fk_child_column_id: { eq: col.id } }, + { fk_parent_column_id: { eq: col.id } }, + { fk_mm_child_column_id: { eq: col.id } }, + { fk_mm_parent_column_id: { eq: col.id } }, + ], + }, + } + ); + + // Delete LTAR columns in which current column is referenced as foreign key + for (const ltarColumn of ltarColumns) { + await Column.delete(ltarColumn.fk_column_id, ncMeta); + } + // Columns await ncMeta.metaDelete(null, null, MetaTable.COLUMNS, col.id); await NocoCache.deepDel( From 30440d94d9c823df9d6a10b5083668c511e508bb Mon Sep 17 00:00:00 2001 From: Pranav C Date: Mon, 19 Sep 2022 18:05:06 +0530 Subject: [PATCH 03/20] fix(gui): get table meta only after loading project table list re #3702 Signed-off-by: Pranav C --- packages/nc-gui/composables/useProject.ts | 8 ++++++++ .../index/[type]/[title]/[[viewTitle]].vue | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/nc-gui/composables/useProject.ts b/packages/nc-gui/composables/useProject.ts index f5b728d4f0..c412e25f8c 100644 --- a/packages/nc-gui/composables/useProject.ts +++ b/packages/nc-gui/composables/useProject.ts @@ -42,6 +42,8 @@ const [setup, use] = useInjectionState((_projectId?: MaybeRef) => { const projectId = computed(() => (_projectId ? unref(_projectId) : (route.params.projectId as string))) + const projectAndTablesLoaded = ref(false) + // todo: refactor path param name and variable name const projectType = $computed(() => route.params.projectType as string) @@ -93,6 +95,7 @@ const [setup, use] = useInjectionState((_projectId?: MaybeRef) => { } async function loadTables() { + projectAndTablesLoaded.value = false if (project.value.id) { const tablesResponse = await api.dbTable.list(project.value.id, { includeM2M: includeM2M.value, @@ -100,9 +103,11 @@ const [setup, use] = useInjectionState((_projectId?: MaybeRef) => { if (tablesResponse.list) tables.value = tablesResponse.list } + projectAndTablesLoaded.value = true } async function loadProject(id?: string) { + projectAndTablesLoaded.value = false if (id) { project.value = await api.project.read(projectId.value) } else if (projectType === 'base') { @@ -128,6 +133,8 @@ const [setup, use] = useInjectionState((_projectId?: MaybeRef) => { setTheme(projectMeta.value?.theme) projectLoadedHook.trigger(project.value) + + projectAndTablesLoaded.value = true } async function updateProject(data: Partial) { @@ -196,6 +203,7 @@ const [setup, use] = useInjectionState((_projectId?: MaybeRef) => { projectLoadedHook: projectLoadedHook.on, reset, isLoading, + projectAndTablesLoaded, } }, 'useProject') diff --git a/packages/nc-gui/pages/[projectType]/[projectId]/index/index/[type]/[title]/[[viewTitle]].vue b/packages/nc-gui/pages/[projectType]/[projectId]/index/index/[type]/[title]/[[viewTitle]].vue index a6c85c05bd..18b4da43fe 100644 --- a/packages/nc-gui/pages/[projectType]/[projectId]/index/index/[type]/[title]/[[viewTitle]].vue +++ b/packages/nc-gui/pages/[projectType]/[projectId]/index/index/[type]/[title]/[[viewTitle]].vue @@ -4,7 +4,7 @@ import { TabMetaInj } from '#imports' const { getMeta } = useMetas() -const { project, projectLoadedHook } = useProject() +const { project, projectLoadedHook, projectAndTablesLoaded } = useProject() const route = useRoute() @@ -15,14 +15,16 @@ const activeTab = inject( computed(() => ({} as TabItem)), ) -if (!project.value.id) { - projectLoadedHook(async () => { - await getMeta(route.params.title as string, true) +/** wait until project and table loads since meta load requires table list **/ +watch( + projectAndTablesLoaded, + (nextVal) => { + if (!nextVal) return + getMeta(route.params.title as string, true).finally(() => (loading.value = false)) loading.value = false - }) -} else { - getMeta(route.params.title as string, true).finally(() => (loading.value = false)) -} + }, + { immediate: true }, +)