Merge remote-tracking branch 'origin/master' into active-enum
This commit is contained in:
commit
6018d3f1b9
@ -21,3 +21,7 @@ syn = { version = "^1", default-features = false, features = [ "full", "derive",
|
|||||||
quote = "^1"
|
quote = "^1"
|
||||||
heck = "^0.3"
|
heck = "^0.3"
|
||||||
proc-macro2 = "^1"
|
proc-macro2 = "^1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
sea-orm = { path = "../", features = ["macros"] }
|
||||||
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
pub mod derive_attr {
|
pub mod derive_attr {
|
||||||
use bae::FromAttributes;
|
use bae::FromAttributes;
|
||||||
|
|
||||||
|
/// Attributes for Models and ActiveModels
|
||||||
#[derive(Default, FromAttributes)]
|
#[derive(Default, FromAttributes)]
|
||||||
pub struct SeaOrm {
|
pub struct SeaOrm {
|
||||||
pub column: Option<syn::Ident>,
|
pub column: Option<syn::Ident>,
|
||||||
@ -16,6 +17,7 @@ pub mod derive_attr {
|
|||||||
pub mod field_attr {
|
pub mod field_attr {
|
||||||
use bae::FromAttributes;
|
use bae::FromAttributes;
|
||||||
|
|
||||||
|
/// Operations for Models and ActiveModels
|
||||||
#[derive(Default, FromAttributes)]
|
#[derive(Default, FromAttributes)]
|
||||||
pub struct SeaOrm {
|
pub struct SeaOrm {
|
||||||
pub belongs_to: Option<syn::Lit>,
|
pub belongs_to: Option<syn::Lit>,
|
||||||
|
@ -4,6 +4,7 @@ use proc_macro2::{Ident, TokenStream};
|
|||||||
use quote::{format_ident, quote, quote_spanned};
|
use quote::{format_ident, quote, quote_spanned};
|
||||||
use syn::{punctuated::Punctuated, token::Comma, Data, DataStruct, Field, Fields, Lit, Meta, Type};
|
use syn::{punctuated::Punctuated, token::Comma, Data, DataStruct, Field, Fields, Lit, Meta, Type};
|
||||||
|
|
||||||
|
/// Method to derive an [ActiveModel](sea_orm::ActiveModel)
|
||||||
pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
||||||
let fields = match data {
|
let fields = match data {
|
||||||
Data::Struct(DataStruct {
|
Data::Struct(DataStruct {
|
||||||
|
@ -2,6 +2,7 @@ use proc_macro2::{Ident, TokenStream};
|
|||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::Data;
|
use syn::Data;
|
||||||
|
|
||||||
|
/// Method to derive an implementation of [ActiveModelBehavior](sea_orm::ActiveModelBehavior)
|
||||||
pub fn expand_derive_active_model_behavior(_ident: Ident, _data: Data) -> syn::Result<TokenStream> {
|
pub fn expand_derive_active_model_behavior(_ident: Ident, _data: Data) -> syn::Result<TokenStream> {
|
||||||
Ok(quote!(
|
Ok(quote!(
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
|
@ -3,6 +3,7 @@ use proc_macro2::{Ident, TokenStream};
|
|||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
use syn::{punctuated::Punctuated, token::Comma, Data, DataEnum, Fields, Lit, Meta, Variant};
|
use syn::{punctuated::Punctuated, token::Comma, Data, DataEnum, Fields, Lit, Meta, Variant};
|
||||||
|
|
||||||
|
/// Derive a Column name for an enum type
|
||||||
pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
|
pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
|
||||||
let variants = match data {
|
let variants = match data {
|
||||||
syn::Data::Enum(DataEnum { variants, .. }) => variants,
|
syn::Data::Enum(DataEnum { variants, .. }) => variants,
|
||||||
@ -65,6 +66,7 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStrea
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implement a column using for an enum using [DeriveColumn](sea_orm::DeriveColumn)
|
||||||
pub fn impl_col_from_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
|
pub fn impl_col_from_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
|
||||||
let data_enum = match data {
|
let data_enum = match data {
|
||||||
Data::Enum(data_enum) => data_enum,
|
Data::Enum(data_enum) => data_enum,
|
||||||
@ -114,6 +116,7 @@ pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result<TokenStre
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derive a column with a non_snake_case name
|
||||||
pub fn expand_derive_custom_column(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
|
pub fn expand_derive_custom_column(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
|
||||||
let impl_default_as_str = impl_default_as_str(ident, data)?;
|
let impl_default_as_str = impl_default_as_str(ident, data)?;
|
||||||
let impl_col_from_str = impl_col_from_str(ident, data)?;
|
let impl_col_from_str = impl_col_from_str(ident, data)?;
|
||||||
|
@ -7,6 +7,7 @@ use syn::{
|
|||||||
Lit, Meta,
|
Lit, Meta,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Method to derive an Model
|
||||||
pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Result<TokenStream> {
|
pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Result<TokenStream> {
|
||||||
// if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct
|
// if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct
|
||||||
let mut table_name = None;
|
let mut table_name = None;
|
||||||
|
@ -2,6 +2,7 @@ use proc_macro2::{Ident, TokenStream};
|
|||||||
use quote::{format_ident, quote, quote_spanned};
|
use quote::{format_ident, quote, quote_spanned};
|
||||||
use syn::{Data, DataStruct, Field, Fields};
|
use syn::{Data, DataStruct, Field, Fields};
|
||||||
|
|
||||||
|
/// Method to derive a [QueryResult](sea_orm::QueryResult)
|
||||||
pub fn expand_derive_from_query_result(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
pub fn expand_derive_from_query_result(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
||||||
let fields = match data {
|
let fields = match data {
|
||||||
Data::Struct(DataStruct {
|
Data::Struct(DataStruct {
|
||||||
|
@ -2,6 +2,7 @@ use bae::FromAttributes;
|
|||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
|
|
||||||
|
/// Attributes to derive an ActiveModel
|
||||||
#[derive(Default, FromAttributes)]
|
#[derive(Default, FromAttributes)]
|
||||||
pub struct SeaOrm {
|
pub struct SeaOrm {
|
||||||
pub active_model: Option<syn::Ident>,
|
pub active_model: Option<syn::Ident>,
|
||||||
@ -89,6 +90,7 @@ impl IntoActiveModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Method to derive the ActiveModel from the [ActiveModelTrait](sea_orm::ActiveModelTrait)
|
||||||
pub fn expand_into_active_model(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
pub fn expand_into_active_model(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||||
let ident_span = input.ident.span();
|
let ident_span = input.ident.span();
|
||||||
|
|
||||||
|
@ -183,6 +183,7 @@ impl DeriveModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Method to derive an ActiveModel
|
||||||
pub fn expand_derive_model(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
pub fn expand_derive_model(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||||
let ident_span = input.ident.span();
|
let ident_span = input.ident.span();
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ use proc_macro2::{Ident, TokenStream};
|
|||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
use syn::{Data, DataEnum, Fields, Variant};
|
use syn::{Data, DataEnum, Fields, Variant};
|
||||||
|
|
||||||
|
/// Method to derive a Primary Key for a Model using the [PrimaryKeyTrait](sea_orm::PrimaryKeyTrait)
|
||||||
pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
||||||
let variants = match data {
|
let variants = match data {
|
||||||
syn::Data::Enum(DataEnum { variants, .. }) => variants,
|
syn::Data::Enum(DataEnum { variants, .. }) => variants,
|
||||||
|
@ -166,6 +166,7 @@ impl DeriveRelation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Method to derive a Relation
|
||||||
pub fn expand_derive_relation(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
pub fn expand_derive_relation(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||||
let ident_span = input.ident.span();
|
let ident_span = input.ident.span();
|
||||||
|
|
||||||
|
@ -7,6 +7,69 @@ mod attributes;
|
|||||||
mod derives;
|
mod derives;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
/// Create an Entity
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// 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 {
|
||||||
|
/// # type ValueType = i32;
|
||||||
|
/// #
|
||||||
|
/// # fn auto_increment() -> bool {
|
||||||
|
/// # true
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
/// # pub enum Relation {}
|
||||||
|
/// #
|
||||||
|
/// # impl ColumnTrait for Column {
|
||||||
|
/// # type EntityName = Entity;
|
||||||
|
/// #
|
||||||
|
/// # fn def(&self) -> ColumnDef {
|
||||||
|
/// # match self {
|
||||||
|
/// # Self::Id => ColumnType::Integer.def(),
|
||||||
|
/// # Self::Name => ColumnType::String(None).def(),
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl RelationTrait for Relation {
|
||||||
|
/// # fn def(&self) -> RelationDef {
|
||||||
|
/// # panic!("No Relation");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DeriveEntity, attributes(sea_orm))]
|
#[proc_macro_derive(DeriveEntity, attributes(sea_orm))]
|
||||||
pub fn derive_entity(input: TokenStream) -> TokenStream {
|
pub fn derive_entity(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
@ -15,6 +78,36 @@ pub fn derive_entity(input: TokenStream) -> TokenStream {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This derive macro is the 'almighty' macro which automatically generates
|
||||||
|
/// Entity, Column, and PrimaryKey from a given Model.
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
/// use serde::{Deserialize, Serialize};
|
||||||
|
///
|
||||||
|
/// #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
|
||||||
|
/// #[sea_orm(table_name = "posts")]
|
||||||
|
/// pub struct Model {
|
||||||
|
/// #[sea_orm(primary_key)]
|
||||||
|
/// pub id: i32,
|
||||||
|
/// pub title: String,
|
||||||
|
/// #[sea_orm(column_type = "Text")]
|
||||||
|
/// pub text: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
/// # pub enum Relation {}
|
||||||
|
/// #
|
||||||
|
/// # impl RelationTrait for Relation {
|
||||||
|
/// # fn def(&self) -> RelationDef {
|
||||||
|
/// # panic!("No Relation");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DeriveEntityModel, attributes(sea_orm))]
|
#[proc_macro_derive(DeriveEntityModel, attributes(sea_orm))]
|
||||||
pub fn derive_entity_model(input: TokenStream) -> TokenStream {
|
pub fn derive_entity_model(input: TokenStream) -> TokenStream {
|
||||||
let input_ts = input.clone();
|
let input_ts = input.clone();
|
||||||
@ -36,6 +129,72 @@ pub fn derive_entity_model(input: TokenStream) -> TokenStream {
|
|||||||
ts
|
ts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The DerivePrimaryKey derive macro will implement [PrimaryKeyToColumn]
|
||||||
|
/// for PrimaryKey which defines tedious mappings between primary keys and columns.
|
||||||
|
/// The [EnumIter] is also derived, allowing iteration over all enum variants.
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||||
|
/// pub enum PrimaryKey {
|
||||||
|
/// CakeId,
|
||||||
|
/// FillingId,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # #[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 cake_id: i32,
|
||||||
|
/// # pub filling_id: i32,
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
|
/// # pub enum Column {
|
||||||
|
/// # CakeId,
|
||||||
|
/// # FillingId,
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
/// # pub enum Relation {}
|
||||||
|
/// #
|
||||||
|
/// # impl ColumnTrait for Column {
|
||||||
|
/// # type EntityName = Entity;
|
||||||
|
/// #
|
||||||
|
/// # fn def(&self) -> ColumnDef {
|
||||||
|
/// # match self {
|
||||||
|
/// # Self::CakeId => ColumnType::Integer.def(),
|
||||||
|
/// # Self::FillingId => ColumnType::Integer.def(),
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl PrimaryKeyTrait for PrimaryKey {
|
||||||
|
/// # type ValueType = (i32, i32);
|
||||||
|
/// #
|
||||||
|
/// # fn auto_increment() -> bool {
|
||||||
|
/// # false
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl RelationTrait for Relation {
|
||||||
|
/// # fn def(&self) -> RelationDef {
|
||||||
|
/// # panic!("No Relation");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DerivePrimaryKey)]
|
#[proc_macro_derive(DerivePrimaryKey)]
|
||||||
pub fn derive_primary_key(input: TokenStream) -> TokenStream {
|
pub fn derive_primary_key(input: TokenStream) -> TokenStream {
|
||||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||||
@ -46,6 +205,21 @@ pub fn derive_primary_key(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The DeriveColumn derive macro will implement [ColumnTrait] for Columns.
|
||||||
|
/// It defines the identifier of each column by implementing Iden and IdenStatic.
|
||||||
|
/// The EnumIter is also derived, allowing iteration over all enum variants.
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
|
/// pub enum Column {
|
||||||
|
/// CakeId,
|
||||||
|
/// FillingId,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DeriveColumn, attributes(sea_orm))]
|
#[proc_macro_derive(DeriveColumn, attributes(sea_orm))]
|
||||||
pub fn derive_column(input: TokenStream) -> TokenStream {
|
pub fn derive_column(input: TokenStream) -> TokenStream {
|
||||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||||
@ -56,6 +230,29 @@ pub fn derive_column(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derive a column if column names are not in snake-case
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter, DeriveCustomColumn)]
|
||||||
|
/// pub enum Column {
|
||||||
|
/// Id,
|
||||||
|
/// Name,
|
||||||
|
/// VendorId,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl IdenStatic for Column {
|
||||||
|
/// fn as_str(&self) -> &str {
|
||||||
|
/// match self {
|
||||||
|
/// Self::Id => "id",
|
||||||
|
/// _ => self.default_as_str(),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DeriveCustomColumn)]
|
#[proc_macro_derive(DeriveCustomColumn)]
|
||||||
pub fn derive_custom_column(input: TokenStream) -> TokenStream {
|
pub fn derive_custom_column(input: TokenStream) -> TokenStream {
|
||||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||||
@ -66,6 +263,71 @@ pub fn derive_custom_column(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The DeriveModel derive macro will implement ModelTrait for Model,
|
||||||
|
/// which provides setters and getters for all attributes in the mod
|
||||||
|
/// It also implements FromQueryResult to convert a query result into the corresponding Model.
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||||
|
/// pub struct Model {
|
||||||
|
/// pub id: i32,
|
||||||
|
/// pub name: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
/// # pub struct Entity;
|
||||||
|
/// #
|
||||||
|
/// # impl EntityName for Entity {
|
||||||
|
/// # fn table_name(&self) -> &str {
|
||||||
|
/// # "cake"
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[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 {
|
||||||
|
/// # type ValueType = i32;
|
||||||
|
/// #
|
||||||
|
/// # fn auto_increment() -> bool {
|
||||||
|
/// # true
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
/// # pub enum Relation {}
|
||||||
|
/// #
|
||||||
|
/// # impl ColumnTrait for Column {
|
||||||
|
/// # type EntityName = Entity;
|
||||||
|
/// #
|
||||||
|
/// # fn def(&self) -> ColumnDef {
|
||||||
|
/// # match self {
|
||||||
|
/// # Self::Id => ColumnType::Integer.def(),
|
||||||
|
/// # Self::Name => ColumnType::String(None).def(),
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl RelationTrait for Relation {
|
||||||
|
/// # fn def(&self) -> RelationDef {
|
||||||
|
/// # panic!("No Relation");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DeriveModel, attributes(sea_orm))]
|
#[proc_macro_derive(DeriveModel, attributes(sea_orm))]
|
||||||
pub fn derive_model(input: TokenStream) -> TokenStream {
|
pub fn derive_model(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
@ -74,6 +336,70 @@ pub fn derive_model(input: TokenStream) -> TokenStream {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The DeriveActiveModel derive macro will implement ActiveModelTrait for ActiveModel
|
||||||
|
/// which provides setters and getters for all active values in the active model.
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||||
|
/// pub struct Model {
|
||||||
|
/// pub id: i32,
|
||||||
|
/// pub name: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
/// # pub struct Entity;
|
||||||
|
/// #
|
||||||
|
/// # impl EntityName for Entity {
|
||||||
|
/// # fn table_name(&self) -> &str {
|
||||||
|
/// # "cake"
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[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 {
|
||||||
|
/// # type ValueType = i32;
|
||||||
|
/// #
|
||||||
|
/// # fn auto_increment() -> bool {
|
||||||
|
/// # true
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
/// # pub enum Relation {}
|
||||||
|
/// #
|
||||||
|
/// # impl ColumnTrait for Column {
|
||||||
|
/// # type EntityName = Entity;
|
||||||
|
/// #
|
||||||
|
/// # fn def(&self) -> ColumnDef {
|
||||||
|
/// # match self {
|
||||||
|
/// # Self::Id => ColumnType::Integer.def(),
|
||||||
|
/// # Self::Name => ColumnType::String(None).def(),
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl RelationTrait for Relation {
|
||||||
|
/// # fn def(&self) -> RelationDef {
|
||||||
|
/// # panic!("No Relation");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DeriveActiveModel, attributes(sea_orm))]
|
#[proc_macro_derive(DeriveActiveModel, attributes(sea_orm))]
|
||||||
pub fn derive_active_model(input: TokenStream) -> TokenStream {
|
pub fn derive_active_model(input: TokenStream) -> TokenStream {
|
||||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||||
@ -84,6 +410,7 @@ pub fn derive_active_model(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derive into an active model
|
||||||
#[proc_macro_derive(DeriveIntoActiveModel, attributes(sea_orm))]
|
#[proc_macro_derive(DeriveIntoActiveModel, attributes(sea_orm))]
|
||||||
pub fn derive_into_active_model(input: TokenStream) -> TokenStream {
|
pub fn derive_into_active_model(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
@ -92,6 +419,69 @@ pub fn derive_into_active_model(input: TokenStream) -> TokenStream {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Models that a user can override
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(
|
||||||
|
/// Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, DeriveActiveModelBehavior,
|
||||||
|
/// )]
|
||||||
|
/// pub struct Model {
|
||||||
|
/// pub id: i32,
|
||||||
|
/// pub name: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
/// # pub struct Entity;
|
||||||
|
/// #
|
||||||
|
/// # impl EntityName for Entity {
|
||||||
|
/// # fn table_name(&self) -> &str {
|
||||||
|
/// # "cake"
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[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 {
|
||||||
|
/// # type ValueType = i32;
|
||||||
|
/// #
|
||||||
|
/// # fn auto_increment() -> bool {
|
||||||
|
/// # true
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
/// # pub enum Relation {}
|
||||||
|
/// #
|
||||||
|
/// # impl ColumnTrait for Column {
|
||||||
|
/// # type EntityName = Entity;
|
||||||
|
/// #
|
||||||
|
/// # fn def(&self) -> ColumnDef {
|
||||||
|
/// # match self {
|
||||||
|
/// # Self::Id => ColumnType::Integer.def(),
|
||||||
|
/// # Self::Name => ColumnType::String(None).def(),
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # impl RelationTrait for Relation {
|
||||||
|
/// # fn def(&self) -> RelationDef {
|
||||||
|
/// # panic!("No Relation");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DeriveActiveModelBehavior)]
|
#[proc_macro_derive(DeriveActiveModelBehavior)]
|
||||||
pub fn derive_active_model_behavior(input: TokenStream) -> TokenStream {
|
pub fn derive_active_model_behavior(input: TokenStream) -> TokenStream {
|
||||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||||
@ -134,6 +524,19 @@ pub fn derive_active_enum(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert a query result into the corresponding Model.
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::{entity::prelude::*, FromQueryResult};
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, FromQueryResult)]
|
||||||
|
/// struct SelectResult {
|
||||||
|
/// name: String,
|
||||||
|
/// num_of_fruits: i32,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(FromQueryResult)]
|
#[proc_macro_derive(FromQueryResult)]
|
||||||
pub fn derive_from_query_result(input: TokenStream) -> TokenStream {
|
pub fn derive_from_query_result(input: TokenStream) -> TokenStream {
|
||||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||||
@ -144,6 +547,30 @@ pub fn derive_from_query_result(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The DeriveRelation derive macro will implement RelationTrait for Relation.
|
||||||
|
///
|
||||||
|
/// ### Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sea_orm::tests_cfg::fruit::Entity;
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
/// pub enum Relation {
|
||||||
|
/// #[sea_orm(
|
||||||
|
/// belongs_to = "sea_orm::tests_cfg::cake::Entity",
|
||||||
|
/// from = "sea_orm::tests_cfg::fruit::Column::CakeId",
|
||||||
|
/// to = "sea_orm::tests_cfg::cake::Column::Id"
|
||||||
|
/// )]
|
||||||
|
/// Cake,
|
||||||
|
/// #[sea_orm(
|
||||||
|
/// belongs_to = "sea_orm::tests_cfg::cake_expanded::Entity",
|
||||||
|
/// from = "sea_orm::tests_cfg::fruit::Column::CakeId",
|
||||||
|
/// to = "sea_orm::tests_cfg::cake_expanded::Column::Id"
|
||||||
|
/// )]
|
||||||
|
/// CakeExpanded,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[proc_macro_derive(DeriveRelation, attributes(sea_orm))]
|
#[proc_macro_derive(DeriveRelation, attributes(sea_orm))]
|
||||||
pub fn derive_relation(input: TokenStream) -> TokenStream {
|
pub fn derive_relation(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
@ -4,23 +4,34 @@ use crate::{
|
|||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use std::{future::Future, pin::Pin};
|
use std::{future::Future, pin::Pin};
|
||||||
|
|
||||||
|
/// Creates constraints for any structure that wants to create a database connection
|
||||||
|
/// and execute SQL statements
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait ConnectionTrait<'a>: Sync {
|
pub trait ConnectionTrait<'a>: Sync {
|
||||||
|
/// Create a stream for the [QueryResult]
|
||||||
type Stream: Stream<Item = Result<QueryResult, DbErr>>;
|
type Stream: Stream<Item = Result<QueryResult, DbErr>>;
|
||||||
|
|
||||||
|
/// Fetch the database backend as specified in [DbBackend].
|
||||||
|
/// This depends on feature flags enabled.
|
||||||
fn get_database_backend(&self) -> DbBackend;
|
fn get_database_backend(&self) -> DbBackend;
|
||||||
|
|
||||||
|
/// Execute a [Statement]
|
||||||
async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr>;
|
async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr>;
|
||||||
|
|
||||||
|
/// Execute a [Statement] and return a query
|
||||||
async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr>;
|
async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr>;
|
||||||
|
|
||||||
|
/// Execute a [Statement] and return a collection Vec<[QueryResult]> on success
|
||||||
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr>;
|
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr>;
|
||||||
|
|
||||||
|
/// Execute a [Statement] and return a stream of results
|
||||||
fn stream(
|
fn stream(
|
||||||
&'a self,
|
&'a self,
|
||||||
stmt: Statement,
|
stmt: Statement,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<Self::Stream, DbErr>> + 'a>>;
|
) -> Pin<Box<dyn Future<Output = Result<Self::Stream, DbErr>> + 'a>>;
|
||||||
|
|
||||||
|
/// Execute SQL `BEGIN` transaction.
|
||||||
|
/// Returns a Transaction that can be committed or rolled back
|
||||||
async fn begin(&self) -> Result<DatabaseTransaction, DbErr>;
|
async fn begin(&self) -> Result<DatabaseTransaction, DbErr>;
|
||||||
|
|
||||||
/// Execute the function inside a transaction.
|
/// Execute the function inside a transaction.
|
||||||
@ -34,6 +45,7 @@ pub trait ConnectionTrait<'a>: Sync {
|
|||||||
T: Send,
|
T: Send,
|
||||||
E: std::error::Error + Send;
|
E: std::error::Error + Send;
|
||||||
|
|
||||||
|
/// Check if the connection is a test connection for the Mock database
|
||||||
fn is_mock_connection(&self) -> bool {
|
fn is_mock_connection(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -12,30 +12,43 @@ use sqlx::pool::PoolConnection;
|
|||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Handle a database connection depending on the backend
|
||||||
|
/// enabled by the feature flags. This creates a database pool.
|
||||||
#[cfg_attr(not(feature = "mock"), derive(Clone))]
|
#[cfg_attr(not(feature = "mock"), derive(Clone))]
|
||||||
pub enum DatabaseConnection {
|
pub enum DatabaseConnection {
|
||||||
|
/// Create a MYSQL database connection and pool
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
SqlxMySqlPoolConnection(crate::SqlxMySqlPoolConnection),
|
SqlxMySqlPoolConnection(crate::SqlxMySqlPoolConnection),
|
||||||
|
/// Create a PostgreSQL database connection and pool
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
SqlxPostgresPoolConnection(crate::SqlxPostgresPoolConnection),
|
SqlxPostgresPoolConnection(crate::SqlxPostgresPoolConnection),
|
||||||
|
/// Create a SQLite database connection and pool
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
SqlxSqlitePoolConnection(crate::SqlxSqlitePoolConnection),
|
SqlxSqlitePoolConnection(crate::SqlxSqlitePoolConnection),
|
||||||
|
/// Create a Mock database connection useful for testing
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
MockDatabaseConnection(Arc<crate::MockDatabaseConnection>),
|
MockDatabaseConnection(Arc<crate::MockDatabaseConnection>),
|
||||||
|
/// The connection to the database has been severed
|
||||||
Disconnected,
|
Disconnected,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The same as a [DatabaseConnection]
|
||||||
pub type DbConn = DatabaseConnection;
|
pub type DbConn = DatabaseConnection;
|
||||||
|
|
||||||
|
/// The type of database backend for real world databases.
|
||||||
|
/// This is enabled by feature flags as specified in the crate documentation
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum DatabaseBackend {
|
pub enum DatabaseBackend {
|
||||||
|
/// A MySQL backend
|
||||||
MySql,
|
MySql,
|
||||||
|
/// A PostgreSQL backend
|
||||||
Postgres,
|
Postgres,
|
||||||
|
/// A SQLite backend
|
||||||
Sqlite,
|
Sqlite,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The same as [DatabaseBackend] just shorter :)
|
||||||
pub type DbBackend = DatabaseBackend;
|
pub type DbBackend = DatabaseBackend;
|
||||||
|
|
||||||
pub(crate) enum InnerConnection {
|
pub(crate) enum InnerConnection {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
MySql(PoolConnection<sqlx::MySql>),
|
MySql(PoolConnection<sqlx::MySql>),
|
||||||
@ -209,6 +222,7 @@ impl<'a> ConnectionTrait<'a> for DatabaseConnection {
|
|||||||
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
impl DatabaseConnection {
|
impl DatabaseConnection {
|
||||||
|
/// Generate a database connection for testing the Mock database
|
||||||
pub fn as_mock_connection(&self) -> &crate::MockDatabaseConnection {
|
pub fn as_mock_connection(&self) -> &crate::MockDatabaseConnection {
|
||||||
match self {
|
match self {
|
||||||
DatabaseConnection::MockDatabaseConnection(mock_conn) => mock_conn,
|
DatabaseConnection::MockDatabaseConnection(mock_conn) => mock_conn,
|
||||||
@ -216,6 +230,7 @@ impl DatabaseConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the transaction log as a collection Vec<[crate::Transaction]>
|
||||||
pub fn into_transaction_log(self) -> Vec<crate::Transaction> {
|
pub fn into_transaction_log(self) -> Vec<crate::Transaction> {
|
||||||
let mut mocker = self.as_mock_connection().get_mocker_mutex().lock().unwrap();
|
let mut mocker = self.as_mock_connection().get_mocker_mutex().lock().unwrap();
|
||||||
mocker.drain_transaction_log()
|
mocker.drain_transaction_log()
|
||||||
@ -223,6 +238,8 @@ impl DatabaseConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DbBackend {
|
impl DbBackend {
|
||||||
|
/// Check if the URI is the same as the specified database backend.
|
||||||
|
/// Returns true if they match.
|
||||||
pub fn is_prefix_of(self, base_url: &str) -> bool {
|
pub fn is_prefix_of(self, base_url: &str) -> bool {
|
||||||
let base_url_parsed = Url::parse(base_url).unwrap();
|
let base_url_parsed = Url::parse(base_url).unwrap();
|
||||||
match self {
|
match self {
|
||||||
@ -234,6 +251,7 @@ impl DbBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build an SQL [Statement]
|
||||||
pub fn build<S>(&self, statement: &S) -> Statement
|
pub fn build<S>(&self, statement: &S) -> Statement
|
||||||
where
|
where
|
||||||
S: StatementBuilder,
|
S: StatementBuilder,
|
||||||
@ -241,6 +259,7 @@ impl DbBackend {
|
|||||||
statement.build(self)
|
statement.build(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A helper for building SQL queries
|
||||||
pub fn get_query_builder(&self) -> Box<dyn QueryBuilder> {
|
pub fn get_query_builder(&self) -> Box<dyn QueryBuilder> {
|
||||||
match self {
|
match self {
|
||||||
Self::MySql => Box::new(MysqlQueryBuilder),
|
Self::MySql => Box::new(MysqlQueryBuilder),
|
||||||
|
@ -6,6 +6,7 @@ use crate::{
|
|||||||
use sea_query::{Value, ValueType, Values};
|
use sea_query::{Value, ValueType, Values};
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
||||||
|
/// Defines a Mock database suitable for testing
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MockDatabase {
|
pub struct MockDatabase {
|
||||||
db_backend: DbBackend,
|
db_backend: DbBackend,
|
||||||
@ -15,33 +16,44 @@ pub struct MockDatabase {
|
|||||||
query_results: Vec<Vec<MockRow>>,
|
query_results: Vec<Vec<MockRow>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines the results obtained from a [MockDatabase]
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct MockExecResult {
|
pub struct MockExecResult {
|
||||||
|
/// The last inserted id on auto-increment
|
||||||
pub last_insert_id: u64,
|
pub last_insert_id: u64,
|
||||||
|
/// The number of rows affected by the database operation
|
||||||
pub rows_affected: u64,
|
pub rows_affected: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines the structure of a test Row for the [MockDatabase]
|
||||||
|
/// which is just a [BTreeMap]<[String], [Value]>
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MockRow {
|
pub struct MockRow {
|
||||||
values: BTreeMap<String, Value>,
|
values: BTreeMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait to get a [MockRow] from a type useful for testing in the [MockDatabase]
|
||||||
pub trait IntoMockRow {
|
pub trait IntoMockRow {
|
||||||
|
/// The method to perform this operation
|
||||||
fn into_mock_row(self) -> MockRow;
|
fn into_mock_row(self) -> MockRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a transaction that is has not been committed
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OpenTransaction {
|
pub struct OpenTransaction {
|
||||||
stmts: Vec<Statement>,
|
stmts: Vec<Statement>,
|
||||||
transaction_depth: usize,
|
transaction_depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a database transaction as it holds a Vec<[Statement]>
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
stmts: Vec<Statement>,
|
stmts: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MockDatabase {
|
impl MockDatabase {
|
||||||
|
/// Instantiate a mock database with a [DbBackend] to simulate real
|
||||||
|
/// world SQL databases
|
||||||
pub fn new(db_backend: DbBackend) -> Self {
|
pub fn new(db_backend: DbBackend) -> Self {
|
||||||
Self {
|
Self {
|
||||||
db_backend,
|
db_backend,
|
||||||
@ -52,15 +64,18 @@ impl MockDatabase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a database connection
|
||||||
pub fn into_connection(self) -> DatabaseConnection {
|
pub fn into_connection(self) -> DatabaseConnection {
|
||||||
DatabaseConnection::MockDatabaseConnection(Arc::new(MockDatabaseConnection::new(self)))
|
DatabaseConnection::MockDatabaseConnection(Arc::new(MockDatabaseConnection::new(self)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add the [MockExecResult]s to the `exec_results` field for `Self`
|
||||||
pub fn append_exec_results(mut self, mut vec: Vec<MockExecResult>) -> Self {
|
pub fn append_exec_results(mut self, mut vec: Vec<MockExecResult>) -> Self {
|
||||||
self.exec_results.append(&mut vec);
|
self.exec_results.append(&mut vec);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add the [MockExecResult]s to the `exec_results` field for `Self`
|
||||||
pub fn append_query_results<T>(mut self, vec: Vec<Vec<T>>) -> Self
|
pub fn append_query_results<T>(mut self, vec: Vec<Vec<T>>) -> Self
|
||||||
where
|
where
|
||||||
T: IntoMockRow,
|
T: IntoMockRow,
|
||||||
@ -150,6 +165,7 @@ impl MockDatabaseTrait for MockDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MockRow {
|
impl MockRow {
|
||||||
|
/// Try to get the values of a [MockRow] and fail gracefully on error
|
||||||
pub fn try_get<T>(&self, col: &str) -> Result<T, DbErr>
|
pub fn try_get<T>(&self, col: &str) -> Result<T, DbErr>
|
||||||
where
|
where
|
||||||
T: ValueType,
|
T: ValueType,
|
||||||
@ -157,6 +173,7 @@ impl MockRow {
|
|||||||
T::try_from(self.values.get(col).unwrap().clone()).map_err(|e| DbErr::Query(e.to_string()))
|
T::try_from(self.values.get(col).unwrap().clone()).map_err(|e| DbErr::Query(e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator over the keys and values of a mock row
|
||||||
pub fn into_column_value_tuples(self) -> impl Iterator<Item = (String, Value)> {
|
pub fn into_column_value_tuples(self) -> impl Iterator<Item = (String, Value)> {
|
||||||
self.values.into_iter()
|
self.values.into_iter()
|
||||||
}
|
}
|
||||||
@ -190,6 +207,7 @@ impl IntoMockRow for BTreeMap<&str, Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Transaction {
|
impl Transaction {
|
||||||
|
/// Get the [Value]s from s raw SQL statement depending on the [DatabaseBackend](crate::DatabaseBackend)
|
||||||
pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self
|
pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = Value>,
|
I: IntoIterator<Item = Value>,
|
||||||
|
@ -18,20 +18,30 @@ pub use transaction::*;
|
|||||||
|
|
||||||
use crate::DbErr;
|
use crate::DbErr;
|
||||||
|
|
||||||
|
/// Defines a database
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Database;
|
pub struct Database;
|
||||||
|
|
||||||
|
/// Defines the configuration options of a database
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ConnectOptions {
|
pub struct ConnectOptions {
|
||||||
|
/// The URI of the database
|
||||||
pub(crate) url: String,
|
pub(crate) url: String,
|
||||||
|
/// Maximum number of connections for a pool
|
||||||
pub(crate) max_connections: Option<u32>,
|
pub(crate) max_connections: Option<u32>,
|
||||||
|
/// Minimum number of connections for a pool
|
||||||
pub(crate) min_connections: Option<u32>,
|
pub(crate) min_connections: Option<u32>,
|
||||||
|
/// The connection timeout for a packet connection
|
||||||
pub(crate) connect_timeout: Option<Duration>,
|
pub(crate) connect_timeout: Option<Duration>,
|
||||||
|
/// Maximum idle time for a particular connection to prevent
|
||||||
|
/// network resource exhaustion
|
||||||
pub(crate) idle_timeout: Option<Duration>,
|
pub(crate) idle_timeout: Option<Duration>,
|
||||||
|
/// Enables or disables logging
|
||||||
pub(crate) sqlx_logging: bool,
|
pub(crate) sqlx_logging: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Database {
|
impl Database {
|
||||||
|
/// Method to create a [DatabaseConnection] on a database
|
||||||
pub async fn connect<C>(opt: C) -> Result<DatabaseConnection, DbErr>
|
pub async fn connect<C>(opt: C) -> Result<DatabaseConnection, DbErr>
|
||||||
where
|
where
|
||||||
C: Into<ConnectOptions>,
|
C: Into<ConnectOptions>,
|
||||||
@ -80,6 +90,7 @@ impl From<String> for ConnectOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectOptions {
|
impl ConnectOptions {
|
||||||
|
/// Create new [ConnectOptions] for a [Database] by passing in a URI string
|
||||||
pub fn new(url: String) -> Self {
|
pub fn new(url: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
url,
|
url,
|
||||||
@ -122,21 +133,41 @@ impl ConnectOptions {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the maximum number of connections of the pool, if set
|
||||||
|
pub fn get_max_connections(&self) -> Option<u32> {
|
||||||
|
self.max_connections
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the minimum number of connections of the pool
|
/// Set the minimum number of connections of the pool
|
||||||
pub fn min_connections(&mut self, value: u32) -> &mut Self {
|
pub fn min_connections(&mut self, value: u32) -> &mut Self {
|
||||||
self.min_connections = Some(value);
|
self.min_connections = Some(value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the minimum number of connections of the pool, if set
|
||||||
|
pub fn get_min_connections(&self) -> Option<u32> {
|
||||||
|
self.min_connections
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the timeout duration when acquiring a connection
|
/// Set the timeout duration when acquiring a connection
|
||||||
pub fn connect_timeout(&mut self, value: Duration) -> &mut Self {
|
pub fn connect_timeout(&mut self, value: Duration) -> &mut Self {
|
||||||
self.connect_timeout = Some(value);
|
self.connect_timeout = Some(value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the timeout duration when acquiring a connection, if set
|
||||||
|
pub fn get_connect_timeout(&self) -> Option<Duration> {
|
||||||
|
self.connect_timeout
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the idle duration before closing a connection
|
/// Set the idle duration before closing a connection
|
||||||
pub fn idle_timeout(&mut self, value: Duration) -> &mut Self {
|
pub fn idle_timeout(&mut self, value: Duration) -> &mut Self {
|
||||||
self.idle_timeout = Some(value);
|
self.idle_timeout = Some(value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the idle duration before closing a connection, if set
|
||||||
|
pub fn get_idle_timeout(&self) -> Option<Duration> {
|
||||||
|
self.idle_timeout
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,25 @@ use sea_query::{inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, Sqli
|
|||||||
pub use sea_query::{Value, Values};
|
pub use sea_query::{Value, Values};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Defines an SQL statement
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Statement {
|
pub struct Statement {
|
||||||
|
/// The SQL query
|
||||||
pub sql: String,
|
pub sql: String,
|
||||||
|
/// The values for the SQL statement
|
||||||
pub values: Option<Values>,
|
pub values: Option<Values>,
|
||||||
|
/// The database backend to use
|
||||||
pub db_backend: DbBackend,
|
pub db_backend: DbBackend,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constraints for building a [Statement]
|
||||||
pub trait StatementBuilder {
|
pub trait StatementBuilder {
|
||||||
|
/// Method to call in order to build a [Statement]
|
||||||
fn build(&self, db_backend: &DbBackend) -> Statement;
|
fn build(&self, db_backend: &DbBackend) -> Statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
|
/// Create a [Statement] from a [crate::DatabaseBackend] and a raw SQL statement
|
||||||
pub fn from_string(db_backend: DbBackend, stmt: String) -> Statement {
|
pub fn from_string(db_backend: DbBackend, stmt: String) -> Statement {
|
||||||
Statement {
|
Statement {
|
||||||
sql: stmt,
|
sql: stmt,
|
||||||
@ -23,6 +30,8 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a SQL statement from a [crate::DatabaseBackend], a
|
||||||
|
/// raw SQL statement and defined values
|
||||||
pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self
|
pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = Value>,
|
I: IntoIterator<Item = Value>,
|
||||||
|
@ -12,6 +12,7 @@ use sqlx::{pool::PoolConnection, Executor};
|
|||||||
|
|
||||||
use crate::{DbErr, InnerConnection, QueryResult, Statement};
|
use crate::{DbErr, InnerConnection, QueryResult, Statement};
|
||||||
|
|
||||||
|
/// Creates a stream from a [QueryResult]
|
||||||
#[ouroboros::self_referencing]
|
#[ouroboros::self_referencing]
|
||||||
pub struct QueryStream {
|
pub struct QueryStream {
|
||||||
stmt: Statement,
|
stmt: Statement,
|
||||||
|
@ -10,6 +10,8 @@ use sqlx::{pool::PoolConnection, TransactionManager};
|
|||||||
use std::{future::Future, pin::Pin, sync::Arc};
|
use std::{future::Future, pin::Pin, sync::Arc};
|
||||||
|
|
||||||
// a Transaction is just a sugar for a connection where START TRANSACTION has been executed
|
// a Transaction is just a sugar for a connection where START TRANSACTION has been executed
|
||||||
|
/// Defines a database transaction, whether it is an open transaction and the type of
|
||||||
|
/// backend to use
|
||||||
pub struct DatabaseTransaction {
|
pub struct DatabaseTransaction {
|
||||||
conn: Arc<Mutex<InnerConnection>>,
|
conn: Arc<Mutex<InnerConnection>>,
|
||||||
backend: DbBackend,
|
backend: DbBackend,
|
||||||
@ -100,6 +102,8 @@ impl DatabaseTransaction {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runs a transaction to completion returning an rolling back the transaction on
|
||||||
|
/// encountering an error if it fails
|
||||||
pub(crate) async fn run<F, T, E>(self, callback: F) -> Result<T, TransactionError<E>>
|
pub(crate) async fn run<F, T, E>(self, callback: F) -> Result<T, TransactionError<E>>
|
||||||
where
|
where
|
||||||
F: for<'b> FnOnce(
|
F: for<'b> FnOnce(
|
||||||
@ -120,6 +124,7 @@ impl DatabaseTransaction {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Commit a transaction atomically
|
||||||
pub async fn commit(mut self) -> Result<(), DbErr> {
|
pub async fn commit(mut self) -> Result<(), DbErr> {
|
||||||
self.open = false;
|
self.open = false;
|
||||||
match *self.conn.lock().await {
|
match *self.conn.lock().await {
|
||||||
@ -149,6 +154,7 @@ impl DatabaseTransaction {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// rolls back a transaction in case error are encountered during the operation
|
||||||
pub async fn rollback(mut self) -> Result<(), DbErr> {
|
pub async fn rollback(mut self) -> Result<(), DbErr> {
|
||||||
self.open = false;
|
self.open = false;
|
||||||
match *self.conn.lock().await {
|
match *self.conn.lock().await {
|
||||||
@ -343,12 +349,15 @@ impl<'a> ConnectionTrait<'a> for DatabaseTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines errors for handling transaction failures
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TransactionError<E>
|
pub enum TransactionError<E>
|
||||||
where
|
where
|
||||||
E: std::error::Error,
|
E: std::error::Error,
|
||||||
{
|
{
|
||||||
|
/// A Database connection error
|
||||||
Connection(DbErr),
|
Connection(DbErr),
|
||||||
|
/// An error occurring when doing database transactions
|
||||||
Transaction(E),
|
Transaction(E),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,32 +12,43 @@ use std::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Defines a database driver for the [MockDatabase]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MockDatabaseConnector;
|
pub struct MockDatabaseConnector;
|
||||||
|
|
||||||
|
/// Defines a connection for the [MockDatabase]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MockDatabaseConnection {
|
pub struct MockDatabaseConnection {
|
||||||
counter: AtomicUsize,
|
counter: AtomicUsize,
|
||||||
mocker: Mutex<Box<dyn MockDatabaseTrait>>,
|
mocker: Mutex<Box<dyn MockDatabaseTrait>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A set of constraints for any type wanting to perform operations on the [MockDatabase]
|
||||||
pub trait MockDatabaseTrait: Send + Debug {
|
pub trait MockDatabaseTrait: Send + Debug {
|
||||||
|
/// Execute a statement in the [MockDatabase]
|
||||||
fn execute(&mut self, counter: usize, stmt: Statement) -> Result<ExecResult, DbErr>;
|
fn execute(&mut self, counter: usize, stmt: Statement) -> Result<ExecResult, DbErr>;
|
||||||
|
|
||||||
|
/// Execute a SQL query in the [MockDatabase]
|
||||||
fn query(&mut self, counter: usize, stmt: Statement) -> Result<Vec<QueryResult>, DbErr>;
|
fn query(&mut self, counter: usize, stmt: Statement) -> Result<Vec<QueryResult>, DbErr>;
|
||||||
|
|
||||||
|
/// Create a transaction that can be committed atomically
|
||||||
fn begin(&mut self);
|
fn begin(&mut self);
|
||||||
|
|
||||||
|
/// Commit a successful transaction atomically into the [MockDatabase]
|
||||||
fn commit(&mut self);
|
fn commit(&mut self);
|
||||||
|
|
||||||
|
/// Roll back a transaction since errors were encountered
|
||||||
fn rollback(&mut self);
|
fn rollback(&mut self);
|
||||||
|
|
||||||
|
/// Get all logs from a [MockDatabase] and return a [Transaction]
|
||||||
fn drain_transaction_log(&mut self) -> Vec<Transaction>;
|
fn drain_transaction_log(&mut self) -> Vec<Transaction>;
|
||||||
|
|
||||||
|
/// Get the backend being used in the [MockDatabase]
|
||||||
fn get_database_backend(&self) -> DbBackend;
|
fn get_database_backend(&self) -> DbBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MockDatabaseConnector {
|
impl MockDatabaseConnector {
|
||||||
|
/// Check if the database URI given and the [DatabaseBackend](crate::DatabaseBackend) selected are the same
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn accepts(string: &str) -> bool {
|
pub fn accepts(string: &str) -> bool {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
@ -55,6 +66,7 @@ impl MockDatabaseConnector {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cpnnect to the [MockDatabase]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub async fn connect(string: &str) -> Result<DatabaseConnection, DbErr> {
|
pub async fn connect(string: &str) -> Result<DatabaseConnection, DbErr> {
|
||||||
macro_rules! connect_mock_db {
|
macro_rules! connect_mock_db {
|
||||||
@ -82,6 +94,7 @@ impl MockDatabaseConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MockDatabaseConnection {
|
impl MockDatabaseConnection {
|
||||||
|
/// Create a connection to the [MockDatabase]
|
||||||
pub fn new<M: 'static>(m: M) -> Self
|
pub fn new<M: 'static>(m: M) -> Self
|
||||||
where
|
where
|
||||||
M: MockDatabaseTrait,
|
M: MockDatabaseTrait,
|
||||||
@ -96,16 +109,19 @@ impl MockDatabaseConnection {
|
|||||||
&self.mocker
|
&self.mocker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the [DatabaseBackend](crate::DatabaseBackend) being used by the [MockDatabase]
|
||||||
pub fn get_database_backend(&self) -> DbBackend {
|
pub fn get_database_backend(&self) -> DbBackend {
|
||||||
self.mocker.lock().unwrap().get_database_backend()
|
self.mocker.lock().unwrap().get_database_backend()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute the SQL statement in the [MockDatabase]
|
||||||
pub fn execute(&self, statement: Statement) -> Result<ExecResult, DbErr> {
|
pub fn execute(&self, statement: Statement) -> Result<ExecResult, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
||||||
self.mocker.lock().unwrap().execute(counter, statement)
|
self.mocker.lock().unwrap().execute(counter, statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return one [QueryResult] if the query was successful
|
||||||
pub fn query_one(&self, statement: Statement) -> Result<Option<QueryResult>, DbErr> {
|
pub fn query_one(&self, statement: Statement) -> Result<Option<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
||||||
@ -113,12 +129,14 @@ impl MockDatabaseConnection {
|
|||||||
Ok(result.into_iter().next())
|
Ok(result.into_iter().next())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return all [QueryResult]s if the query was successful
|
||||||
pub fn query_all(&self, statement: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
pub fn query_all(&self, statement: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
|
||||||
self.mocker.lock().unwrap().query(counter, statement)
|
self.mocker.lock().unwrap().query(counter, statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return [QueryResult]s from a multi-query operation
|
||||||
pub fn fetch(
|
pub fn fetch(
|
||||||
&self,
|
&self,
|
||||||
statement: &Statement,
|
statement: &Statement,
|
||||||
@ -129,14 +147,17 @@ impl MockDatabaseConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a statement block of SQL statements that execute together.
|
||||||
pub fn begin(&self) {
|
pub fn begin(&self) {
|
||||||
self.mocker.lock().unwrap().begin()
|
self.mocker.lock().unwrap().begin()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Commit a transaction atomically to the database
|
||||||
pub fn commit(&self) {
|
pub fn commit(&self) {
|
||||||
self.mocker.lock().unwrap().commit()
|
self.mocker.lock().unwrap().commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Roll back a faulty transaction
|
||||||
pub fn rollback(&self) {
|
pub fn rollback(&self) {
|
||||||
self.mocker.lock().unwrap().rollback()
|
self.mocker.lock().unwrap().rollback()
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
use crate::DbErr;
|
use crate::DbErr;
|
||||||
|
|
||||||
|
/// Converts an [sqlx::error] execution error to a [DbErr]
|
||||||
pub fn sqlx_error_to_exec_err(err: sqlx::Error) -> DbErr {
|
pub fn sqlx_error_to_exec_err(err: sqlx::Error) -> DbErr {
|
||||||
DbErr::Exec(err.to_string())
|
DbErr::Exec(err.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts an [sqlx::error] query error to a [DbErr]
|
||||||
pub fn sqlx_error_to_query_err(err: sqlx::Error) -> DbErr {
|
pub fn sqlx_error_to_query_err(err: sqlx::Error) -> DbErr {
|
||||||
DbErr::Query(err.to_string())
|
DbErr::Query(err.to_string())
|
||||||
}
|
}
|
||||||
|
@ -15,19 +15,23 @@ use crate::{
|
|||||||
|
|
||||||
use super::sqlx_common::*;
|
use super::sqlx_common::*;
|
||||||
|
|
||||||
|
/// Defines the [sqlx::mysql] connector
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SqlxMySqlConnector;
|
pub struct SqlxMySqlConnector;
|
||||||
|
|
||||||
|
/// Defines a sqlx MySQL pool
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SqlxMySqlPoolConnection {
|
pub struct SqlxMySqlPoolConnection {
|
||||||
pool: MySqlPool,
|
pool: MySqlPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxMySqlConnector {
|
impl SqlxMySqlConnector {
|
||||||
|
/// Check if the URI provided corresponds to `mysql://` for a MySQL database
|
||||||
pub fn accepts(string: &str) -> bool {
|
pub fn accepts(string: &str) -> bool {
|
||||||
string.starts_with("mysql://") && string.parse::<MySqlConnectOptions>().is_ok()
|
string.starts_with("mysql://") && string.parse::<MySqlConnectOptions>().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add configuration options for the MySQL database
|
||||||
pub async fn connect(options: ConnectOptions) -> Result<DatabaseConnection, DbErr> {
|
pub async fn connect(options: ConnectOptions) -> Result<DatabaseConnection, DbErr> {
|
||||||
let mut opt = options
|
let mut opt = options
|
||||||
.url
|
.url
|
||||||
@ -48,12 +52,14 @@ impl SqlxMySqlConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxMySqlConnector {
|
impl SqlxMySqlConnector {
|
||||||
|
/// Instantiate a sqlx pool connection to a [DatabaseConnection]
|
||||||
pub fn from_sqlx_mysql_pool(pool: MySqlPool) -> DatabaseConnection {
|
pub fn from_sqlx_mysql_pool(pool: MySqlPool) -> DatabaseConnection {
|
||||||
DatabaseConnection::SqlxMySqlPoolConnection(SqlxMySqlPoolConnection { pool })
|
DatabaseConnection::SqlxMySqlPoolConnection(SqlxMySqlPoolConnection { pool })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxMySqlPoolConnection {
|
impl SqlxMySqlPoolConnection {
|
||||||
|
/// Execute a [Statement] on a MySQL backend
|
||||||
pub async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
|
pub async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -70,6 +76,7 @@ impl SqlxMySqlPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get one result from a SQL query. Returns [Option::None] if no match was found
|
||||||
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
|
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -89,6 +96,7 @@ impl SqlxMySqlPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the results of a query returning them as a Vec<[QueryResult]>
|
||||||
pub async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
pub async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -105,6 +113,7 @@ impl SqlxMySqlPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stream the results of executing a SQL query
|
||||||
pub async fn stream(&self, stmt: Statement) -> Result<QueryStream, DbErr> {
|
pub async fn stream(&self, stmt: Statement) -> Result<QueryStream, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -117,6 +126,7 @@ impl SqlxMySqlPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bundle a set of SQL statements that execute together.
|
||||||
pub async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
pub async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
||||||
if let Ok(conn) = self.pool.acquire().await {
|
if let Ok(conn) = self.pool.acquire().await {
|
||||||
DatabaseTransaction::new_mysql(conn).await
|
DatabaseTransaction::new_mysql(conn).await
|
||||||
@ -127,6 +137,7 @@ impl SqlxMySqlPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a MySQL transaction
|
||||||
pub async fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
|
pub async fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
|
||||||
where
|
where
|
||||||
F: for<'b> FnOnce(
|
F: for<'b> FnOnce(
|
||||||
|
@ -15,19 +15,23 @@ use crate::{
|
|||||||
|
|
||||||
use super::sqlx_common::*;
|
use super::sqlx_common::*;
|
||||||
|
|
||||||
|
/// Defines the [sqlx::postgres] connector
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SqlxPostgresConnector;
|
pub struct SqlxPostgresConnector;
|
||||||
|
|
||||||
|
/// Defines a sqlx PostgreSQL pool
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SqlxPostgresPoolConnection {
|
pub struct SqlxPostgresPoolConnection {
|
||||||
pool: PgPool,
|
pool: PgPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxPostgresConnector {
|
impl SqlxPostgresConnector {
|
||||||
|
/// Check if the URI provided corresponds to `postgres://` for a PostgreSQL database
|
||||||
pub fn accepts(string: &str) -> bool {
|
pub fn accepts(string: &str) -> bool {
|
||||||
string.starts_with("postgres://") && string.parse::<PgConnectOptions>().is_ok()
|
string.starts_with("postgres://") && string.parse::<PgConnectOptions>().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add configuration options for the MySQL database
|
||||||
pub async fn connect(options: ConnectOptions) -> Result<DatabaseConnection, DbErr> {
|
pub async fn connect(options: ConnectOptions) -> Result<DatabaseConnection, DbErr> {
|
||||||
let mut opt = options
|
let mut opt = options
|
||||||
.url
|
.url
|
||||||
@ -48,12 +52,14 @@ impl SqlxPostgresConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxPostgresConnector {
|
impl SqlxPostgresConnector {
|
||||||
|
/// Instantiate a sqlx pool connection to a [DatabaseConnection]
|
||||||
pub fn from_sqlx_postgres_pool(pool: PgPool) -> DatabaseConnection {
|
pub fn from_sqlx_postgres_pool(pool: PgPool) -> DatabaseConnection {
|
||||||
DatabaseConnection::SqlxPostgresPoolConnection(SqlxPostgresPoolConnection { pool })
|
DatabaseConnection::SqlxPostgresPoolConnection(SqlxPostgresPoolConnection { pool })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxPostgresPoolConnection {
|
impl SqlxPostgresPoolConnection {
|
||||||
|
/// Execute a [Statement] on a PostgreSQL backend
|
||||||
pub async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
|
pub async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -70,6 +76,7 @@ impl SqlxPostgresPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get one result from a SQL query. Returns [Option::None] if no match was found
|
||||||
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
|
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -89,6 +96,7 @@ impl SqlxPostgresPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the results of a query returning them as a Vec<[QueryResult]>
|
||||||
pub async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
pub async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -105,6 +113,7 @@ impl SqlxPostgresPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stream the results of executing a SQL query
|
||||||
pub async fn stream(&self, stmt: Statement) -> Result<QueryStream, DbErr> {
|
pub async fn stream(&self, stmt: Statement) -> Result<QueryStream, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -117,6 +126,7 @@ impl SqlxPostgresPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bundle a set of SQL statements that execute together.
|
||||||
pub async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
pub async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
||||||
if let Ok(conn) = self.pool.acquire().await {
|
if let Ok(conn) = self.pool.acquire().await {
|
||||||
DatabaseTransaction::new_postgres(conn).await
|
DatabaseTransaction::new_postgres(conn).await
|
||||||
@ -127,6 +137,7 @@ impl SqlxPostgresPoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a PostgreSQL transaction
|
||||||
pub async fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
|
pub async fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
|
||||||
where
|
where
|
||||||
F: for<'b> FnOnce(
|
F: for<'b> FnOnce(
|
||||||
|
@ -15,20 +15,25 @@ use crate::{
|
|||||||
|
|
||||||
use super::sqlx_common::*;
|
use super::sqlx_common::*;
|
||||||
|
|
||||||
|
/// Defines the [sqlx::sqlite] connector
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SqlxSqliteConnector;
|
pub struct SqlxSqliteConnector;
|
||||||
|
|
||||||
|
/// Defines a sqlx SQLite pool
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SqlxSqlitePoolConnection {
|
pub struct SqlxSqlitePoolConnection {
|
||||||
pool: SqlitePool,
|
pool: SqlitePool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxSqliteConnector {
|
impl SqlxSqliteConnector {
|
||||||
|
/// Check if the URI provided corresponds to `sqlite:` for a SQLite database
|
||||||
pub fn accepts(string: &str) -> bool {
|
pub fn accepts(string: &str) -> bool {
|
||||||
string.starts_with("sqlite:") && string.parse::<SqliteConnectOptions>().is_ok()
|
string.starts_with("sqlite:") && string.parse::<SqliteConnectOptions>().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add configuration options for the SQLite database
|
||||||
pub async fn connect(options: ConnectOptions) -> Result<DatabaseConnection, DbErr> {
|
pub async fn connect(options: ConnectOptions) -> Result<DatabaseConnection, DbErr> {
|
||||||
|
let mut options = options;
|
||||||
let mut opt = options
|
let mut opt = options
|
||||||
.url
|
.url
|
||||||
.parse::<SqliteConnectOptions>()
|
.parse::<SqliteConnectOptions>()
|
||||||
@ -37,12 +42,10 @@ impl SqlxSqliteConnector {
|
|||||||
use sqlx::ConnectOptions;
|
use sqlx::ConnectOptions;
|
||||||
opt.disable_statement_logging();
|
opt.disable_statement_logging();
|
||||||
}
|
}
|
||||||
if let Ok(pool) = options
|
if options.get_max_connections().is_none() {
|
||||||
.pool_options()
|
options.max_connections(1);
|
||||||
.max_connections(1)
|
}
|
||||||
.connect_with(opt)
|
if let Ok(pool) = options.pool_options().connect_with(opt).await {
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(DatabaseConnection::SqlxSqlitePoolConnection(
|
Ok(DatabaseConnection::SqlxSqlitePoolConnection(
|
||||||
SqlxSqlitePoolConnection { pool },
|
SqlxSqlitePoolConnection { pool },
|
||||||
))
|
))
|
||||||
@ -53,12 +56,14 @@ impl SqlxSqliteConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxSqliteConnector {
|
impl SqlxSqliteConnector {
|
||||||
|
/// Instantiate a sqlx pool connection to a [DatabaseConnection]
|
||||||
pub fn from_sqlx_sqlite_pool(pool: SqlitePool) -> DatabaseConnection {
|
pub fn from_sqlx_sqlite_pool(pool: SqlitePool) -> DatabaseConnection {
|
||||||
DatabaseConnection::SqlxSqlitePoolConnection(SqlxSqlitePoolConnection { pool })
|
DatabaseConnection::SqlxSqlitePoolConnection(SqlxSqlitePoolConnection { pool })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqlxSqlitePoolConnection {
|
impl SqlxSqlitePoolConnection {
|
||||||
|
/// Execute a [Statement] on a SQLite backend
|
||||||
pub async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
|
pub async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -75,6 +80,7 @@ impl SqlxSqlitePoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get one result from a SQL query. Returns [Option::None] if no match was found
|
||||||
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
|
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -94,6 +100,7 @@ impl SqlxSqlitePoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the results of a query returning them as a Vec<[QueryResult]>
|
||||||
pub async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
pub async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -110,6 +117,7 @@ impl SqlxSqlitePoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stream the results of executing a SQL query
|
||||||
pub async fn stream(&self, stmt: Statement) -> Result<QueryStream, DbErr> {
|
pub async fn stream(&self, stmt: Statement) -> Result<QueryStream, DbErr> {
|
||||||
debug_print!("{}", stmt);
|
debug_print!("{}", stmt);
|
||||||
|
|
||||||
@ -122,6 +130,7 @@ impl SqlxSqlitePoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bundle a set of SQL statements that execute together.
|
||||||
pub async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
pub async fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
|
||||||
if let Ok(conn) = self.pool.acquire().await {
|
if let Ok(conn) = self.pool.acquire().await {
|
||||||
DatabaseTransaction::new_sqlite(conn).await
|
DatabaseTransaction::new_sqlite(conn).await
|
||||||
@ -132,6 +141,7 @@ impl SqlxSqlitePoolConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a MySQL transaction
|
||||||
pub async fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
|
pub async fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
|
||||||
where
|
where
|
||||||
F: for<'b> FnOnce(
|
F: for<'b> FnOnce(
|
||||||
|
@ -5,6 +5,28 @@ use async_trait::async_trait;
|
|||||||
use sea_query::{Nullable, ValueTuple};
|
use sea_query::{Nullable, ValueTuple};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
/// Defines a value from an ActiveModel and its state.
|
||||||
|
/// The field `value` takes in an [Option] type where `Option::Some(V)` , with `V` holding
|
||||||
|
/// the value that operations like `UPDATE` are being performed on and
|
||||||
|
/// the `state` field is either `ActiveValueState::Set` or `ActiveValueState::Unchanged`.
|
||||||
|
/// [Option::None] in the `value` field indicates no value being performed by an operation
|
||||||
|
/// and that the `state` field of the [ActiveValue] is set to `ActiveValueState::Unset` .
|
||||||
|
/// #### Example snippet
|
||||||
|
/// ```no_run
|
||||||
|
/// // The code snipped below does an UPDATE operation on a [ActiveValue]
|
||||||
|
/// // yielding the the SQL statement ` r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"# `
|
||||||
|
///
|
||||||
|
/// use sea_orm::tests_cfg::{cake, fruit};
|
||||||
|
/// use sea_orm::{entity::*, query::*, DbBackend};
|
||||||
|
///
|
||||||
|
/// Update::one(fruit::ActiveModel {
|
||||||
|
/// id: ActiveValue::set(1),
|
||||||
|
/// name: ActiveValue::set("Orange".to_owned()),
|
||||||
|
/// cake_id: ActiveValue::unset(),
|
||||||
|
/// })
|
||||||
|
/// .build(DbBackend::Postgres)
|
||||||
|
/// .to_string();
|
||||||
|
/// ```
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct ActiveValue<V>
|
pub struct ActiveValue<V>
|
||||||
where
|
where
|
||||||
@ -14,6 +36,7 @@ where
|
|||||||
state: ActiveValueState,
|
state: ActiveValueState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a set operation on an [ActiveValue]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Set<V>(v: V) -> ActiveValue<V>
|
pub fn Set<V>(v: V) -> ActiveValue<V>
|
||||||
where
|
where
|
||||||
@ -22,6 +45,7 @@ where
|
|||||||
ActiveValue::set(v)
|
ActiveValue::set(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines an unset operation on an [ActiveValue]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Unset<V>(_: Option<bool>) -> ActiveValue<V>
|
pub fn Unset<V>(_: Option<bool>) -> ActiveValue<V>
|
||||||
where
|
where
|
||||||
@ -30,6 +54,7 @@ where
|
|||||||
ActiveValue::unset()
|
ActiveValue::unset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defines the state of an [ActiveValue]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum ActiveValueState {
|
enum ActiveValueState {
|
||||||
Set,
|
Set,
|
||||||
@ -51,22 +76,33 @@ where
|
|||||||
ActiveValue::unchanged(value)
|
ActiveValue::unchanged(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enforces a set of constraints on any type performing an Create, Update or Delete operation.
|
||||||
|
/// The type must also implement the [EntityTrait].
|
||||||
|
/// See module level docs [crate::entity] for a full example
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait ActiveModelTrait: Clone + Debug {
|
pub trait ActiveModelTrait: Clone + Debug {
|
||||||
|
/// Enforce the type to the constraints of the [EntityTrait]
|
||||||
type Entity: EntityTrait;
|
type Entity: EntityTrait;
|
||||||
|
|
||||||
|
/// Get a mutable [ActiveValue] from an ActiveModel
|
||||||
fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
|
fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
|
||||||
|
|
||||||
|
/// Get a immutable [ActiveValue] from an ActiveModel
|
||||||
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
|
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
|
||||||
|
|
||||||
|
/// Set the Value into an ActiveModel
|
||||||
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
|
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
|
||||||
|
|
||||||
|
/// Set the state of an [ActiveValue] to the Unset state
|
||||||
fn unset(&mut self, c: <Self::Entity as EntityTrait>::Column);
|
fn unset(&mut self, c: <Self::Entity as EntityTrait>::Column);
|
||||||
|
|
||||||
|
/// Check the state of a [ActiveValue]
|
||||||
fn is_unset(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
|
fn is_unset(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
|
||||||
|
|
||||||
|
/// The default implementation of the ActiveModel
|
||||||
fn default() -> Self;
|
fn default() -> Self;
|
||||||
|
|
||||||
|
/// Get the primary key of the ActiveModel
|
||||||
#[allow(clippy::question_mark)]
|
#[allow(clippy::question_mark)]
|
||||||
fn get_primary_key_value(&self) -> Option<ValueTuple> {
|
fn get_primary_key_value(&self) -> Option<ValueTuple> {
|
||||||
let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
|
let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
|
||||||
@ -103,6 +139,7 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform an `INSERT` operation on the ActiveModel
|
||||||
async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
||||||
where
|
where
|
||||||
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
||||||
@ -121,6 +158,7 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
ActiveModelBehavior::after_save(am, true)
|
ActiveModelBehavior::after_save(am, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform the `UPDATE` operation on an ActiveModel
|
||||||
async fn update<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
async fn update<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
||||||
where
|
where
|
||||||
Self: ActiveModelBehavior + 'a,
|
Self: ActiveModelBehavior + 'a,
|
||||||
@ -170,7 +208,35 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Behaviors for users to override
|
/// Enforce a set of constraints to a override the ActiveModel behavior
|
||||||
|
/// Behaviors for users to override.
|
||||||
|
/// The type must also implement the [ActiveModelTrait]
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```ignore
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// // Use [DeriveEntity] to derive the EntityTrait automatically
|
||||||
|
/// #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
/// pub struct Entity;
|
||||||
|
///
|
||||||
|
/// /// The [EntityName] describes the name of a table
|
||||||
|
/// impl EntityName for Entity {
|
||||||
|
/// fn table_name(&self) -> &str {
|
||||||
|
/// "cake"
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Derive the ActiveModel
|
||||||
|
/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||||
|
/// pub struct Model {
|
||||||
|
/// pub id: i32,
|
||||||
|
/// pub name: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
/// ```
|
||||||
|
/// See module level docs [crate::entity] for a full example
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait ActiveModelBehavior: ActiveModelTrait {
|
pub trait ActiveModelBehavior: ActiveModelTrait {
|
||||||
/// Create a new ActiveModel with default values. Also used by `Default::default()`.
|
/// Create a new ActiveModel with default values. Also used by `Default::default()`.
|
||||||
@ -199,10 +265,12 @@ pub trait ActiveModelBehavior: ActiveModelTrait {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enforce constraints for conversion to an ActiveModel
|
||||||
pub trait IntoActiveModel<A>
|
pub trait IntoActiveModel<A>
|
||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
|
/// Method to call to perform the conversion
|
||||||
fn into_active_model(self) -> A;
|
fn into_active_model(self) -> A;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,10 +283,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constraints to perform the conversion of a type into an [ActiveValue]
|
||||||
pub trait IntoActiveValue<V>
|
pub trait IntoActiveValue<V>
|
||||||
where
|
where
|
||||||
V: Into<Value>,
|
V: Into<Value>,
|
||||||
{
|
{
|
||||||
|
/// Method to perform the conversion
|
||||||
fn into_active_value(self) -> ActiveValue<V>;
|
fn into_active_value(self) -> ActiveValue<V>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,6 +366,7 @@ impl<V> ActiveValue<V>
|
|||||||
where
|
where
|
||||||
V: Into<Value>,
|
V: Into<Value>,
|
||||||
{
|
{
|
||||||
|
/// Set the value of an [ActiveValue] and also set its state to `ActiveValueState::Set`
|
||||||
pub fn set(value: V) -> Self {
|
pub fn set(value: V) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value: Some(value),
|
value: Some(value),
|
||||||
@ -303,6 +374,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the state of an [ActiveValue] is `ActiveValueState::Set` which returns true
|
||||||
pub fn is_set(&self) -> bool {
|
pub fn is_set(&self) -> bool {
|
||||||
matches!(self.state, ActiveValueState::Set)
|
matches!(self.state, ActiveValueState::Set)
|
||||||
}
|
}
|
||||||
@ -314,10 +386,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the status of the [ActiveValue] is `ActiveValueState::Unchanged`
|
||||||
|
/// which returns `true` if it is
|
||||||
pub fn is_unchanged(&self) -> bool {
|
pub fn is_unchanged(&self) -> bool {
|
||||||
matches!(self.state, ActiveValueState::Unchanged)
|
matches!(self.state, ActiveValueState::Unchanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the `value` field of the ActiveModel to [Option::None] and the
|
||||||
|
/// `state` field to `ActiveValueState::Unset`
|
||||||
pub fn unset() -> Self {
|
pub fn unset() -> Self {
|
||||||
Self {
|
Self {
|
||||||
value: None,
|
value: None,
|
||||||
@ -325,23 +401,30 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the state of an [ActiveValue] is `ActiveValueState::Unset`
|
||||||
|
/// which returns true if it is
|
||||||
pub fn is_unset(&self) -> bool {
|
pub fn is_unset(&self) -> bool {
|
||||||
matches!(self.state, ActiveValueState::Unset)
|
matches!(self.state, ActiveValueState::Unset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the mutable value of the `value` field of an [ActiveValue]
|
||||||
|
/// also setting it's state to `ActiveValueState::Unset`
|
||||||
pub fn take(&mut self) -> Option<V> {
|
pub fn take(&mut self) -> Option<V> {
|
||||||
self.state = ActiveValueState::Unset;
|
self.state = ActiveValueState::Unset;
|
||||||
self.value.take()
|
self.value.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an owned value of the `value` field of the [ActiveValue]
|
||||||
pub fn unwrap(self) -> V {
|
pub fn unwrap(self) -> V {
|
||||||
self.value.unwrap()
|
self.value.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check is a [Value] exists or not
|
||||||
pub fn into_value(self) -> Option<Value> {
|
pub fn into_value(self) -> Option<Value> {
|
||||||
self.value.map(Into::into)
|
self.value.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wrap the [Value] into a `ActiveValue<Value>`
|
||||||
pub fn into_wrapped_value(self) -> ActiveValue<Value> {
|
pub fn into_wrapped_value(self) -> ActiveValue<Value> {
|
||||||
match self.state {
|
match self.state {
|
||||||
ActiveValueState::Set => ActiveValue::set(self.into_value().unwrap()),
|
ActiveValueState::Set => ActiveValue::set(self.into_value().unwrap()),
|
||||||
|
@ -7,21 +7,28 @@ use sea_query::{Alias, Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef};
|
|||||||
pub use sea_strum::IntoEnumIterator as Iterable;
|
pub use sea_strum::IntoEnumIterator as Iterable;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
/// Ensure the identifier for an Entity can be converted to a static str
|
||||||
pub trait IdenStatic: Iden + Copy + Debug + 'static {
|
pub trait IdenStatic: Iden + Copy + Debug + 'static {
|
||||||
|
/// Method to call to get the static string identity
|
||||||
fn as_str(&self) -> &str;
|
fn as_str(&self) -> &str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enforces the naming of an entity to a set of constraints
|
||||||
pub trait EntityName: IdenStatic + Default {
|
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> {
|
fn schema_name(&self) -> Option<&str> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the name of the table
|
||||||
fn table_name(&self) -> &str;
|
fn table_name(&self) -> &str;
|
||||||
|
|
||||||
|
/// Get the name of the module from the invoking `self.table_name()`
|
||||||
fn module_name(&self) -> &str {
|
fn module_name(&self) -> &str {
|
||||||
self.table_name()
|
self.table_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the [TableRef] from invoking the `self.schema_name()`
|
||||||
fn table_ref(&self) -> TableRef {
|
fn table_ref(&self) -> TableRef {
|
||||||
match self.schema_name() {
|
match self.schema_name() {
|
||||||
Some(schema) => (Alias::new(schema).into_iden(), self.into_iden()).into_table_ref(),
|
Some(schema) => (Alias::new(schema).into_iden(), self.into_iden()).into_table_ref(),
|
||||||
@ -43,14 +50,19 @@ pub trait EntityName: IdenStatic + Default {
|
|||||||
/// - Update: `update`, `update_*`
|
/// - Update: `update`, `update_*`
|
||||||
/// - Delete: `delete`, `delete_*`
|
/// - Delete: `delete`, `delete_*`
|
||||||
pub trait EntityTrait: EntityName {
|
pub trait EntityTrait: EntityName {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type Model: ModelTrait<Entity = Self> + FromQueryResult;
|
type Model: ModelTrait<Entity = Self> + FromQueryResult;
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
type Column: ColumnTrait;
|
type Column: ColumnTrait;
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
type Relation: RelationTrait;
|
type Relation: RelationTrait;
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
type PrimaryKey: PrimaryKeyTrait + PrimaryKeyToColumn<Column = Self::Column>;
|
type PrimaryKey: PrimaryKeyTrait + PrimaryKeyToColumn<Column = Self::Column>;
|
||||||
|
|
||||||
|
/// Check if the relation belongs to an Entity
|
||||||
fn belongs_to<R>(related: R) -> RelationBuilder<Self, R>
|
fn belongs_to<R>(related: R) -> RelationBuilder<Self, R>
|
||||||
where
|
where
|
||||||
R: EntityTrait,
|
R: EntityTrait,
|
||||||
@ -58,6 +70,7 @@ pub trait EntityTrait: EntityName {
|
|||||||
RelationBuilder::new(RelationType::HasOne, Self::default(), related, false)
|
RelationBuilder::new(RelationType::HasOne, Self::default(), related, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the entity has at least one relation
|
||||||
fn has_one<R>(_: R) -> RelationBuilder<Self, R>
|
fn has_one<R>(_: R) -> RelationBuilder<Self, R>
|
||||||
where
|
where
|
||||||
R: EntityTrait + Related<Self>,
|
R: EntityTrait + Related<Self>,
|
||||||
@ -65,6 +78,7 @@ pub trait EntityTrait: EntityName {
|
|||||||
RelationBuilder::from_rel(RelationType::HasOne, R::to().rev(), true)
|
RelationBuilder::from_rel(RelationType::HasOne, R::to().rev(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the Entity has many relations
|
||||||
fn has_many<R>(_: R) -> RelationBuilder<Self, R>
|
fn has_many<R>(_: R) -> RelationBuilder<Self, R>
|
||||||
where
|
where
|
||||||
R: EntityTrait + Related<Self>,
|
R: EntityTrait + Related<Self>,
|
||||||
|
@ -2,6 +2,7 @@ use crate::{EntityName, IdenStatic, Iterable};
|
|||||||
use sea_query::{DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value};
|
use sea_query::{DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
/// Defines a Column for an Entity
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ColumnDef {
|
pub struct ColumnDef {
|
||||||
pub(crate) col_type: ColumnType,
|
pub(crate) col_type: ColumnType,
|
||||||
@ -10,35 +11,63 @@ pub struct ColumnDef {
|
|||||||
pub(crate) indexed: bool,
|
pub(crate) indexed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The type of column as defined in the SQL format
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum ColumnType {
|
pub enum ColumnType {
|
||||||
|
/// `CHAR` type of specified fixed length
|
||||||
Char(Option<u32>),
|
Char(Option<u32>),
|
||||||
|
/// `STRING` type for variable string length
|
||||||
String(Option<u32>),
|
String(Option<u32>),
|
||||||
|
/// `TEXT` type used for large pieces of string data and stored out of row in case size is too big
|
||||||
Text,
|
Text,
|
||||||
|
/// `TINYINT` useful for storing one byte of data (range of 0-255)
|
||||||
TinyInteger,
|
TinyInteger,
|
||||||
|
/// `SMALLINT` data type stores small whole numbers that range from –32,767 to 32,767
|
||||||
SmallInteger,
|
SmallInteger,
|
||||||
|
/// `INTEGER` data types hold numbers that are whole, or without a decimal point
|
||||||
Integer,
|
Integer,
|
||||||
|
/// `BIGINT` is a 64-bit representation of an integer taking up 8 bytes of storage and
|
||||||
|
/// ranging from -2^63 (-9,223,372,036,854,775,808) to 2^63 (9,223,372,036,854,775,807).
|
||||||
BigInteger,
|
BigInteger,
|
||||||
|
/// `FLOAT` an approximate-number data type, where values range cannot be represented exactly.
|
||||||
Float,
|
Float,
|
||||||
|
/// `DOUBLE` is a normal-size floating point number where the
|
||||||
|
/// total number of digits is specified in size.
|
||||||
Double,
|
Double,
|
||||||
|
/// `DECIMAL` type store numbers that have fixed precision and scale
|
||||||
Decimal(Option<(u32, u32)>),
|
Decimal(Option<(u32, u32)>),
|
||||||
|
/// `DATETIME` type is used for values that contain both date and time parts.
|
||||||
DateTime,
|
DateTime,
|
||||||
|
/// `TIMESTAMP` is a temporal data type that holds the combination of date and time.
|
||||||
Timestamp,
|
Timestamp,
|
||||||
|
/// `TIMESTAMP WITH TIME ZONE` (or `TIMESTAMPTZ`) data type stores 8-byte
|
||||||
|
/// date values that include timestamp and time zone information in UTC format.
|
||||||
TimestampWithTimeZone,
|
TimestampWithTimeZone,
|
||||||
|
/// `TIME` data type defines a time of a day based on 24-hour clock
|
||||||
Time,
|
Time,
|
||||||
|
/// `DATE` data type stores the calendar date
|
||||||
Date,
|
Date,
|
||||||
|
/// `BINARY` data types contain byte strings—a sequence of octets or bytes.
|
||||||
Binary,
|
Binary,
|
||||||
|
/// `BOOLEAN` is the result of a comparison operator
|
||||||
Boolean,
|
Boolean,
|
||||||
|
/// `MONEY` data type handles monetary data
|
||||||
Money(Option<(u32, u32)>),
|
Money(Option<(u32, u32)>),
|
||||||
|
/// `JSON` represents the JavaScript Object Notation type
|
||||||
Json,
|
Json,
|
||||||
|
/// JSON binary format is structured in the way that permits the server to search for
|
||||||
|
/// values within the JSON document directly by key or array index, which is very fast.
|
||||||
JsonBinary,
|
JsonBinary,
|
||||||
|
/// A custom implementation of a data type
|
||||||
Custom(String),
|
Custom(String),
|
||||||
|
/// A Universally Unique IDentifier that is specified in RFC 4122
|
||||||
Uuid,
|
Uuid,
|
||||||
Enum(String, Vec<String>),
|
Enum(String, Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! bind_oper {
|
macro_rules! bind_oper {
|
||||||
( $op: ident ) => {
|
( $op: ident ) => {
|
||||||
|
#[allow(missing_docs)]
|
||||||
fn $op<V>(&self, v: V) -> SimpleExpr
|
fn $op<V>(&self, v: V) -> SimpleExpr
|
||||||
where
|
where
|
||||||
V: Into<Value>,
|
V: Into<Value>,
|
||||||
@ -59,6 +88,7 @@ macro_rules! bind_func_no_params {
|
|||||||
|
|
||||||
macro_rules! bind_vec_func {
|
macro_rules! bind_vec_func {
|
||||||
( $func: ident ) => {
|
( $func: ident ) => {
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
fn $func<V, I>(&self, v: I) -> SimpleExpr
|
fn $func<V, I>(&self, v: I) -> SimpleExpr
|
||||||
where
|
where
|
||||||
@ -73,6 +103,7 @@ macro_rules! bind_vec_func {
|
|||||||
macro_rules! bind_subquery_func {
|
macro_rules! bind_subquery_func {
|
||||||
( $func: ident ) => {
|
( $func: ident ) => {
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
fn $func(&self, s: SelectStatement) -> SimpleExpr {
|
fn $func(&self, s: SelectStatement) -> SimpleExpr {
|
||||||
Expr::tbl(self.entity_name(), *self).$func(s)
|
Expr::tbl(self.entity_name(), *self).$func(s)
|
||||||
}
|
}
|
||||||
@ -82,14 +113,18 @@ macro_rules! bind_subquery_func {
|
|||||||
// LINT: when the operand value does not match column type
|
// LINT: when the operand value does not match column type
|
||||||
/// Wrapper of the identically named method in [`sea_query::Expr`]
|
/// Wrapper of the identically named method in [`sea_query::Expr`]
|
||||||
pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
|
pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type EntityName: EntityName;
|
type EntityName: EntityName;
|
||||||
|
|
||||||
|
/// Define a column for an Entity
|
||||||
fn def(&self) -> ColumnDef;
|
fn def(&self) -> ColumnDef;
|
||||||
|
|
||||||
|
/// Get the name of the entity the column belongs to
|
||||||
fn entity_name(&self) -> DynIden {
|
fn entity_name(&self) -> DynIden {
|
||||||
SeaRc::new(Self::EntityName::default()) as DynIden
|
SeaRc::new(Self::EntityName::default()) as DynIden
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get the name of the entity the column belongs to
|
||||||
fn as_column_ref(&self) -> (DynIden, DynIden) {
|
fn as_column_ref(&self) -> (DynIden, DynIden) {
|
||||||
(self.entity_name(), SeaRc::new(*self) as DynIden)
|
(self.entity_name(), SeaRc::new(*self) as DynIden)
|
||||||
}
|
}
|
||||||
@ -222,6 +257,7 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
|
|||||||
bind_func_no_params!(is_null);
|
bind_func_no_params!(is_null);
|
||||||
bind_func_no_params!(is_not_null);
|
bind_func_no_params!(is_not_null);
|
||||||
|
|
||||||
|
/// Perform an operation if the column is null
|
||||||
fn if_null<V>(&self, v: V) -> SimpleExpr
|
fn if_null<V>(&self, v: V) -> SimpleExpr
|
||||||
where
|
where
|
||||||
V: Into<Value>,
|
V: Into<Value>,
|
||||||
@ -237,6 +273,7 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ColumnType {
|
impl ColumnType {
|
||||||
|
/// instantiate a new [ColumnDef]
|
||||||
pub fn def(self) -> ColumnDef {
|
pub fn def(self) -> ColumnDef {
|
||||||
ColumnDef {
|
ColumnDef {
|
||||||
col_type: self,
|
col_type: self,
|
||||||
@ -255,20 +292,24 @@ impl ColumnType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ColumnDef {
|
impl ColumnDef {
|
||||||
|
/// Marks the column as `UNIQUE`
|
||||||
pub fn unique(mut self) -> Self {
|
pub fn unique(mut self) -> Self {
|
||||||
self.unique = true;
|
self.unique = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mark the column as nullable
|
||||||
pub fn null(self) -> Self {
|
pub fn null(self) -> Self {
|
||||||
self.nullable()
|
self.nullable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mark the column as nullable
|
||||||
pub fn nullable(mut self) -> Self {
|
pub fn nullable(mut self) -> Self {
|
||||||
self.null = true;
|
self.null = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the `indexed` field to `true`
|
||||||
pub fn indexed(mut self) -> Self {
|
pub fn indexed(mut self) -> Self {
|
||||||
self.indexed = true;
|
self.indexed = true;
|
||||||
self
|
self
|
||||||
|
@ -2,10 +2,14 @@ use crate::{ColumnTrait, EntityTrait, IdenStatic};
|
|||||||
use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc};
|
use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Defines an operation for an Entity
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Identity {
|
pub enum Identity {
|
||||||
|
/// Performs one operation
|
||||||
Unary(DynIden),
|
Unary(DynIden),
|
||||||
|
/// Performs two operations
|
||||||
Binary(DynIden, DynIden),
|
Binary(DynIden, DynIden),
|
||||||
|
/// Performs three operations
|
||||||
Ternary(DynIden, DynIden, DynIden),
|
Ternary(DynIden, DynIden, DynIden),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,14 +32,18 @@ impl Iden for Identity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a conversion into an [Identity]
|
||||||
pub trait IntoIdentity {
|
pub trait IntoIdentity {
|
||||||
|
/// Method to perform the conversion
|
||||||
fn into_identity(self) -> Identity;
|
fn into_identity(self) -> Identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check the [Identity] of an Entity
|
||||||
pub trait IdentityOf<E>
|
pub trait IdentityOf<E>
|
||||||
where
|
where
|
||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
{
|
{
|
||||||
|
/// Method to call to perform this check
|
||||||
fn identity_of(self) -> Identity;
|
fn identity_of(self) -> Identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,15 +3,21 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use sea_query::{Alias, IntoIden, JoinType, SeaRc};
|
use sea_query::{Alias, IntoIden, JoinType, SeaRc};
|
||||||
|
|
||||||
|
/// Same as [RelationDef]
|
||||||
pub type LinkDef = RelationDef;
|
pub type LinkDef = RelationDef;
|
||||||
|
|
||||||
|
/// A set of constraints for links between Entities
|
||||||
pub trait Linked {
|
pub trait Linked {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type FromEntity: EntityTrait;
|
type FromEntity: EntityTrait;
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
type ToEntity: EntityTrait;
|
type ToEntity: EntityTrait;
|
||||||
|
|
||||||
|
/// Link for an Entity
|
||||||
fn link(&self) -> Vec<LinkDef>;
|
fn link(&self) -> Vec<LinkDef>;
|
||||||
|
|
||||||
|
/// Find all the Entities that are linked to the Entity
|
||||||
fn find_linked(&self) -> Select<Self::ToEntity> {
|
fn find_linked(&self) -> Select<Self::ToEntity> {
|
||||||
let mut select = Select::new();
|
let mut select = Select::new();
|
||||||
for (i, rel) in self.link().into_iter().rev().enumerate() {
|
for (i, rel) in self.link().into_iter().rev().enumerate() {
|
||||||
|
@ -1,3 +1,103 @@
|
|||||||
|
/// This modules contains types and traits for an Entity, ActiveMode, Model, PrimaryKey, ForeignKey and Relations.
|
||||||
|
///
|
||||||
|
/// // An Entity
|
||||||
|
/// A unit struct implements [EntityTrait](crate::EntityTrait) representing a table in the database.
|
||||||
|
///
|
||||||
|
/// This trait contains the properties of an entity including
|
||||||
|
///
|
||||||
|
/// - The Table Name which is implemented by [EntityName](crate::EntityName)
|
||||||
|
/// - The Column which is implemented by [ColumnTrait](crate::ColumnTrait)
|
||||||
|
/// - A Relation which is implemented by [RelationTrait](crate::RelationTrait)
|
||||||
|
/// - The Primary Key which is implemented by [PrimaryKeyTrait](crate::PrimaryKeyTrait)
|
||||||
|
/// and [PrimaryKeyToColumn](crate::PrimaryKeyToColumn)
|
||||||
|
///
|
||||||
|
/// This trait also provides an API for CRUD actions
|
||||||
|
///
|
||||||
|
/// #### Example for creating an Entity, Model and ActiveModel
|
||||||
|
/// ```
|
||||||
|
/// #[cfg(feature = "macros")]
|
||||||
|
///
|
||||||
|
/// # use sea_orm::entity::prelude::*;
|
||||||
|
/// use sea_orm::ActiveModelBehavior;
|
||||||
|
/// use sea_orm::RelationDef;
|
||||||
|
/// use sea_orm::RelationTrait;
|
||||||
|
/// use sea_orm::ColumnType;
|
||||||
|
/// use sea_orm::ColumnDef;
|
||||||
|
/// use sea_orm::ColumnTrait;
|
||||||
|
/// use sea_orm::PrimaryKeyTrait;
|
||||||
|
/// use sea_orm::EntityName;
|
||||||
|
///
|
||||||
|
/// // Use [DeriveEntity] to derive the EntityTrait automatically
|
||||||
|
/// #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
/// pub struct Entity;
|
||||||
|
///
|
||||||
|
/// /// The [EntityName] describes the name of a table
|
||||||
|
/// impl EntityName for Entity {
|
||||||
|
/// fn table_name(&self) -> &str {
|
||||||
|
/// "filling"
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Create a Model for the Entity through [DeriveModel].
|
||||||
|
/// // The `Model` handles `READ` operations on a table in a database.
|
||||||
|
/// // The [DeriveActiveModel] creates a way to perform `CREATE` , `READ` and `UPDATE` operations
|
||||||
|
/// // in a database
|
||||||
|
/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||||
|
/// pub struct Model {
|
||||||
|
/// pub id: i32,
|
||||||
|
/// pub name: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Use the [DeriveColumn] to create a Column for an the table called Entity
|
||||||
|
/// // The [EnumIter] which creates a new type that iterates of the variants of a Column.
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
|
/// pub enum Column {
|
||||||
|
/// Id,
|
||||||
|
/// Name,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Create a PrimaryKey for the Entity using the [PrimaryKeyTrait]
|
||||||
|
/// // The [EnumIter] which creates a new type that iterates of the variants of a PrimaryKey.
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||||
|
/// pub enum PrimaryKey {
|
||||||
|
/// Id,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Or implement the [PrimaryKeyTrait] manually instead of using the macro [DerivePrimaryKey]
|
||||||
|
/// impl PrimaryKeyTrait for PrimaryKey {
|
||||||
|
/// type ValueType = i32;
|
||||||
|
///
|
||||||
|
/// fn auto_increment() -> bool {
|
||||||
|
/// true
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
/// pub enum Relation {}
|
||||||
|
///
|
||||||
|
/// impl ColumnTrait for Column {
|
||||||
|
/// type EntityName = Entity;
|
||||||
|
///
|
||||||
|
/// fn def(&self) -> ColumnDef {
|
||||||
|
/// match self {
|
||||||
|
/// Self::Id => ColumnType::Integer.def(),
|
||||||
|
/// Self::Name => ColumnType::String(None).def(),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Create a Relation for the Entity
|
||||||
|
/// impl RelationTrait for Relation {
|
||||||
|
/// fn def(&self) -> RelationDef {
|
||||||
|
/// panic!()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// // Implement user defined operations for CREATE, UPDATE and DELETE operations
|
||||||
|
/// // to create an ActiveModel using the [ActiveModelBehavior]
|
||||||
|
/// impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
mod active_enum;
|
mod active_enum;
|
||||||
mod active_model;
|
mod active_model;
|
||||||
mod base_entity;
|
mod base_entity;
|
||||||
@ -5,6 +105,7 @@ mod column;
|
|||||||
mod identity;
|
mod identity;
|
||||||
mod link;
|
mod link;
|
||||||
mod model;
|
mod model;
|
||||||
|
/// Re-export common types from the entity
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
mod primary_key;
|
mod primary_key;
|
||||||
mod relation;
|
mod relation;
|
||||||
|
@ -5,13 +5,18 @@ use crate::{
|
|||||||
pub use sea_query::Value;
|
pub use sea_query::Value;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
/// A set of constraints for a Model
|
||||||
pub trait ModelTrait: Clone + Send + Debug {
|
pub trait ModelTrait: Clone + Send + Debug {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type Entity: EntityTrait;
|
type Entity: EntityTrait;
|
||||||
|
|
||||||
|
/// Get the [Value] of a column from an Entity
|
||||||
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> Value;
|
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> Value;
|
||||||
|
|
||||||
|
/// Set the [Value] of a column in an Entity
|
||||||
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
|
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
|
||||||
|
|
||||||
|
/// Find related Models
|
||||||
fn find_related<R>(&self, _: R) -> Select<R>
|
fn find_related<R>(&self, _: R) -> Select<R>
|
||||||
where
|
where
|
||||||
R: EntityTrait,
|
R: EntityTrait,
|
||||||
@ -20,6 +25,7 @@ pub trait ModelTrait: Clone + Send + Debug {
|
|||||||
<Self::Entity as Related<R>>::find_related().belongs_to(self)
|
<Self::Entity as Related<R>>::find_related().belongs_to(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find linked Models
|
||||||
fn find_linked<L>(&self, l: L) -> Select<L::ToEntity>
|
fn find_linked<L>(&self, l: L) -> Select<L::ToEntity>
|
||||||
where
|
where
|
||||||
L: Linked<FromEntity = Self::Entity>,
|
L: Linked<FromEntity = Self::Entity>,
|
||||||
@ -29,9 +35,13 @@ pub trait ModelTrait: Clone + Send + Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A set of constraints for implementing a [QueryResult]
|
||||||
pub trait FromQueryResult: Sized {
|
pub trait FromQueryResult: Sized {
|
||||||
|
/// Instantiate a Model from a [QueryResult]
|
||||||
fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr>;
|
fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr>;
|
||||||
|
|
||||||
|
/// Transform the error from instantiating a Model from a [QueryResult]
|
||||||
|
/// and converting it to an [Option]
|
||||||
fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result<Option<Self>, DbErr> {
|
fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result<Option<Self>, DbErr> {
|
||||||
Ok(Self::from_query_result(res, pre).ok())
|
Ok(Self::from_query_result(res, pre).ok())
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ pub use chrono::NaiveTime as Time;
|
|||||||
#[cfg(feature = "with-chrono")]
|
#[cfg(feature = "with-chrono")]
|
||||||
pub use chrono::NaiveDateTime as DateTime;
|
pub use chrono::NaiveDateTime as DateTime;
|
||||||
|
|
||||||
|
/// Handles the time and dates
|
||||||
#[cfg(feature = "with-chrono")]
|
#[cfg(feature = "with-chrono")]
|
||||||
pub type DateTimeWithTimeZone = chrono::DateTime<chrono::FixedOffset>;
|
pub type DateTimeWithTimeZone = chrono::DateTime<chrono::FixedOffset>;
|
||||||
|
|
||||||
|
@ -4,7 +4,41 @@ use sea_query::{FromValueTuple, IntoValueTuple};
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
//LINT: composite primary key cannot auto increment
|
//LINT: composite primary key cannot auto increment
|
||||||
|
/// A set of constraints to be used to define a Primary Key.
|
||||||
|
///
|
||||||
|
/// A primary key can be derived manually
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```text
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
/// pub enum PrimaryKey {
|
||||||
|
/// Id,
|
||||||
|
/// }
|
||||||
|
/// impl PrimaryKeyTrait for PrimaryKey {
|
||||||
|
/// type ValueType = i32;
|
||||||
|
///
|
||||||
|
/// fn auto_increment() -> bool {
|
||||||
|
/// true
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Alternatively, use derive macros to automatically implement the trait for a Primary Key
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```text
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||||
|
/// pub enum PrimaryKey {
|
||||||
|
/// Id,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// See module level docs [crate::entity] for a full example
|
||||||
pub trait PrimaryKeyTrait: IdenStatic + Iterable {
|
pub trait PrimaryKeyTrait: IdenStatic + Iterable {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type ValueType: Sized
|
type ValueType: Sized
|
||||||
+ Send
|
+ Send
|
||||||
+ Debug
|
+ Debug
|
||||||
@ -14,14 +48,19 @@ pub trait PrimaryKeyTrait: IdenStatic + Iterable {
|
|||||||
+ TryGetableMany
|
+ TryGetableMany
|
||||||
+ TryFromU64;
|
+ TryFromU64;
|
||||||
|
|
||||||
|
/// Method to call to perform `AUTOINCREMENT` operation on a Primary Kay
|
||||||
fn auto_increment() -> bool;
|
fn auto_increment() -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How to map a Primary Key to a column
|
||||||
pub trait PrimaryKeyToColumn {
|
pub trait PrimaryKeyToColumn {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type Column: ColumnTrait;
|
type Column: ColumnTrait;
|
||||||
|
|
||||||
|
/// Method to map a primary key to a column in an Entity
|
||||||
fn into_column(self) -> Self::Column;
|
fn into_column(self) -> Self::Column;
|
||||||
|
|
||||||
|
/// Method to map a primary key from a column in an Entity
|
||||||
fn from_column(col: Self::Column) -> Option<Self>
|
fn from_column(col: Self::Column) -> Option<Self>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
@ -3,45 +3,68 @@ use core::marker::PhantomData;
|
|||||||
use sea_query::{JoinType, TableRef};
|
use sea_query::{JoinType, TableRef};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
/// Defines the type of relationship
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum RelationType {
|
pub enum RelationType {
|
||||||
|
/// An Entity has one relationship
|
||||||
HasOne,
|
HasOne,
|
||||||
|
/// An Entity has many relationships
|
||||||
HasMany,
|
HasMany,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Action to perform on a foreign key whenever there are changes
|
||||||
|
/// to an ActiveModel
|
||||||
pub type ForeignKeyAction = sea_query::ForeignKeyAction;
|
pub type ForeignKeyAction = sea_query::ForeignKeyAction;
|
||||||
|
|
||||||
|
/// Constraints a type to implement the trait to create a relationship
|
||||||
pub trait RelationTrait: Iterable + Debug + 'static {
|
pub trait RelationTrait: Iterable + Debug + 'static {
|
||||||
|
/// The method to call
|
||||||
fn def(&self) -> RelationDef;
|
fn def(&self) -> RelationDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if Entities are related
|
||||||
pub trait Related<R>
|
pub trait Related<R>
|
||||||
where
|
where
|
||||||
R: EntityTrait,
|
R: EntityTrait,
|
||||||
{
|
{
|
||||||
|
/// Check if an entity is related to another entity
|
||||||
fn to() -> RelationDef;
|
fn to() -> RelationDef;
|
||||||
|
|
||||||
|
/// Check if an entity is related through another entity
|
||||||
fn via() -> Option<RelationDef> {
|
fn via() -> Option<RelationDef> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find related Entities
|
||||||
fn find_related() -> Select<R> {
|
fn find_related() -> Select<R> {
|
||||||
Select::<R>::new().join_join_rev(JoinType::InnerJoin, Self::to(), Self::via())
|
Select::<R>::new().join_join_rev(JoinType::InnerJoin, Self::to(), Self::via())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a relationship
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RelationDef {
|
pub struct RelationDef {
|
||||||
|
/// The type of relationship defined in [RelationType]
|
||||||
pub rel_type: RelationType,
|
pub rel_type: RelationType,
|
||||||
|
/// Reference from another Entity
|
||||||
pub from_tbl: TableRef,
|
pub from_tbl: TableRef,
|
||||||
|
/// Reference to another ENtity
|
||||||
pub to_tbl: TableRef,
|
pub to_tbl: TableRef,
|
||||||
|
/// Reference to from a Column
|
||||||
pub from_col: Identity,
|
pub from_col: Identity,
|
||||||
|
/// Reference to another column
|
||||||
pub to_col: Identity,
|
pub to_col: Identity,
|
||||||
|
/// Defines the owner of the Relation
|
||||||
pub is_owner: bool,
|
pub is_owner: bool,
|
||||||
|
/// Defines an operation to be performed on a Foreign Key when a
|
||||||
|
/// `DELETE` Operation is performed
|
||||||
pub on_delete: Option<ForeignKeyAction>,
|
pub on_delete: Option<ForeignKeyAction>,
|
||||||
|
/// Defines an operation to be performed on a Foreign Key when a
|
||||||
|
/// `UPDATE` Operation is performed
|
||||||
pub on_update: Option<ForeignKeyAction>,
|
pub on_update: Option<ForeignKeyAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a helper to build a relation
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RelationBuilder<E, R>
|
pub struct RelationBuilder<E, R>
|
||||||
where
|
where
|
||||||
@ -108,6 +131,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build a relationship from an Entity
|
||||||
pub fn from<T>(mut self, identifier: T) -> Self
|
pub fn from<T>(mut self, identifier: T) -> Self
|
||||||
where
|
where
|
||||||
T: IdentityOf<E>,
|
T: IdentityOf<E>,
|
||||||
@ -116,6 +140,7 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build a relationship to an Entity
|
||||||
pub fn to<T>(mut self, identifier: T) -> Self
|
pub fn to<T>(mut self, identifier: T) -> Self
|
||||||
where
|
where
|
||||||
T: IdentityOf<R>,
|
T: IdentityOf<R>,
|
||||||
@ -124,11 +149,13 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An operation to perform on a foreign key when a delete operation occurs
|
||||||
pub fn on_delete(mut self, action: ForeignKeyAction) -> Self {
|
pub fn on_delete(mut self, action: ForeignKeyAction) -> Self {
|
||||||
self.on_delete = Some(action);
|
self.on_delete = Some(action);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An operation to perform on a foreign key when an update operation occurs
|
||||||
pub fn on_update(mut self, action: ForeignKeyAction) -> Self {
|
pub fn on_update(mut self, action: ForeignKeyAction) -> Self {
|
||||||
self.on_update = Some(action);
|
self.on_update = Some(action);
|
||||||
self
|
self
|
||||||
|
18
src/error.rs
18
src/error.rs
@ -1,21 +1,16 @@
|
|||||||
/// Represents all the errors in SeaORM.
|
/// An error from unsuccessful database operations
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum DbErr {
|
pub enum DbErr {
|
||||||
/// Error occurred while connecting to database engine.
|
/// There was a problem with the database connection
|
||||||
Conn(String),
|
Conn(String),
|
||||||
|
/// An operation did not execute successfully
|
||||||
/// Error occurred while executing SQL statement.
|
|
||||||
Exec(String),
|
Exec(String),
|
||||||
|
/// An error occurred while performing a query
|
||||||
/// Error occurred while querying SQL statement.
|
|
||||||
Query(String),
|
Query(String),
|
||||||
|
/// The record was not found in the database
|
||||||
/// Error occurred while updating a non-existing row in database.
|
|
||||||
RecordNotFound(String),
|
RecordNotFound(String),
|
||||||
|
/// A custom error
|
||||||
/// Error occurred while performing custom validation logics in [ActiveModelBehavior](crate::ActiveModelBehavior)
|
|
||||||
Custom(String),
|
Custom(String),
|
||||||
|
|
||||||
/// Error occurred while parsing value into [ActiveEnum](crate::ActiveEnum)
|
/// Error occurred while parsing value into [ActiveEnum](crate::ActiveEnum)
|
||||||
Type(String),
|
Type(String),
|
||||||
}
|
}
|
||||||
@ -35,6 +30,7 @@ impl std::fmt::Display for DbErr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error from a failed column operation when trying to convert the column to a string
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ColumnFromStrErr(pub String);
|
pub struct ColumnFromStrErr(pub String);
|
||||||
|
|
||||||
|
@ -4,13 +4,16 @@ use crate::{
|
|||||||
use sea_query::DeleteStatement;
|
use sea_query::DeleteStatement;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
|
/// Handles DELETE operations in a ActiveModel using [DeleteStatement]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Deleter {
|
pub struct Deleter {
|
||||||
query: DeleteStatement,
|
query: DeleteStatement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of a DELETE operation
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteResult {
|
pub struct DeleteResult {
|
||||||
|
/// The number of rows affected by the DELETE operation
|
||||||
pub rows_affected: u64,
|
pub rows_affected: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,6 +21,7 @@ impl<'a, A: 'a> DeleteOne<A>
|
|||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
|
/// Execute a DELETE operation on one ActiveModel
|
||||||
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -31,6 +35,7 @@ impl<'a, E> DeleteMany<E>
|
|||||||
where
|
where
|
||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
{
|
{
|
||||||
|
/// Execute a DELETE operation on many ActiveModels
|
||||||
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -41,10 +46,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Deleter {
|
impl Deleter {
|
||||||
|
/// Instantiate a new [Deleter] by passing it a [DeleteStatement]
|
||||||
pub fn new(query: DeleteStatement) -> Self {
|
pub fn new(query: DeleteStatement) -> Self {
|
||||||
Self { query }
|
Self { query }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute a DELETE operation
|
||||||
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
|
@ -1,16 +1,24 @@
|
|||||||
|
/// Defines the result of executing an operation
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ExecResult {
|
pub struct ExecResult {
|
||||||
|
/// The type of result from the execution depending on the feature flag enabled
|
||||||
|
/// to choose a database backend
|
||||||
pub(crate) result: ExecResultHolder,
|
pub(crate) result: ExecResultHolder,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds a result depending on the database backend chosen by the feature flag
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum ExecResultHolder {
|
pub(crate) enum ExecResultHolder {
|
||||||
|
/// Holds the result of executing an operation on a MySQL database
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
SqlxMySql(sqlx::mysql::MySqlQueryResult),
|
SqlxMySql(sqlx::mysql::MySqlQueryResult),
|
||||||
|
/// Holds the result of executing an operation on a PostgreSQL database
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
SqlxPostgres(sqlx::postgres::PgQueryResult),
|
SqlxPostgres(sqlx::postgres::PgQueryResult),
|
||||||
|
/// Holds the result of executing an operation on a SQLite database
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
SqlxSqlite(sqlx::sqlite::SqliteQueryResult),
|
SqlxSqlite(sqlx::sqlite::SqliteQueryResult),
|
||||||
|
/// Holds the result of executing an operation on the Mock database
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
Mock(crate::MockExecResult),
|
Mock(crate::MockExecResult),
|
||||||
}
|
}
|
||||||
@ -18,6 +26,7 @@ pub(crate) enum ExecResultHolder {
|
|||||||
// ExecResult //
|
// ExecResult //
|
||||||
|
|
||||||
impl ExecResult {
|
impl ExecResult {
|
||||||
|
/// Get the last id after `AUTOINCREMENT` is done on the primary key
|
||||||
pub fn last_insert_id(&self) -> u64 {
|
pub fn last_insert_id(&self) -> u64 {
|
||||||
match &self.result {
|
match &self.result {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
@ -40,6 +49,7 @@ impl ExecResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the number of rows affedted by the operation
|
||||||
pub fn rows_affected(&self) -> u64 {
|
pub fn rows_affected(&self) -> u64 {
|
||||||
match &self.result {
|
match &self.result {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
|
@ -5,6 +5,7 @@ use crate::{
|
|||||||
use sea_query::{FromValueTuple, InsertStatement, ValueTuple};
|
use sea_query::{FromValueTuple, InsertStatement, ValueTuple};
|
||||||
use std::{future::Future, marker::PhantomData};
|
use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
|
/// Defines a structure to perform INSERT operations in an ActiveModel
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Inserter<A>
|
pub struct Inserter<A>
|
||||||
where
|
where
|
||||||
@ -15,11 +16,13 @@ where
|
|||||||
model: PhantomData<A>,
|
model: PhantomData<A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of an INSERT operation on an ActiveModel
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InsertResult<A>
|
pub struct InsertResult<A>
|
||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
|
/// The id performed when AUTOINCREMENT was performed on the PrimaryKey
|
||||||
pub last_insert_id: <<<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType,
|
pub last_insert_id: <<<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,6 +30,7 @@ impl<A> Insert<A>
|
|||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
|
/// Execute an insert operation
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + '_
|
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + '_
|
||||||
where
|
where
|
||||||
@ -53,6 +57,7 @@ impl<A> Inserter<A>
|
|||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
|
/// Instantiate a new insert operation
|
||||||
pub fn new(primary_key: Option<ValueTuple>, query: InsertStatement) -> Self {
|
pub fn new(primary_key: Option<ValueTuple>, query: InsertStatement) -> Self {
|
||||||
Self {
|
Self {
|
||||||
primary_key,
|
primary_key,
|
||||||
@ -61,6 +66,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute an insert operation
|
||||||
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + '_
|
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
|
@ -4,8 +4,10 @@ use futures::Stream;
|
|||||||
use sea_query::{Alias, Expr, SelectStatement};
|
use sea_query::{Alias, Expr, SelectStatement};
|
||||||
use std::{marker::PhantomData, pin::Pin};
|
use std::{marker::PhantomData, pin::Pin};
|
||||||
|
|
||||||
|
/// Pin a Model so that stream operations can be performed on the model
|
||||||
pub type PinBoxStream<'db, Item> = Pin<Box<dyn Stream<Item = Item> + 'db>>;
|
pub type PinBoxStream<'db, Item> = Pin<Box<dyn Stream<Item = Item> + 'db>>;
|
||||||
|
|
||||||
|
/// Defined a structure to handle pagination of a result from a query operation on a Model
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Paginator<'db, C, S>
|
pub struct Paginator<'db, C, S>
|
||||||
where
|
where
|
||||||
|
@ -3,6 +3,7 @@ use crate::debug_print;
|
|||||||
use crate::{DbErr, SelectGetableValue, SelectorRaw, Statement};
|
use crate::{DbErr, SelectGetableValue, SelectorRaw, Statement};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Defines the result of a query operation on a Model
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct QueryResult {
|
pub struct QueryResult {
|
||||||
pub(crate) row: QueryResultRow,
|
pub(crate) row: QueryResultRow,
|
||||||
@ -19,13 +20,18 @@ pub(crate) enum QueryResultRow {
|
|||||||
Mock(crate::MockRow),
|
Mock(crate::MockRow),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constrain any type trying to get a Row in a database
|
||||||
pub trait TryGetable: Sized {
|
pub trait TryGetable: Sized {
|
||||||
|
/// Ensure the type implements this method
|
||||||
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError>;
|
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error from trying to get a row from a Model
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TryGetError {
|
pub enum TryGetError {
|
||||||
|
/// A database error was encountered as defined in [crate::DbErr]
|
||||||
DbErr(DbErr),
|
DbErr(DbErr),
|
||||||
|
/// A null value was encountered
|
||||||
Null,
|
Null,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +47,7 @@ impl From<TryGetError> for DbErr {
|
|||||||
// QueryResult //
|
// QueryResult //
|
||||||
|
|
||||||
impl QueryResult {
|
impl QueryResult {
|
||||||
|
/// Get a Row from a Column
|
||||||
pub fn try_get<T>(&self, pre: &str, col: &str) -> Result<T, DbErr>
|
pub fn try_get<T>(&self, pre: &str, col: &str) -> Result<T, DbErr>
|
||||||
where
|
where
|
||||||
T: TryGetable,
|
T: TryGetable,
|
||||||
@ -48,6 +55,7 @@ impl QueryResult {
|
|||||||
Ok(T::try_get(self, pre, col)?)
|
Ok(T::try_get(self, pre, col)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform query operations on multiple Columns
|
||||||
pub fn try_get_many<T>(&self, pre: &str, cols: &[String]) -> Result<T, DbErr>
|
pub fn try_get_many<T>(&self, pre: &str, cols: &[String]) -> Result<T, DbErr>
|
||||||
where
|
where
|
||||||
T: TryGetableMany,
|
T: TryGetableMany,
|
||||||
@ -306,7 +314,9 @@ try_getable_all!(uuid::Uuid);
|
|||||||
|
|
||||||
// TryGetableMany //
|
// TryGetableMany //
|
||||||
|
|
||||||
|
/// Perform a query on multiple columns
|
||||||
pub trait TryGetableMany: Sized {
|
pub trait TryGetableMany: Sized {
|
||||||
|
/// THe method to perform a query on multiple columns
|
||||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
|
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
|
||||||
|
|
||||||
/// ```
|
/// ```
|
||||||
@ -453,8 +463,9 @@ fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), Try
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TryFromU64 //
|
// TryFromU64 //
|
||||||
|
/// Try to convert a type to a u64
|
||||||
pub trait TryFromU64: Sized {
|
pub trait TryFromU64: Sized {
|
||||||
|
/// The method to convert the type to a u64
|
||||||
fn try_from_u64(n: u64) -> Result<Self, DbErr>;
|
fn try_from_u64(n: u64) -> Result<Self, DbErr>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use std::pin::Pin;
|
|||||||
#[cfg(feature = "with-json")]
|
#[cfg(feature = "with-json")]
|
||||||
use crate::JsonValue;
|
use crate::JsonValue;
|
||||||
|
|
||||||
|
/// Defines a type to do `SELECT` operations though a [SelectStatement] on a Model
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Selector<S>
|
pub struct Selector<S>
|
||||||
where
|
where
|
||||||
@ -20,6 +21,7 @@ where
|
|||||||
selector: S,
|
selector: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a raw `SELECT` operation on a model
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SelectorRaw<S>
|
pub struct SelectorRaw<S>
|
||||||
where
|
where
|
||||||
@ -29,12 +31,16 @@ where
|
|||||||
selector: S,
|
selector: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to enforce constraints on any type that wants to perform SELECT queries
|
||||||
pub trait SelectorTrait {
|
pub trait SelectorTrait {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type Item: Sized;
|
type Item: Sized;
|
||||||
|
|
||||||
|
/// The method to perform a query on a Model
|
||||||
fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
|
fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform an operation on an entity that can yield a Value
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SelectGetableValue<T, C>
|
pub struct SelectGetableValue<T, C>
|
||||||
where
|
where
|
||||||
@ -45,6 +51,7 @@ where
|
|||||||
model: PhantomData<T>,
|
model: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a type to get a Model
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SelectModel<M>
|
pub struct SelectModel<M>
|
||||||
where
|
where
|
||||||
@ -53,6 +60,7 @@ where
|
|||||||
model: PhantomData<M>,
|
model: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a type to get two Modelss
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SelectTwoModel<M, N>
|
pub struct SelectTwoModel<M, N>
|
||||||
where
|
where
|
||||||
@ -105,6 +113,7 @@ impl<E> Select<E>
|
|||||||
where
|
where
|
||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
{
|
{
|
||||||
|
/// Perform a Select operation on a Model using a [Statement]
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw<SelectModel<E::Model>> {
|
pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw<SelectModel<E::Model>> {
|
||||||
SelectorRaw {
|
SelectorRaw {
|
||||||
@ -113,6 +122,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a [Selector] from `Self` that wraps a [SelectModel]
|
||||||
pub fn into_model<M>(self) -> Selector<SelectModel<M>>
|
pub fn into_model<M>(self) -> Selector<SelectModel<M>>
|
||||||
where
|
where
|
||||||
M: FromQueryResult,
|
M: FromQueryResult,
|
||||||
@ -123,6 +133,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a selectable Model as a [JsonValue] for SQL JSON operations
|
||||||
#[cfg(feature = "with-json")]
|
#[cfg(feature = "with-json")]
|
||||||
pub fn into_json(self) -> Selector<SelectModel<JsonValue>> {
|
pub fn into_json(self) -> Selector<SelectModel<JsonValue>> {
|
||||||
Selector {
|
Selector {
|
||||||
@ -239,6 +250,7 @@ where
|
|||||||
Selector::<SelectGetableValue<T, C>>::with_columns(self.query)
|
Selector::<SelectGetableValue<T, C>>::with_columns(self.query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get one Model from a SELECT operation
|
||||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
|
pub async fn one<'a, C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -246,6 +258,7 @@ where
|
|||||||
self.into_model().one(db).await
|
self.into_model().one(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all the Models from a SELECT operation
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -253,6 +266,7 @@ where
|
|||||||
self.into_model().all(db).await
|
self.into_model().all(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stream the results of a SELECT operation on a Model
|
||||||
pub async fn stream<'a: 'b, 'b, C>(
|
pub async fn stream<'a: 'b, 'b, C>(
|
||||||
self,
|
self,
|
||||||
db: &'a C,
|
db: &'a C,
|
||||||
@ -263,6 +277,7 @@ where
|
|||||||
self.into_model().stream(db).await
|
self.into_model().stream(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Paginate the results of a SELECT operation on a Model
|
||||||
pub fn paginate<'a, C>(
|
pub fn paginate<'a, C>(
|
||||||
self,
|
self,
|
||||||
db: &'a C,
|
db: &'a C,
|
||||||
@ -274,6 +289,7 @@ where
|
|||||||
self.into_model().paginate(db, page_size)
|
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>
|
pub async fn count<'a, C>(self, db: &'a C) -> Result<usize, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -287,6 +303,7 @@ where
|
|||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
F: EntityTrait,
|
F: EntityTrait,
|
||||||
{
|
{
|
||||||
|
/// Perform a conversion into a [SelectTwoModel]
|
||||||
pub fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
|
pub fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
|
||||||
where
|
where
|
||||||
M: FromQueryResult,
|
M: FromQueryResult,
|
||||||
@ -298,6 +315,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert the Models into JsonValue
|
||||||
#[cfg(feature = "with-json")]
|
#[cfg(feature = "with-json")]
|
||||||
pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
|
pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
|
||||||
Selector {
|
Selector {
|
||||||
@ -306,6 +324,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get one Model from a Select operation
|
||||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -313,6 +332,7 @@ where
|
|||||||
self.into_model().one(db).await
|
self.into_model().one(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all Models from a Select operation
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -320,6 +340,7 @@ where
|
|||||||
self.into_model().all(db).await
|
self.into_model().all(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stream the results of a Select operation on a Model
|
||||||
pub async fn stream<'a: 'b, 'b, C>(
|
pub async fn stream<'a: 'b, 'b, C>(
|
||||||
self,
|
self,
|
||||||
db: &'a C,
|
db: &'a C,
|
||||||
@ -330,6 +351,7 @@ where
|
|||||||
self.into_model().stream(db).await
|
self.into_model().stream(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Paginate the results of a select operation on two models
|
||||||
pub fn paginate<'a, C>(
|
pub fn paginate<'a, C>(
|
||||||
self,
|
self,
|
||||||
db: &'a C,
|
db: &'a C,
|
||||||
@ -341,6 +363,7 @@ where
|
|||||||
self.into_model().paginate(db, page_size)
|
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>
|
pub async fn count<'a, C>(self, db: &'a C) -> Result<usize, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -354,6 +377,7 @@ where
|
|||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
F: EntityTrait,
|
F: EntityTrait,
|
||||||
{
|
{
|
||||||
|
/// Performs a conversion to [Selector]
|
||||||
fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
|
fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
|
||||||
where
|
where
|
||||||
M: FromQueryResult,
|
M: FromQueryResult,
|
||||||
@ -365,6 +389,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert the results to JSON
|
||||||
#[cfg(feature = "with-json")]
|
#[cfg(feature = "with-json")]
|
||||||
pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
|
pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
|
||||||
Selector {
|
Selector {
|
||||||
@ -373,6 +398,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Select one Model
|
||||||
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
pub async fn one<'a, C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -380,6 +406,7 @@ where
|
|||||||
self.into_model().one(db).await
|
self.into_model().one(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stream the result of the operation
|
||||||
pub async fn stream<'a: 'b, 'b, C>(
|
pub async fn stream<'a: 'b, 'b, C>(
|
||||||
self,
|
self,
|
||||||
db: &'a C,
|
db: &'a C,
|
||||||
@ -390,6 +417,7 @@ where
|
|||||||
self.into_model().stream(db).await
|
self.into_model().stream(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all the Models from the select operation
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -428,6 +456,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a Model from a Select operation
|
||||||
pub async fn one<'a, C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
|
pub async fn one<'a, C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -441,6 +470,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all results from a Select operation
|
||||||
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
pub async fn all<'a, C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -454,6 +484,7 @@ where
|
|||||||
Ok(models)
|
Ok(models)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stream the results of the operation
|
||||||
pub async fn stream<'a: 'b, 'b, C>(
|
pub async fn stream<'a: 'b, 'b, C>(
|
||||||
self,
|
self,
|
||||||
db: &'a C,
|
db: &'a C,
|
||||||
@ -469,6 +500,7 @@ where
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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>
|
pub fn paginate<'a, C>(self, db: &'a C, page_size: usize) -> Paginator<'a, C, S>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -499,7 +531,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create `SelectorRaw` from Statment and columns. Executing this `SelectorRaw` will
|
/// Create `SelectorRaw` from Statement and columns. Executing this `SelectorRaw` will
|
||||||
/// return a type `T` which implement `TryGetableMany`.
|
/// return a type `T` which implement `TryGetableMany`.
|
||||||
pub fn with_columns<T, C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<T, C>>
|
pub fn with_columns<T, C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<T, C>>
|
||||||
where
|
where
|
||||||
|
@ -4,14 +4,17 @@ use crate::{
|
|||||||
use sea_query::UpdateStatement;
|
use sea_query::UpdateStatement;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
|
/// Defines an update operation
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Updater {
|
pub struct Updater {
|
||||||
query: UpdateStatement,
|
query: UpdateStatement,
|
||||||
check_record_exists: bool,
|
check_record_exists: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of an update operation on an ActiveModel
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct UpdateResult {
|
pub struct UpdateResult {
|
||||||
|
/// The rows affected by the update operation
|
||||||
pub rows_affected: u64,
|
pub rows_affected: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,6 +22,7 @@ impl<'a, A: 'a> UpdateOne<A>
|
|||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
|
/// Execute an update operation on an ActiveModel
|
||||||
pub async fn exec<'b, C>(self, db: &'b C) -> Result<A, DbErr>
|
pub async fn exec<'b, C>(self, db: &'b C) -> Result<A, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'b>,
|
C: ConnectionTrait<'b>,
|
||||||
@ -32,6 +36,7 @@ impl<'a, E> UpdateMany<E>
|
|||||||
where
|
where
|
||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
{
|
{
|
||||||
|
/// Execute an update operation on multiple ActiveModels
|
||||||
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_
|
pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
@ -42,6 +47,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Updater {
|
impl Updater {
|
||||||
|
/// Instantiate an update using an [UpdateStatement]
|
||||||
pub fn new(query: UpdateStatement) -> Self {
|
pub fn new(query: UpdateStatement) -> Self {
|
||||||
Self {
|
Self {
|
||||||
query,
|
query,
|
||||||
@ -49,11 +55,13 @@ impl Updater {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a record exists on the ActiveModel to perform the update operation on
|
||||||
pub fn check_record_exists(mut self) -> Self {
|
pub fn check_record_exists(mut self) -> Self {
|
||||||
self.check_record_exists = true;
|
self.check_record_exists = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute an update operation
|
||||||
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_
|
pub fn exec<'a, C>(self, db: &'a C) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
|
@ -266,10 +266,15 @@
|
|||||||
mod database;
|
mod database;
|
||||||
mod docs;
|
mod docs;
|
||||||
mod driver;
|
mod driver;
|
||||||
|
/// Module for the Entity type and operations
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
|
/// Error types for all database operations
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
/// This module performs execution of queries on a Model or ActiveModel
|
||||||
mod executor;
|
mod executor;
|
||||||
|
/// Holds types and methods to perform queries
|
||||||
pub mod query;
|
pub mod query;
|
||||||
|
/// Holds types that defines the schemas of an Entity
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[cfg(feature = "macros")]
|
#[cfg(feature = "macros")]
|
||||||
|
@ -7,6 +7,7 @@ use sea_query::{Alias, ColumnRef, Iden, Order, SeaRc, SelectExpr, SelectStatemen
|
|||||||
|
|
||||||
macro_rules! select_def {
|
macro_rules! select_def {
|
||||||
( $ident: ident, $str: expr ) => {
|
( $ident: ident, $str: expr ) => {
|
||||||
|
/// Implements the traits [Iden] and [IdenStatic] for a type
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct $ident;
|
pub struct $ident;
|
||||||
|
|
||||||
@ -54,6 +55,7 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Selects and Entity and returns it together with the Entity from `Self`
|
||||||
pub fn select_also<F>(mut self, _: F) -> SelectTwo<E, F>
|
pub fn select_also<F>(mut self, _: F) -> SelectTwo<E, F>
|
||||||
where
|
where
|
||||||
F: EntityTrait,
|
F: EntityTrait,
|
||||||
@ -62,6 +64,7 @@ where
|
|||||||
SelectTwo::new(self.into_query())
|
SelectTwo::new(self.into_query())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a SELECT operation in conjunction to another relation
|
||||||
pub fn select_with<F>(mut self, _: F) -> SelectTwoMany<E, F>
|
pub fn select_with<F>(mut self, _: F) -> SelectTwoMany<E, F>
|
||||||
where
|
where
|
||||||
F: EntityTrait,
|
F: EntityTrait,
|
||||||
|
@ -5,9 +5,11 @@ use crate::{
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use sea_query::{DeleteStatement, IntoIden};
|
use sea_query::{DeleteStatement, IntoIden};
|
||||||
|
|
||||||
|
/// Defines the structure for a delete operation
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Delete;
|
pub struct Delete;
|
||||||
|
|
||||||
|
/// Perform a delete operation on a model
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteOne<A>
|
pub struct DeleteOne<A>
|
||||||
where
|
where
|
||||||
@ -17,6 +19,7 @@ where
|
|||||||
pub(crate) model: A,
|
pub(crate) model: A,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform a delete operation on multiple models
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteMany<E>
|
pub struct DeleteMany<E>
|
||||||
where
|
where
|
||||||
|
@ -11,9 +11,12 @@ pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, O
|
|||||||
// LINT: when the column does not appear in tables selected from
|
// LINT: when the column does not appear in tables selected from
|
||||||
// LINT: when there is a group by clause, but some columns don't have aggregate functions
|
// LINT: when there is a group by clause, but some columns don't have aggregate functions
|
||||||
// LINT: when the join table or column does not exists
|
// LINT: when the join table or column does not exists
|
||||||
|
/// Constraints for any type that needs to perform select statements on a Model
|
||||||
pub trait QuerySelect: Sized {
|
pub trait QuerySelect: Sized {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type QueryStatement;
|
type QueryStatement;
|
||||||
|
|
||||||
|
/// Add the select SQL statement
|
||||||
fn query(&mut self) -> &mut SelectStatement;
|
fn query(&mut self) -> &mut SelectStatement;
|
||||||
|
|
||||||
/// Clear the selection list
|
/// Clear the selection list
|
||||||
@ -164,9 +167,12 @@ pub trait QuerySelect: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LINT: when the column does not appear in tables selected from
|
// LINT: when the column does not appear in tables selected from
|
||||||
|
/// Performs ORDER BY operations
|
||||||
pub trait QueryOrder: Sized {
|
pub trait QueryOrder: Sized {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type QueryStatement: OrderedStatement;
|
type QueryStatement: OrderedStatement;
|
||||||
|
|
||||||
|
/// Add the query to perform an ORDER BY operation
|
||||||
fn query(&mut self) -> &mut SelectStatement;
|
fn query(&mut self) -> &mut SelectStatement;
|
||||||
|
|
||||||
/// Add an order_by expression
|
/// Add an order_by expression
|
||||||
@ -234,9 +240,12 @@ pub trait QueryOrder: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LINT: when the column does not appear in tables selected from
|
// LINT: when the column does not appear in tables selected from
|
||||||
|
/// Perform a FILTER opertation on a statement
|
||||||
pub trait QueryFilter: Sized {
|
pub trait QueryFilter: Sized {
|
||||||
|
#[allow(missing_docs)]
|
||||||
type QueryStatement: ConditionalStatement;
|
type QueryStatement: ConditionalStatement;
|
||||||
|
|
||||||
|
/// Add the query to perform a FILTER on
|
||||||
fn query(&mut self) -> &mut Self::QueryStatement;
|
fn query(&mut self) -> &mut Self::QueryStatement;
|
||||||
|
|
||||||
/// Add an AND WHERE expression
|
/// Add an AND WHERE expression
|
||||||
@ -372,6 +381,7 @@ pub trait QueryFilter: Sized {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform a check to determine table belongs to a Model through it's name alias
|
||||||
fn belongs_to_tbl_alias<M>(mut self, model: &M, tbl_alias: &str) -> Self
|
fn belongs_to_tbl_alias<M>(mut self, model: &M, tbl_alias: &str) -> Self
|
||||||
where
|
where
|
||||||
M: ModelTrait,
|
M: ModelTrait,
|
||||||
|
@ -5,6 +5,7 @@ use crate::{
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use sea_query::{Alias, Expr, InsertStatement, ValueTuple};
|
use sea_query::{Alias, Expr, InsertStatement, ValueTuple};
|
||||||
|
|
||||||
|
/// Performs INSERT operations on a ActiveModel
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Insert<A>
|
pub struct Insert<A>
|
||||||
where
|
where
|
||||||
@ -106,6 +107,7 @@ where
|
|||||||
Self::new().add_many(models)
|
Self::new().add_many(models)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a Model to Self
|
||||||
#[allow(clippy::should_implement_trait)]
|
#[allow(clippy::should_implement_trait)]
|
||||||
pub fn add<M>(mut self, m: M) -> Self
|
pub fn add<M>(mut self, m: M) -> Self
|
||||||
where
|
where
|
||||||
@ -144,6 +146,7 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add many Models to Self
|
||||||
pub fn add_many<M, I>(mut self, models: I) -> Self
|
pub fn add_many<M, I>(mut self, models: I) -> Self
|
||||||
where
|
where
|
||||||
M: IntoActiveModel<A>,
|
M: IntoActiveModel<A>,
|
||||||
|
@ -4,6 +4,7 @@ use core::marker::PhantomData;
|
|||||||
pub use sea_query::JoinType;
|
pub use sea_query::JoinType;
|
||||||
use sea_query::{Alias, DynIden, Expr, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr};
|
use sea_query::{Alias, DynIden, Expr, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr};
|
||||||
|
|
||||||
|
/// Defines a structure to perform select operations
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Select<E>
|
pub struct Select<E>
|
||||||
where
|
where
|
||||||
@ -13,6 +14,7 @@ where
|
|||||||
pub(crate) entity: PhantomData<E>,
|
pub(crate) entity: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a structure to perform a SELECT operation on two Models
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SelectTwo<E, F>
|
pub struct SelectTwo<E, F>
|
||||||
where
|
where
|
||||||
@ -23,6 +25,7 @@ where
|
|||||||
pub(crate) entity: PhantomData<(E, F)>,
|
pub(crate) entity: PhantomData<(E, F)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a structure to perform a SELECT operation on many Models
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SelectTwoMany<E, F>
|
pub struct SelectTwoMany<E, F>
|
||||||
where
|
where
|
||||||
@ -33,7 +36,9 @@ where
|
|||||||
pub(crate) entity: PhantomData<(E, F)>,
|
pub(crate) entity: PhantomData<(E, F)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a conversion to [SimpleExpr]
|
||||||
pub trait IntoSimpleExpr {
|
pub trait IntoSimpleExpr {
|
||||||
|
/// Method to perform the conversion
|
||||||
fn into_simple_expr(self) -> SimpleExpr;
|
fn into_simple_expr(self) -> SimpleExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::{DbBackend, Statement};
|
use crate::{DbBackend, Statement};
|
||||||
use sea_query::QueryStatementBuilder;
|
use sea_query::QueryStatementBuilder;
|
||||||
|
|
||||||
|
/// Enforces a set of constraints to any type performing queries on a Model or ActiveModel
|
||||||
pub trait QueryTrait {
|
pub trait QueryTrait {
|
||||||
|
/// Constrain the QueryStatement to [QueryStatementBuilder] trait
|
||||||
type QueryStatement: QueryStatementBuilder;
|
type QueryStatement: QueryStatementBuilder;
|
||||||
|
|
||||||
/// Get a mutable ref to the query builder
|
/// Get a mutable ref to the query builder
|
||||||
|
@ -5,9 +5,11 @@ use crate::{
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use sea_query::{Alias, Expr, IntoIden, SimpleExpr, UpdateStatement};
|
use sea_query::{Alias, Expr, IntoIden, SimpleExpr, UpdateStatement};
|
||||||
|
|
||||||
|
/// Defines a structure to perform UPDATE query operations on a ActiveModel
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Update;
|
pub struct Update;
|
||||||
|
|
||||||
|
/// Defines an UPDATE operation on one ActiveModel
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct UpdateOne<A>
|
pub struct UpdateOne<A>
|
||||||
where
|
where
|
||||||
@ -17,6 +19,7 @@ where
|
|||||||
pub(crate) model: A,
|
pub(crate) model: A,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines an UPDATE operation on multiple ActiveModels
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct UpdateMany<E>
|
pub struct UpdateMany<E>
|
||||||
where
|
where
|
||||||
@ -182,6 +185,7 @@ impl<E> UpdateMany<E>
|
|||||||
where
|
where
|
||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
{
|
{
|
||||||
|
/// Add the models to update to Self
|
||||||
pub fn set<A>(mut self, model: A) -> Self
|
pub fn set<A>(mut self, model: A) -> Self
|
||||||
where
|
where
|
||||||
A: ActiveModelTrait<Entity = E>,
|
A: ActiveModelTrait<Entity = E>,
|
||||||
@ -195,6 +199,7 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a [SimpleExpr] from a column
|
||||||
pub fn col_expr<T>(mut self, col: T, expr: SimpleExpr) -> Self
|
pub fn col_expr<T>(mut self, col: T, expr: SimpleExpr) -> Self
|
||||||
where
|
where
|
||||||
T: IntoIden,
|
T: IntoIden,
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
use crate::{database::*, QueryTrait, Statement};
|
use crate::{database::*, QueryTrait, Statement};
|
||||||
|
|
||||||
|
/// This structure provides debug capabilities
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DebugQuery<'a, Q, T> {
|
pub struct DebugQuery<'a, Q, T> {
|
||||||
|
/// The query to debug
|
||||||
pub query: &'a Q,
|
pub query: &'a Q,
|
||||||
|
/// The value of the query
|
||||||
pub value: T,
|
pub value: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,6 +15,7 @@ macro_rules! debug_query_build {
|
|||||||
where
|
where
|
||||||
Q: QueryTrait,
|
Q: QueryTrait,
|
||||||
{
|
{
|
||||||
|
/// This macro builds a [Statement] when invoked
|
||||||
pub fn build(&self) -> Statement {
|
pub fn build(&self) -> Statement {
|
||||||
let func = $db_expr;
|
let func = $db_expr;
|
||||||
let db_backend = func(self);
|
let db_backend = func(self);
|
||||||
|
@ -8,6 +8,7 @@ use sea_query::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
impl Schema {
|
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>(entity: E, db_backend: DbBackend) -> Vec<TypeCreateStatement>
|
||||||
where
|
where
|
||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
@ -15,6 +16,7 @@ impl Schema {
|
|||||||
create_enum_from_entity(entity, db_backend)
|
create_enum_from_entity(entity, db_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>(entity: E, db_backend: DbBackend) -> TableCreateStatement
|
||||||
where
|
where
|
||||||
E: EntityTrait,
|
E: EntityTrait,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
mod entity;
|
mod entity;
|
||||||
|
|
||||||
|
/// This structure defines a schema for a table
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Schema;
|
pub struct Schema;
|
||||||
|
16
src/util.rs
16
src/util.rs
@ -1,3 +1,17 @@
|
|||||||
|
/// Uses the `log` crate to perform logging.
|
||||||
|
/// This must be enabled using the feature flag `debug-print`.
|
||||||
|
/// ### Usage
|
||||||
|
/// ```
|
||||||
|
/// use sea_orm::debug_print;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug)]
|
||||||
|
/// enum FooError {
|
||||||
|
/// Bar,
|
||||||
|
/// Baz,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// debug_print!("{:?}", FooError::Bar);
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[cfg(feature = "debug-print")]
|
#[cfg(feature = "debug-print")]
|
||||||
macro_rules! debug_print {
|
macro_rules! debug_print {
|
||||||
@ -5,7 +19,7 @@ macro_rules! debug_print {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
// Non-debug version
|
/// Non-debug version
|
||||||
#[cfg(not(feature = "debug-print"))]
|
#[cfg(not(feature = "debug-print"))]
|
||||||
macro_rules! debug_print {
|
macro_rules! debug_print {
|
||||||
($( $args:expr ),*) => {
|
($( $args:expr ),*) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user