diff --git a/README.md b/README.md index 93bcb3a..af859e8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ > 仓颉版 ORM:**基于数据模型(POCO + 注解)的映射、增删改查、数据库迁移**。 -面向多数据库的方言架构:内置 PostgreSQL(`PostgreSqlDialect`)与 openGauss(`OpenGaussDialect`,继承 PG)方言(对接 [opengauss-driver](../opengauss-driver)),可通过实现 `ISqlDialect` 接口接入 sqlite / mysql 等新数据库。包本身零外部依赖。 +面向多数据库的方言架构:内置 PostgreSQL(`PostgreSqlDialect`)与 openGauss(`OpenGaussDialect`,继承 PG)方言(对接 [opengauss-driver](../opengauss-driver)),可通过实现 `SqlDialect` 接口接入 sqlite / mysql 等新数据库。包本身零外部依赖。 --- @@ -279,7 +279,7 @@ orm-cj/ │ ├── model/ # EntityModel(反射映射)、ModelCache(模型缓存)、 │ │ # ColumnNamingPolicy(列命名策略)、ValueReader、ParamBinder、GuidUtil │ ├── tracking/ # ChangeTracker(操作队列)、EntityState、EntityEntry -│ ├── sql/ # ISqlDialect 接口(独立文件)+ PostgreSqlDialect(PG 实现)+ +│ ├── sql/ # SqlDialect 接口(独立文件)+ PostgreSqlDialect(PG 实现)+ │ │ # OpenGaussDialect(继承 PG)、ColumnTypes(列类型) │ ├── query/ # QueryBuilder(条件/排序/分页)、PagedResult │ ├── db/ # DbContext(连接 + 提交 + 物化 + 数据库存在性/迁移状态检查)、DbSet @@ -439,7 +439,7 @@ cjpm test # 纯逻辑单元测试(模型映射/SQL 生成/DDL 生成/QueryB - 不支持导航属性 / 延迟加载 / 级联删除(这些能力属于 v2+); - 不支持 LINQ 表达式树,查询以 `filter` 条件方法 + SQL 片段组合; - `QueryBuilder` 的 SQL 片段形式(`filter(condition, params)`)需自行保证列名合法(会做标识符引号包裹校验外的处理)——推荐优先使用三参属性形式; -- 自增主键回读依赖驱动 `RETURNING` 支持(openGauss/PostgreSQL 原生支持;换方言时由 `ISqlDialect.buildInsert` 决定回读策略)。 +- 自增主键回读依赖驱动 `RETURNING` 支持(openGauss/PostgreSQL 原生支持;换方言时由 `SqlDialect.buildInsert` 决定回读策略)。 --- @@ -450,7 +450,7 @@ cjpm test # 纯逻辑单元测试(模型映射/SQL 生成/DDL 生成/QueryB | 数据库驱动(使用者引入,如 `opengauss` → `../opengauss-driver`) | 实现 `std.database.sql` 的 `Datasource`/`Connection`/`Statement` | | `stdx`(CANGJIE_STDX_PATH) | 标准扩展库(std.database.sql 接口) | -> orm-cj 包本身零依赖:连接层走 `std.database.sql` 标准接口,SQL/DDL 生成走 `ISqlDialect` 方言接口。新数据库接入 = 实现 `ISqlDialect`(CRUD + 列类型映射 + 差异 DDL 语句)+ 提供对应 `std.database.sql` 驱动。 +> orm-cj 包本身零依赖:连接层走 `std.database.sql` 标准接口,SQL/DDL 生成走 `SqlDialect` 方言接口。新数据库接入 = 实现 `SqlDialect`(CRUD + 列类型映射 + 差异 DDL 语句)+ 提供对应 `std.database.sql` 驱动。 --- diff --git a/src/cli/cli_context.cj b/src/cli/cli_context.cj index d79dd5d..5b1b1cd 100644 --- a/src/cli/cli_context.cj +++ b/src/cli/cli_context.cj @@ -20,7 +20,7 @@ public interface CliContext { /// 应用主数据源 func getDatasource(): Datasource /// SQL 方言 - func getDialect(): ISqlDialect + func getDialect(): SqlDialect /// 迁移列表(子类 override migrations() 提供) func getMigrations(): ArrayList /// 应用所有迁移 diff --git a/src/cli/migration_cli.cj b/src/cli/migration_cli.cj index a0f870f..729792f 100644 --- a/src/cli/migration_cli.cj +++ b/src/cli/migration_cli.cj @@ -94,7 +94,7 @@ public class MigrationCli { private func dispatch(args: ArrayList, models: () -> ArrayList, datasource: () -> Datasource, migrations: () -> ArrayList, - dialect: ISqlDialect, seedCtx: ?Any): Int64 { + dialect: SqlDialect, seedCtx: ?Any): Int64 { if (args.size == 0) { printHelp() return 0 @@ -122,7 +122,7 @@ public class MigrationCli { /// database <子命令>:数据库级操作(不需要迁移注册) private func cmdDatabase(args: ArrayList, datasource: () -> Datasource, - dialect: ISqlDialect): Int64 { + dialect: SqlDialect): Int64 { if (args.size < 2) { println("用法: simcu::orm database ") return 1 @@ -137,7 +137,7 @@ public class MigrationCli { } /// database truncate:清空所有业务表数据(保留表结构与迁移历史) - private func cmdTruncate(datasource: () -> Datasource, dialect: ISqlDialect): Int64 { + private func cmdTruncate(datasource: () -> Datasource, dialect: SqlDialect): Int64 { try { let migrator = Migrator(datasource(), dialect) let n = migrator.truncateAll() @@ -151,7 +151,7 @@ public class MigrationCli { } /// database drop:删除所有表(含迁移历史),完全清空数据库;之后可 update 重建 - private func cmdDrop(datasource: () -> Datasource, dialect: ISqlDialect): Int64 { + private func cmdDrop(datasource: () -> Datasource, dialect: SqlDialect): Int64 { try { let migrator = Migrator(datasource(), dialect) let n = migrator.dropAllTables() @@ -217,7 +217,7 @@ public class MigrationCli { /// update:应用所有未执行的迁移 private func cmdUpdate(datasource: () -> Datasource, - migrations: () -> ArrayList, dialect: ISqlDialect): Int64 { + migrations: () -> ArrayList, dialect: SqlDialect): Int64 { let list = migrations() if (list.size == 0) { println("simcu::orm: 未注册任何迁移(检查 ${_registryPath})") @@ -231,7 +231,7 @@ public class MigrationCli { /// downgrade [目标]:回退迁移(执行 down + 删除历史记录;无目标 = 回退最近一个) private func cmdDowngrade(datasource: () -> Datasource, migrations: () -> ArrayList, - dialect: ISqlDialect, args: ArrayList): Int64 { + dialect: SqlDialect, args: ArrayList): Int64 { let list = migrations() if (list.size == 0) { println("simcu::orm: 未注册任何迁移(检查 ${_registryPath})") @@ -334,7 +334,7 @@ public class MigrationCli { /// list:显示已应用/待应用迁移(空库/全新库时全部显示为待应用) private func cmdList(datasource: () -> Datasource, migrations: () -> ArrayList, - dialect: ISqlDialect): Int64 { + dialect: SqlDialect): Int64 { let list = migrations() if (list.size == 0) { println("simcu::orm: 未注册任何迁移(检查 ${_registryPath})") @@ -365,7 +365,7 @@ public class MigrationCli { /// seed:列出/运行数据填充(@Seed 标注的类,按 seedId 唯一前缀匹配;--all 全部;无参=列出) private func cmdSeed(datasource: () -> Datasource, migrations: () -> ArrayList, - dialect: ISqlDialect, args: ArrayList, seedCtx: ?Any): Int64 { + dialect: SqlDialect, args: ArrayList, seedCtx: ?Any): Int64 { let list = allSeeds() if (list.size == 0) { println("simcu::orm: 未注册任何填充(检查 @Seed 标注的类是否存在,并确认应用已 import 对应包)") diff --git a/src/db/db_context.cj b/src/db/db_context.cj index aabf17d..c9c7584 100644 --- a/src/db/db_context.cj +++ b/src/db/db_context.cj @@ -41,13 +41,13 @@ import simcu::orm.migrations.{Migrator, Migration} */ public open class DbContext <: CliContext { internal let datasource: Datasource - internal let dialect: ISqlDialect + internal let dialect: SqlDialect internal let tracker = ChangeTracker() private let _sets = HashMap() private var _driverName: String private var _connString: String - public init(datasource: Datasource, dialect: ISqlDialect) { + public init(datasource: Datasource, dialect: SqlDialect) { this.datasource = datasource this.dialect = dialect this._driverName = "" @@ -59,7 +59,7 @@ public open class DbContext <: CliContext { } /// 便捷构造:由连接字符串创建 Datasource(驱动构建收敛在 DatasourceFactory) - public init(connStr: String, dialect: ISqlDialect) { + public init(connStr: String, dialect: SqlDialect) { this(DatasourceFactory.create(connStr), dialect) this._driverName = DatasourceFactory.detectDriver(connStr, DatasourceFactory.DEFAULT_DRIVER) this._connString = connStr @@ -70,7 +70,7 @@ public open class DbContext <: CliContext { } /// 便捷构造:显式指定驱动类型(如 "pgsql")+ 连接字符串 - public init(driverName: String, connStr: String, dialect: ISqlDialect) { + public init(driverName: String, connStr: String, dialect: SqlDialect) { this(DatasourceFactory.create(connStr, driverName), dialect) this._driverName = DatasourceFactory.normalizeDriverName(driverName) this._connString = connStr @@ -200,7 +200,7 @@ public open class DbContext <: CliContext { } /// 当前方言(子类/应用可读取) - public func getDialect(): ISqlDialect { + public func getDialect(): SqlDialect { dialect } diff --git a/src/migrations/migrations.cj b/src/migrations/migrations.cj index c1c7bf7..53a9c1b 100644 --- a/src/migrations/migrations.cj +++ b/src/migrations/migrations.cj @@ -275,12 +275,12 @@ public open class Migration { } /** - * DDL SQL 工厂:MigrationOperation → SQL(类型映射与差异语法委托给 ISqlDialect)。 + * DDL SQL 工厂:MigrationOperation → SQL(类型映射与差异语法委托给 SqlDialect)。 */ public class DdlFactory { public init() {} - public func toSql(op: MigrationOperation, dialect: ISqlDialect): String { + public func toSql(op: MigrationOperation, dialect: SqlDialect): String { match (op.kind) { case MigrationOperationKind.CreateTable => createTableSql(op, dialect) case MigrationOperationKind.DropTable => "DROP TABLE IF EXISTS ${dialect.quoteName(op.tableName)}" @@ -303,7 +303,7 @@ public class DdlFactory { /// - 有同名列且类型一致 → AddColumn 幂等跳过(空列表);AlterColumn 保留原 SQL(处理非空/长度等变化) /// - 有同名列但类型不同 → 先 DROP COLUMN 再 ADD COLUMN(重建该字段) /// existingType 来自 information_schema.data_type;None 表示列不存在。 - public func resolveColumnSqls(op: MigrationOperation, dialect: ISqlDialect, + public func resolveColumnSqls(op: MigrationOperation, dialect: SqlDialect, existingType: ?String): ArrayList { let result = ArrayList() let col = op.column.getOrThrow() @@ -369,7 +369,7 @@ public class DdlFactory { sb.toString() } - private func createTableSql(op: MigrationOperation, dialect: ISqlDialect): String { + private func createTableSql(op: MigrationOperation, dialect: SqlDialect): String { let sb = StringBuilder() sb.append("CREATE TABLE IF NOT EXISTS ${dialect.quoteName(op.tableName)} (\n") var first = true @@ -384,7 +384,7 @@ public class DdlFactory { sb.toString() } - private func createIndexSql(op: MigrationOperation, dialect: ISqlDialect): String { + private func createIndexSql(op: MigrationOperation, dialect: SqlDialect): String { let sb = StringBuilder() sb.append("CREATE ") if (op.unique) { @@ -406,7 +406,7 @@ public class DdlFactory { sb.toString() } - private func columnDefSql(col: ColumnDefinition, dialect: ISqlDialect): String { + private func columnDefSql(col: ColumnDefinition, dialect: SqlDialect): String { let sb = StringBuilder() sb.append(dialect.quoteName(col.name)) sb.append(" ${dialect.columnTypeSql(col.columnType, col.autoIncrement, col.maxLength)}") diff --git a/src/migrations/migrator.cj b/src/migrations/migrator.cj index 3a39ded..f29e31d 100644 --- a/src/migrations/migrator.cj +++ b/src/migrations/migrator.cj @@ -18,10 +18,10 @@ import simcu::orm.sql.* */ public class Migrator { private let _datasource: Datasource - private let _dialect: ISqlDialect + private let _dialect: SqlDialect private let _historyTable = "simcu_orm_migrations" - public init(datasource: Datasource, dialect: ISqlDialect) { + public init(datasource: Datasource, dialect: SqlDialect) { this._datasource = datasource this._dialect = dialect } diff --git a/src/query/query_builder.cj b/src/query/query_builder.cj index 88fa9d5..145afae 100644 --- a/src/query/query_builder.cj +++ b/src/query/query_builder.cj @@ -48,7 +48,7 @@ public class PagedResult { */ public class QueryBuilder { private let _model: EntityModel - private let _dialect: ISqlDialect + private let _dialect: SqlDialect private let _executor: (String, ArrayList) -> ArrayList private let _counter: (String, ArrayList) -> Int64 @@ -58,7 +58,7 @@ public class QueryBuilder { private var _skip: Int64 = 0 private var _take: Int64 = 0 - public init(model: EntityModel, dialect: ISqlDialect, executor: (String, ArrayList) -> ArrayList, + public init(model: EntityModel, dialect: SqlDialect, executor: (String, ArrayList) -> ArrayList, counter: (String, ArrayList) -> Int64) { this._model = model this._dialect = dialect diff --git a/src/sql/column_types.cj b/src/sql/column_types.cj index 516a6cd..ff1c5f7 100644 --- a/src/sql/column_types.cj +++ b/src/sql/column_types.cj @@ -1,6 +1,6 @@ /* * Copyright (c) 2025 SimcuTeam. All rights reserved. - * 列类型:与具体数据库无关的抽象,DDL 映射由 ISqlDialect 决定。 + * 列类型:与具体数据库无关的抽象,DDL 映射由 SqlDialect 决定。 */ package simcu::orm.sql diff --git a/src/sql/postgre_sql_dialect.cj b/src/sql/postgre_sql_dialect.cj index 12f0f99..760ecd0 100644 --- a/src/sql/postgre_sql_dialect.cj +++ b/src/sql/postgre_sql_dialect.cj @@ -13,7 +13,7 @@ import std.collection.* /** * PostgreSQL 方言。 */ -public open class PostgreSqlDialect <: ISqlDialect { +public open class PostgreSqlDialect <: SqlDialect { public init() {} public func quoteName(name: String): String { diff --git a/src/sql/i_sql_dialect.cj b/src/sql/sql_dialect.cj similarity index 78% rename from src/sql/i_sql_dialect.cj rename to src/sql/sql_dialect.cj index 68a5c4b..7571d42 100644 --- a/src/sql/i_sql_dialect.cj +++ b/src/sql/sql_dialect.cj @@ -1,9 +1,9 @@ /* * Copyright (c) 2025 SimcuTeam. All rights reserved. - * SQL 方言接口(I 前缀命名,对齐 EF Core 接口风格):标识符引用、增删改查 SQL 生成、DDL 类型/语句生成。 + * SQL 方言接口:标识符引用、增删改查 SQL 生成、DDL 类型/语句生成。 * - * 新数据库接入:实现 ISqlDialect 即可(参考 PostgreSqlDialect / OpenGaussDialect)。 - * 内置实现见 PostgreSqlDialect.cj(PostgreSQL)、OpenGaussDialect.cj(openGauss,继承 PG)。 + * 新数据库接入:实现 SqlDialect 即可(参考 PostgreSqlDialect / OpenGaussDialect)。 + * 内置实现见 postgre_sql_dialect.cj(PostgreSQL)、open_gauss_dialect.cj(openGauss,继承 PG)。 */ package simcu::orm.sql @@ -13,7 +13,7 @@ import std.collection.* /** * SQL 方言接口。 */ -public interface ISqlDialect { +public interface SqlDialect { /// 引用标识符(表名/列名) func quoteName(name: String): String @@ -51,6 +51,3 @@ public interface ISqlDialect { /// 探测数据库是否存在的 SELECT(返回带 ? 占位符的语句,库名作为参数值传入避免拼接注入) func databaseExistsSql(): String } - -/// 兼容别名:旧名称 SqlDialect 仍可用(新代码请使用 ISqlDialect) -public type SqlDialect = ISqlDialect diff --git a/src/tests/sim_orm_test.cj b/src/tests/sim_orm_test.cj index 427bac0..44bde48 100644 --- a/src/tests/sim_orm_test.cj +++ b/src/tests/sim_orm_test.cj @@ -301,7 +301,7 @@ class ChangeTrackerTests { // ---------- OpenGaussDialect SQL 生成 ---------- @Test -class ISqlDialectTests { +class SqlDialectTests { @TestCase public func testQuoteInsertUpdateDelete(): Unit { let d = OpenGaussDialect() @@ -709,7 +709,7 @@ class MigrationGeneratorTests { MigrationGenerator() } - private func upSql(m: Migration, dialect: ISqlDialect): ArrayList { + private func upSql(m: Migration, dialect: SqlDialect): ArrayList { let builder = MigrationBuilder() m.up(builder) let f = DdlFactory() @@ -720,7 +720,7 @@ class MigrationGeneratorTests { sqls } - private func downSql(m: Migration, dialect: ISqlDialect): ArrayList { + private func downSql(m: Migration, dialect: SqlDialect): ArrayList { let builder = MigrationBuilder() m.down(builder) let f = DdlFactory() @@ -987,7 +987,7 @@ class AppDbContext <: DbContext { orders = set() } - init(ds: Datasource, dialect: ISqlDialect) { + init(ds: Datasource, dialect: SqlDialect) { super(ds, dialect) users = set() orders = set() @@ -1044,7 +1044,7 @@ class ModelSnapshotTests { ms } - private func upSql(m: Migration, dialect: ISqlDialect): ArrayList { + private func upSql(m: Migration, dialect: SqlDialect): ArrayList { let builder = MigrationBuilder() m.up(builder) let f = DdlFactory()