diff --git a/examples/sqlx-mysql/Readme.md b/examples/sqlx-mysql/Readme.md new file mode 100644 index 00000000..78260e69 --- /dev/null +++ b/examples/sqlx-mysql/Readme.md @@ -0,0 +1,15 @@ +# SeaORM SQLx MySql example + +Running: +```sh +cargo run +``` + +Example output: +```sh +Database { connection: SqlxMySqlPoolConnection } + +CakeModel { id: 1, name: "New York Cheese" } + +CakeModel { id: 2, name: "Chocolate Fudge" } +``` \ No newline at end of file diff --git a/examples/sqlx-mysql/src/main.rs b/examples/sqlx-mysql/src/main.rs index 4bd819e8..9be91c41 100644 --- a/examples/sqlx-mysql/src/main.rs +++ b/examples/sqlx-mysql/src/main.rs @@ -7,12 +7,12 @@ async fn main() { .await .unwrap(); println!("{:?}", db); - println!(""); + println!(); - let rows = cake::Cake::find().all(&db).await.unwrap(); + let cakes = cake::Cake::find().all(&db).await.unwrap(); - for row in rows.iter() { - println!("{:?}", row); - println!(""); + for cc in cakes.iter() { + println!("{:?}", cc); + println!(); } } diff --git a/src/connector/mod.rs b/src/connector/mod.rs index 55c5b138..e3912775 100644 --- a/src/connector/mod.rs +++ b/src/connector/mod.rs @@ -2,7 +2,7 @@ mod select; pub use select::*; -use crate::{DatabaseConnection, QueryResult}; +use crate::{DatabaseConnection, QueryResult, TypeErr}; use async_trait::async_trait; use sea_query::{inject_parameters, MySqlQueryBuilder, Values}; use std::{error::Error, fmt}; @@ -64,6 +64,12 @@ impl fmt::Display for QueryErr { } } +impl From for QueryErr { + fn from(_: TypeErr) -> QueryErr { + QueryErr + } +} + // ConnectionErr // impl Error for ConnectionErr {} diff --git a/src/connector/select.rs b/src/connector/select.rs index e3617da2..79ec0da5 100644 --- a/src/connector/select.rs +++ b/src/connector/select.rs @@ -1,16 +1,22 @@ -use crate::{Connection, Database, Entity, QueryErr, QueryResult, Select}; +use crate::{Connection, Database, Entity, Model, QueryErr, Select}; impl Select<'_, E> where E: Entity, { - pub async fn one(self, db: &Database) -> Result { + pub async fn one(self, db: &Database) -> Result { let builder = db.get_query_builder_backend(); - db.get_connection().query_one(self.build(builder)).await + let row = db.get_connection().query_one(self.build(builder)).await?; + Ok(::Model::from_query_result(row)?) } - pub async fn all(self, db: &Database) -> Result, QueryErr> { + pub async fn all(self, db: &Database) -> Result, QueryErr> { let builder = db.get_query_builder_backend(); - db.get_connection().query_all(self.build(builder)).await + let rows = db.get_connection().query_all(self.build(builder)).await?; + let mut models = Vec::new(); + for row in rows.into_iter() { + models.push(::Model::from_query_result(row)?); + } + Ok(models) } } diff --git a/src/entity/base.rs b/src/entity/base.rs index a3162103..b116dd0a 100644 --- a/src/entity/base.rs +++ b/src/entity/base.rs @@ -1,11 +1,11 @@ -use super::{Column, Identity, Relation}; +use super::{Column, Identity, Model, Relation}; use crate::Select; use sea_query::Iden; use std::fmt::Debug; use strum::IntoEnumIterator; pub trait Entity: Iden + Default + Debug { - type Model; + type Model: Model; type Column: Column + IntoEnumIterator; diff --git a/src/entity/mod.rs b/src/entity/mod.rs index 21477aa2..546663c1 100644 --- a/src/entity/mod.rs +++ b/src/entity/mod.rs @@ -1,9 +1,11 @@ mod base; mod column; mod identity; +mod model; mod relation; pub use base::*; pub use column::*; pub use identity::*; +pub use model::*; pub use relation::*; diff --git a/src/entity/model.rs b/src/entity/model.rs new file mode 100644 index 00000000..fa29df96 --- /dev/null +++ b/src/entity/model.rs @@ -0,0 +1,7 @@ +use crate::{QueryResult, TypeErr}; + +pub trait Model { + fn from_query_result(row: QueryResult) -> Result + where + Self: std::marker::Sized; +} diff --git a/src/query/result.rs b/src/query/result.rs index 2b6932b2..3225612f 100644 --- a/src/query/result.rs +++ b/src/query/result.rs @@ -1,4 +1,5 @@ use sqlx::mysql::MySqlRow; +use std::{error::Error, fmt}; #[derive(Debug)] pub struct QueryResult { @@ -9,3 +10,48 @@ pub struct QueryResult { pub(crate) enum QueryResultRow { SqlxMySql(MySqlRow), } + +#[derive(Debug)] +pub struct TypeErr; + +// QueryResult // + +impl QueryResult { + pub fn try_get_i32(&self, col: &str) -> Result { + match &self.row { + QueryResultRow::SqlxMySql(row) => { + use sqlx::Row; + + if let Ok(val) = row.try_get(col) { + Ok(val) + } else { + Err(TypeErr) + } + } + } + } + + pub fn try_get_string(&self, col: &str) -> Result { + match &self.row { + QueryResultRow::SqlxMySql(row) => { + use sqlx::Row; + + if let Ok(val) = row.try_get(col) { + Ok(val) + } else { + Err(TypeErr) + } + } + } + } +} + +// TypeErr // + +impl Error for TypeErr {} + +impl fmt::Display for TypeErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} diff --git a/src/tests_cfg/cake.rs b/src/tests_cfg/cake.rs index d6650a7d..f8243e85 100644 --- a/src/tests_cfg/cake.rs +++ b/src/tests_cfg/cake.rs @@ -1,4 +1,7 @@ -use crate::{Column, ColumnType, Entity, Identity, IntoIdentity, Relation, RelationDef}; +use crate::{ + Column, ColumnType, Entity, Identity, IntoIdentity, Model, QueryResult, Relation, RelationDef, + TypeErr, +}; use sea_query::Iden; use strum::EnumIter; @@ -7,8 +10,8 @@ pub struct Cake; #[derive(Debug, Default, PartialEq)] pub struct CakeModel { - pub id: Option, - pub name: Option, + pub id: i32, + pub name: String, } #[derive(Iden, EnumIter)] @@ -46,3 +49,12 @@ impl Relation for CakeRelation { panic!() } } + +impl Model for CakeModel { + fn from_query_result(row: QueryResult) -> Result { + Ok(Self { + id: row.try_get_i32("id")?, + name: row.try_get_string("name")?, + }) + } +}