Merge remote-tracking branch 'origin/master' into returning
This commit is contained in:
commit
fd50ffd5ea
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
@ -316,7 +316,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
path: [86, 249, 262]
|
||||
path: [86, 249, 262, 319]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
@ -63,7 +63,7 @@ default = [
|
||||
]
|
||||
macros = ["sea-orm-macros"]
|
||||
mock = []
|
||||
with-json = ["serde_json", "sea-query/with-json"]
|
||||
with-json = ["serde_json", "sea-query/with-json", "chrono/serde"]
|
||||
with-chrono = ["chrono", "sea-query/with-chrono"]
|
||||
with-rust_decimal = ["rust_decimal", "sea-query/with-rust_decimal"]
|
||||
with-uuid = ["uuid", "sea-query/with-uuid"]
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use sea_orm::{entity::*, error::*, query::*, DbConn};
|
||||
use sea_orm::{entity::*, error::*, DbConn};
|
||||
|
||||
pub async fn all_about_operation(db: &DbConn) -> Result<(), DbErr> {
|
||||
insert_and_update(db).await?;
|
||||
|
18
issues/319/Cargo.toml
Normal file
18
issues/319/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[workspace]
|
||||
# A separate workspace
|
||||
|
||||
[package]
|
||||
name = "sea-orm-issues-319"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
async-std = { version = "^1", features = ["attributes"] }
|
||||
serde = { version = "^1", features = ["derive"] }
|
||||
sea-orm = { path = "../../", features = [
|
||||
"sqlx-mysql",
|
||||
"runtime-async-std-native-tls",
|
||||
"with-json",
|
||||
"macros",
|
||||
], default-features = false }
|
14
issues/319/src/main.rs
Normal file
14
issues/319/src/main.rs
Normal file
@ -0,0 +1,14 @@
|
||||
mod material;
|
||||
use sea_orm::*;
|
||||
|
||||
#[async_std::main]
|
||||
pub async fn main() {
|
||||
let db = Database::connect("mysql://sea:sea@localhost/bakery")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
async_std::task::spawn(async move {
|
||||
material::Entity::find().one(&db).await.unwrap();
|
||||
})
|
||||
.await;
|
||||
}
|
20
issues/319/src/material.rs
Normal file
20
issues/319/src/material.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "materials")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub created_at: DateTimeWithTimeZone,
|
||||
pub updated_at: DateTimeWithTimeZone,
|
||||
pub name: String,
|
||||
#[sea_orm(column_type = "Text", nullable)]
|
||||
pub description: Option<String>,
|
||||
pub tag_ids: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
@ -4,7 +4,7 @@ use crate::{
|
||||
use futures::Stream;
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
/// Creates constraints for any structure that wants to create a database connection
|
||||
/// Creates constraints for any structure that can create a database connection
|
||||
/// and execute SQL statements
|
||||
#[async_trait::async_trait]
|
||||
pub trait ConnectionTrait<'a>: Sync {
|
||||
|
@ -8,9 +8,10 @@ use std::fmt;
|
||||
pub struct Statement {
|
||||
/// The SQL query
|
||||
pub sql: String,
|
||||
/// The values for the SQL statement
|
||||
/// The values for the SQL statement's parameters
|
||||
pub values: Option<Values>,
|
||||
/// The database backend to use
|
||||
/// The database backend this statement is constructed for.
|
||||
/// The SQL dialect and values should be valid for the DbBackend.
|
||||
pub db_backend: DbBackend,
|
||||
}
|
||||
|
||||
@ -31,7 +32,7 @@ impl Statement {
|
||||
}
|
||||
|
||||
/// Create a SQL statement from a [crate::DatabaseBackend], a
|
||||
/// raw SQL statement and defined values
|
||||
/// raw SQL statement and param values
|
||||
pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = Value>,
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::{pin::Pin, task::Poll};
|
||||
|
||||
#[cfg(feature = "mock")]
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::{ops::DerefMut, pin::Pin, task::Poll};
|
||||
|
||||
use futures::Stream;
|
||||
@ -11,9 +13,9 @@ use futures::lock::MutexGuard;
|
||||
|
||||
use crate::{DbErr, InnerConnection, QueryResult, Statement};
|
||||
|
||||
#[ouroboros::self_referencing]
|
||||
/// `TransactionStream` cannot be used in a `transaction` closure as it does not impl `Send`.
|
||||
/// It seems to be a Rust limitation right now, and solution to work around this deemed to be extremely hard.
|
||||
#[ouroboros::self_referencing]
|
||||
pub struct TransactionStream<'a> {
|
||||
stmt: Statement,
|
||||
conn: MutexGuard<'a, InnerConnection>,
|
||||
|
@ -23,7 +23,7 @@ pub struct MockDatabaseConnection {
|
||||
mocker: Mutex<Box<dyn MockDatabaseTrait>>,
|
||||
}
|
||||
|
||||
/// A set of constraints for any type wanting to perform operations on the [MockDatabase]
|
||||
/// A Trait for any type wanting to perform operations on the [MockDatabase]
|
||||
pub trait MockDatabaseTrait: Send + Debug {
|
||||
/// Execute a statement in the [MockDatabase]
|
||||
fn execute(&mut self, counter: usize, stmt: Statement) -> Result<ExecResult, DbErr>;
|
||||
|
@ -9,3 +9,8 @@ pub fn sqlx_error_to_exec_err(err: sqlx::Error) -> DbErr {
|
||||
pub fn sqlx_error_to_query_err(err: sqlx::Error) -> DbErr {
|
||||
DbErr::Query(err.to_string())
|
||||
}
|
||||
|
||||
/// Converts an [sqlx::error] connection error to a [DbErr]
|
||||
pub fn sqlx_error_to_conn_err(err: sqlx::Error) -> DbErr {
|
||||
DbErr::Conn(err.to_string())
|
||||
}
|
||||
|
@ -41,12 +41,11 @@ impl SqlxMySqlConnector {
|
||||
use sqlx::ConnectOptions;
|
||||
opt.disable_statement_logging();
|
||||
}
|
||||
if let Ok(pool) = options.pool_options().connect_with(opt).await {
|
||||
Ok(DatabaseConnection::SqlxMySqlPoolConnection(
|
||||
match options.pool_options().connect_with(opt).await {
|
||||
Ok(pool) => Ok(DatabaseConnection::SqlxMySqlPoolConnection(
|
||||
SqlxMySqlPoolConnection { pool },
|
||||
))
|
||||
} else {
|
||||
Err(DbErr::Conn("Failed to connect.".to_owned()))
|
||||
)),
|
||||
Err(e) => Err(sqlx_error_to_conn_err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,12 +41,11 @@ impl SqlxPostgresConnector {
|
||||
use sqlx::ConnectOptions;
|
||||
opt.disable_statement_logging();
|
||||
}
|
||||
if let Ok(pool) = options.pool_options().connect_with(opt).await {
|
||||
Ok(DatabaseConnection::SqlxPostgresPoolConnection(
|
||||
match options.pool_options().connect_with(opt).await {
|
||||
Ok(pool) => Ok(DatabaseConnection::SqlxPostgresPoolConnection(
|
||||
SqlxPostgresPoolConnection { pool },
|
||||
))
|
||||
} else {
|
||||
Err(DbErr::Conn("Failed to connect.".to_owned()))
|
||||
)),
|
||||
Err(e) => Err(sqlx_error_to_conn_err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,12 +45,11 @@ impl SqlxSqliteConnector {
|
||||
if options.get_max_connections().is_none() {
|
||||
options.max_connections(1);
|
||||
}
|
||||
if let Ok(pool) = options.pool_options().connect_with(opt).await {
|
||||
Ok(DatabaseConnection::SqlxSqlitePoolConnection(
|
||||
match options.pool_options().connect_with(opt).await {
|
||||
Ok(pool) => Ok(DatabaseConnection::SqlxSqlitePoolConnection(
|
||||
SqlxSqlitePoolConnection { pool },
|
||||
))
|
||||
} else {
|
||||
Err(DbErr::Conn("Failed to connect.".to_owned()))
|
||||
)),
|
||||
Err(e) => Err(sqlx_error_to_conn_err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,12 +76,12 @@ where
|
||||
ActiveValue::unchanged(value)
|
||||
}
|
||||
|
||||
/// Enforces a set of constraints on any type performing an Create, Update or Delete operation.
|
||||
/// A Trait for ActiveModel to perform Create, Update or Delete operation.
|
||||
/// The type must also implement the [EntityTrait].
|
||||
/// See module level docs [crate::entity] for a full example
|
||||
#[async_trait]
|
||||
pub trait ActiveModelTrait: Clone + Debug {
|
||||
/// Enforce the type to the constraints of the [EntityTrait]
|
||||
/// The Entity this ActiveModel belongs to
|
||||
type Entity: EntityTrait;
|
||||
|
||||
/// Get a mutable [ActiveValue] from an ActiveModel
|
||||
@ -204,9 +204,7 @@ pub trait ActiveModelTrait: Clone + Debug {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enforce a set of constraints to a override the ActiveModel behavior
|
||||
/// Behaviors for users to override.
|
||||
/// The type must also implement the [ActiveModelTrait]
|
||||
/// A Trait for overriding the ActiveModel behavior
|
||||
///
|
||||
/// ### Example
|
||||
/// ```ignore
|
||||
@ -261,7 +259,7 @@ pub trait ActiveModelBehavior: ActiveModelTrait {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enforce constraints for conversion to an ActiveModel
|
||||
/// A Trait for any type that can be converted into an ActiveModel
|
||||
pub trait IntoActiveModel<A>
|
||||
where
|
||||
A: ActiveModelTrait,
|
||||
|
@ -13,7 +13,7 @@ pub trait IdenStatic: Iden + Copy + Debug + 'static {
|
||||
fn as_str(&self) -> &str;
|
||||
}
|
||||
|
||||
/// Enforces the naming of an entity to a set of constraints
|
||||
/// A Trait for mapping an Entity to a database table
|
||||
pub trait EntityName: IdenStatic + Default {
|
||||
/// Method to get the name for the schema, defaults to [Option::None] if not set
|
||||
fn schema_name(&self) -> Option<&str> {
|
||||
|
@ -6,7 +6,7 @@ use sea_query::{Alias, IntoIden, JoinType, SeaRc};
|
||||
/// Same as [RelationDef]
|
||||
pub type LinkDef = RelationDef;
|
||||
|
||||
/// A set of constraints for links between Entities
|
||||
/// A Trait for links between Entities
|
||||
pub trait Linked {
|
||||
#[allow(missing_docs)]
|
||||
type FromEntity: EntityTrait;
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
pub use sea_query::Value;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// A set of constraints for a Model
|
||||
/// A Trait for a Model
|
||||
pub trait ModelTrait: Clone + Send + Debug {
|
||||
#[allow(missing_docs)]
|
||||
type Entity: EntityTrait;
|
||||
@ -35,7 +35,7 @@ pub trait ModelTrait: Clone + Send + Debug {
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of constraints for implementing a [QueryResult]
|
||||
/// A Trait for implementing a [QueryResult]
|
||||
pub trait FromQueryResult: Sized {
|
||||
/// Instantiate a Model from a [QueryResult]
|
||||
fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr>;
|
||||
|
@ -1,8 +1,8 @@
|
||||
pub use crate::{
|
||||
error::*, ActiveEnum, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait,
|
||||
ColumnType, DatabaseConnection, DbConn, EntityName, EntityTrait, EnumIter, ForeignKeyAction,
|
||||
Iden, IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter,
|
||||
QueryResult, Related, RelationDef, RelationTrait, Select, Value,
|
||||
Iden, IdenStatic, Linked, ModelTrait, PaginatorTrait, PrimaryKeyToColumn, PrimaryKeyTrait,
|
||||
QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value,
|
||||
};
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
|
@ -4,7 +4,7 @@ use sea_query::{FromValueTuple, IntoValueTuple};
|
||||
use std::fmt::Debug;
|
||||
|
||||
//LINT: composite primary key cannot auto increment
|
||||
/// A set of constraints to be used to define a Primary Key.
|
||||
/// A Trait for to be used to define a Primary Key.
|
||||
///
|
||||
/// A primary key can be derived manually
|
||||
///
|
||||
|
@ -1,4 +1,7 @@
|
||||
use crate::{error::*, ConnectionTrait, DbBackend, SelectorTrait};
|
||||
use crate::{
|
||||
error::*, ConnectionTrait, DbBackend, EntityTrait, FromQueryResult, Select, SelectModel,
|
||||
SelectTwo, SelectTwoModel, Selector, SelectorTrait,
|
||||
};
|
||||
use async_stream::stream;
|
||||
use futures::Stream;
|
||||
use sea_query::{Alias, Expr, SelectStatement};
|
||||
@ -155,9 +158,77 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
/// A Trait for any type that can paginate results
|
||||
pub trait PaginatorTrait<'db, C>
|
||||
where
|
||||
C: ConnectionTrait<'db>,
|
||||
{
|
||||
/// Select operation
|
||||
type Selector: SelectorTrait + Send + Sync + 'db;
|
||||
|
||||
/// Paginate the result of a select operation.
|
||||
fn paginate(self, db: &'db C, page_size: usize) -> Paginator<'db, C, Self::Selector>;
|
||||
|
||||
/// Perform a count on the paginated results
|
||||
async fn count(self, db: &'db C) -> Result<usize, DbErr>
|
||||
where
|
||||
Self: Send + Sized,
|
||||
{
|
||||
self.paginate(db, 1).num_items().await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db, C, S> PaginatorTrait<'db, C> for Selector<S>
|
||||
where
|
||||
C: ConnectionTrait<'db>,
|
||||
S: SelectorTrait + Send + Sync + 'db,
|
||||
{
|
||||
type Selector = S;
|
||||
|
||||
fn paginate(self, db: &'db C, page_size: usize) -> Paginator<'db, C, S> {
|
||||
Paginator {
|
||||
query: self.query,
|
||||
page: 0,
|
||||
page_size,
|
||||
db,
|
||||
selector: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db, C, M, E> PaginatorTrait<'db, C> for Select<E>
|
||||
where
|
||||
C: ConnectionTrait<'db>,
|
||||
E: EntityTrait<Model = M>,
|
||||
M: FromQueryResult + Sized + Send + Sync + 'db,
|
||||
{
|
||||
type Selector = SelectModel<M>;
|
||||
|
||||
fn paginate(self, db: &'db C, page_size: usize) -> Paginator<'db, C, Self::Selector> {
|
||||
self.into_model().paginate(db, page_size)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db, C, M, N, E, F> PaginatorTrait<'db, C> for SelectTwo<E, F>
|
||||
where
|
||||
C: ConnectionTrait<'db>,
|
||||
E: EntityTrait<Model = M>,
|
||||
F: EntityTrait<Model = N>,
|
||||
M: FromQueryResult + Sized + Send + Sync + 'db,
|
||||
N: FromQueryResult + Sized + Send + Sync + 'db,
|
||||
{
|
||||
type Selector = SelectTwoModel<M, N>;
|
||||
|
||||
fn paginate(self, db: &'db C, page_size: usize) -> Paginator<'db, C, Self::Selector> {
|
||||
self.into_model().paginate(db, page_size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "mock")]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::entity::prelude::*;
|
||||
use crate::{tests_cfg::*, ConnectionTrait};
|
||||
use crate::{DatabaseConnection, DbBackend, MockDatabase, Transaction};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
error::*, ConnectionTrait, EntityTrait, FromQueryResult, IdenStatic, Iterable, ModelTrait,
|
||||
Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo, SelectTwoMany,
|
||||
Statement, TryGetableMany,
|
||||
PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo, SelectTwoMany, Statement,
|
||||
TryGetableMany,
|
||||
};
|
||||
use futures::{Stream, TryStreamExt};
|
||||
use sea_query::SelectStatement;
|
||||
@ -11,13 +11,13 @@ use std::pin::Pin;
|
||||
#[cfg(feature = "with-json")]
|
||||
use crate::JsonValue;
|
||||
|
||||
/// Defines a type to do `SELECT` operations though a [SelectStatement] on a Model
|
||||
/// Defines a type to do `SELECT` operations through a [SelectStatement] on a Model
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Selector<S>
|
||||
where
|
||||
S: SelectorTrait,
|
||||
{
|
||||
query: SelectStatement,
|
||||
pub(crate) query: SelectStatement,
|
||||
selector: S,
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ where
|
||||
selector: S,
|
||||
}
|
||||
|
||||
/// Used to enforce constraints on any type that wants to perform SELECT queries
|
||||
/// A Trait for any type that can perform SELECT queries
|
||||
pub trait SelectorTrait {
|
||||
#[allow(missing_docs)]
|
||||
type Item: Sized;
|
||||
@ -250,7 +250,7 @@ where
|
||||
Selector::<SelectGetableValue<T, C>>::with_columns(self.query)
|
||||
}
|
||||
|
||||
/// Get one Model from a SELECT operation
|
||||
/// Get one Model from the SELECT query
|
||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
@ -258,7 +258,7 @@ where
|
||||
self.into_model().one(db).await
|
||||
}
|
||||
|
||||
/// Get all the Models from a SELECT operation
|
||||
/// Get all Models from the SELECT query
|
||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
@ -276,26 +276,6 @@ where
|
||||
{
|
||||
self.into_model().stream(db).await
|
||||
}
|
||||
|
||||
/// Paginate the results of a SELECT operation on a Model
|
||||
pub fn paginate<'a, C>(
|
||||
self,
|
||||
db: &'a C,
|
||||
page_size: usize,
|
||||
) -> Paginator<'a, C, SelectModel<E::Model>>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
{
|
||||
self.into_model().paginate(db, page_size)
|
||||
}
|
||||
|
||||
/// Perform a `COUNT` operation on a items on a Model using pagination
|
||||
pub async fn count<'a, C>(self, db: &'a C) -> Result<usize, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
{
|
||||
self.paginate(db, 1).num_items().await
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, F> SelectTwo<E, F>
|
||||
@ -324,7 +304,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Get one Model from a Select operation
|
||||
/// Get one Model from the Select query
|
||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
@ -332,7 +312,7 @@ where
|
||||
self.into_model().one(db).await
|
||||
}
|
||||
|
||||
/// Get all Models from a Select operation
|
||||
/// Get all Models from the Select query
|
||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
@ -350,26 +330,6 @@ where
|
||||
{
|
||||
self.into_model().stream(db).await
|
||||
}
|
||||
|
||||
/// Paginate the results of a select operation on two models
|
||||
pub fn paginate<'a, C>(
|
||||
self,
|
||||
db: &'a C,
|
||||
page_size: usize,
|
||||
) -> Paginator<'a, C, SelectTwoModel<E::Model, F::Model>>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
{
|
||||
self.into_model().paginate(db, page_size)
|
||||
}
|
||||
|
||||
/// Perform a count on the paginated results
|
||||
pub async fn count<'a, C>(self, db: &'a C) -> Result<usize, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
{
|
||||
self.paginate(db, 1).num_items().await
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, F> SelectTwoMany<E, F>
|
||||
@ -417,7 +377,7 @@ where
|
||||
self.into_model().stream(db).await
|
||||
}
|
||||
|
||||
/// Get all the Models from the select operation
|
||||
/// Get all Models from the select operation
|
||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
@ -456,35 +416,36 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a Model from a Select operation
|
||||
fn into_selector_raw<'a, C>(self, db: &C) -> SelectorRaw<S>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
{
|
||||
let builder = db.get_database_backend();
|
||||
let stmt = builder.build(&self.query);
|
||||
SelectorRaw {
|
||||
stmt,
|
||||
selector: self.selector,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an item from the Select query
|
||||
pub async fn one<'a, C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
{
|
||||
let builder = db.get_database_backend();
|
||||
self.query.limit(1);
|
||||
let row = db.query_one(builder.build(&self.query)).await?;
|
||||
match row {
|
||||
Some(row) => Ok(Some(S::from_raw_query_result(row)?)),
|
||||
None => Ok(None),
|
||||
}
|
||||
self.into_selector_raw(db).one(db).await
|
||||
}
|
||||
|
||||
/// Get all results from a Select operation
|
||||
/// Get all items from the Select query
|
||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
{
|
||||
let builder = db.get_database_backend();
|
||||
let rows = db.query_all(builder.build(&self.query)).await?;
|
||||
let mut models = Vec::new();
|
||||
for row in rows.into_iter() {
|
||||
models.push(S::from_raw_query_result(row)?);
|
||||
}
|
||||
Ok(models)
|
||||
self.into_selector_raw(db).all(db).await
|
||||
}
|
||||
|
||||
/// Stream the results of the operation
|
||||
/// Stream the results of the Select operation
|
||||
pub async fn stream<'a: 'b, 'b, C>(
|
||||
self,
|
||||
db: &'a C,
|
||||
@ -493,25 +454,7 @@ where
|
||||
C: ConnectionTrait<'a>,
|
||||
S: 'b,
|
||||
{
|
||||
let builder = db.get_database_backend();
|
||||
let stream = db.stream(builder.build(&self.query)).await?;
|
||||
Ok(Box::pin(stream.and_then(|row| {
|
||||
futures::future::ready(S::from_raw_query_result(row))
|
||||
})))
|
||||
}
|
||||
|
||||
/// Paginate the result of a select operation on a Model
|
||||
pub fn paginate<'a, C>(self, db: &'a C, page_size: usize) -> Paginator<'a, C, S>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
{
|
||||
Paginator {
|
||||
query: self.query,
|
||||
page: 0,
|
||||
page_size,
|
||||
db,
|
||||
selector: PhantomData,
|
||||
}
|
||||
self.into_selector_raw(db).stream(db).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -519,8 +462,7 @@ impl<S> SelectorRaw<S>
|
||||
where
|
||||
S: SelectorTrait,
|
||||
{
|
||||
/// Create `SelectorRaw` from Statment. Executing this `SelectorRaw` will
|
||||
/// return a type `M` which implement `FromQueryResult`.
|
||||
/// Select a custom Model from a raw SQL [Statement].
|
||||
pub fn from_statement<M>(stmt: Statement) -> SelectorRaw<SelectModel<M>>
|
||||
where
|
||||
M: FromQueryResult,
|
||||
@ -683,6 +625,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an item from the Select query
|
||||
/// ```
|
||||
/// # #[cfg(feature = "mock")]
|
||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
||||
@ -725,6 +668,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all items from the Select query
|
||||
/// ```
|
||||
/// # #[cfg(feature = "mock")]
|
||||
/// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
|
||||
@ -767,6 +711,21 @@ where
|
||||
}
|
||||
Ok(models)
|
||||
}
|
||||
|
||||
/// Stream the results of the Select operation
|
||||
pub async fn stream<'a: 'b, 'b, C>(
|
||||
self,
|
||||
db: &'a C,
|
||||
) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b>>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait<'a>,
|
||||
S: 'b,
|
||||
{
|
||||
let stream = db.stream(self.stmt).await?;
|
||||
Ok(Box::pin(stream.and_then(|row| {
|
||||
futures::future::ready(S::from_raw_query_result(row))
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
fn consolidate_query_result<L, R>(
|
||||
|
@ -22,4 +22,6 @@ pub use traits::*;
|
||||
pub use update::*;
|
||||
pub use util::*;
|
||||
|
||||
pub use crate::{ConnectionTrait, InsertResult, Statement, UpdateResult, Value, Values};
|
||||
pub use crate::{
|
||||
ConnectionTrait, InsertResult, PaginatorTrait, Statement, UpdateResult, Value, Values,
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{DbBackend, Statement};
|
||||
use sea_query::QueryStatementBuilder;
|
||||
|
||||
/// Enforces a set of constraints to any type performing queries on a Model or ActiveModel
|
||||
/// A Trait for any type performing queries on a Model or ActiveModel
|
||||
pub trait QueryTrait {
|
||||
/// Constrain the QueryStatement to [QueryStatementBuilder] trait
|
||||
type QueryStatement: QueryStatementBuilder;
|
||||
|
@ -9,27 +9,27 @@ use sea_query::{
|
||||
|
||||
impl Schema {
|
||||
/// Creates Postgres enums from an Entity. See [TypeCreateStatement] for more details
|
||||
pub fn create_enum_from_entity<E>(entity: E, db_backend: DbBackend) -> Vec<TypeCreateStatement>
|
||||
pub fn create_enum_from_entity<E>(&self, entity: E) -> Vec<TypeCreateStatement>
|
||||
where
|
||||
E: EntityTrait,
|
||||
{
|
||||
create_enum_from_entity(entity, db_backend)
|
||||
create_enum_from_entity(entity, self.backend)
|
||||
}
|
||||
|
||||
/// Creates a table from an Entity. See [TableCreateStatement] for more details
|
||||
pub fn create_table_from_entity<E>(entity: E, db_backend: DbBackend) -> TableCreateStatement
|
||||
pub fn create_table_from_entity<E>(&self, entity: E) -> TableCreateStatement
|
||||
where
|
||||
E: EntityTrait,
|
||||
{
|
||||
create_table_from_entity(entity, db_backend)
|
||||
create_table_from_entity(entity, self.backend)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create_enum_from_entity<E>(_: E, db_backend: DbBackend) -> Vec<TypeCreateStatement>
|
||||
pub(crate) fn create_enum_from_entity<E>(_: E, backend: DbBackend) -> Vec<TypeCreateStatement>
|
||||
where
|
||||
E: EntityTrait,
|
||||
{
|
||||
if matches!(db_backend, DbBackend::MySql | DbBackend::Sqlite) {
|
||||
if matches!(backend, DbBackend::MySql | DbBackend::Sqlite) {
|
||||
return Vec::new();
|
||||
}
|
||||
let mut vec = Vec::new();
|
||||
@ -52,7 +52,7 @@ where
|
||||
vec
|
||||
}
|
||||
|
||||
pub(crate) fn create_table_from_entity<E>(entity: E, db_backend: DbBackend) -> TableCreateStatement
|
||||
pub(crate) fn create_table_from_entity<E>(entity: E, backend: DbBackend) -> TableCreateStatement
|
||||
where
|
||||
E: EntityTrait,
|
||||
{
|
||||
@ -61,7 +61,7 @@ where
|
||||
for column in E::Column::iter() {
|
||||
let orm_column_def = column.def();
|
||||
let types = match orm_column_def.col_type {
|
||||
ColumnType::Enum(s, variants) => match db_backend {
|
||||
ColumnType::Enum(s, variants) => match backend {
|
||||
DbBackend::MySql => {
|
||||
ColumnType::Custom(format!("ENUM('{}')", variants.join("', '")))
|
||||
}
|
||||
@ -175,8 +175,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_create_table_from_entity() {
|
||||
let schema = Schema::new(DbBackend::MySql);
|
||||
assert_eq!(
|
||||
Schema::create_table_from_entity(CakeFillingPrice, DbBackend::MySql)
|
||||
schema
|
||||
.create_table_from_entity(CakeFillingPrice)
|
||||
.to_string(MysqlQueryBuilder),
|
||||
Table::create()
|
||||
.table(CakeFillingPrice)
|
||||
|
@ -1,5 +1,17 @@
|
||||
use crate::DbBackend;
|
||||
|
||||
mod entity;
|
||||
|
||||
/// This structure defines a schema for a table
|
||||
/// This is a helper struct to convert [`EntityTrait`](crate::EntityTrait)
|
||||
/// into different [`sea_query`](crate::sea_query) statements.
|
||||
#[derive(Debug)]
|
||||
pub struct Schema;
|
||||
pub struct Schema {
|
||||
backend: DbBackend,
|
||||
}
|
||||
|
||||
impl Schema {
|
||||
/// Create a helper for a specific database backend
|
||||
pub fn new(backend: DbBackend) -> Self {
|
||||
Self { backend }
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,9 @@ where
|
||||
}
|
||||
|
||||
let expect_stmts: Vec<Statement> = creates.iter().map(|stmt| builder.build(stmt)).collect();
|
||||
let create_from_entity_stmts: Vec<Statement> = Schema::create_enum_from_entity(entity, builder)
|
||||
let schema = Schema::new(builder);
|
||||
let create_from_entity_stmts: Vec<Statement> = schema
|
||||
.create_enum_from_entity(entity)
|
||||
.iter()
|
||||
.map(|stmt| builder.build(stmt))
|
||||
.collect();
|
||||
@ -131,8 +133,9 @@ where
|
||||
E: EntityTrait,
|
||||
{
|
||||
let builder = db.get_database_backend();
|
||||
let schema = Schema::new(builder);
|
||||
assert_eq!(
|
||||
builder.build(&Schema::create_table_from_entity(entity, builder)),
|
||||
builder.build(&schema.create_table_from_entity(entity)),
|
||||
builder.build(create)
|
||||
);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
pub use super::*;
|
||||
use rust_decimal_macros::dec;
|
||||
use sea_orm::DbErr;
|
||||
use sea_orm::{query::*, DbErr};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn test_update_cake(db: &DbConn) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user