package aceboot::orm_demo
import aceboot::orm.*
import aceboot::orm.macros.*
import std.collection.*
/**
* 实体:@Entity 生成 UserMapper + UserRepository。无需写 init()(仓颉对全字段有初值的类自动生成)。
* @Id[] 主键(自增);@Column[] 数据列(列名=字段名),@Column["别名"] 自定义列名。
*/
@Entity["users"]
public class User {
@Id[]
public var id: Int64 = 0
@Column[]
public var name: String = ""
@Column["age_years"] // 字段 age 映射到列 age_years(列别名)
public var age: Int64 = 0
}
/** 演示外键:@ManyToOne["users"] 生成 FK 列 + DDL 的 FOREIGN KEY 约束。 */
@Entity["posts"]
public class Post {
@Id[]
public var id: Int64 = 0
@Column[]
public var title: String = ""
@ManyToOne["users"] // 外键 -> users(id)
public var authorId: Int64 = 0
}
func mkUser(name: String, age: Int64): User {
let u = User()
u.name = name
u.age = age
return u
}
/** 服务:@Transactional 把多步写操作包成一个原子事务。 */
class UserService {
let repo: Repository<User>
init(repo: Repository<User>) {
this.repo = repo
}
@Transactional
public func addTwo(a: User, b: User): Unit {
repo.insert(a)
repo.insert(b)
}
@Transactional
public func addThenFail(a: User): Unit {
repo.insert(a)
throw OrmException("boom: rollback expected")
}
}
main(): Int64 {
let ds = DataSource(SqliteDriver(":memory:"))
setGlobalDataSource(ds) // 供 @Transactional 与 @Entity 生成的 UserRepository() 使用
let repo = UserRepository() // @Entity 生成的具体子类:无参构造,用全局数据源 + UserMapper
repo.createTable()
// ---- 基本 CRUD ----
let alice = mkUser("alice", 30)
let id = repo.insert(alice)
println("insert alice -> id=${id}, 回填 alice.id=${alice.id}")
repo.insert(mkUser("bob", 25))
println("count=${repo.count()}")
match (repo.findById(DbInt(id))) {
case Some(u) => println("findById ${id} -> ${u.name}, age=${u.age}")
case None => println("findById ${id} -> not found")
}
alice.age = 31
repo.update(alice)
println("update alice.age=31 -> 回查 age=${repo.findById(DbInt(id)).getOrThrow().age}")
println("findBy name=bob -> ${repo.findBy("name", DbText("bob")).size} 行")
// ---- 事务:提交 ----
let svc = UserService(repo)
svc.addTwo(mkUser("carol", 40), mkUser("dave", 50))
println("addTwo 提交后 count=${repo.count()}")
// ---- 事务:回滚 ----
let before = repo.count()
try {
svc.addThenFail(mkUser("eve", 99))
} catch (e: Exception) {
println("addThenFail 抛出: ${e.message}")
}
println("回滚后 count=${repo.count()} (期望 ${before})")
println("--- 全表 ---")
for (u in repo.findAll()) {
println(" #${u.id} ${u.name} (${u.age})")
}
// ---- 联表查询(QueryBuilder JOIN)----
let postRepo = PostRepository()
postRepo.createTable()
// users 表里 alice=#1、bob=#2;插入两条帖子,外键 authorId 指向作者
let pa = Post()
pa.title = "alice writes ORM"
pa.authorId = 1
postRepo.insert(pa)
let pb = Post()
pb.title = "bob writes API"
pb.authorId = 2
postRepo.insert(pb)
// 1) JOIN users 按作者名过滤,返回 Post 实体
println("--- 联表:alice 写的帖子(JOIN users WHERE u.name='alice')---")
let alicePosts = postRepo.createQueryBuilder("p").innerJoin("users", "u", "u.id = p.authorId").andWhere("u.name",
"=", DbText("alice")).orderBy("p.id", "ASC").getMany()
for (post in alicePosts) {
println(" #${post.id} ${post.title} (authorId=${post.authorId})")
}
// 2) 联表投影:帖子标题 + 作者名(多表列,取原始 Row)
println("--- 联表投影:标题 + 作者名 ---")
for (r in postRepo.createQueryBuilder("p").innerJoin("users", "u", "u.id = p.authorId").orderBy("p.id",
"ASC").getRawMany("p.title AS title, u.name AS author")) {
println(" '${r.getText("title")}' by ${r.getText("author")}")
}
// ---- 由方言生成的 DDL(同一套实体,三种数据库语法)----
println("--- 生成的 DDL(SQLite)---")
println("users: ${SqliteDialect().createTable("users", UserMapper().columns())}")
println("posts: ${SqliteDialect().createTable("posts", PostMapper().columns())}")
ds.driver.close()
return 0
}