From 5ff99cdd0fd0bb61da635ab3136a118f1fa738cd Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Tue, 28 Apr 2026 11:10:03 +0800 Subject: [PATCH] refactor: use dot notation for table name config (schema.table instead of schema_table) Replace underscore-based table name splitting with dot-based splitting to match the standard schema.tablename format, removing MySQL compatibility. Co-Authored-By: Claude Opus 4.6 --- docs/cleaner/cleaner-validation-flow.md | 27 +++++++------ .../Configuration-Architecture-Analysis.md | 2 +- docs/user/CONFIG_FILE_LOCATION.md | 2 +- src/main/services/erp/order-resolver.ts | 39 ++++++++----------- .../validation/production-input-service.ts | 2 +- .../validation-application-service.ts | 8 ++-- .../validation/validation-database.ts | 27 ++++++------- .../validation/validation-database.test.ts | 18 +++------ 8 files changed, 57 insertions(+), 68 deletions(-) diff --git a/docs/cleaner/cleaner-validation-flow.md b/docs/cleaner/cleaner-validation-flow.md index 2968a8a..6d7f8bb 100644 --- a/docs/cleaner/cleaner-validation-flow.md +++ b/docs/cleaner/cleaner-validation-flow.md @@ -188,21 +188,26 @@ flowchart LR **表名转换逻辑**: ```typescript -// MySQL: dbo_MaterialsToBeDeleted +// 输入格式: dbo.MaterialsToBeDeleted // SQL Server: [dbo].[MaterialsToBeDeleted] -function getTableName(mysqlTableName: string): string { - const dbType = process.env.DB_TYPE?.toLowerCase() - if (dbType === 'sqlserver' || dbType === 'mssql') { - // 找到第一个下划线分割schema和表名 - const firstUnderscoreIndex = mysqlTableName.indexOf('_') - if (firstUnderscoreIndex > 0) { - const schema = mysqlTableName.substring(0, firstUnderscoreIndex) - const tableName = mysqlTableName.substring(firstUnderscoreIndex + 1) +// PostgreSQL: "dbo"."MaterialsToBeDeleted" +function getValidationTableName(dottedTableName: string): string { + const configManager = ConfigManager.getInstance() + const dbType = configManager.getDatabaseType() + + const dotIndex = dottedTableName.indexOf('.') + if (dotIndex > 0) { + const schema = dottedTableName.substring(0, dotIndex) + const tableName = dottedTableName.substring(dotIndex + 1) + if (dbType === 'sqlserver') { return `[${schema}].[${tableName}]` } - return `[dbo].[${mysqlTableName}]` + return `"${schema}"."${tableName}"` } - return mysqlTableName + if (dbType === 'sqlserver') { + return `[dbo].[${dottedTableName}]` + } + return `"public"."${dottedTableName}"` } ``` diff --git a/docs/internal/Configuration-Architecture-Analysis.md b/docs/internal/Configuration-Architecture-Analysis.md index 501065b..8ab5393 100644 --- a/docs/internal/Configuration-Architecture-Analysis.md +++ b/docs/internal/Configuration-Architecture-Analysis.md @@ -541,7 +541,7 @@ graph LR ### 10.2 默认配置示例 ```env -DB_TABLE_NAME=productionContractData_26 年压力表合同数据 +DB_TABLE_NAME=ERPAuto.vw_productionContractData DB_FIELD_PRODUCTION_ID=总排号 DB_FIELD_ORDER_NUMBER=生产订单号 ``` diff --git a/docs/user/CONFIG_FILE_LOCATION.md b/docs/user/CONFIG_FILE_LOCATION.md index 363b451..630d69d 100644 --- a/docs/user/CONFIG_FILE_LOCATION.md +++ b/docs/user/CONFIG_FILE_LOCATION.md @@ -180,7 +180,7 @@ validation: # 订单号解析配置 orderResolution: - tableName: 'productionContractData_26 年压力表合同数据' + tableName: 'ERPAuto.vw_productionContractData' productionIdField: '总排号' orderNumberField: '生产订单号' ``` diff --git a/src/main/services/erp/order-resolver.ts b/src/main/services/erp/order-resolver.ts index 9e1c403..4b2c097 100644 --- a/src/main/services/erp/order-resolver.ts +++ b/src/main/services/erp/order-resolver.ts @@ -40,7 +40,7 @@ export function getDbConfig() { const configManager = ConfigManager.getInstance() const config = configManager.getConfig() return { - TABLE_NAME: config.orderResolution.tableName || 'productionContractData_26 年压力表合同数据', + TABLE_NAME: config.orderResolution.tableName || 'ERPAuto.vw_productionContractData', FIELD_PRODUCTION_ID: config.orderResolution.productionIdField || '总排号', FIELD_ORDER_NUMBER: config.orderResolution.orderNumberField || '生产订单号' } @@ -58,35 +58,28 @@ export class OrderNumberResolver { /** * Get table name based on database type - * Converts schema_tablename format to database-specific quoting: + * Converts schema.tablename format to database-specific quoting: * - SQL Server: [schema].[tablename] * - PostgreSQL: "schema"."tablename" - * - MySQL: schema_tablename (as-is) - * e.g., productionContractData_26年压力表合同数据 -> - * SQL Server: [productionContractData].[26年压力表合同数据] - * PostgreSQL: "productionContractData"."26年压力表合同数据" - * MySQL: productionContractData_26年压力表合同数据 + * e.g., ERPAuto.vw_productionContractData -> + * SQL Server: [ERPAuto].[vw_productionContractData] + * PostgreSQL: "ERPAuto"."vw_productionContractData" */ private getTableName(tableName: string): string { - if (this.dbService.type === 'sqlserver' || this.dbService.type === 'postgresql') { - // Find the FIRST underscore to split schema and table name - // This handles patterns like: schema_tablename - const firstUnderscoreIndex = tableName.indexOf('_') - if (firstUnderscoreIndex > 0) { - const schema = tableName.substring(0, firstUnderscoreIndex) - const actualTableName = tableName.substring(firstUnderscoreIndex + 1) - if (this.dbService.type === 'sqlserver') { - return `[${schema}].[${actualTableName}]` - } - return `"${schema}"."${actualTableName}"` - } - // If no underscore found, default schema + const dotIndex = tableName.indexOf('.') + if (dotIndex > 0) { + const schema = tableName.substring(0, dotIndex) + const actualTableName = tableName.substring(dotIndex + 1) if (this.dbService.type === 'sqlserver') { - return `[dbo].[${tableName}]` + return `[${schema}].[${actualTableName}]` } - return `"public"."${tableName}"` + return `"${schema}"."${actualTableName}"` } - return tableName + // No dot found — use default schema + if (this.dbService.type === 'sqlserver') { + return `[dbo].[${tableName}]` + } + return `"public"."${tableName}"` } /** diff --git a/src/main/services/validation/production-input-service.ts b/src/main/services/validation/production-input-service.ts index 7c54b36..205a8ae 100644 --- a/src/main/services/validation/production-input-service.ts +++ b/src/main/services/validation/production-input-service.ts @@ -41,7 +41,7 @@ export async function getSourceNumbersFromInputs( } if (productionIds.length > 0) { - const contractTableName = getValidationTableName('productionContractData_26年压力表合同数据') + const contractTableName = getValidationTableName('ERPAuto.vw_productionContractData') const batchSize = 2000 if (dbType === 'sqlserver') { diff --git a/src/main/services/validation/validation-application-service.ts b/src/main/services/validation/validation-application-service.ts index d64f80f..1fd3531 100644 --- a/src/main/services/validation/validation-application-service.ts +++ b/src/main/services/validation/validation-application-service.ts @@ -325,7 +325,7 @@ export class ValidationApplicationService { } private async loadTypeKeywords(dbService: ValidationDatabaseService): Promise { - const typeKeywordTableName = getValidationTableName('dbo_MaterialsTypeToBeDeleted') + const typeKeywordTableName = getValidationTableName('dbo.MaterialsTypeToBeDeleted') const sql = ` SELECT MaterialName, ManagerName FROM ${typeKeywordTableName} @@ -341,7 +341,7 @@ export class ValidationApplicationService { private async loadMarkedCodes( dbService: ValidationDatabaseService ): Promise> { - const markedTableName = getValidationTableName('dbo_MaterialsToBeDeleted') + const markedTableName = getValidationTableName('dbo.MaterialsToBeDeleted') const sql = ` SELECT MaterialCode, ManagerName FROM ${markedTableName} @@ -416,7 +416,7 @@ export class ValidationApplicationService { try { dbService = await createValidationDatabaseService() - const detailTableName = getValidationTableName('dbo_DiscreteMaterialPlanData') + const detailTableName = getValidationTableName('dbo.DiscreteMaterialPlanData') const enrichedMaterials: MaterialRecordSummary[] = [] log.info(`Enriching ${materials.length} materials with details`) @@ -501,7 +501,7 @@ export class ValidationApplicationService { selectedManagers: string[], orderNumbers: string[] ): Promise { - const markedTableName = getValidationTableName('dbo_MaterialsToBeDeleted') + const markedTableName = getValidationTableName('dbo.MaterialsToBeDeleted') // Admin with selected managers: filter MaterialsToBeDeleted by ManagerName IN (selectedManagers) if (isAdmin && selectedManagers && selectedManagers.length > 0) { diff --git a/src/main/services/validation/validation-database.ts b/src/main/services/validation/validation-database.ts index 0916d8c..2ba6c5e 100644 --- a/src/main/services/validation/validation-database.ts +++ b/src/main/services/validation/validation-database.ts @@ -52,25 +52,22 @@ export async function createValidationDatabaseService(): Promise 0) { - const schema = mysqlTableName.substring(0, firstUnderscoreIndex) - const tableName = mysqlTableName.substring(firstUnderscoreIndex + 1) - if (dbType === 'sqlserver') { - return `[${schema}].[${tableName}]` - } - return `"${schema}"."${tableName}"` - } + const dotIndex = dottedTableName.indexOf('.') + if (dotIndex > 0) { + const schema = dottedTableName.substring(0, dotIndex) + const tableName = dottedTableName.substring(dotIndex + 1) if (dbType === 'sqlserver') { - return `[dbo].[${mysqlTableName}]` + return `[${schema}].[${tableName}]` } - return `"public"."${mysqlTableName}"` + return `"${schema}"."${tableName}"` } - - return mysqlTableName + // No dot found — use default schema + if (dbType === 'sqlserver') { + return `[dbo].[${dottedTableName}]` + } + return `"public"."${dottedTableName}"` } diff --git a/tests/unit/services/validation/validation-database.test.ts b/tests/unit/services/validation/validation-database.test.ts index b8abd46..3342417 100644 --- a/tests/unit/services/validation/validation-database.test.ts +++ b/tests/unit/services/validation/validation-database.test.ts @@ -125,31 +125,25 @@ describe('ValidationDatabaseService', () => { }) describe('getValidationTableName', () => { - it('returns table name unchanged for mysql', async () => { - currentDbType = 'mysql' - const mod = await import('../../../../src/main/services/validation/validation-database') - expect(mod.getValidationTableName('MaterialsToBeDeleted')).toBe('MaterialsToBeDeleted') - }) - - it('converts schema_table to [schema].[table] for sqlserver', async () => { + it('converts schema.table to [schema].[table] for sqlserver', async () => { currentDbType = 'sqlserver' const mod = await import('../../../../src/main/services/validation/validation-database') - expect(mod.getValidationTableName('dbo_Materials')).toBe('[dbo].[Materials]') + expect(mod.getValidationTableName('dbo.Materials')).toBe('[dbo].[Materials]') }) - it('wraps nameless table in [dbo].[name] for sqlserver', async () => { + it('wraps dotless table in [dbo].[name] for sqlserver', async () => { currentDbType = 'sqlserver' const mod = await import('../../../../src/main/services/validation/validation-database') expect(mod.getValidationTableName('Materials')).toBe('[dbo].[Materials]') }) - it('converts schema_table to "schema"."table" for postgresql', async () => { + it('converts schema.table to "schema"."table" for postgresql', async () => { currentDbType = 'postgresql' const mod = await import('../../../../src/main/services/validation/validation-database') - expect(mod.getValidationTableName('public_Materials')).toBe('"public"."Materials"') + expect(mod.getValidationTableName('public.Materials')).toBe('"public"."Materials"') }) - it('wraps nameless table in "public"."name" for postgresql', async () => { + it('wraps dotless table in "public"."name" for postgresql', async () => { currentDbType = 'postgresql' const mod = await import('../../../../src/main/services/validation/validation-database') expect(mod.getValidationTableName('Materials')).toBe('"public"."Materials"')