From 21ec91a3d51222f1bd75333544cb30f25fdc9e7a Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Tue, 23 Jun 2026 18:20:15 +0800 Subject: [PATCH] feat(schema-diff): add table filters --- .../src/components/diff/SchemaDiffDialog.vue | 28 +++--- .../diff/SchemaDiffOptionsPanel.vue | 92 +++++++++++++------ apps/desktop/src/i18n/locales/en.ts | 15 +++ apps/desktop/src/i18n/locales/es.ts | 15 +++ apps/desktop/src/i18n/locales/ja.ts | 15 +++ apps/desktop/src/i18n/locales/zh-CN.ts | 15 +++ apps/desktop/src/i18n/locales/zh-TW.ts | 15 +++ apps/desktop/src/lib/schemaDiff.ts | 1 + apps/desktop/src/lib/schemaDiffOptions.ts | 7 +- apps/desktop/src/lib/schemaDiffTableFilter.ts | 49 ++++++++++ apps/desktop/src/types/schemaDiff.ts | 27 +++++- crates/dbx-core/src/schema_diff.rs | 63 ++++++++++++- .../app-tests/schemaDiffTableFilter.test.ts | 65 +++++++++++++ 13 files changed, 360 insertions(+), 47 deletions(-) create mode 100644 apps/desktop/src/lib/schemaDiffTableFilter.ts create mode 100644 packages/app-tests/schemaDiffTableFilter.test.ts diff --git a/apps/desktop/src/components/diff/SchemaDiffDialog.vue b/apps/desktop/src/components/diff/SchemaDiffDialog.vue index 773feec89..61163c03c 100644 --- a/apps/desktop/src/components/diff/SchemaDiffDialog.vue +++ b/apps/desktop/src/components/diff/SchemaDiffDialog.vue @@ -15,10 +15,11 @@ import SchemaDiffDeployStep from "@/components/diff/SchemaDiffDeployStep.vue"; import SchemaDiffOptionsPanel from "@/components/diff/SchemaDiffOptionsPanel.vue"; import { getSchemaDiffOptionsForDbType } from "@/lib/schemaDiffOptions"; -import { getDefaultOptionsForDbType } from "@/types/schemaDiff"; +import { normalizeSchemaDiffCompareOptions } from "@/types/schemaDiff"; import type { SchemaDiffCompareOptions, SchemaDiffConfig } from "@/types/schemaDiff"; import type { ObjectSourceKind } from "@/types/database"; import { buildDeploySqlForObjects, convertToSchemaDiffObjects, groupDiffObjects, type OperationGroup, type SchemaDiffObject, type DiffOperationType, type DiffObjectKind, type SchemaDiffPreparation } from "@/lib/schemaDiff"; +import { compileSchemaDiffTableFilter, filterSchemaDiffTables } from "@/lib/schemaDiffTableFilter"; import { Splitpanes, Pane } from "splitpanes"; import "splitpanes/dist/splitpanes.css"; @@ -180,6 +181,7 @@ onBeforeUnmount(() => { // Config management const { configs, activeConfigId, activeConfig, recentConfigs, ensureDefaultConfig, updateActiveConfigConnection, updateActiveConfigOptions, saveToHistory, deleteFromHistory } = useSchemaDiffConfig(); +const schemaDiffPanelOptions = computed(() => normalizeSchemaDiffCompareOptions(activeConfig.value?.options, getDbType())); const selectedObject = computed(() => { if (!selectedObjectId.value) return null; @@ -259,7 +261,7 @@ function handleSwap() { function handleOptionsUpdate(options: SchemaDiffCompareOptions) { if (activeConfig.value) { - updateActiveConfigOptions(options); + updateActiveConfigOptions(normalizeSchemaDiffCompareOptions(options, getDbType())); } } @@ -282,14 +284,20 @@ async function handleCompare() { step.value = "compare"; try { + const targetConfig = store.getConfig(targetConnectionId.value); + const dbType = targetConfig?.db_type || "mysql"; + const opts = normalizeSchemaDiffCompareOptions(activeConfig.value?.options, dbType); + const tableFilter = compileSchemaDiffTableFilter(opts); + await store.ensureConnected(sourceConnectionId.value); await store.ensureConnected(targetConnectionId.value); const [srcTables, tgtTables] = await Promise.all([api.listTables(sourceConnectionId.value, sourceDatabase.value, sourceSchema.value), api.listTables(targetConnectionId.value, targetDatabase.value, targetSchema.value)]); + const { sourceTables, targetTables } = filterSchemaDiffTables(srcTables, tgtTables, tableFilter); // Load schema details in parallel const sourceDetails = await Promise.all( - srcTables.map(async (table) => { + sourceTables.map(async (table) => { const objectType = isViewOrMaterializedView(table.table_type); const [columns, indexes, foreignKeys, triggers, ddl] = await Promise.all([ api.getColumns(sourceConnectionId.value, sourceDatabase.value, sourceSchema.value, table.name), @@ -303,7 +311,7 @@ async function handleCompare() { ); const targetDetails = await Promise.all( - tgtTables.map(async (table) => { + targetTables.map(async (table) => { const objectType = isViewOrMaterializedView(table.table_type); const [columns, indexes, foreignKeys, triggers, ddl] = await Promise.all([ api.getColumns(targetConnectionId.value, targetDatabase.value, targetSchema.value, table.name), @@ -316,10 +324,7 @@ async function handleCompare() { }), ); - const targetConfig = store.getConfig(targetConnectionId.value); - const dbType = targetConfig?.db_type || "mysql"; const isPostgresLike = dbType === "postgres" || dbType === "opengauss"; - const opts = activeConfig.value?.options; // Fetch new object types for PostgreSQL-like databases const promises: Promise[] = []; @@ -352,8 +357,8 @@ async function handleCompare() { const tgtOwners = opts?.owners && isPostgresLike ? results[idx++] : []; const result = await api.prepareSchemaDiff({ - sourceTables: srcTables, - targetTables: tgtTables, + sourceTables, + targetTables, sourceDetails, targetDetails, sourceFunctions: srcFunctions, @@ -368,6 +373,7 @@ async function handleCompare() { targetSchema: targetSchema.value, ignoreComments: ignoreComments.value, cascadeDelete: opts?.cascadeDelete ?? false, + compareColumnOrder: opts.compareColumnOrder, }); // Convert to unified objects @@ -822,12 +828,12 @@ const targetConnectionInfo = computed(() => {
-
+

{{ t("schemaDiff.optionsTitle") }}

- +
diff --git a/apps/desktop/src/components/diff/SchemaDiffOptionsPanel.vue b/apps/desktop/src/components/diff/SchemaDiffOptionsPanel.vue index 299b38ae6..8c82e10c7 100644 --- a/apps/desktop/src/components/diff/SchemaDiffOptionsPanel.vue +++ b/apps/desktop/src/components/diff/SchemaDiffOptionsPanel.vue @@ -2,7 +2,10 @@ import { ref, watch } from "vue"; import { useI18n } from "vue-i18n"; import { Button } from "@/components/ui/button"; -import type { SchemaDiffCompareOptions, SchemaDiffOptionItem } from "@/types/schemaDiff"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { HelpTooltip } from "@/components/ui/tooltip"; +import type { BooleanSchemaDiffCompareOptionKey, SchemaDiffCompareOptions, SchemaDiffOptionItem } from "@/types/schemaDiff"; +import { normalizeSchemaDiffCompareOptions } from "@/types/schemaDiff"; const props = defineProps<{ options: SchemaDiffCompareOptions; @@ -17,22 +20,22 @@ const emit = defineEmits<{ const { t } = useI18n(); // Local copy of options -const localOptions = ref({ ...props.options }); +const localOptions = ref(normalizeSchemaDiffCompareOptions(props.options)); // Watch for external changes watch( () => props.options, (newOptions) => { - localOptions.value = { ...newOptions }; + localOptions.value = normalizeSchemaDiffCompareOptions(newOptions); }, { deep: true }, ); -function isChecked(id: keyof SchemaDiffCompareOptions): boolean { +function isChecked(id: BooleanSchemaDiffCompareOptionKey): boolean { return !!localOptions.value[id]; } -function setOption(id: keyof SchemaDiffCompareOptions, checked: boolean) { +function setOption(id: BooleanSchemaDiffCompareOptionKey, checked: boolean) { localOptions.value = { ...localOptions.value, [id]: checked }; } @@ -84,32 +87,67 @@ function getItemClasses(state: "checked" | "unchecked" | "indeterminate"): strin