refactor(db): use SqlDialect in DiscreteMaterialPlanDAO

Replace all manual isSqlServer checks and inline SQL dialect logic with the
SqlDialect abstraction. Removes buildPlaceholders(), TABLE_NAME_SQLSERVER,
and TABLE_NAME_MYSQL in favor of dialect.params(), dialect.param(), and
dialect.quoteTableName(). Batch size logic now uses dialect.maxBatchRows().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-04-05 10:10:54 +08:00
parent 7e521da3f1
commit 9300f3455f

View File

@@ -9,6 +9,7 @@
*/ */
import { create, type IDatabaseService } from './index' import { create, type IDatabaseService } from './index'
import { createDialect, type SqlDialect } from './dialects'
import { createLogger, run, getRequestId, trackDuration } from '../logger' import { createLogger, run, getRequestId, trackDuration } from '../logger'
const log = createLogger('DiscreteMaterialPlanDAO') const log = createLogger('DiscreteMaterialPlanDAO')
@@ -53,8 +54,6 @@ export interface MaterialPlanRecord {
* Configuration for DiscreteMaterialPlanData table * Configuration for DiscreteMaterialPlanData table
*/ */
export const DISCRETE_MATERIAL_PLAN_CONFIG = { export const DISCRETE_MATERIAL_PLAN_CONFIG = {
TABLE_NAME_SQLSERVER: '[dbo].[DiscreteMaterialPlanData]',
TABLE_NAME_MYSQL: 'dbo_DiscreteMaterialPlanData',
COLUMNS: { COLUMNS: {
ID: 'ID', ID: 'ID',
FACTORY: 'Factory', FACTORY: 'Factory',
@@ -94,15 +93,20 @@ export const DISCRETE_MATERIAL_PLAN_CONFIG = {
*/ */
export class DiscreteMaterialPlanDAO { export class DiscreteMaterialPlanDAO {
private dbService: IDatabaseService | null = null private dbService: IDatabaseService | null = null
private dialect: SqlDialect | null = null
private getDialect(): SqlDialect {
if (!this.dialect) {
this.dialect = createDialect(this.dbService!.type)
}
return this.dialect
}
/** /**
* Get the appropriate table name based on database type * Get the appropriate table name based on database type
*/ */
private getTableName(): string { private getTableName(): string {
const isSqlServer = this.dbService?.type === 'sqlserver' return this.getDialect().quoteTableName('dbo', 'DiscreteMaterialPlanData')
return isSqlServer
? DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_SQLSERVER
: DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL
} }
/** /**
@@ -117,15 +121,6 @@ export class DiscreteMaterialPlanDAO {
return this.dbService return this.dbService
} }
/**
* Build placeholders for IN clause based on database type
*/
private buildPlaceholders(count: number, isSqlServer: boolean): string {
return isSqlServer
? Array.from({ length: count }, (_, idx) => `@p${idx}`).join(',')
: Array.from({ length: count }, () => '?').join(',')
}
// ==================== QUERY ALL ==================== // ==================== QUERY ALL ====================
/** /**
@@ -219,13 +214,13 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
const batchSize = 1500 const batchSize = 1500
const allResults: any[] = [] const allResults: any[] = []
for (let i = 0; i < sourceNumbers.length; i += batchSize) { for (let i = 0; i < sourceNumbers.length; i += batchSize) {
const batch = sourceNumbers.slice(i, i + batchSize) const batch = sourceNumbers.slice(i, i + batchSize)
const placeholders = this.buildPlaceholders(batch.length, isSqlServer) const placeholders = dialect.params(batch.length)
const sqlString = ` const sqlString = `
SELECT * SELECT *
@@ -273,13 +268,13 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
const batchSize = 1500 const batchSize = 1500
const allResults: any[] = [] const allResults: any[] = []
for (let i = 0; i < sourceNumbers.length; i += batchSize) { for (let i = 0; i < sourceNumbers.length; i += batchSize) {
const batch = sourceNumbers.slice(i, i + batchSize) const batch = sourceNumbers.slice(i, i + batchSize)
const placeholders = this.buildPlaceholders(batch.length, isSqlServer) const placeholders = dialect.params(batch.length)
const sqlString = ` const sqlString = `
WITH RankedRecords AS ( WITH RankedRecords AS (
@@ -338,9 +333,9 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
const placeholder = isSqlServer ? '@p0' : '?' const placeholder = dialect.param(0)
const sqlString = ` const sqlString = `
SELECT * SELECT *
FROM ${tableName} FROM ${tableName}
@@ -377,9 +372,9 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
const placeholder = isSqlServer ? '@p0' : '?' const placeholder = dialect.param(0)
const sqlString = ` const sqlString = `
SELECT * SELECT *
FROM ${tableName} FROM ${tableName}
@@ -418,13 +413,13 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
const batchSize = 1500 const batchSize = 1500
const allResults: any[] = [] const allResults: any[] = []
for (let i = 0; i < planNumbers.length; i += batchSize) { for (let i = 0; i < planNumbers.length; i += batchSize) {
const batch = planNumbers.slice(i, i + batchSize) const batch = planNumbers.slice(i, i + batchSize)
const placeholders = this.buildPlaceholders(batch.length, isSqlServer) const placeholders = dialect.params(batch.length)
const sqlString = ` const sqlString = `
SELECT * SELECT *
@@ -476,7 +471,7 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
const batchSize = 2000 const batchSize = 2000
// Get unique source numbers // Get unique source numbers
@@ -495,7 +490,7 @@ export class DiscreteMaterialPlanDAO {
for (let i = 0; i < uniqueSourceNumbers.length; i += batchSize) { for (let i = 0; i < uniqueSourceNumbers.length; i += batchSize) {
const batch = uniqueSourceNumbers.slice(i, i + batchSize) const batch = uniqueSourceNumbers.slice(i, i + batchSize)
const batchNumber = Math.floor(i / batchSize) + 1 const batchNumber = Math.floor(i / batchSize) + 1
const placeholders = this.buildPlaceholders(batch.length, isSqlServer) const placeholders = dialect.params(batch.length)
const sqlString = ` const sqlString = `
DELETE FROM ${tableName} DELETE FROM ${tableName}
@@ -565,23 +560,19 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
// SQL Server has a limit of 2100 parameters per query // SQL Server has a limit of 2100 parameters per query
// Each record has 28 columns, so max rows per batch = 2100 / 28 = 75 // Each record has 28 columns, so max rows per batch = 2100 / 28 = 75
// Leave some margin for query overhead // Leave some margin for query overhead
const columnsPerRow = 28 const columnsPerRow = 28
const sqlServerMaxParams = 2000 const effectiveBatchSize = Math.min(batchSize, dialect.maxBatchRows(columnsPerRow))
const effectiveBatchSize = isSqlServer
? Math.min(batchSize, Math.floor(sqlServerMaxParams / columnsPerRow))
: batchSize
const totalBatches = Math.ceil(records.length / effectiveBatchSize) const totalBatches = Math.ceil(records.length / effectiveBatchSize)
log.info('Batch insert started', { log.info('Batch insert started', {
tableName, tableName,
operationType: 'INSERT', operationType: 'INSERT',
requestId: batchId, requestId: batchId,
isSqlServer,
dbType: dbService.type, dbType: dbService.type,
columnsPerRow, columnsPerRow,
effectiveBatchSize, effectiveBatchSize,
@@ -598,7 +589,6 @@ export class DiscreteMaterialPlanDAO {
dbService, dbService,
tableName, tableName,
batch, batch,
isSqlServer,
batchId, batchId,
batchNumber, batchNumber,
totalBatches totalBatches
@@ -643,7 +633,6 @@ export class DiscreteMaterialPlanDAO {
dbService: IDatabaseService, dbService: IDatabaseService,
tableName: string, tableName: string,
records: MaterialPlanRecord[], records: MaterialPlanRecord[],
isSqlServer: boolean,
batchId: string, batchId: string,
batchNumber: number, batchNumber: number,
totalBatches: number totalBatches: number
@@ -689,7 +678,7 @@ export class DiscreteMaterialPlanDAO {
const rowPlaceholders: string[] = [] const rowPlaceholders: string[] = []
records.forEach((record, rowIndex) => { records.forEach((record, rowIndex) => {
const rowValues = this.buildRowValues(record, columns, rowIndex, isSqlServer, values) const rowValues = this.buildRowValues(record, columns, rowIndex, values)
rowPlaceholders.push(`(${rowValues.join(',')})`) rowPlaceholders.push(`(${rowValues.join(',')})`)
}) })
@@ -718,10 +707,9 @@ export class DiscreteMaterialPlanDAO {
private async insertBatch( private async insertBatch(
dbService: IDatabaseService, dbService: IDatabaseService,
tableName: string, tableName: string,
records: MaterialPlanRecord[], records: MaterialPlanRecord[]
isSqlServer: boolean
): Promise<number> { ): Promise<number> {
return this.insertBatchWithTracking(dbService, tableName, records, isSqlServer, 'unknown', 1, 1) return this.insertBatchWithTracking(dbService, tableName, records, 'unknown', 1, 1)
} }
/** /**
@@ -731,18 +719,14 @@ export class DiscreteMaterialPlanDAO {
record: MaterialPlanRecord, record: MaterialPlanRecord,
columns: string[], columns: string[],
_rowIndex: number, _rowIndex: number,
isSqlServer: boolean,
values: any[] values: any[]
): string[] { ): string[] {
const dialect = this.getDialect()
return columns.map((col) => { return columns.map((col) => {
const value = this.getColumnValue(record, col) const value = this.getColumnValue(record, col)
values.push(value) values.push(value)
if (isSqlServer) { return dialect.param(values.length - 1)
return `@p${values.length - 1}`
} else {
return '?'
}
}) })
} }
@@ -839,9 +823,9 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
const placeholder = isSqlServer ? '@p0' : '?' const placeholder = dialect.param(0)
const sqlString = ` const sqlString = `
SELECT COUNT(*) as count SELECT COUNT(*) as count
FROM ${tableName} FROM ${tableName}
@@ -876,7 +860,7 @@ export class DiscreteMaterialPlanDAO {
try { try {
const dbService = await this.getDatabaseService() const dbService = await this.getDatabaseService()
const tableName = this.getTableName() const tableName = this.getTableName()
const isSqlServer = dbService.type === 'sqlserver' const dialect = this.getDialect()
if (sourceNumbers && sourceNumbers.length > 0) { if (sourceNumbers && sourceNumbers.length > 0) {
const batchSize = 1500 const batchSize = 1500
@@ -884,7 +868,7 @@ export class DiscreteMaterialPlanDAO {
for (let i = 0; i < sourceNumbers.length; i += batchSize) { for (let i = 0; i < sourceNumbers.length; i += batchSize) {
const batch = sourceNumbers.slice(i, i + batchSize) const batch = sourceNumbers.slice(i, i + batchSize)
const placeholders = this.buildPlaceholders(batch.length, isSqlServer) const placeholders = dialect.params(batch.length)
const sqlString = ` const sqlString = `
SELECT DISTINCT MaterialName SELECT DISTINCT MaterialName
@@ -975,6 +959,7 @@ export class DiscreteMaterialPlanDAO {
if (this.dbService) { if (this.dbService) {
await this.dbService.disconnect() await this.dbService.disconnect()
this.dbService = null this.dbService = null
this.dialect = null
} }
} }
} }