diff --git a/src/main/types/config.schema.ts b/src/main/types/config.schema.ts index 81f9779..c016782 100644 --- a/src/main/types/config.schema.ts +++ b/src/main/types/config.schema.ts @@ -12,7 +12,7 @@ import { z } from 'zod' /** * 数据库类型枚举 */ -export const databaseTypeSchema = z.enum(['mysql', 'sqlserver']) +export const databaseTypeSchema = z.enum(['mysql', 'sqlserver', 'postgresql']) export type DatabaseType = z.infer /** @@ -57,13 +57,27 @@ export const sqlServerConfigSchema = z.object({ trustServerCertificate: z.boolean().default(true) }) +/** + * PostgreSQL 配置 Schema + */ +export const postgresqlConfigSchema = z.object({ + host: z.string().min(1, 'PostgreSQL host is required'), + port: z.number().int().min(1).max(65535).default(5432), + database: z.string().min(1, 'PostgreSQL database is required'), + username: z.string().min(1, 'PostgreSQL username is required'), + password: z.string(), + maxPoolSize: z.number().int().min(1).max(100).default(10) +}) +export type PostgreSqlConfigSchema = z.infer + /** * 数据库配置(包含两种数据库的完整配置) */ export const databaseConfigSchema = z.object({ activeType: databaseTypeSchema.default('mysql'), mysql: mysqlConfigSchema, - sqlserver: sqlServerConfigSchema + sqlserver: sqlServerConfigSchema, + postgresql: postgresqlConfigSchema }) /** @@ -199,6 +213,7 @@ export type FullConfig = z.infer export type DatabaseConfig = z.infer export type MySqlConfig = z.infer export type SqlServerConfig = z.infer +export type PostgreSqlConfig = z.infer export type ErpSystemConfig = z.infer export type LoggingConfig = z.infer export type RustfsConfig = z.infer diff --git a/src/main/types/database.types.ts b/src/main/types/database.types.ts index 8874fc3..9e3653d 100644 --- a/src/main/types/database.types.ts +++ b/src/main/types/database.types.ts @@ -8,7 +8,7 @@ /** * Supported database types */ -export type DatabaseType = 'mysql' | 'sqlserver' +export type DatabaseType = 'mysql' | 'sqlserver' | 'postgresql' /** * Standard query result interface @@ -102,3 +102,15 @@ export interface SqlServerConfig extends DatabaseConfig { trustServerCertificate?: boolean } } + +/** + * PostgreSQL-specific configuration + */ +export interface PostgreSqlConfig extends DatabaseConfig { + host: string + port: number + user: string + password: string + database: string + maxPoolSize?: number +} diff --git a/src/main/types/sql-dialect.types.ts b/src/main/types/sql-dialect.types.ts new file mode 100644 index 0000000..155f043 --- /dev/null +++ b/src/main/types/sql-dialect.types.ts @@ -0,0 +1,80 @@ +/** + * SQL Dialect Abstraction + * + * Provides a unified interface for database-specific SQL syntax differences. + * Each database type implements this interface to encapsulate: + * - Parameter placeholder format + * - Table name quoting + * - UPSERT syntax + * - Pagination syntax + * - Current timestamp function + * - Batch size limits + */ + +import type { DatabaseType } from './database.types' + +export interface SqlDialect { + /** Database type identifier */ + readonly dbType: DatabaseType + + /** + * Quote a table name with schema prefix + * MySQL: dbo_TableName + * SQL Server: [dbo].[TableName] + * PostgreSQL: "dbo"."TableName" + */ + quoteTableName(schema: string, table: string): string + + /** + * Get placeholder for parameter at given index (0-based) + * MySQL: ? + * SQL Server: @p0 + * PostgreSQL: $1 + */ + param(index: number): string + + /** + * Get comma-separated placeholders for count parameters + */ + params(count: number): string + + /** + * Get current timestamp SQL function + * MySQL: NOW() + * SQL Server: GETDATE() + * PostgreSQL: CURRENT_TIMESTAMP + */ + currentTimestamp(): string + + /** + * Generate UPSERT SQL for a single row + * MySQL: INSERT ... ON DUPLICATE KEY UPDATE + * SQL Server: MERGE ... USING ... + * PostgreSQL: INSERT ... ON CONFLICT ... DO UPDATE SET + */ + upsert(params: { + table: string + keyColumns: string[] + allColumns: string[] + startParamIndex: number + }): { sql: string; nextParamIndex: number } + + /** + * Append pagination clause to SQL + * MySQL/PostgreSQL: LIMIT x OFFSET y + * SQL Server: OFFSET x ROWS FETCH NEXT y ROWS ONLY + */ + paginate(params: { + sql: string + limit: number + offset?: number + paramIndex: number + }): { sql: string; nextParamIndex: number } + + /** + * Maximum rows per batch given columns per row + * SQL Server: ~71 (due to 2100 param limit) + * MySQL/PostgreSQL: 1000 + */ + maxBatchRows(columnsPerRow: number): number +}