feat: orm-cj 仓颉版 EF Core 风格 ORM 初始版本

- 基于数据模型(POCO + 注解)的映射与增删改查:DbContext/DbSet/ChangeTracker/QueryBuilder
- ISqlDialect 方言接口 + PostgreSQL/openGauss 实现,零外部依赖
- @DbContext 宏:纯声明 DbSet 类自动展开为完整 DbContext 子类
- 迁移:Migration/Migrator/ModelSnapshot(快照 JSON)/MiniJson,从模型生成迁移
- 迁移 CLI:add/rm/update/downgrade/list/help,应用内嵌一行 db.cli(args) 接入
- DbContext 便捷方法:databaseExists/hasPendingMigrations/migrate
- 57 个单元测试全部通过
This commit is contained in:
2026-08-19 09:14:01 +08:00
commit afa6096ed2
28 changed files with 5822 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright (c) 2025 SimcuTeam. All rights reserved.
* 连接串 → Datasource 工厂:把"驱动与配置构建"收敛到 orm-cj,应用侧只需传连接字符串。
*
* 支持两种连接串格式:
* 1. URL 格式(推荐):postgres://user:pass@host:port/db?sslmode=disableopengauss:// 亦可)
* 2. ADO.NET 风格:Host=..;Port=..;Database=..;Username=..;Password=..(自动转 URL
*
* 驱动通过 std.database.sql.DriverManager 查找:应用只需引入并链接驱动包
* (如 opengauss-driver,其模块加载时自动注册 "postgres"/"opengauss"),
* orm-cj 本身不依赖任何具体驱动实现。
*/
package simcu::orm.db
import std.database.sql.*
/**
* 连接串 → Datasource 工厂(对齐 .NET NpgsqlDataSource.Create / EF Core UseNpgsql(connStr))。
*/
public class DatasourceFactory {
/// 默认驱动名(ADO 风格连接串无 scheme 时使用)
public static let DEFAULT_DRIVER = "postgres"
/**
* 由连接字符串创建 Datasource。驱动名自动推断:
* URL 格式按 schemepostgres/postgresql/pgsql/pg → postgresopengauss → opengauss);
* ADO 风格默认 postgres。
*/
public static func create(connStr: String): Datasource {
build(detectDriver(connStr, DEFAULT_DRIVER), toUrl(connStr))
}
/**
* 由连接字符串创建 Datasource,可显式指定驱动名(如 "pgsql"/"postgres"/"opengauss")。
* 显式驱动名优先于连接串内 scheme。
*/
public static func create(connStr: String, driverName: String): Datasource {
build(normalizeDriverName(driverName), toUrl(connStr))
}
private static func build(name: String, url: String): Datasource {
let driver = DriverManager.getDriver(name) ??
throw Exception(
"simorm: 未注册数据库驱动 '${name}'。请确认应用已引入并链接对应驱动包" +
"(如 opengauss-driver,其加载时自动注册 postgres/opengauss")
driver.open(url)
}
/**
* 从连接串推断驱动注册名。
*/
public static func detectDriver(connStr: String, defaultDriver: String): String {
if (connStr.contains("://")) {
let i = connStr.indexOf("://").getOrThrow()
let scheme = connStr[0..i].toAsciiLower()
match (scheme) {
case "postgresql" | "pgsql" | "pg" => "postgres"
case _ => scheme
}
} else {
normalizeDriverName(defaultDriver)
}
}
/**
* 驱动名别名归一化到 DriverManager 注册名。
*/
public static func normalizeDriverName(name: String): String {
match (name.trimAscii().toAsciiLower()) {
case "pgsql" | "pg" | "postgresql" => "postgres"
case _ => name.trimAscii()
}
}
/**
* 统一为驱动可解析的 URL 格式。
* ADO.NET 风格(.NET Npgsql 连接串)示例:
* Host=192.168.0.2;Port=5432;Database=lemon-lurmix;Username=postgres;Password=Love@1314
* → postgres://postgres:Love@1314@192.168.0.2:5432/lemon-lurmix?sslmode=disable
* 已是 URL(含 "://")则原样返回。
*/
public static func toUrl(connStr: String): String {
if (connStr.contains("://")) {
return connStr
}
var host = ""
var port = "5432"
var database = ""
var username = ""
var password = ""
for (part in connStr.split(";")) {
let seg = part.trimAscii()
if (seg.isEmpty()) {
continue
}
match (seg.indexOf("=")) {
case Some(i) =>
let key = seg[0..i].trimAscii().toAsciiLower()
let value = seg[i + 1..].trimAscii()
match (key) {
case "host" => host = value
case "port" => port = value
case "database" => database = value
case "username" | "user id" | "uid" => username = value
case "password" | "pwd" => password = value
case _ => ()
}
case None => ()
}
}
return "${DEFAULT_DRIVER}://${username}:${password}@${host}:${port}/${database}?sslmode=disable"
}
}