"bin-deps": {
"oboard/morm": "latest"
},options(
"pre-build": [
{
"command": "$mod_dir/.mooncakes/oboard/morm/morm-gen $input -o $output && moonfmt -w $output",
"input": "entities.mbt",
"output": "entities.g.mbt",
},
{
"command": "$mod_dir/.mooncakes/oboard/morm/morm-gen $input -o $output && moonfmt -w $output",
"input": "mapper.mbt",
"output": "mapper.g.mbt",
},
],
)///|
#morm.entity(name="teacher")
pub(all) struct Teacher {
#morm.primary_key
#morm.auto_increment
#morm.bigint
id : Int
#morm.varchar(length="255")
name : String
#morm.varchar(length="255")
major : String
age : Int
#morm.datetime
birth_date : String?
} derive(ToJson, FromJson)| 属性 | 示例 | 说明 |
|---|---|---|
| #morm.entity | 置于 struct 顶部 | 声明该结构体为 ORM 实体,生成 impl @morm.Entity |
| #morm.primary_key | 放在某字段上一行 | 将该列标记为主键;主键总是非空 |
| #morm.auto_increment | 放在主键字段上一行 | 将该列设置为自增,同时 primary_key=true、nullable=false |
| #morm.not_null | 放在字段上一行 | 当前版本仅作标记,实际可空性仍由类型 T / T? 决定 |
| #morm.varchar | #morm.varchar(length="255") | 将该列类型设为 VarChar(255);若未提供参数,默认 255 |
| #morm.char | #morm.char(length="1") | 将该列类型设为 Char(1);若未提供参数,默认 1 |
| #morm.text | 纯标签 | 将该列类型设为 Text |
| #morm.mediumtext | 纯标签 | 将该列类型设为 MediumText |
| #morm.longtext | 纯标签 | 将该列类型设为 LongText |
| #morm.binary | #morm.binary(length="1") | 将该列类型设为 Binary(1);若未提供参数,默认 1 |
| #morm.varbinary | #morm.varbinary(length="255") | 将该列类型设为 VarBinary(255);若未提供参数,默认 255 |
| #morm.blob | 纯标签 | 将该列类型设为 Blob |
| #morm.tinyint | 纯标签 | 将该列类型设为 TinyInt |
| #morm.smallint | 纯标签 | 将该列类型设为 SmallInt |
| #morm.int | 纯标签 | 将该列类型设为 Int |
| #morm.bigint | 纯标签 | 将该列类型设为 BigInt |
| #morm.float | 纯标签 | 将该列类型设为 Float |
| #morm.double | 纯标签 | 将该列类型设为 Double |
| #morm.decimal | #morm.decimal(precision="10", scale="2") | 将该列类型设为 Decimal(10,2);若未提供参数,默认 10,2 |
| #morm.boolean | 纯标签 | 将该列类型设为 Boolean |
| #morm.json | 纯标签 | 将该列类型设为 Json |
| #morm.jsonb | 纯标签 | 将该列类型设为 JsonB |
| #morm.uuid | 纯标签 | 将该列类型设为 VarChar(36) |
| #morm.datetime | 纯标签 | 将该列类型设为 DateTime |
| #morm.date | #morm.date(format="yyyy/MM/dd") | 将该列类型设为 Date;可选 format 影响该字段参数的 to_json/字符串输出 |
| #morm.time | #morm.time(format="HH-mm-ss") | 将该列类型设为 Time;可选 format 影响该字段参数的 to_json/字符串输出 |
| #morm.timestamp | #morm.timestamp(format="yyyy-MM-dd HH:mm:ss Z") | 将该列类型设为 Timestamp;可选 format 影响该字段参数的 to_json/字符串输出 |
| #morm.foreign_key | 放在外键字段上一行 | 将该字段解析为外键,约束名:fk_<表名>_<列名>,引用列默认 id;引用表按列名约定或类型名推断 |
| #morm.on_delete_cascade | 与 #morm.foreign_key 同用 | 外键 on_delete 设为 CASCADE |
| #morm.on_update_cascade | 与 #morm.foreign_key 同用 | 外键 on_update 设为 CASCADE |
| #morm.transient | 纯标签 | 字段仅保留在实体中,不会生成数据库列,也不会参与 insert/update/upsert ... from(entity) |
mormgen -i <input_file> -o <output_file># 生成实体的 table() 实现
mormgen example/entities.mbt -o example/entities.g.mbt
# 生成 mapper 实现
mormgen example/mapper.mbt -o example/mapper.g.mbt#morm.mapper(entity="Student")
pub trait StudentMapper {
#morm.query("SELECT * FROM students WHERE id = ?")
pub fn find_student_by_id(Self, id : Int) -> Student?
#morm.query("SELECT count(*) FROM students WHERE age = ?")
pub fn count_students_by_age(Self, age : Int) -> Int?
}///|
let engine = MySQLEngine::open("mysql://...")
///|
let mapper = StudentMapperImpl::new(engine)
///|
let stu = mapper.find_student_by_id(1)
///|
let n = mapper.count_students_by_age(18)
///|
let saved = mapper.save(stu)
///|
let deleted = mapper.delete(stu)let q = @morm.select_from("students")
.where_eq("id", 1)
.where_eq("name", "Alice")
.order_by(Desc("id"))
.offset(5)
.limit(5)
let (sql, params) = @engine.render_default_sql(q.to_statement())SELECT * FROM students WHERE id = ? AND name = ? ORDER BY id DESC LIMIT 5 OFFSET 5let engine = MySQLEngine::open("mysql://root:123456@localhost:3306/test")
@morm.auto_migrate(engine, [Student::table()])
engine.close()# 运行全部测试
moon testpub(open) trait Driver {
open(Self, dsn : String) -> Result[Self, DbError]
close(Self) -> Result[Self, DbError]
ping(Self) -> Result[Unit, DbError]
exec(Self, sql : String, args : FixedArray[Param]) -> Result[Unit, DbError]
query(Self, sql : String, args : FixedArray[Param]) -> Result[FixedArray[Json], DbError]
}pub(all) struct Association {
name : String
kind : AssociationKind
owner_key : String
target_table : String
target_key : String
join_table : String?
join_owner_key : String?
join_target_key : String?
}impl Eq for Associationimpl Show for Associationimpl ToJson for Associationimpl FromJson for Associationpub(all) enum AssociationKind {
BelongsTo
HasOne
HasMany
ManyToMany
}impl Eq for AssociationKindimpl Show for AssociationKindimpl ToJson for AssociationKindimpl FromJson for AssociationKindpub(all) struct Column {
name : String
column_type : ColumnType
size : Int
nullable : Bool
default_value : String?
auto_increment : Bool
primary_key : Bool
unique : Bool
comment : String
charset : String?
collation : String?
engine_options : FixedArray[ColumnEngineOption]
}impl Eq for ColumnDiffimpl Show for ColumnDiffimpl ToJson for ColumnDiffimpl FromJson for ColumnDiffpub(all) struct ColumnEngineOption {
key : String
value : String
}impl Compare for ColumnEngineOptionimpl Eq for ColumnEngineOptionimpl Hash for ColumnEngineOptionimpl Show for ColumnEngineOptionimpl ToJson for ColumnEngineOptionimpl FromJson for ColumnEngineOptionpub(all) enum ColumnType {
TinyInt
SmallInt
MediumInt
Int
BigInt
Float
Double
Decimal(Int, Int)
Char(Int)
VarChar(Int)
Text
MediumText
LongText
Binary(Int)
VarBinary(Int)
Blob
MediumBlob
LongBlob
Date
Time
DateTime
Timestamp
Year
Json
JsonB
Boolean
}impl Compare for ColumnTypeimpl Eq for ColumnTypeimpl Hash for ColumnTypeimpl Show for ColumnTypeimpl ToJson for ColumnTypeimpl FromJson for ColumnTypepub(all) struct DbError {
message : String
}impl Eq for DeleteQueryimpl Show for DeleteQueryimpl ToJson for DeleteQueryimpl FromJson for DeleteQueryimpl QueryBuilder for DeleteQueryfn[V : ToParam] DeleteQuery::where_like(self : DeleteQuery, col : String, pattern : V) -> DeleteQuerypub(all) struct ForeignKey {
name : String
column : String
referenced_table : String
referenced_column : String
on_delete : String
on_update : String
}impl Compare for ForeignKeyimpl Eq for ForeignKeyimpl Hash for ForeignKeyimpl Show for ForeignKeyimpl ToJson for ForeignKeyimpl FromJson for ForeignKeyfn ForeignKey::new(name : String, column : String, referenced_table : String, referenced_column : String) -> ForeignKeypub(all) struct ForeignKeyDiff {
added : FixedArray[ForeignKey]
removed : FixedArray[ForeignKey]
changed : FixedArray[(String, ForeignKey, ForeignKey)]
}impl Eq for ForeignKeyDiffimpl Show for ForeignKeyDiffimpl ToJson for ForeignKeyDiffimpl FromJson for ForeignKeyDiffpub(all) struct Index {
name : String
index_type : IndexType
columns : FixedArray[String]
comment : String
}pub(all) enum IndexType {
Primary
Unique
Index
FullText
Spatial
}impl Eq for InsertQueryimpl Show for InsertQueryimpl ToJson for InsertQueryimpl FromJson for InsertQueryimpl QueryBuilder for InsertQuerypub(all) enum OrderBy {
Asc(String)
Desc(String)
}impl QueryBuilder for Querypub(all) struct Table {
name : String
schema : String?
catalog : String?
columns : FixedArray[Column]
indexes : FixedArray[Index]
foreign_keys : FixedArray[ForeignKey]
temporary : Bool
if_not_exists : Bool
engine : String?
charset : String?
collation : String?
tablespace : String?
comment : String
auto_increment : Int?
engine_options : FixedArray[TableEngineOption]
}pub(all) struct TableEngineOption {
key : String
value : String
}impl Compare for TableEngineOptionimpl Eq for TableEngineOptionimpl Hash for TableEngineOptionimpl Show for TableEngineOptionimpl ToJson for TableEngineOptionimpl FromJson for TableEngineOptionimpl Eq for UpdateQueryimpl Show for UpdateQueryimpl ToJson for UpdateQueryimpl FromJson for UpdateQueryimpl QueryBuilder for UpdateQueryfn[V : ToParam] UpdateQuery::where_like(self : UpdateQuery, col : String, pattern : V) -> UpdateQueryimpl Eq for UpsertQueryimpl Show for UpsertQueryimpl ToJson for UpsertQueryimpl FromJson for UpsertQueryimpl QueryBuilder for UpsertQuerypub enum WhereType {
Eq
Ne
Gt
Lt
Gte
Lte
Like
}fn belongs_to(name : String, owner_key : String, target_table : String, target_key : String) -> Associationfn has_many(name : String, owner_key : String, target_table : String, target_key : String) -> Associationfn has_one(name : String, owner_key : String, target_table : String, target_key : String) -> Associationfn many_to_many(name : String, owner_key : String, target_table : String, target_key : String, join_table : String, join_owner_key : String, join_target_key : String) -> Associationasync fn[E : Engine, O : ToJson, T : FromJson] preload(engine : E, owners : FixedArray[O], association : Association) -> PreloadResult[T]fn register_driver_scheme(scheme : String, driver_name : String) -> Unitfn[V : ToParam] restore_by_id(table : String, id_col : String, id : V, deleted_col? : String) -> UpdateQueryfn[V : ToParam] soft_delete_by_id(table : String, id_col : String, id : V, deleted_col? : String) -> UpdateQuery