Unit test sea-orm-codegen
This commit is contained in:
parent
1e6a778a0f
commit
a94224e0f2
1
.github/workflows/rust.yml
vendored
1
.github/workflows/rust.yml
vendored
@ -31,3 +31,4 @@ jobs:
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
|
@ -38,6 +38,7 @@ futures-util = { version = "^0.3" }
|
||||
rust_decimal = { version = "^1", optional = true }
|
||||
sea-query = { version = "^0.12" }
|
||||
sea-orm-macros = { path = "sea-orm-macros", optional = true }
|
||||
sea-orm-codegen = { path = "sea-orm-codegen", optional = true }
|
||||
serde = { version = "^1.0", features = [ "derive" ] }
|
||||
sqlx = { version = "^0.5", optional = true }
|
||||
strum = { git = "https://github.com/SeaQL/strum.git", branch = "sea-orm", version = "^0.21", features = [ "derive", "sea-orm" ] }
|
||||
@ -51,8 +52,9 @@ sea-orm = { path = ".", features = ["sqlx-sqlite", "sqlx-json", "sqlx-chrono", "
|
||||
|
||||
[features]
|
||||
debug-print = []
|
||||
default = [ "macros", "with-json", "with-chrono", "with-rust_decimal", "mock" ]
|
||||
default = [ "macros", "codegen", "with-json", "with-chrono", "with-rust_decimal", "mock" ]
|
||||
macros = [ "sea-orm-macros" ]
|
||||
codegen = [ "sea-orm-codegen" ]
|
||||
mock = []
|
||||
with-json = [ "serde_json", "sea-query/with-json" ]
|
||||
with-chrono = [ "chrono", "sea-query/with-chrono" ]
|
||||
@ -69,4 +71,4 @@ runtime-async-std-native-tls = [ "sqlx/runtime-async-std-native-tls" ]
|
||||
runtime-tokio-native-tls = [ "sqlx/runtime-tokio-native-tls" ]
|
||||
runtime-actix-rustls = [ "sqlx/runtime-actix-rustls" ]
|
||||
runtime-async-std-rustls = [ "sqlx/runtime-async-std-rustls" ]
|
||||
runtime-tokio-rustls = [ "sqlx/runtime-tokio-rustls" ]
|
||||
runtime-tokio-rustls = [ "sqlx/runtime-tokio-rustls" ]
|
||||
|
@ -23,3 +23,7 @@ syn = { version = "^1", default-features = false, features = [ "derive", "parsin
|
||||
quote = "^1"
|
||||
heck = "^0.3"
|
||||
proc-macro2 = "^1"
|
||||
|
||||
[dev-dependencies]
|
||||
async-std = { version = "^1.9", features = [ "attributes" ] }
|
||||
sea-orm = { path = "../", features = ["mock", "sqlx-json", "sqlx-chrono", "runtime-async-std-native-tls"] }
|
||||
|
@ -22,7 +22,7 @@ impl Column {
|
||||
}
|
||||
|
||||
pub fn get_rs_type(&self) -> TokenStream {
|
||||
let ident = match self.col_type {
|
||||
let ident: TokenStream = match self.col_type {
|
||||
ColumnType::Char(_)
|
||||
| ColumnType::String(_)
|
||||
| ColumnType::Text
|
||||
@ -32,18 +32,18 @@ impl Column {
|
||||
| ColumnType::Date
|
||||
| ColumnType::Json
|
||||
| ColumnType::JsonBinary
|
||||
| ColumnType::Custom(_) => format_ident!("String"),
|
||||
ColumnType::TinyInteger(_) => format_ident!("i8"),
|
||||
ColumnType::SmallInteger(_) => format_ident!("i16"),
|
||||
ColumnType::Integer(_) => format_ident!("i32"),
|
||||
ColumnType::BigInteger(_) => format_ident!("i64"),
|
||||
ColumnType::Float(_) | ColumnType::Decimal(_) | ColumnType::Money(_) => {
|
||||
format_ident!("f32")
|
||||
}
|
||||
ColumnType::Double(_) => format_ident!("f64"),
|
||||
ColumnType::Binary(_) => format_ident!("Vec<u8>"),
|
||||
ColumnType::Boolean => format_ident!("bool"),
|
||||
};
|
||||
| ColumnType::Custom(_) => "String",
|
||||
ColumnType::TinyInteger(_) => "i8",
|
||||
ColumnType::SmallInteger(_) => "i16",
|
||||
ColumnType::Integer(_) => "i32",
|
||||
ColumnType::BigInteger(_) => "i64",
|
||||
ColumnType::Float(_) | ColumnType::Decimal(_) | ColumnType::Money(_) => "f32",
|
||||
ColumnType::Double(_) => "f64",
|
||||
ColumnType::Binary(_) => "Vec<u8>",
|
||||
ColumnType::Boolean => "bool",
|
||||
}
|
||||
.parse()
|
||||
.unwrap();
|
||||
match self.not_null {
|
||||
true => quote! { #ident },
|
||||
false => quote! { Option<#ident> },
|
||||
@ -102,6 +102,12 @@ impl Column {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ColumnDef> for Column {
|
||||
fn from(col_def: ColumnDef) -> Self {
|
||||
(&col_def).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ColumnDef> for Column {
|
||||
fn from(col_def: &ColumnDef) -> Self {
|
||||
let name = col_def.get_column_name();
|
||||
@ -145,3 +151,164 @@ impl From<&ColumnDef> for Column {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Column;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use sea_query::{Alias, ColumnDef, ColumnType, SeaRc};
|
||||
|
||||
fn setup() -> Vec<Column> {
|
||||
macro_rules! make_col {
|
||||
($name:expr, $col_type:expr) => {
|
||||
Column {
|
||||
name: $name.to_owned(),
|
||||
col_type: $col_type,
|
||||
auto_increment: false,
|
||||
not_null: false,
|
||||
unique: false,
|
||||
}
|
||||
};
|
||||
}
|
||||
vec![
|
||||
make_col!("id", ColumnType::String(Some(255))),
|
||||
make_col!(
|
||||
"cake_id",
|
||||
ColumnType::Custom(SeaRc::new(Alias::new("cus_col")))
|
||||
),
|
||||
make_col!("CakeId", ColumnType::TinyInteger(None)),
|
||||
make_col!("CakeId", ColumnType::SmallInteger(None)),
|
||||
make_col!("CakeId", ColumnType::Integer(Some(11))),
|
||||
make_col!("CakeFillingId", ColumnType::BigInteger(None)),
|
||||
make_col!("cake-filling-id", ColumnType::Float(None)),
|
||||
make_col!("CAKE_FILLING_ID", ColumnType::Double(None)),
|
||||
make_col!("CAKE-FILLING-ID", ColumnType::Binary(None)),
|
||||
make_col!("CAKE", ColumnType::Boolean),
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_name_snake_case() {
|
||||
let columns = setup();
|
||||
let snack_cases = vec![
|
||||
"id",
|
||||
"cake_id",
|
||||
"cake_id",
|
||||
"cake_id",
|
||||
"cake_id",
|
||||
"cake_filling_id",
|
||||
"cake_filling_id",
|
||||
"cake_filling_id",
|
||||
"cake_filling_id",
|
||||
"cake",
|
||||
];
|
||||
for (col, snack_case) in columns.into_iter().zip(snack_cases) {
|
||||
assert_eq!(col.get_name_snake_case().to_string(), snack_case);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_name_camel_case() {
|
||||
let columns = setup();
|
||||
let camel_cases = vec![
|
||||
"Id",
|
||||
"CakeId",
|
||||
"CakeId",
|
||||
"CakeId",
|
||||
"CakeId",
|
||||
"CakeFillingId",
|
||||
"CakeFillingId",
|
||||
"CakeFillingId",
|
||||
"CakeFillingId",
|
||||
"Cake",
|
||||
];
|
||||
for (col, camel_case) in columns.into_iter().zip(camel_cases) {
|
||||
assert_eq!(col.get_name_camel_case().to_string(), camel_case);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_rs_type() {
|
||||
let columns = setup();
|
||||
let rs_types = vec![
|
||||
"String", "String", "i8", "i16", "i32", "i64", "f32", "f64", "Vec<u8>", "bool",
|
||||
];
|
||||
for (mut col, rs_type) in columns.into_iter().zip(rs_types) {
|
||||
let rs_type: TokenStream = rs_type.parse().unwrap();
|
||||
|
||||
col.not_null = true;
|
||||
assert_eq!(col.get_rs_type().to_string(), quote!(#rs_type).to_string());
|
||||
|
||||
col.not_null = false;
|
||||
assert_eq!(
|
||||
col.get_rs_type().to_string(),
|
||||
quote!(Option<#rs_type>).to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_def() {
|
||||
let columns = setup();
|
||||
let col_defs = vec![
|
||||
"ColumnType::String(Some(255u32)).def()",
|
||||
"ColumnType::Custom(\"cus_col\".to_owned()).def()",
|
||||
"ColumnType::TinyInteger.def()",
|
||||
"ColumnType::SmallInteger.def()",
|
||||
"ColumnType::Integer.def()",
|
||||
"ColumnType::BigInteger.def()",
|
||||
"ColumnType::Float.def()",
|
||||
"ColumnType::Double.def()",
|
||||
"ColumnType::Binary.def()",
|
||||
"ColumnType::Boolean.def()",
|
||||
];
|
||||
for (mut col, col_def) in columns.into_iter().zip(col_defs) {
|
||||
let mut col_def: TokenStream = col_def.parse().unwrap();
|
||||
|
||||
col.not_null = true;
|
||||
assert_eq!(col.get_def().to_string(), col_def.to_string());
|
||||
|
||||
col.not_null = false;
|
||||
col_def.extend(quote!(.null()));
|
||||
assert_eq!(col.get_def().to_string(), col_def.to_string());
|
||||
|
||||
col.unique = true;
|
||||
col_def.extend(quote!(.unique()));
|
||||
assert_eq!(col.get_def().to_string(), col_def.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_column_def() {
|
||||
let column: Column = ColumnDef::new(Alias::new("id")).string().into();
|
||||
assert_eq!(
|
||||
column.get_def().to_string(),
|
||||
quote! {
|
||||
ColumnType::String(None).def().null()
|
||||
}
|
||||
.to_string()
|
||||
);
|
||||
|
||||
let column: Column = ColumnDef::new(Alias::new("id")).string().not_null().into();
|
||||
assert!(column.not_null);
|
||||
|
||||
let column: Column = ColumnDef::new(Alias::new("id"))
|
||||
.string()
|
||||
.unique_key()
|
||||
.not_null()
|
||||
.into();
|
||||
assert!(column.unique);
|
||||
assert!(column.not_null);
|
||||
|
||||
let column: Column = ColumnDef::new(Alias::new("id"))
|
||||
.string()
|
||||
.auto_increment()
|
||||
.unique_key()
|
||||
.not_null()
|
||||
.into();
|
||||
assert!(column.auto_increment);
|
||||
assert!(column.unique);
|
||||
assert!(column.not_null);
|
||||
}
|
||||
}
|
||||
|
@ -111,15 +111,242 @@ impl Entity {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_relation_rel_find_helpers(&self) -> Vec<Ident> {
|
||||
self.relations
|
||||
.iter()
|
||||
.map(|rel| rel.get_rel_find_helper())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_primary_key_auto_increment(&self) -> Ident {
|
||||
let auto_increment = self.columns.iter().any(|col| col.auto_increment);
|
||||
format_ident!("{}", auto_increment)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Column, Entity, PrimaryKey, Relation, RelationType};
|
||||
use quote::format_ident;
|
||||
use sea_query::ColumnType;
|
||||
|
||||
fn setup() -> Entity {
|
||||
Entity {
|
||||
table_name: "special_cake".to_owned(),
|
||||
columns: vec![
|
||||
Column {
|
||||
name: "id".to_owned(),
|
||||
col_type: ColumnType::String(None),
|
||||
auto_increment: false,
|
||||
not_null: false,
|
||||
unique: false,
|
||||
},
|
||||
Column {
|
||||
name: "name".to_owned(),
|
||||
col_type: ColumnType::String(None),
|
||||
auto_increment: false,
|
||||
not_null: false,
|
||||
unique: false,
|
||||
},
|
||||
],
|
||||
relations: vec![
|
||||
Relation {
|
||||
ref_table: "fruit".to_owned(),
|
||||
columns: vec!["id".to_owned()],
|
||||
ref_columns: vec!["cake_id".to_owned()],
|
||||
rel_type: RelationType::HasOne,
|
||||
},
|
||||
Relation {
|
||||
ref_table: "filling".to_owned(),
|
||||
columns: vec!["id".to_owned()],
|
||||
ref_columns: vec!["cake_id".to_owned()],
|
||||
rel_type: RelationType::HasOne,
|
||||
},
|
||||
],
|
||||
primary_keys: vec![PrimaryKey {
|
||||
name: "id".to_owned(),
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_table_name_snake_case() {
|
||||
let entity = setup();
|
||||
|
||||
assert_eq!(
|
||||
entity.get_table_name_snake_case(),
|
||||
"special_cake".to_owned()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_table_name_camel_case() {
|
||||
let entity = setup();
|
||||
|
||||
assert_eq!(entity.get_table_name_camel_case(), "SpecialCake".to_owned());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_table_name_snake_case_ident() {
|
||||
let entity = setup();
|
||||
|
||||
assert_eq!(
|
||||
entity.get_table_name_snake_case_ident(),
|
||||
format_ident!("{}", "special_cake")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_table_name_camel_case_ident() {
|
||||
let entity = setup();
|
||||
|
||||
assert_eq!(
|
||||
entity.get_table_name_camel_case_ident(),
|
||||
format_ident!("{}", "SpecialCake")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_column_names_snake_case() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity.get_column_names_snake_case().into_iter().enumerate() {
|
||||
assert_eq!(elem, entity.columns[i].get_name_snake_case());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_column_names_camel_case() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity.get_column_names_camel_case().into_iter().enumerate() {
|
||||
assert_eq!(elem, entity.columns[i].get_name_camel_case());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_column_rs_types() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity.get_column_rs_types().into_iter().enumerate() {
|
||||
assert_eq!(
|
||||
elem.to_string(),
|
||||
entity.columns[i].get_rs_type().to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_column_defs() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity.get_column_defs().into_iter().enumerate() {
|
||||
assert_eq!(elem.to_string(), entity.columns[i].get_def().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_primary_key_names_snake_case() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity
|
||||
.get_primary_key_names_snake_case()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
assert_eq!(elem, entity.primary_keys[i].get_name_snake_case());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_primary_key_names_camel_case() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity
|
||||
.get_primary_key_names_camel_case()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
assert_eq!(elem, entity.primary_keys[i].get_name_camel_case());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_relation_ref_tables_snake_case() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity
|
||||
.get_relation_ref_tables_snake_case()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
assert_eq!(elem, entity.relations[i].get_ref_table_snake_case());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_relation_ref_tables_camel_case() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity
|
||||
.get_relation_ref_tables_camel_case()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
assert_eq!(elem, entity.relations[i].get_ref_table_camel_case());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_relation_defs() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity.get_relation_defs().into_iter().enumerate() {
|
||||
assert_eq!(elem.to_string(), entity.relations[i].get_def().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_relation_rel_types() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity.get_relation_rel_types().into_iter().enumerate() {
|
||||
assert_eq!(elem, entity.relations[i].get_rel_type());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_relation_columns_camel_case() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity
|
||||
.get_relation_columns_camel_case()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
assert_eq!(elem, entity.relations[i].get_column_camel_case());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_relation_ref_columns_camel_case() {
|
||||
let entity = setup();
|
||||
|
||||
for (i, elem) in entity
|
||||
.get_relation_ref_columns_camel_case()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
assert_eq!(elem, entity.relations[i].get_ref_column_camel_case());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_primary_key_auto_increment() {
|
||||
let mut entity = setup();
|
||||
|
||||
assert_eq!(
|
||||
entity.get_primary_key_auto_increment(),
|
||||
format_ident!("{}", false)
|
||||
);
|
||||
|
||||
entity.columns[0].auto_increment = true;
|
||||
assert_eq!(
|
||||
entity.get_primary_key_auto_increment(),
|
||||
format_ident!("{}", true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -16,3 +16,28 @@ impl PrimaryKey {
|
||||
format_ident!("{}", self.name.to_camel_case())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::PrimaryKey;
|
||||
|
||||
fn setup() -> PrimaryKey {
|
||||
PrimaryKey {
|
||||
name: "cake_id".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_name_snake_case() {
|
||||
let primary_key = setup();
|
||||
|
||||
assert_eq!(primary_key.get_name_snake_case(), "cake_id".to_owned());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_name_camel_case() {
|
||||
let primary_key = setup();
|
||||
|
||||
assert_eq!(primary_key.get_name_camel_case(), "CakeId".to_owned());
|
||||
}
|
||||
}
|
||||
|
@ -64,10 +64,6 @@ impl Relation {
|
||||
pub fn get_ref_column_camel_case(&self) -> Ident {
|
||||
format_ident!("{}", self.ref_columns[0].to_camel_case())
|
||||
}
|
||||
|
||||
pub fn get_rel_find_helper(&self) -> Ident {
|
||||
format_ident!("find_{}", self.ref_table.to_snake_case())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&TableForeignKey> for Relation {
|
||||
@ -87,3 +83,95 @@ impl From<&TableForeignKey> for Relation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Relation, RelationType};
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
fn setup() -> Vec<Relation> {
|
||||
vec![
|
||||
Relation {
|
||||
ref_table: "fruit".to_owned(),
|
||||
columns: vec!["id".to_owned()],
|
||||
ref_columns: vec!["cake_id".to_owned()],
|
||||
rel_type: RelationType::HasOne,
|
||||
},
|
||||
Relation {
|
||||
ref_table: "filling".to_owned(),
|
||||
columns: vec!["filling_id".to_owned()],
|
||||
ref_columns: vec!["id".to_owned()],
|
||||
rel_type: RelationType::BelongsTo,
|
||||
},
|
||||
Relation {
|
||||
ref_table: "filling".to_owned(),
|
||||
columns: vec!["filling_id".to_owned()],
|
||||
ref_columns: vec!["id".to_owned()],
|
||||
rel_type: RelationType::HasMany,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_ref_table_snake_case() {
|
||||
let relations = setup();
|
||||
let snake_cases = vec!["fruit", "filling", "filling"];
|
||||
for (rel, snake_case) in relations.into_iter().zip(snake_cases) {
|
||||
assert_eq!(rel.get_ref_table_snake_case().to_string(), snake_case);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_ref_table_camel_case() {
|
||||
let relations = setup();
|
||||
let camel_cases = vec!["Fruit", "Filling", "Filling"];
|
||||
for (rel, camel_case) in relations.into_iter().zip(camel_cases) {
|
||||
assert_eq!(rel.get_ref_table_camel_case().to_string(), camel_case);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_def() {
|
||||
let relations = setup();
|
||||
let rel_defs = vec![
|
||||
"Entity::has_one(super::fruit::Entity).into()",
|
||||
"Entity::belongs_to(super::filling::Entity) \
|
||||
.from(Column::FillingId) \
|
||||
.to(super::filling::Column::Id) \
|
||||
.into()",
|
||||
"Entity::has_many(super::filling::Entity).into()",
|
||||
];
|
||||
for (rel, rel_def) in relations.into_iter().zip(rel_defs) {
|
||||
let rel_def: TokenStream = rel_def.parse().unwrap();
|
||||
|
||||
assert_eq!(rel.get_def().to_string(), rel_def.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_rel_type() {
|
||||
let relations = setup();
|
||||
let rel_types = vec!["has_one", "belongs_to", "has_many"];
|
||||
for (rel, rel_type) in relations.into_iter().zip(rel_types) {
|
||||
assert_eq!(rel.get_rel_type(), rel_type);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_column_camel_case() {
|
||||
let relations = setup();
|
||||
let cols = vec!["Id", "FillingId", "FillingId"];
|
||||
for (rel, col) in relations.into_iter().zip(cols) {
|
||||
assert_eq!(rel.get_column_camel_case(), col);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_ref_column_camel_case() {
|
||||
let relations = setup();
|
||||
let ref_cols = vec!["CakeId", "Id", "Id"];
|
||||
for (rel, ref_col) in relations.into_iter().zip(ref_cols) {
|
||||
assert_eq!(rel.get_ref_column_camel_case(), ref_col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ impl EntityTransformer {
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("{:#?}", entities);
|
||||
Ok(EntityWriter { entities })
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ impl EntityWriter {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
#(pub #column_names_snake_case: #column_rs_types),*
|
||||
#(pub #column_names_snake_case: #column_rs_types,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,7 +160,7 @@ impl EntityWriter {
|
||||
quote! {
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
#(#column_names_camel_case),*
|
||||
#(#column_names_camel_case,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,7 +170,7 @@ impl EntityWriter {
|
||||
quote! {
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
#(#primary_key_names_camel_case),*
|
||||
#(#primary_key_names_camel_case,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -191,7 +191,7 @@ impl EntityWriter {
|
||||
quote! {
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
#(#relation_ref_tables_camel_case),*
|
||||
#(#relation_ref_tables_camel_case,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -205,7 +205,7 @@ impl EntityWriter {
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
#(Self::#column_names_camel_case => #column_defs),*
|
||||
#(Self::#column_names_camel_case => #column_defs,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -221,7 +221,7 @@ impl EntityWriter {
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#(Self::#relation_ref_tables_camel_case => #relation_defs),*
|
||||
#(Self::#relation_ref_tables_camel_case => #relation_defs,)*
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
@ -274,3 +274,239 @@ impl EntityWriter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Column, Entity, EntityWriter, PrimaryKey, Relation, RelationType};
|
||||
use proc_macro2::TokenStream;
|
||||
use sea_query::ColumnType;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
|
||||
const ENTITY_FILES: [&'static str; 5] = [
|
||||
include_str!("../../tests/entity/cake.rs"),
|
||||
include_str!("../../tests/entity/cake_filling.rs"),
|
||||
include_str!("../../tests/entity/filling.rs"),
|
||||
include_str!("../../tests/entity/fruit.rs"),
|
||||
include_str!("../../tests/entity/vendor.rs"),
|
||||
];
|
||||
|
||||
fn setup() -> Vec<Entity> {
|
||||
vec![
|
||||
Entity {
|
||||
table_name: "cake".to_owned(),
|
||||
columns: vec![
|
||||
Column {
|
||||
name: "id".to_owned(),
|
||||
col_type: ColumnType::Integer(Some(11)),
|
||||
auto_increment: true,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
Column {
|
||||
name: "name".to_owned(),
|
||||
col_type: ColumnType::String(Some(255)),
|
||||
auto_increment: false,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
],
|
||||
relations: vec![
|
||||
Relation {
|
||||
ref_table: "cake_filling".to_owned(),
|
||||
columns: vec![],
|
||||
ref_columns: vec![],
|
||||
rel_type: RelationType::HasMany,
|
||||
},
|
||||
Relation {
|
||||
ref_table: "fruit".to_owned(),
|
||||
columns: vec![],
|
||||
ref_columns: vec![],
|
||||
rel_type: RelationType::HasMany,
|
||||
},
|
||||
],
|
||||
primary_keys: vec![PrimaryKey {
|
||||
name: "id".to_owned(),
|
||||
}],
|
||||
},
|
||||
Entity {
|
||||
table_name: "cake_filling".to_owned(),
|
||||
columns: vec![
|
||||
Column {
|
||||
name: "cake_id".to_owned(),
|
||||
col_type: ColumnType::Integer(Some(11)),
|
||||
auto_increment: false,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
Column {
|
||||
name: "filling_id".to_owned(),
|
||||
col_type: ColumnType::Integer(Some(11)),
|
||||
auto_increment: false,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
],
|
||||
relations: vec![
|
||||
Relation {
|
||||
ref_table: "cake".to_owned(),
|
||||
columns: vec!["cake_id".to_owned()],
|
||||
ref_columns: vec!["id".to_owned()],
|
||||
rel_type: RelationType::BelongsTo,
|
||||
},
|
||||
Relation {
|
||||
ref_table: "filling".to_owned(),
|
||||
columns: vec!["filling_id".to_owned()],
|
||||
ref_columns: vec!["id".to_owned()],
|
||||
rel_type: RelationType::BelongsTo,
|
||||
},
|
||||
],
|
||||
primary_keys: vec![
|
||||
PrimaryKey {
|
||||
name: "cake_id".to_owned(),
|
||||
},
|
||||
PrimaryKey {
|
||||
name: "filling_id".to_owned(),
|
||||
},
|
||||
],
|
||||
},
|
||||
Entity {
|
||||
table_name: "filling".to_owned(),
|
||||
columns: vec![
|
||||
Column {
|
||||
name: "id".to_owned(),
|
||||
col_type: ColumnType::Integer(Some(11)),
|
||||
auto_increment: true,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
Column {
|
||||
name: "name".to_owned(),
|
||||
col_type: ColumnType::String(Some(255)),
|
||||
auto_increment: false,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
],
|
||||
relations: vec![Relation {
|
||||
ref_table: "cake_filling".to_owned(),
|
||||
columns: vec![],
|
||||
ref_columns: vec![],
|
||||
rel_type: RelationType::HasMany,
|
||||
}],
|
||||
primary_keys: vec![PrimaryKey {
|
||||
name: "id".to_owned(),
|
||||
}],
|
||||
},
|
||||
Entity {
|
||||
table_name: "fruit".to_owned(),
|
||||
columns: vec![
|
||||
Column {
|
||||
name: "id".to_owned(),
|
||||
col_type: ColumnType::Integer(Some(11)),
|
||||
auto_increment: true,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
Column {
|
||||
name: "name".to_owned(),
|
||||
col_type: ColumnType::String(Some(255)),
|
||||
auto_increment: false,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
Column {
|
||||
name: "cake_id".to_owned(),
|
||||
col_type: ColumnType::Integer(Some(11)),
|
||||
auto_increment: false,
|
||||
not_null: false,
|
||||
unique: false,
|
||||
},
|
||||
],
|
||||
relations: vec![
|
||||
Relation {
|
||||
ref_table: "cake".to_owned(),
|
||||
columns: vec!["cake_id".to_owned()],
|
||||
ref_columns: vec!["id".to_owned()],
|
||||
rel_type: RelationType::BelongsTo,
|
||||
},
|
||||
Relation {
|
||||
ref_table: "vendor".to_owned(),
|
||||
columns: vec![],
|
||||
ref_columns: vec![],
|
||||
rel_type: RelationType::HasMany,
|
||||
},
|
||||
],
|
||||
primary_keys: vec![PrimaryKey {
|
||||
name: "id".to_owned(),
|
||||
}],
|
||||
},
|
||||
Entity {
|
||||
table_name: "vendor".to_owned(),
|
||||
columns: vec![
|
||||
Column {
|
||||
name: "id".to_owned(),
|
||||
col_type: ColumnType::Integer(Some(11)),
|
||||
auto_increment: true,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
Column {
|
||||
name: "name".to_owned(),
|
||||
col_type: ColumnType::String(Some(255)),
|
||||
auto_increment: false,
|
||||
not_null: true,
|
||||
unique: false,
|
||||
},
|
||||
Column {
|
||||
name: "fruit_id".to_owned(),
|
||||
col_type: ColumnType::Integer(Some(11)),
|
||||
auto_increment: false,
|
||||
not_null: false,
|
||||
unique: false,
|
||||
},
|
||||
],
|
||||
relations: vec![Relation {
|
||||
ref_table: "fruit".to_owned(),
|
||||
columns: vec!["fruit_id".to_owned()],
|
||||
ref_columns: vec!["id".to_owned()],
|
||||
rel_type: RelationType::BelongsTo,
|
||||
}],
|
||||
primary_keys: vec![PrimaryKey {
|
||||
name: "id".to_owned(),
|
||||
}],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gen_code_blocks() -> io::Result<()> {
|
||||
let entities = setup();
|
||||
|
||||
assert_eq!(entities.len(), ENTITY_FILES.len());
|
||||
|
||||
for (i, entity) in entities.iter().enumerate() {
|
||||
let mut reader = BufReader::new(ENTITY_FILES[i].as_bytes());
|
||||
let mut lines: Vec<String> = Vec::new();
|
||||
|
||||
reader.read_until(b';', &mut Vec::new())?;
|
||||
|
||||
let mut line = String::new();
|
||||
while reader.read_line(&mut line)? > 0 {
|
||||
lines.push(line.to_owned());
|
||||
line.clear();
|
||||
}
|
||||
let content = lines.join("");
|
||||
let expected: TokenStream = content.parse().unwrap();
|
||||
let generated = EntityWriter::gen_code_blocks(entity)
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
.fold(TokenStream::new(), |mut acc, tok| {
|
||||
acc.extend(tok);
|
||||
acc
|
||||
});
|
||||
assert_eq!(expected.to_string(), generated.to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
74
sea-orm-codegen/tests/entity/cake.rs
Normal file
74
sea-orm-codegen/tests/entity/cake.rs
Normal file
@ -0,0 +1,74 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"cake"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Id,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
fn auto_increment() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
CakeFilling,
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(Some(255u32)).def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::CakeFilling => Entity::has_many(super::cake_filling::Entity).into(),
|
||||
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::cake_filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::CakeFilling.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
81
sea-orm-codegen/tests/entity/cake_filling.rs
Normal file
81
sea-orm-codegen/tests/entity/cake_filling.rs
Normal file
@ -0,0 +1,81 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"cake_filling"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
pub cake_id: i32,
|
||||
pub filling_id: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
CakeId,
|
||||
FillingId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
CakeId,
|
||||
FillingId,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
fn auto_increment() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
Cake,
|
||||
Filling,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::CakeId => ColumnType::Integer.def(),
|
||||
Self::FillingId => ColumnType::Integer.def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Cake => Entity::belongs_to(super::cake::Entity)
|
||||
.from(Column::CakeId)
|
||||
.to(super::cake::Column::Id)
|
||||
.into(),
|
||||
Self::Filling => Entity::belongs_to(super::filling::Entity)
|
||||
.from(Column::FillingId)
|
||||
.to(super::filling::Column::Id)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::cake::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Cake.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Filling.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
66
sea-orm-codegen/tests/entity/filling.rs
Normal file
66
sea-orm-codegen/tests/entity/filling.rs
Normal file
@ -0,0 +1,66 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"filling"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Id,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
fn auto_increment() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
CakeFilling,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(Some(255u32)).def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::CakeFilling => Entity::has_many(super::cake_filling::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::cake_filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::CakeFilling.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
80
sea-orm-codegen/tests/entity/fruit.rs
Normal file
80
sea-orm-codegen/tests/entity/fruit.rs
Normal file
@ -0,0 +1,80 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"fruit"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub cake_id: Option<i32> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
CakeId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Id,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
fn auto_increment() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
Cake,
|
||||
Vendor,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(Some(255u32)).def(),
|
||||
Self::CakeId => ColumnType::Integer.def().null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Cake => Entity::belongs_to(super::cake::Entity)
|
||||
.from(Column::CakeId)
|
||||
.to(super::cake::Column::Id)
|
||||
.into(),
|
||||
Self::Vendor => Entity::has_many(super::vendor::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::cake::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Cake.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::vendor::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Vendor.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
7
sea-orm-codegen/tests/entity/mod.rs
Normal file
7
sea-orm-codegen/tests/entity/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
pub mod cake;
|
||||
pub mod cake_filling;
|
||||
pub mod filling;
|
||||
pub mod fruit;
|
||||
pub mod vendor;
|
7
sea-orm-codegen/tests/entity/prelude.rs
Normal file
7
sea-orm-codegen/tests/entity/prelude.rs
Normal file
@ -0,0 +1,7 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
pub use super::cake::Entity as Cake;
|
||||
pub use super::cake_filling::Entity as CakeFilling;
|
||||
pub use super::filling::Entity as Filling;
|
||||
pub use super::fruit::Entity as Fruit;
|
||||
pub use super::vendor::Entity as Vendor;
|
72
sea-orm-codegen/tests/entity/vendor.rs
Normal file
72
sea-orm-codegen/tests/entity/vendor.rs
Normal file
@ -0,0 +1,72 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"vendor"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub fruit_id: Option<i32> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
FruitId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Id,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
fn auto_increment() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(Some(255u32)).def(),
|
||||
Self::FruitId => ColumnType::Integer.def().null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Fruit => Entity::belongs_to(super::fruit::Entity)
|
||||
.from(Column::FruitId)
|
||||
.to(super::fruit::Column::Id)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
127
sea-orm-codegen/tests/mod.rs
Normal file
127
sea-orm-codegen/tests/mod.rs
Normal file
@ -0,0 +1,127 @@
|
||||
mod entity;
|
||||
|
||||
use entity::*;
|
||||
|
||||
use sea_orm::{entity::*, error::*, MockDatabase, MockExecResult, Transaction};
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_insert() -> Result<(), DbErr> {
|
||||
let exec_result = MockExecResult {
|
||||
last_insert_id: 1,
|
||||
rows_affected: 1,
|
||||
};
|
||||
|
||||
let db = MockDatabase::new()
|
||||
.append_exec_results(vec![exec_result.clone()])
|
||||
.into_connection();
|
||||
|
||||
let apple = cake::ActiveModel {
|
||||
name: Set("Apple Pie".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let insert_result = cake::Entity::insert(apple).exec(&db).await?;
|
||||
|
||||
assert_eq!(insert_result.last_insert_id, exec_result.last_insert_id);
|
||||
|
||||
assert_eq!(
|
||||
db.into_transaction_log(),
|
||||
vec![Transaction::from_sql_and_values(
|
||||
r#"INSERT INTO "cake" ("name") VALUES ($1)"#,
|
||||
vec!["Apple Pie".into()]
|
||||
)]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_select() -> Result<(), DbErr> {
|
||||
let query_results = vec![cake_filling::Model {
|
||||
cake_id: 2,
|
||||
filling_id: 3,
|
||||
}];
|
||||
|
||||
let db = MockDatabase::new()
|
||||
.append_query_results(vec![query_results.clone()])
|
||||
.into_connection();
|
||||
|
||||
let selected_models = cake_filling::Entity::find_by_id((2, 3)).all(&db).await?;
|
||||
|
||||
assert_eq!(selected_models, query_results);
|
||||
|
||||
assert_eq!(
|
||||
db.into_transaction_log(),
|
||||
vec![Transaction::from_sql_and_values([
|
||||
r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#,
|
||||
r#"WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
|
||||
].join(" ").as_str(),
|
||||
vec![2i32.into(), 3i32.into()]
|
||||
)]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_update() -> Result<(), DbErr> {
|
||||
let exec_result = MockExecResult {
|
||||
last_insert_id: 1,
|
||||
rows_affected: 1,
|
||||
};
|
||||
|
||||
let db = MockDatabase::new()
|
||||
.append_exec_results(vec![exec_result.clone()])
|
||||
.into_connection();
|
||||
|
||||
let orange = fruit::ActiveModel {
|
||||
id: Set(1),
|
||||
name: Set("Orange".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let updated_model = fruit::Entity::update(orange.clone()).exec(&db).await?;
|
||||
|
||||
assert_eq!(updated_model, orange);
|
||||
|
||||
assert_eq!(
|
||||
db.into_transaction_log(),
|
||||
vec![Transaction::from_sql_and_values(
|
||||
r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2"#,
|
||||
vec!["Orange".into(), 1i32.into()]
|
||||
)]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_delete() -> Result<(), DbErr> {
|
||||
let exec_result = MockExecResult {
|
||||
last_insert_id: 1,
|
||||
rows_affected: 1,
|
||||
};
|
||||
|
||||
let db = MockDatabase::new()
|
||||
.append_exec_results(vec![exec_result.clone()])
|
||||
.into_connection();
|
||||
|
||||
let orange = fruit::ActiveModel {
|
||||
id: Set(3),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let delete_result = fruit::Entity::delete(orange).exec(&db).await?;
|
||||
|
||||
assert_eq!(delete_result.rows_affected, exec_result.rows_affected);
|
||||
|
||||
assert_eq!(
|
||||
db.into_transaction_log(),
|
||||
vec![Transaction::from_sql_and_values(
|
||||
r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
|
||||
vec![3i32.into()]
|
||||
)]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user