fix: resolve production ID case-sensitivity and SQL Server compatibility issues

- Add getTableName() method to convert MySQL table names to SQL Server format
- Use queryWithParams with sql.NVarChar for proper SQL Server parameter handling
- Implement case-insensitive matching for production IDs (e.g., 26b10433 vs 26B10433)
- Align resolver logic with validation-handler.ts for consistent database queries

Co-Authored-By: Claude (glm-5) <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-03-04 11:27:37 +08:00
parent 240e3838ba
commit abe51d17fa
4 changed files with 342 additions and 206 deletions

View File

@@ -12,6 +12,19 @@
*/
import type { IDatabaseService } from '../database'
import { SqlServerService } from '../database/sql-server'
import { createLogger } from '../logger'
const log = createLogger('OrderResolver')
// Dynamically import mssql for SQL Server parameter types
let mssql: typeof import('mssql') | null = null
async function getMssql() {
if (!mssql) {
mssql = await import('mssql')
}
return mssql
}
/**
* Order mapping result
@@ -77,6 +90,24 @@ export class OrderNumberResolver {
this.dbService = dbService
}
/**
* Get table name based on database type
* Converts MySQL schema_tablename format to SQL Server [schema].[tablename] format
* e.g., productionContractData_26年压力表合同数据 -> [productionContractData].[26年压力表合同数据]
*/
private getTableName(mysqlTableName: string): string {
if (this.dbService.type === 'sqlserver') {
const firstUnderscoreIndex = mysqlTableName.indexOf('_')
if (firstUnderscoreIndex > 0) {
const schema = mysqlTableName.substring(0, firstUnderscoreIndex)
const tableName = mysqlTableName.substring(firstUnderscoreIndex + 1)
return `[${schema}].[${tableName}]`
}
return `[dbo].[${mysqlTableName}]`
}
return mysqlTableName
}
/**
* Recognize the type of an input string
* @param input - The input string to recognize
@@ -217,35 +248,56 @@ export class OrderNumberResolver {
}
try {
// Build query - use different placeholder style based on database type
const isSqlServer = this.dbService.type === 'sqlserver'
const placeholders = isSqlServer
? productionIds.map((_, idx) => `@p${idx}`).join(', ')
: productionIds.map(() => '?').join(', ')
const tableName = this.getTableName(DB_CONFIG.TABLE_NAME)
// Use appropriate quoting for table/field names
const quote = isSqlServer ? '' : '`'
const query = `
SELECT ${quote}${DB_CONFIG.FIELD_PRODUCTION_ID}${quote}, ${quote}${DB_CONFIG.FIELD_ORDER_NUMBER}${quote}
FROM ${quote}${DB_CONFIG.TABLE_NAME}${quote}
WHERE ${quote}${DB_CONFIG.FIELD_PRODUCTION_ID}${quote} IN (${placeholders})
`
log.debug('Resolving production IDs', { count: productionIds.length, dbType: this.dbService.type })
const result = await this.dbService.query(query, productionIds)
let result
// Create a map for quick lookup
if (isSqlServer) {
// Use queryWithParams for SQL Server with explicit parameter types
const sql = await getMssql()
const placeholders = productionIds.map((_, idx) => `@p${idx}`).join(', ')
const params: Record<string, { value: string; type: sql.ISqlType }> = {}
productionIds.forEach((id, idx) => {
params[`p${idx}`] = { value: id, type: sql.NVarChar }
})
const query = `
SELECT ${DB_CONFIG.FIELD_PRODUCTION_ID}, ${DB_CONFIG.FIELD_ORDER_NUMBER}
FROM ${tableName}
WHERE ${DB_CONFIG.FIELD_PRODUCTION_ID} IN (${placeholders})
`
result = await (this.dbService as SqlServerService).queryWithParams(query, params)
} else {
// Use standard query for MySQL
const placeholders = productionIds.map(() => '?').join(', ')
const query = `
SELECT \`${DB_CONFIG.FIELD_PRODUCTION_ID}\`, \`${DB_CONFIG.FIELD_ORDER_NUMBER}\`
FROM ${tableName}
WHERE \`${DB_CONFIG.FIELD_PRODUCTION_ID}\` IN (${placeholders})
`
result = await this.dbService.query(query, productionIds)
}
// Create a map for quick lookup (use lowercase key for case-insensitive matching)
const resultMap = new Map<string, string>()
for (const row of result.rows) {
const prodId = row[DB_CONFIG.FIELD_PRODUCTION_ID] as string
const orderNum = row[DB_CONFIG.FIELD_ORDER_NUMBER] as string
if (prodId && orderNum) {
resultMap.set(prodId, orderNum)
// Store with lowercase key for case-insensitive matching
resultMap.set(prodId.toLowerCase(), orderNum)
}
}
// Build mappings
for (const pid of productionIds) {
const orderNumber = resultMap.get(pid)
// Use lowercase for case-insensitive lookup
const orderNumber = resultMap.get(pid.toLowerCase())
if (orderNumber) {
mappings.push({
@@ -292,21 +344,39 @@ export class OrderNumberResolver {
}
try {
// Build query - use different placeholder style based on database type
const isSqlServer = this.dbService.type === 'sqlserver'
const placeholders = isSqlServer
? orderNumbers.map((_, idx) => `@p${idx}`).join(', ')
: orderNumbers.map(() => '?').join(', ')
const tableName = this.getTableName(DB_CONFIG.TABLE_NAME)
// Use appropriate quoting for table/field names
const quote = isSqlServer ? '' : '`'
const query = `
SELECT ${quote}${DB_CONFIG.FIELD_ORDER_NUMBER}${quote}
FROM ${quote}${DB_CONFIG.TABLE_NAME}${quote}
WHERE ${quote}${DB_CONFIG.FIELD_ORDER_NUMBER}${quote} IN (${placeholders})
`
let result
if (isSqlServer) {
// Use queryWithParams for SQL Server with explicit parameter types
const sql = await getMssql()
const placeholders = orderNumbers.map((_, idx) => `@p${idx}`).join(', ')
const params: Record<string, { value: string; type: sql.ISqlType }> = {}
orderNumbers.forEach((id, idx) => {
params[`p${idx}`] = { value: id, type: sql.NVarChar }
})
const query = `
SELECT ${DB_CONFIG.FIELD_ORDER_NUMBER}
FROM ${tableName}
WHERE ${DB_CONFIG.FIELD_ORDER_NUMBER} IN (${placeholders})
`
result = await (this.dbService as SqlServerService).queryWithParams(query, params)
} else {
// Use standard query for MySQL
const placeholders = orderNumbers.map(() => '?').join(', ')
const query = `
SELECT \`${DB_CONFIG.FIELD_ORDER_NUMBER}\`
FROM ${tableName}
WHERE \`${DB_CONFIG.FIELD_ORDER_NUMBER}\` IN (${placeholders})
`
result = await this.dbService.query(query, orderNumbers)
}
const result = await this.dbService.query(query, orderNumbers)
return result.rows.map((row) => row[DB_CONFIG.FIELD_ORDER_NUMBER] as string)
} catch (error) {
console.warn('[OrderResolver] Failed to verify order numbers:', error)