diff --git a/sea-orm-macros/Cargo.toml b/sea-orm-macros/Cargo.toml index 453c1441..c62a0633 100644 --- a/sea-orm-macros/Cargo.toml +++ b/sea-orm-macros/Cargo.toml @@ -21,3 +21,7 @@ syn = { version = "^1", default-features = false, features = [ "full", "derive", quote = "^1" heck = "^0.3" proc-macro2 = "^1" + +[dev-dependencies] +sea-orm = { path = "../", features = ["macros"] } +serde = { version = "^1.0", features = ["derive"] } diff --git a/sea-orm-macros/src/attributes.rs b/sea-orm-macros/src/attributes.rs index fbfa0778..3f479bb9 100644 --- a/sea-orm-macros/src/attributes.rs +++ b/sea-orm-macros/src/attributes.rs @@ -1,6 +1,7 @@ pub mod derive_attr { use bae::FromAttributes; + /// Attributes for Models and ActiveModels #[derive(Default, FromAttributes)] pub struct SeaOrm { pub column: Option, @@ -16,6 +17,7 @@ pub mod derive_attr { pub mod field_attr { use bae::FromAttributes; + /// Operations for Models and ActiveModels #[derive(Default, FromAttributes)] pub struct SeaOrm { pub belongs_to: Option, diff --git a/sea-orm-macros/src/derives/active_model.rs b/sea-orm-macros/src/derives/active_model.rs index add31f20..d691a724 100644 --- a/sea-orm-macros/src/derives/active_model.rs +++ b/sea-orm-macros/src/derives/active_model.rs @@ -4,6 +4,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, quote_spanned}; 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 { let fields = match data { Data::Struct(DataStruct { diff --git a/sea-orm-macros/src/derives/active_model_behavior.rs b/sea-orm-macros/src/derives/active_model_behavior.rs index 7ae9d375..0ff02f34 100644 --- a/sea-orm-macros/src/derives/active_model_behavior.rs +++ b/sea-orm-macros/src/derives/active_model_behavior.rs @@ -2,6 +2,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; 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 { Ok(quote!( #[automatically_derived] diff --git a/sea-orm-macros/src/derives/column.rs b/sea-orm-macros/src/derives/column.rs index 7446340e..8e60c560 100644 --- a/sea-orm-macros/src/derives/column.rs +++ b/sea-orm-macros/src/derives/column.rs @@ -3,6 +3,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{quote, quote_spanned}; 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 { let variants = match data { syn::Data::Enum(DataEnum { variants, .. }) => variants, @@ -65,6 +66,7 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result syn::Result { let data_enum = match data { Data::Enum(data_enum) => data_enum, @@ -114,6 +116,7 @@ pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result syn::Result { let impl_default_as_str = impl_default_as_str(ident, data)?; let impl_col_from_str = impl_col_from_str(ident, data)?; diff --git a/sea-orm-macros/src/derives/entity_model.rs b/sea-orm-macros/src/derives/entity_model.rs index 54d00149..5f1508ef 100644 --- a/sea-orm-macros/src/derives/entity_model.rs +++ b/sea-orm-macros/src/derives/entity_model.rs @@ -7,6 +7,7 @@ use syn::{ Lit, Meta, }; +/// Method to derive an Model pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Result { // if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct let mut table_name = None; diff --git a/sea-orm-macros/src/derives/from_query_result.rs b/sea-orm-macros/src/derives/from_query_result.rs index fcef9da3..dc6bbc44 100644 --- a/sea-orm-macros/src/derives/from_query_result.rs +++ b/sea-orm-macros/src/derives/from_query_result.rs @@ -2,6 +2,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, quote_spanned}; 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 { let fields = match data { Data::Struct(DataStruct { diff --git a/sea-orm-macros/src/derives/into_active_model.rs b/sea-orm-macros/src/derives/into_active_model.rs index 3d95e927..2f7dc3f2 100644 --- a/sea-orm-macros/src/derives/into_active_model.rs +++ b/sea-orm-macros/src/derives/into_active_model.rs @@ -2,6 +2,7 @@ use bae::FromAttributes; use proc_macro2::{Span, TokenStream}; use quote::{quote, quote_spanned}; +/// Attributes to derive an ActiveModel #[derive(Default, FromAttributes)] pub struct SeaOrm { pub active_model: Option, @@ -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 { let ident_span = input.ident.span(); diff --git a/sea-orm-macros/src/derives/model.rs b/sea-orm-macros/src/derives/model.rs index 85d690f2..97ca66a8 100644 --- a/sea-orm-macros/src/derives/model.rs +++ b/sea-orm-macros/src/derives/model.rs @@ -183,6 +183,7 @@ impl DeriveModel { } } +/// Method to derive an ActiveModel pub fn expand_derive_model(input: syn::DeriveInput) -> syn::Result { let ident_span = input.ident.span(); diff --git a/sea-orm-macros/src/derives/primary_key.rs b/sea-orm-macros/src/derives/primary_key.rs index f699749f..13c7b5ab 100644 --- a/sea-orm-macros/src/derives/primary_key.rs +++ b/sea-orm-macros/src/derives/primary_key.rs @@ -3,6 +3,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{quote, quote_spanned}; 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 { let variants = match data { syn::Data::Enum(DataEnum { variants, .. }) => variants, diff --git a/sea-orm-macros/src/derives/relation.rs b/sea-orm-macros/src/derives/relation.rs index 4304ab21..ee4f332c 100644 --- a/sea-orm-macros/src/derives/relation.rs +++ b/sea-orm-macros/src/derives/relation.rs @@ -166,6 +166,7 @@ impl DeriveRelation { } } +/// Method to derive a Relation pub fn expand_derive_relation(input: syn::DeriveInput) -> syn::Result { let ident_span = input.ident.span(); diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index f8503756..1db680b0 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -7,6 +7,69 @@ mod attributes; mod derives; 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))] pub fn derive_entity(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -15,6 +78,36 @@ pub fn derive_entity(input: TokenStream) -> TokenStream { .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))] pub fn derive_entity_model(input: TokenStream) -> TokenStream { let input_ts = input.clone(); @@ -36,6 +129,72 @@ pub fn derive_entity_model(input: TokenStream) -> TokenStream { 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)] pub fn derive_primary_key(input: TokenStream) -> TokenStream { 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))] pub fn derive_column(input: TokenStream) -> TokenStream { 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)] pub fn derive_custom_column(input: TokenStream) -> TokenStream { 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))] pub fn derive_model(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -74,6 +336,70 @@ pub fn derive_model(input: TokenStream) -> TokenStream { .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))] pub fn derive_active_model(input: TokenStream) -> TokenStream { 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))] pub fn derive_into_active_model(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -92,6 +419,69 @@ pub fn derive_into_active_model(input: TokenStream) -> TokenStream { .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)] pub fn derive_active_model_behavior(input: TokenStream) -> TokenStream { 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)] pub fn derive_from_query_result(input: TokenStream) -> TokenStream { 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))] pub fn derive_relation(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); diff --git a/src/database/connection.rs b/src/database/connection.rs index d90c72a9..be47f9da 100644 --- a/src/database/connection.rs +++ b/src/database/connection.rs @@ -4,23 +4,34 @@ use crate::{ use futures::Stream; 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] pub trait ConnectionTrait<'a>: Sync { + /// Create a stream for the [QueryResult] type Stream: Stream>; + /// Fetch the database backend as specified in [DbBackend]. + /// This depends on feature flags enabled. fn get_database_backend(&self) -> DbBackend; + /// Execute a [Statement] async fn execute(&self, stmt: Statement) -> Result; + /// Execute a [Statement] and return a query async fn query_one(&self, stmt: Statement) -> Result, DbErr>; + /// Execute a [Statement] and return a collection Vec<[QueryResult]> on success async fn query_all(&self, stmt: Statement) -> Result, DbErr>; + /// Execute a [Statement] and return a stream of results fn stream( &'a self, stmt: Statement, ) -> Pin> + 'a>>; + /// Execute SQL `BEGIN` transaction. + /// Returns a Transaction that can be committed or rolled back async fn begin(&self) -> Result; /// Execute the function inside a transaction. @@ -34,6 +45,7 @@ pub trait ConnectionTrait<'a>: Sync { T: Send, E: std::error::Error + Send; + /// Check if the connection is a test connection for the Mock database fn is_mock_connection(&self) -> bool { false } diff --git a/src/database/db_connection.rs b/src/database/db_connection.rs index 6b8e3356..681903dd 100644 --- a/src/database/db_connection.rs +++ b/src/database/db_connection.rs @@ -12,30 +12,43 @@ use sqlx::pool::PoolConnection; #[cfg(feature = "mock")] 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))] pub enum DatabaseConnection { + /// Create a MYSQL database connection and pool #[cfg(feature = "sqlx-mysql")] SqlxMySqlPoolConnection(crate::SqlxMySqlPoolConnection), + /// Create a PostgreSQL database connection and pool #[cfg(feature = "sqlx-postgres")] SqlxPostgresPoolConnection(crate::SqlxPostgresPoolConnection), + /// Create a SQLite database connection and pool #[cfg(feature = "sqlx-sqlite")] SqlxSqlitePoolConnection(crate::SqlxSqlitePoolConnection), + /// Create a Mock database connection useful for testing #[cfg(feature = "mock")] MockDatabaseConnection(Arc), + /// The connection to the database has been severed Disconnected, } +/// The same as a [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)] pub enum DatabaseBackend { + /// A MySQL backend MySql, + /// A PostgreSQL backend Postgres, + /// A SQLite backend Sqlite, } +/// The same as [DatabaseBackend] just shorter :) pub type DbBackend = DatabaseBackend; - pub(crate) enum InnerConnection { #[cfg(feature = "sqlx-mysql")] MySql(PoolConnection), @@ -209,6 +222,7 @@ impl<'a> ConnectionTrait<'a> for DatabaseConnection { #[cfg(feature = "mock")] impl DatabaseConnection { + /// Generate a database connection for testing the Mock database pub fn as_mock_connection(&self) -> &crate::MockDatabaseConnection { match self { 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 { let mut mocker = self.as_mock_connection().get_mocker_mutex().lock().unwrap(); mocker.drain_transaction_log() @@ -223,6 +238,8 @@ impl DatabaseConnection { } 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 { let base_url_parsed = Url::parse(base_url).unwrap(); match self { @@ -234,6 +251,7 @@ impl DbBackend { } } + /// Build an SQL [Statement] pub fn build(&self, statement: &S) -> Statement where S: StatementBuilder, @@ -241,6 +259,7 @@ impl DbBackend { statement.build(self) } + /// A helper for building SQL queries pub fn get_query_builder(&self) -> Box { match self { Self::MySql => Box::new(MysqlQueryBuilder), diff --git a/src/database/mock.rs b/src/database/mock.rs index 44522944..74ffd8bf 100644 --- a/src/database/mock.rs +++ b/src/database/mock.rs @@ -6,6 +6,7 @@ use crate::{ use sea_query::{Value, ValueType, Values}; use std::{collections::BTreeMap, sync::Arc}; +/// Defines a Mock database suitable for testing #[derive(Debug)] pub struct MockDatabase { db_backend: DbBackend, @@ -15,33 +16,44 @@ pub struct MockDatabase { query_results: Vec>, } +/// Defines the results obtained from a [MockDatabase] #[derive(Clone, Debug, Default)] pub struct MockExecResult { + /// The last inserted id on auto-increment pub last_insert_id: u64, + /// The number of rows affected by the database operation pub rows_affected: u64, } +/// Defines the structure of a test Row for the [MockDatabase] +/// which is just a [BTreeMap]<[String], [Value]> #[derive(Clone, Debug)] pub struct MockRow { values: BTreeMap, } +/// A trait to get a [MockRow] from a type useful for testing in the [MockDatabase] pub trait IntoMockRow { + /// The method to perform this operation fn into_mock_row(self) -> MockRow; } +/// Defines a transaction that is has not been committed #[derive(Debug)] pub struct OpenTransaction { stmts: Vec, transaction_depth: usize, } +/// Defines a database transaction as it holds a Vec<[Statement]> #[derive(Debug, Clone, PartialEq)] pub struct Transaction { stmts: Vec, } impl MockDatabase { + /// Instantiate a mock database with a [DbBackend] to simulate real + /// world SQL databases pub fn new(db_backend: DbBackend) -> Self { Self { db_backend, @@ -52,15 +64,18 @@ impl MockDatabase { } } + /// Create a database connection pub fn into_connection(self) -> DatabaseConnection { 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) -> Self { self.exec_results.append(&mut vec); self } + /// Add the [MockExecResult]s to the `exec_results` field for `Self` pub fn append_query_results(mut self, vec: Vec>) -> Self where T: IntoMockRow, @@ -150,6 +165,7 @@ impl MockDatabaseTrait for MockDatabase { } impl MockRow { + /// Try to get the values of a [MockRow] and fail gracefully on error pub fn try_get(&self, col: &str) -> Result where 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())) } + /// An iterator over the keys and values of a mock row pub fn into_column_value_tuples(self) -> impl Iterator { self.values.into_iter() } @@ -190,6 +207,7 @@ impl IntoMockRow for BTreeMap<&str, Value> { } impl Transaction { + /// Get the [Value]s from s raw SQL statement depending on the [DatabaseBackend](crate::DatabaseBackend) pub fn from_sql_and_values(db_backend: DbBackend, sql: &str, values: I) -> Self where I: IntoIterator, diff --git a/src/database/mod.rs b/src/database/mod.rs index 6a06a48c..351679d6 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -18,20 +18,30 @@ pub use transaction::*; use crate::DbErr; +/// Defines a database #[derive(Debug, Default)] pub struct Database; +/// Defines the configuration options of a database #[derive(Debug)] pub struct ConnectOptions { + /// The URI of the database pub(crate) url: String, + /// Maximum number of connections for a pool pub(crate) max_connections: Option, + /// Minimum number of connections for a pool pub(crate) min_connections: Option, + /// The connection timeout for a packet connection pub(crate) connect_timeout: Option, + /// Maximum idle time for a particular connection to prevent + /// network resource exhaustion pub(crate) idle_timeout: Option, + /// Enables or disables logging pub(crate) sqlx_logging: bool, } impl Database { + /// Method to create a [DatabaseConnection] on a database pub async fn connect(opt: C) -> Result where C: Into, @@ -80,6 +90,7 @@ impl From for ConnectOptions { } impl ConnectOptions { + /// Create new [ConnectOptions] for a [Database] by passing in a URI string pub fn new(url: String) -> Self { Self { url, @@ -122,21 +133,41 @@ impl ConnectOptions { self } + /// Get the maximum number of connections of the pool, if set + pub fn get_max_connections(&self) -> Option { + self.max_connections + } + /// Set the minimum number of connections of the pool pub fn min_connections(&mut self, value: u32) -> &mut Self { self.min_connections = Some(value); self } + /// Get the minimum number of connections of the pool, if set + pub fn get_min_connections(&self) -> Option { + self.min_connections + } + /// Set the timeout duration when acquiring a connection pub fn connect_timeout(&mut self, value: Duration) -> &mut Self { self.connect_timeout = Some(value); self } + /// Get the timeout duration when acquiring a connection, if set + pub fn get_connect_timeout(&self) -> Option { + self.connect_timeout + } + /// Set the idle duration before closing a connection pub fn idle_timeout(&mut self, value: Duration) -> &mut Self { self.idle_timeout = Some(value); self } + + /// Get the idle duration before closing a connection, if set + pub fn get_idle_timeout(&self) -> Option { + self.idle_timeout + } } diff --git a/src/database/statement.rs b/src/database/statement.rs index 86d7c630..ce911295 100644 --- a/src/database/statement.rs +++ b/src/database/statement.rs @@ -3,18 +3,25 @@ use sea_query::{inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, Sqli pub use sea_query::{Value, Values}; use std::fmt; +/// Defines an SQL statement #[derive(Debug, Clone, PartialEq)] pub struct Statement { + /// The SQL query pub sql: String, + /// The values for the SQL statement pub values: Option, + /// The database backend to use pub db_backend: DbBackend, } +/// Constraints for building a [Statement] pub trait StatementBuilder { + /// Method to call in order to build a [Statement] fn build(&self, db_backend: &DbBackend) -> 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 { Statement { 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(db_backend: DbBackend, sql: &str, values: I) -> Self where I: IntoIterator, diff --git a/src/database/stream/query.rs b/src/database/stream/query.rs index 8383659a..03a0fc6e 100644 --- a/src/database/stream/query.rs +++ b/src/database/stream/query.rs @@ -12,6 +12,7 @@ use sqlx::{pool::PoolConnection, Executor}; use crate::{DbErr, InnerConnection, QueryResult, Statement}; +/// Creates a stream from a [QueryResult] #[ouroboros::self_referencing] pub struct QueryStream { stmt: Statement, diff --git a/src/database/transaction.rs b/src/database/transaction.rs index d7bbc058..f4a1b678 100644 --- a/src/database/transaction.rs +++ b/src/database/transaction.rs @@ -10,6 +10,8 @@ use sqlx::{pool::PoolConnection, TransactionManager}; use std::{future::Future, pin::Pin, sync::Arc}; // 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 { conn: Arc>, backend: DbBackend, @@ -100,6 +102,8 @@ impl DatabaseTransaction { 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(self, callback: F) -> Result> where F: for<'b> FnOnce( @@ -120,6 +124,7 @@ impl DatabaseTransaction { res } + /// Commit a transaction atomically pub async fn commit(mut self) -> Result<(), DbErr> { self.open = false; match *self.conn.lock().await { @@ -149,6 +154,7 @@ impl DatabaseTransaction { Ok(()) } + /// rolls back a transaction in case error are encountered during the operation pub async fn rollback(mut self) -> Result<(), DbErr> { self.open = false; match *self.conn.lock().await { @@ -343,12 +349,15 @@ impl<'a> ConnectionTrait<'a> for DatabaseTransaction { } } +/// Defines errors for handling transaction failures #[derive(Debug)] pub enum TransactionError where E: std::error::Error, { + /// A Database connection error Connection(DbErr), + /// An error occurring when doing database transactions Transaction(E), } diff --git a/src/driver/mock.rs b/src/driver/mock.rs index ad0c35cf..3f271759 100644 --- a/src/driver/mock.rs +++ b/src/driver/mock.rs @@ -12,32 +12,43 @@ use std::{ }, }; +/// Defines a database driver for the [MockDatabase] #[derive(Debug)] pub struct MockDatabaseConnector; +/// Defines a connection for the [MockDatabase] #[derive(Debug)] pub struct MockDatabaseConnection { counter: AtomicUsize, mocker: Mutex>, } +/// A set of constraints for any type wanting to perform operations on the [MockDatabase] pub trait MockDatabaseTrait: Send + Debug { + /// Execute a statement in the [MockDatabase] fn execute(&mut self, counter: usize, stmt: Statement) -> Result; + /// Execute a SQL query in the [MockDatabase] fn query(&mut self, counter: usize, stmt: Statement) -> Result, DbErr>; + /// Create a transaction that can be committed atomically fn begin(&mut self); + /// Commit a successful transaction atomically into the [MockDatabase] fn commit(&mut self); + /// Roll back a transaction since errors were encountered fn rollback(&mut self); + /// Get all logs from a [MockDatabase] and return a [Transaction] fn drain_transaction_log(&mut self) -> Vec; + /// Get the backend being used in the [MockDatabase] fn get_database_backend(&self) -> DbBackend; } impl MockDatabaseConnector { + /// Check if the database URI given and the [DatabaseBackend](crate::DatabaseBackend) selected are the same #[allow(unused_variables)] pub fn accepts(string: &str) -> bool { #[cfg(feature = "sqlx-mysql")] @@ -55,6 +66,7 @@ impl MockDatabaseConnector { false } + /// Cpnnect to the [MockDatabase] #[allow(unused_variables)] pub async fn connect(string: &str) -> Result { macro_rules! connect_mock_db { @@ -82,6 +94,7 @@ impl MockDatabaseConnector { } impl MockDatabaseConnection { + /// Create a connection to the [MockDatabase] pub fn new(m: M) -> Self where M: MockDatabaseTrait, @@ -96,16 +109,19 @@ impl MockDatabaseConnection { &self.mocker } + /// Get the [DatabaseBackend](crate::DatabaseBackend) being used by the [MockDatabase] pub fn get_database_backend(&self) -> DbBackend { self.mocker.lock().unwrap().get_database_backend() } + /// Execute the SQL statement in the [MockDatabase] pub fn execute(&self, statement: Statement) -> Result { debug_print!("{}", statement); let counter = self.counter.fetch_add(1, Ordering::SeqCst); self.mocker.lock().unwrap().execute(counter, statement) } + /// Return one [QueryResult] if the query was successful pub fn query_one(&self, statement: Statement) -> Result, DbErr> { debug_print!("{}", statement); let counter = self.counter.fetch_add(1, Ordering::SeqCst); @@ -113,12 +129,14 @@ impl MockDatabaseConnection { Ok(result.into_iter().next()) } + /// Return all [QueryResult]s if the query was successful pub fn query_all(&self, statement: Statement) -> Result, DbErr> { debug_print!("{}", statement); let counter = self.counter.fetch_add(1, Ordering::SeqCst); self.mocker.lock().unwrap().query(counter, statement) } + /// Return [QueryResult]s from a multi-query operation pub fn fetch( &self, statement: &Statement, @@ -129,14 +147,17 @@ impl MockDatabaseConnection { } } + /// Create a statement block of SQL statements that execute together. pub fn begin(&self) { self.mocker.lock().unwrap().begin() } + /// Commit a transaction atomically to the database pub fn commit(&self) { self.mocker.lock().unwrap().commit() } + /// Roll back a faulty transaction pub fn rollback(&self) { self.mocker.lock().unwrap().rollback() } diff --git a/src/driver/sqlx_common.rs b/src/driver/sqlx_common.rs index 5b1f7b35..5e035c9c 100644 --- a/src/driver/sqlx_common.rs +++ b/src/driver/sqlx_common.rs @@ -1,9 +1,11 @@ use crate::DbErr; +/// Converts an [sqlx::error] execution error to a [DbErr] pub fn sqlx_error_to_exec_err(err: sqlx::Error) -> DbErr { 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 { DbErr::Query(err.to_string()) } diff --git a/src/driver/sqlx_mysql.rs b/src/driver/sqlx_mysql.rs index 895707d1..b2b89c68 100644 --- a/src/driver/sqlx_mysql.rs +++ b/src/driver/sqlx_mysql.rs @@ -15,19 +15,23 @@ use crate::{ use super::sqlx_common::*; +/// Defines the [sqlx::mysql] connector #[derive(Debug)] pub struct SqlxMySqlConnector; +/// Defines a sqlx MySQL pool #[derive(Debug, Clone)] pub struct SqlxMySqlPoolConnection { pool: MySqlPool, } impl SqlxMySqlConnector { + /// Check if the URI provided corresponds to `mysql://` for a MySQL database pub fn accepts(string: &str) -> bool { string.starts_with("mysql://") && string.parse::().is_ok() } + /// Add configuration options for the MySQL database pub async fn connect(options: ConnectOptions) -> Result { let mut opt = options .url @@ -48,12 +52,14 @@ impl SqlxMySqlConnector { } impl SqlxMySqlConnector { + /// Instantiate a sqlx pool connection to a [DatabaseConnection] pub fn from_sqlx_mysql_pool(pool: MySqlPool) -> DatabaseConnection { DatabaseConnection::SqlxMySqlPoolConnection(SqlxMySqlPoolConnection { pool }) } } impl SqlxMySqlPoolConnection { + /// Execute a [Statement] on a MySQL backend pub async fn execute(&self, stmt: Statement) -> Result { 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, DbErr> { 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, DbErr> { 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 { debug_print!("{}", stmt); @@ -117,6 +126,7 @@ impl SqlxMySqlPoolConnection { } } + /// Bundle a set of SQL statements that execute together. pub async fn begin(&self) -> Result { if let Ok(conn) = self.pool.acquire().await { DatabaseTransaction::new_mysql(conn).await @@ -127,6 +137,7 @@ impl SqlxMySqlPoolConnection { } } + /// Create a MySQL transaction pub async fn transaction(&self, callback: F) -> Result> where F: for<'b> FnOnce( diff --git a/src/driver/sqlx_postgres.rs b/src/driver/sqlx_postgres.rs index a9f138a4..84645a58 100644 --- a/src/driver/sqlx_postgres.rs +++ b/src/driver/sqlx_postgres.rs @@ -15,19 +15,23 @@ use crate::{ use super::sqlx_common::*; +/// Defines the [sqlx::postgres] connector #[derive(Debug)] pub struct SqlxPostgresConnector; +/// Defines a sqlx PostgreSQL pool #[derive(Debug, Clone)] pub struct SqlxPostgresPoolConnection { pool: PgPool, } impl SqlxPostgresConnector { + /// Check if the URI provided corresponds to `postgres://` for a PostgreSQL database pub fn accepts(string: &str) -> bool { string.starts_with("postgres://") && string.parse::().is_ok() } + /// Add configuration options for the MySQL database pub async fn connect(options: ConnectOptions) -> Result { let mut opt = options .url @@ -48,12 +52,14 @@ impl SqlxPostgresConnector { } impl SqlxPostgresConnector { + /// Instantiate a sqlx pool connection to a [DatabaseConnection] pub fn from_sqlx_postgres_pool(pool: PgPool) -> DatabaseConnection { DatabaseConnection::SqlxPostgresPoolConnection(SqlxPostgresPoolConnection { pool }) } } impl SqlxPostgresPoolConnection { + /// Execute a [Statement] on a PostgreSQL backend pub async fn execute(&self, stmt: Statement) -> Result { 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, DbErr> { 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, DbErr> { 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 { debug_print!("{}", stmt); @@ -117,6 +126,7 @@ impl SqlxPostgresPoolConnection { } } + /// Bundle a set of SQL statements that execute together. pub async fn begin(&self) -> Result { if let Ok(conn) = self.pool.acquire().await { DatabaseTransaction::new_postgres(conn).await @@ -127,6 +137,7 @@ impl SqlxPostgresPoolConnection { } } + /// Create a PostgreSQL transaction pub async fn transaction(&self, callback: F) -> Result> where F: for<'b> FnOnce( diff --git a/src/driver/sqlx_sqlite.rs b/src/driver/sqlx_sqlite.rs index 2001fac1..69eee575 100644 --- a/src/driver/sqlx_sqlite.rs +++ b/src/driver/sqlx_sqlite.rs @@ -15,20 +15,25 @@ use crate::{ use super::sqlx_common::*; +/// Defines the [sqlx::sqlite] connector #[derive(Debug)] pub struct SqlxSqliteConnector; +/// Defines a sqlx SQLite pool #[derive(Debug, Clone)] pub struct SqlxSqlitePoolConnection { pool: SqlitePool, } impl SqlxSqliteConnector { + /// Check if the URI provided corresponds to `sqlite:` for a SQLite database pub fn accepts(string: &str) -> bool { string.starts_with("sqlite:") && string.parse::().is_ok() } + /// Add configuration options for the SQLite database pub async fn connect(options: ConnectOptions) -> Result { + let mut options = options; let mut opt = options .url .parse::() @@ -37,12 +42,10 @@ impl SqlxSqliteConnector { use sqlx::ConnectOptions; opt.disable_statement_logging(); } - if let Ok(pool) = options - .pool_options() - .max_connections(1) - .connect_with(opt) - .await - { + if options.get_max_connections().is_none() { + options.max_connections(1); + } + if let Ok(pool) = options.pool_options().connect_with(opt).await { Ok(DatabaseConnection::SqlxSqlitePoolConnection( SqlxSqlitePoolConnection { pool }, )) @@ -53,12 +56,14 @@ impl SqlxSqliteConnector { } impl SqlxSqliteConnector { + /// Instantiate a sqlx pool connection to a [DatabaseConnection] pub fn from_sqlx_sqlite_pool(pool: SqlitePool) -> DatabaseConnection { DatabaseConnection::SqlxSqlitePoolConnection(SqlxSqlitePoolConnection { pool }) } } impl SqlxSqlitePoolConnection { + /// Execute a [Statement] on a SQLite backend pub async fn execute(&self, stmt: Statement) -> Result { 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, DbErr> { 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, DbErr> { 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 { debug_print!("{}", stmt); @@ -122,6 +130,7 @@ impl SqlxSqlitePoolConnection { } } + /// Bundle a set of SQL statements that execute together. pub async fn begin(&self) -> Result { if let Ok(conn) = self.pool.acquire().await { DatabaseTransaction::new_sqlite(conn).await @@ -132,6 +141,7 @@ impl SqlxSqlitePoolConnection { } } + /// Create a MySQL transaction pub async fn transaction(&self, callback: F) -> Result> where F: for<'b> FnOnce( diff --git a/src/entity/active_model.rs b/src/entity/active_model.rs index b17ade72..d46c6dbf 100644 --- a/src/entity/active_model.rs +++ b/src/entity/active_model.rs @@ -5,6 +5,28 @@ use async_trait::async_trait; use sea_query::{Nullable, ValueTuple}; 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)] pub struct ActiveValue where @@ -14,6 +36,7 @@ where state: ActiveValueState, } +/// Defines a set operation on an [ActiveValue] #[allow(non_snake_case)] pub fn Set(v: V) -> ActiveValue where @@ -22,6 +45,7 @@ where ActiveValue::set(v) } +/// Defines an unset operation on an [ActiveValue] #[allow(non_snake_case)] pub fn Unset(_: Option) -> ActiveValue where @@ -30,6 +54,7 @@ where ActiveValue::unset() } +// Defines the state of an [ActiveValue] #[derive(Clone, Debug)] enum ActiveValueState { Set, @@ -51,22 +76,33 @@ where 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] pub trait ActiveModelTrait: Clone + Debug { + /// Enforce the type to the constraints of the [EntityTrait] type Entity: EntityTrait; + /// Get a mutable [ActiveValue] from an ActiveModel fn take(&mut self, c: ::Column) -> ActiveValue; + /// Get a immutable [ActiveValue] from an ActiveModel fn get(&self, c: ::Column) -> ActiveValue; + /// Set the Value into an ActiveModel fn set(&mut self, c: ::Column, v: Value); + /// Set the state of an [ActiveValue] to the Unset state fn unset(&mut self, c: ::Column); + /// Check the state of a [ActiveValue] fn is_unset(&self, c: ::Column) -> bool; + /// The default implementation of the ActiveModel fn default() -> Self; + /// Get the primary key of the ActiveModel #[allow(clippy::question_mark)] fn get_primary_key_value(&self) -> Option { let mut cols = ::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 where ::Model: IntoActiveModel, @@ -121,6 +158,7 @@ pub trait ActiveModelTrait: Clone + Debug { ActiveModelBehavior::after_save(am, true) } + /// Perform the `UPDATE` operation on an ActiveModel async fn update<'a, C>(self, db: &'a C) -> Result where 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)] pub trait ActiveModelBehavior: ActiveModelTrait { /// 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 where A: ActiveModelTrait, { + /// Method to call to perform the conversion 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 where V: Into, { + /// Method to perform the conversion fn into_active_value(self) -> ActiveValue; } @@ -296,6 +366,7 @@ impl ActiveValue where V: Into, { + /// Set the value of an [ActiveValue] and also set its state to `ActiveValueState::Set` pub fn set(value: V) -> Self { Self { 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 { 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 { 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 { Self { 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 { 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 { self.state = ActiveValueState::Unset; self.value.take() } + /// Get an owned value of the `value` field of the [ActiveValue] pub fn unwrap(self) -> V { self.value.unwrap() } + /// Check is a [Value] exists or not pub fn into_value(self) -> Option { self.value.map(Into::into) } + /// Wrap the [Value] into a `ActiveValue` pub fn into_wrapped_value(self) -> ActiveValue { match self.state { ActiveValueState::Set => ActiveValue::set(self.into_value().unwrap()), diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index aef46207..c03199d7 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -7,21 +7,28 @@ use sea_query::{Alias, Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef}; pub use sea_strum::IntoEnumIterator as Iterable; use std::fmt::Debug; +/// Ensure the identifier for an Entity can be converted to a static str pub trait IdenStatic: Iden + Copy + Debug + 'static { + /// Method to call to get the static string identity fn as_str(&self) -> &str; } +/// Enforces the naming of an entity to a set of constraints 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> { None } + /// Get the name of the table fn table_name(&self) -> &str; + /// Get the name of the module from the invoking `self.table_name()` fn module_name(&self) -> &str { self.table_name() } + /// Get the [TableRef] from invoking the `self.schema_name()` fn table_ref(&self) -> TableRef { match self.schema_name() { 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_*` /// - Delete: `delete`, `delete_*` pub trait EntityTrait: EntityName { + #[allow(missing_docs)] type Model: ModelTrait + FromQueryResult; + #[allow(missing_docs)] type Column: ColumnTrait; + #[allow(missing_docs)] type Relation: RelationTrait; + #[allow(missing_docs)] type PrimaryKey: PrimaryKeyTrait + PrimaryKeyToColumn; + /// Check if the relation belongs to an Entity fn belongs_to(related: R) -> RelationBuilder where R: EntityTrait, @@ -58,6 +70,7 @@ pub trait EntityTrait: EntityName { RelationBuilder::new(RelationType::HasOne, Self::default(), related, false) } + /// Check if the entity has at least one relation fn has_one(_: R) -> RelationBuilder where R: EntityTrait + Related, @@ -65,6 +78,7 @@ pub trait EntityTrait: EntityName { RelationBuilder::from_rel(RelationType::HasOne, R::to().rev(), true) } + /// Check if the Entity has many relations fn has_many(_: R) -> RelationBuilder where R: EntityTrait + Related, diff --git a/src/entity/column.rs b/src/entity/column.rs index 55a7d86e..cc93bde4 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -2,6 +2,7 @@ use crate::{EntityName, IdenStatic, Iterable}; use sea_query::{DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value}; use std::str::FromStr; +/// Defines a Column for an Entity #[derive(Debug, Clone, PartialEq)] pub struct ColumnDef { pub(crate) col_type: ColumnType, @@ -10,35 +11,63 @@ pub struct ColumnDef { pub(crate) indexed: bool, } +/// The type of column as defined in the SQL format #[derive(Debug, Clone, PartialEq)] pub enum ColumnType { + /// `CHAR` type of specified fixed length Char(Option), + /// `STRING` type for variable string length String(Option), + /// `TEXT` type used for large pieces of string data and stored out of row in case size is too big Text, + /// `TINYINT` useful for storing one byte of data (range of 0-255) TinyInteger, + /// `SMALLINT` data type stores small whole numbers that range from –32,767 to 32,767 SmallInteger, + /// `INTEGER` data types hold numbers that are whole, or without a decimal point 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, + /// `FLOAT` an approximate-number data type, where values range cannot be represented exactly. Float, + /// `DOUBLE` is a normal-size floating point number where the + /// total number of digits is specified in size. Double, + /// `DECIMAL` type store numbers that have fixed precision and scale Decimal(Option<(u32, u32)>), + /// `DATETIME` type is used for values that contain both date and time parts. DateTime, + /// `TIMESTAMP` is a temporal data type that holds the combination of date and time. 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, + /// `TIME` data type defines a time of a day based on 24-hour clock Time, + /// `DATE` data type stores the calendar date Date, + /// `BINARY` data types contain byte strings—a sequence of octets or bytes. Binary, + /// `BOOLEAN` is the result of a comparison operator Boolean, + /// `MONEY` data type handles monetary data Money(Option<(u32, u32)>), + /// `JSON` represents the JavaScript Object Notation type 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, + /// A custom implementation of a data type Custom(String), + /// A Universally Unique IDentifier that is specified in RFC 4122 Uuid, Enum(String, Vec), } macro_rules! bind_oper { ( $op: ident ) => { + #[allow(missing_docs)] fn $op(&self, v: V) -> SimpleExpr where V: Into, @@ -59,6 +88,7 @@ macro_rules! bind_func_no_params { macro_rules! bind_vec_func { ( $func: ident ) => { + #[allow(missing_docs)] #[allow(clippy::wrong_self_convention)] fn $func(&self, v: I) -> SimpleExpr where @@ -73,6 +103,7 @@ macro_rules! bind_vec_func { macro_rules! bind_subquery_func { ( $func: ident ) => { #[allow(clippy::wrong_self_convention)] + #[allow(missing_docs)] fn $func(&self, s: SelectStatement) -> SimpleExpr { 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 /// Wrapper of the identically named method in [`sea_query::Expr`] pub trait ColumnTrait: IdenStatic + Iterable + FromStr { + #[allow(missing_docs)] type EntityName: EntityName; + /// Define a column for an Entity fn def(&self) -> ColumnDef; + /// Get the name of the entity the column belongs to fn entity_name(&self) -> 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) { (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_not_null); + /// Perform an operation if the column is null fn if_null(&self, v: V) -> SimpleExpr where V: Into, @@ -237,6 +273,7 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr { } impl ColumnType { + /// instantiate a new [ColumnDef] pub fn def(self) -> ColumnDef { ColumnDef { col_type: self, @@ -255,20 +292,24 @@ impl ColumnType { } impl ColumnDef { + /// Marks the column as `UNIQUE` pub fn unique(mut self) -> Self { self.unique = true; self } + /// Mark the column as nullable pub fn null(self) -> Self { self.nullable() } + /// Mark the column as nullable pub fn nullable(mut self) -> Self { self.null = true; self } + /// Set the `indexed` field to `true` pub fn indexed(mut self) -> Self { self.indexed = true; self diff --git a/src/entity/identity.rs b/src/entity/identity.rs index d8623b7d..b9316f9f 100644 --- a/src/entity/identity.rs +++ b/src/entity/identity.rs @@ -2,10 +2,14 @@ use crate::{ColumnTrait, EntityTrait, IdenStatic}; use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc}; use std::fmt; +/// Defines an operation for an Entity #[derive(Debug, Clone)] pub enum Identity { + /// Performs one operation Unary(DynIden), + /// Performs two operations Binary(DynIden, DynIden), + /// Performs three operations Ternary(DynIden, DynIden, DynIden), } @@ -28,14 +32,18 @@ impl Iden for Identity { } } +/// Performs a conversion into an [Identity] pub trait IntoIdentity { + /// Method to perform the conversion fn into_identity(self) -> Identity; } +/// Check the [Identity] of an Entity pub trait IdentityOf where E: EntityTrait, { + /// Method to call to perform this check fn identity_of(self) -> Identity; } diff --git a/src/entity/link.rs b/src/entity/link.rs index d0c262d7..53d23b97 100644 --- a/src/entity/link.rs +++ b/src/entity/link.rs @@ -3,15 +3,21 @@ use crate::{ }; use sea_query::{Alias, IntoIden, JoinType, SeaRc}; +/// Same as [RelationDef] pub type LinkDef = RelationDef; +/// A set of constraints for links between Entities pub trait Linked { + #[allow(missing_docs)] type FromEntity: EntityTrait; + #[allow(missing_docs)] type ToEntity: EntityTrait; + /// Link for an Entity fn link(&self) -> Vec; + /// Find all the Entities that are linked to the Entity fn find_linked(&self) -> Select { let mut select = Select::new(); for (i, rel) in self.link().into_iter().rev().enumerate() { diff --git a/src/entity/mod.rs b/src/entity/mod.rs index 7e8b7830..0fb10ace 100644 --- a/src/entity/mod.rs +++ b/src/entity/mod.rs @@ -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_model; mod base_entity; @@ -5,6 +105,7 @@ mod column; mod identity; mod link; mod model; +/// Re-export common types from the entity pub mod prelude; mod primary_key; mod relation; diff --git a/src/entity/model.rs b/src/entity/model.rs index cd96b22e..3f162dbe 100644 --- a/src/entity/model.rs +++ b/src/entity/model.rs @@ -5,13 +5,18 @@ use crate::{ pub use sea_query::Value; use std::fmt::Debug; +/// A set of constraints for a Model pub trait ModelTrait: Clone + Send + Debug { + #[allow(missing_docs)] type Entity: EntityTrait; + /// Get the [Value] of a column from an Entity fn get(&self, c: ::Column) -> Value; + /// Set the [Value] of a column in an Entity fn set(&mut self, c: ::Column, v: Value); + /// Find related Models fn find_related(&self, _: R) -> Select where R: EntityTrait, @@ -20,6 +25,7 @@ pub trait ModelTrait: Clone + Send + Debug { >::find_related().belongs_to(self) } + /// Find linked Models fn find_linked(&self, l: L) -> Select where L: Linked, @@ -29,9 +35,13 @@ pub trait ModelTrait: Clone + Send + Debug { } } +/// A set of constraints for implementing a [QueryResult] pub trait FromQueryResult: Sized { + /// Instantiate a Model from a [QueryResult] fn from_query_result(res: &QueryResult, pre: &str) -> Result; + /// 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, DbErr> { Ok(Self::from_query_result(res, pre).ok()) } diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 98f89c92..211cf853 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -24,6 +24,7 @@ pub use chrono::NaiveTime as Time; #[cfg(feature = "with-chrono")] pub use chrono::NaiveDateTime as DateTime; +/// Handles the time and dates #[cfg(feature = "with-chrono")] pub type DateTimeWithTimeZone = chrono::DateTime; diff --git a/src/entity/primary_key.rs b/src/entity/primary_key.rs index a5e4cde0..d4075a2c 100644 --- a/src/entity/primary_key.rs +++ b/src/entity/primary_key.rs @@ -4,7 +4,41 @@ use sea_query::{FromValueTuple, IntoValueTuple}; use std::fmt::Debug; //LINT: composite primary key cannot auto increment +/// A set of constraints to be used to define a Primary Key. +/// +/// A 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 { + #[allow(missing_docs)] type ValueType: Sized + Send + Debug @@ -14,14 +48,19 @@ pub trait PrimaryKeyTrait: IdenStatic + Iterable { + TryGetableMany + TryFromU64; + /// Method to call to perform `AUTOINCREMENT` operation on a Primary Kay fn auto_increment() -> bool; } +/// How to map a Primary Key to a column pub trait PrimaryKeyToColumn { + #[allow(missing_docs)] type Column: ColumnTrait; + /// Method to map a primary key to a column in an Entity 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 where Self: Sized; diff --git a/src/entity/relation.rs b/src/entity/relation.rs index 93c00596..0733c982 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -3,45 +3,68 @@ use core::marker::PhantomData; use sea_query::{JoinType, TableRef}; use std::fmt::Debug; +/// Defines the type of relationship #[derive(Clone, Debug)] pub enum RelationType { + /// An Entity has one relationship HasOne, + /// An Entity has many relationships HasMany, } +/// Action to perform on a foreign key whenever there are changes +/// to an ActiveModel pub type ForeignKeyAction = sea_query::ForeignKeyAction; +/// Constraints a type to implement the trait to create a relationship pub trait RelationTrait: Iterable + Debug + 'static { + /// The method to call fn def(&self) -> RelationDef; } +/// Checks if Entities are related pub trait Related where R: EntityTrait, { + /// Check if an entity is related to another entity fn to() -> RelationDef; + /// Check if an entity is related through another entity fn via() -> Option { None } + /// Find related Entities fn find_related() -> Select { Select::::new().join_join_rev(JoinType::InnerJoin, Self::to(), Self::via()) } } +/// Defines a relationship #[derive(Debug)] pub struct RelationDef { + /// The type of relationship defined in [RelationType] pub rel_type: RelationType, + /// Reference from another Entity pub from_tbl: TableRef, + /// Reference to another ENtity pub to_tbl: TableRef, + /// Reference to from a Column pub from_col: Identity, + /// Reference to another column pub to_col: Identity, + /// Defines the owner of the Relation pub is_owner: bool, + /// Defines an operation to be performed on a Foreign Key when a + /// `DELETE` Operation is performed pub on_delete: Option, + /// Defines an operation to be performed on a Foreign Key when a + /// `UPDATE` Operation is performed pub on_update: Option, } +/// Defines a helper to build a relation #[derive(Debug)] pub struct RelationBuilder where @@ -108,6 +131,7 @@ where } } + /// Build a relationship from an Entity pub fn from(mut self, identifier: T) -> Self where T: IdentityOf, @@ -116,6 +140,7 @@ where self } + /// Build a relationship to an Entity pub fn to(mut self, identifier: T) -> Self where T: IdentityOf, @@ -124,11 +149,13 @@ where self } + /// An operation to perform on a foreign key when a delete operation occurs pub fn on_delete(mut self, action: ForeignKeyAction) -> Self { self.on_delete = Some(action); self } + /// An operation to perform on a foreign key when an update operation occurs pub fn on_update(mut self, action: ForeignKeyAction) -> Self { self.on_update = Some(action); self diff --git a/src/error.rs b/src/error.rs index c138009b..e2f24c0b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,21 +1,16 @@ -/// Represents all the errors in SeaORM. +/// An error from unsuccessful database operations #[derive(Debug, PartialEq)] pub enum DbErr { - /// Error occurred while connecting to database engine. + /// There was a problem with the database connection Conn(String), - - /// Error occurred while executing SQL statement. + /// An operation did not execute successfully Exec(String), - - /// Error occurred while querying SQL statement. + /// An error occurred while performing a query Query(String), - - /// Error occurred while updating a non-existing row in database. + /// The record was not found in the database RecordNotFound(String), - - /// Error occurred while performing custom validation logics in [ActiveModelBehavior](crate::ActiveModelBehavior) + /// A custom error Custom(String), - /// Error occurred while parsing value into [ActiveEnum](crate::ActiveEnum) 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)] pub struct ColumnFromStrErr(pub String); diff --git a/src/executor/delete.rs b/src/executor/delete.rs index c4a8c7de..7577b976 100644 --- a/src/executor/delete.rs +++ b/src/executor/delete.rs @@ -4,13 +4,16 @@ use crate::{ use sea_query::DeleteStatement; use std::future::Future; +/// Handles DELETE operations in a ActiveModel using [DeleteStatement] #[derive(Clone, Debug)] pub struct Deleter { query: DeleteStatement, } +/// The result of a DELETE operation #[derive(Clone, Debug)] pub struct DeleteResult { + /// The number of rows affected by the DELETE operation pub rows_affected: u64, } @@ -18,6 +21,7 @@ impl<'a, A: 'a> DeleteOne where A: ActiveModelTrait, { + /// Execute a DELETE operation on one ActiveModel pub fn exec(self, db: &'a C) -> impl Future> + '_ where C: ConnectionTrait<'a>, @@ -31,6 +35,7 @@ impl<'a, E> DeleteMany where E: EntityTrait, { + /// Execute a DELETE operation on many ActiveModels pub fn exec(self, db: &'a C) -> impl Future> + '_ where C: ConnectionTrait<'a>, @@ -41,10 +46,12 @@ where } impl Deleter { + /// Instantiate a new [Deleter] by passing it a [DeleteStatement] pub fn new(query: DeleteStatement) -> Self { Self { query } } + /// Execute a DELETE operation pub fn exec<'a, C>(self, db: &'a C) -> impl Future> + '_ where C: ConnectionTrait<'a>, diff --git a/src/executor/execute.rs b/src/executor/execute.rs index 46ba2d69..f3168180 100644 --- a/src/executor/execute.rs +++ b/src/executor/execute.rs @@ -1,16 +1,24 @@ +/// Defines the result of executing an operation #[derive(Debug)] 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, } +/// Holds a result depending on the database backend chosen by the feature flag #[derive(Debug)] pub(crate) enum ExecResultHolder { + /// Holds the result of executing an operation on a MySQL database #[cfg(feature = "sqlx-mysql")] SqlxMySql(sqlx::mysql::MySqlQueryResult), + /// Holds the result of executing an operation on a PostgreSQL database #[cfg(feature = "sqlx-postgres")] SqlxPostgres(sqlx::postgres::PgQueryResult), + /// Holds the result of executing an operation on a SQLite database #[cfg(feature = "sqlx-sqlite")] SqlxSqlite(sqlx::sqlite::SqliteQueryResult), + /// Holds the result of executing an operation on the Mock database #[cfg(feature = "mock")] Mock(crate::MockExecResult), } @@ -18,6 +26,7 @@ pub(crate) enum ExecResultHolder { // ExecResult // impl ExecResult { + /// Get the last id after `AUTOINCREMENT` is done on the primary key pub fn last_insert_id(&self) -> u64 { match &self.result { #[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 { match &self.result { #[cfg(feature = "sqlx-mysql")] diff --git a/src/executor/insert.rs b/src/executor/insert.rs index 9e186ccd..64b6c145 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -5,6 +5,7 @@ use crate::{ use sea_query::{FromValueTuple, InsertStatement, ValueTuple}; use std::{future::Future, marker::PhantomData}; +/// Defines a structure to perform INSERT operations in an ActiveModel #[derive(Debug)] pub struct Inserter where @@ -15,11 +16,13 @@ where model: PhantomData, } +/// The result of an INSERT operation on an ActiveModel #[derive(Debug)] pub struct InsertResult where A: ActiveModelTrait, { + /// The id performed when AUTOINCREMENT was performed on the PrimaryKey pub last_insert_id: <<::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType, } @@ -27,6 +30,7 @@ impl Insert where A: ActiveModelTrait, { + /// Execute an insert operation #[allow(unused_mut)] pub fn exec<'a, C>(self, db: &'a C) -> impl Future, DbErr>> + '_ where @@ -53,6 +57,7 @@ impl Inserter where A: ActiveModelTrait, { + /// Instantiate a new insert operation pub fn new(primary_key: Option, query: InsertStatement) -> Self { Self { primary_key, @@ -61,6 +66,7 @@ where } } + /// Execute an insert operation pub fn exec<'a, C>(self, db: &'a C) -> impl Future, DbErr>> + '_ where C: ConnectionTrait<'a>, diff --git a/src/executor/paginator.rs b/src/executor/paginator.rs index 28f8574b..fd8e822c 100644 --- a/src/executor/paginator.rs +++ b/src/executor/paginator.rs @@ -4,8 +4,10 @@ use futures::Stream; use sea_query::{Alias, Expr, SelectStatement}; 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 + 'db>>; +/// Defined a structure to handle pagination of a result from a query operation on a Model #[derive(Clone, Debug)] pub struct Paginator<'db, C, S> where diff --git a/src/executor/query.rs b/src/executor/query.rs index a164e911..96455945 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -3,6 +3,7 @@ use crate::debug_print; use crate::{DbErr, SelectGetableValue, SelectorRaw, Statement}; use std::fmt; +/// Defines the result of a query operation on a Model #[derive(Debug)] pub struct QueryResult { pub(crate) row: QueryResultRow, @@ -19,13 +20,18 @@ pub(crate) enum QueryResultRow { Mock(crate::MockRow), } +/// Constrain any type trying to get a Row in a database pub trait TryGetable: Sized { + /// Ensure the type implements this method fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result; } +/// An error from trying to get a row from a Model #[derive(Debug)] pub enum TryGetError { + /// A database error was encountered as defined in [crate::DbErr] DbErr(DbErr), + /// A null value was encountered Null, } @@ -41,6 +47,7 @@ impl From for DbErr { // QueryResult // impl QueryResult { + /// Get a Row from a Column pub fn try_get(&self, pre: &str, col: &str) -> Result where T: TryGetable, @@ -48,6 +55,7 @@ impl QueryResult { Ok(T::try_get(self, pre, col)?) } + /// Perform query operations on multiple Columns pub fn try_get_many(&self, pre: &str, cols: &[String]) -> Result where T: TryGetableMany, @@ -306,7 +314,9 @@ try_getable_all!(uuid::Uuid); // TryGetableMany // +/// Perform a query on multiple columns pub trait TryGetableMany: Sized { + /// THe method to perform a query on multiple columns fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result; /// ``` @@ -453,8 +463,9 @@ fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), Try } // TryFromU64 // - +/// Try to convert a type to a u64 pub trait TryFromU64: Sized { + /// The method to convert the type to a u64 fn try_from_u64(n: u64) -> Result; } diff --git a/src/executor/select.rs b/src/executor/select.rs index 78786b76..5acdae02 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -11,6 +11,7 @@ use std::pin::Pin; #[cfg(feature = "with-json")] use crate::JsonValue; +/// Defines a type to do `SELECT` operations though a [SelectStatement] on a Model #[derive(Clone, Debug)] pub struct Selector where @@ -20,6 +21,7 @@ where selector: S, } +/// Performs a raw `SELECT` operation on a model #[derive(Clone, Debug)] pub struct SelectorRaw where @@ -29,12 +31,16 @@ where selector: S, } +/// Used to enforce constraints on any type that wants to perform SELECT queries pub trait SelectorTrait { + #[allow(missing_docs)] type Item: Sized; + /// The method to perform a query on a Model fn from_raw_query_result(res: QueryResult) -> Result; } +/// Perform an operation on an entity that can yield a Value #[derive(Debug)] pub struct SelectGetableValue where @@ -45,6 +51,7 @@ where model: PhantomData, } +/// Defines a type to get a Model #[derive(Debug)] pub struct SelectModel where @@ -53,6 +60,7 @@ where model: PhantomData, } +/// Defines a type to get two Modelss #[derive(Clone, Debug)] pub struct SelectTwoModel where @@ -105,6 +113,7 @@ impl Select where E: EntityTrait, { + /// Perform a Select operation on a Model using a [Statement] #[allow(clippy::wrong_self_convention)] pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw> { SelectorRaw { @@ -113,6 +122,7 @@ where } } + /// Return a [Selector] from `Self` that wraps a [SelectModel] pub fn into_model(self) -> Selector> where M: FromQueryResult, @@ -123,6 +133,7 @@ where } } + /// Get a selectable Model as a [JsonValue] for SQL JSON operations #[cfg(feature = "with-json")] pub fn into_json(self) -> Selector> { Selector { @@ -239,6 +250,7 @@ where Selector::>::with_columns(self.query) } + /// Get one Model from a SELECT operation pub async fn one<'a, C>(self, db: &C) -> Result, DbErr> where C: ConnectionTrait<'a>, @@ -246,6 +258,7 @@ where self.into_model().one(db).await } + /// Get all the Models from a SELECT operation pub async fn all<'a, C>(self, db: &C) -> Result, DbErr> where C: ConnectionTrait<'a>, @@ -253,6 +266,7 @@ where self.into_model().all(db).await } + /// Stream the results of a SELECT operation on a Model pub async fn stream<'a: 'b, 'b, C>( self, db: &'a C, @@ -263,6 +277,7 @@ where self.into_model().stream(db).await } + /// Paginate the results of a SELECT operation on a Model pub fn paginate<'a, C>( self, db: &'a C, @@ -274,6 +289,7 @@ where 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 where C: ConnectionTrait<'a>, @@ -287,6 +303,7 @@ where E: EntityTrait, F: EntityTrait, { + /// Perform a conversion into a [SelectTwoModel] pub fn into_model(self) -> Selector> where M: FromQueryResult, @@ -298,6 +315,7 @@ where } } + /// Convert the Models into JsonValue #[cfg(feature = "with-json")] pub fn into_json(self) -> Selector> { Selector { @@ -306,6 +324,7 @@ where } } + /// Get one Model from a Select operation pub async fn one<'a, C>(self, db: &C) -> Result)>, DbErr> where C: ConnectionTrait<'a>, @@ -313,6 +332,7 @@ where self.into_model().one(db).await } + /// Get all Models from a Select operation pub async fn all<'a, C>(self, db: &C) -> Result)>, DbErr> where C: ConnectionTrait<'a>, @@ -320,6 +340,7 @@ where self.into_model().all(db).await } + /// Stream the results of a Select operation on a Model pub async fn stream<'a: 'b, 'b, C>( self, db: &'a C, @@ -330,6 +351,7 @@ where self.into_model().stream(db).await } + /// Paginate the results of a select operation on two models pub fn paginate<'a, C>( self, db: &'a C, @@ -341,6 +363,7 @@ where 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 where C: ConnectionTrait<'a>, @@ -354,6 +377,7 @@ where E: EntityTrait, F: EntityTrait, { + /// Performs a conversion to [Selector] fn into_model(self) -> Selector> where M: FromQueryResult, @@ -365,6 +389,7 @@ where } } + /// Convert the results to JSON #[cfg(feature = "with-json")] pub fn into_json(self) -> Selector> { Selector { @@ -373,6 +398,7 @@ where } } + /// Select one Model pub async fn one<'a, C>(self, db: &C) -> Result)>, DbErr> where C: ConnectionTrait<'a>, @@ -380,6 +406,7 @@ where self.into_model().one(db).await } + /// Stream the result of the operation pub async fn stream<'a: 'b, 'b, C>( self, db: &'a C, @@ -390,6 +417,7 @@ where self.into_model().stream(db).await } + /// Get all the Models from the select operation pub async fn all<'a, C>(self, db: &C) -> Result)>, DbErr> where 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, DbErr> where 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, DbErr> where C: ConnectionTrait<'a>, @@ -454,6 +484,7 @@ where Ok(models) } + /// Stream the results of the operation pub async fn stream<'a: 'b, 'b, C>( self, 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> where 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`. pub fn with_columns(stmt: Statement) -> SelectorRaw> where diff --git a/src/executor/update.rs b/src/executor/update.rs index c228730b..402f29ac 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -4,14 +4,17 @@ use crate::{ use sea_query::UpdateStatement; use std::future::Future; +/// Defines an update operation #[derive(Clone, Debug)] pub struct Updater { query: UpdateStatement, check_record_exists: bool, } +/// The result of an update operation on an ActiveModel #[derive(Clone, Debug, PartialEq)] pub struct UpdateResult { + /// The rows affected by the update operation pub rows_affected: u64, } @@ -19,6 +22,7 @@ impl<'a, A: 'a> UpdateOne where A: ActiveModelTrait, { + /// Execute an update operation on an ActiveModel pub async fn exec<'b, C>(self, db: &'b C) -> Result where C: ConnectionTrait<'b>, @@ -32,6 +36,7 @@ impl<'a, E> UpdateMany where E: EntityTrait, { + /// Execute an update operation on multiple ActiveModels pub fn exec(self, db: &'a C) -> impl Future> + '_ where C: ConnectionTrait<'a>, @@ -42,6 +47,7 @@ where } impl Updater { + /// Instantiate an update using an [UpdateStatement] pub fn new(query: UpdateStatement) -> Self { Self { 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 { self.check_record_exists = true; self } + /// Execute an update operation pub fn exec<'a, C>(self, db: &'a C) -> impl Future> + '_ where C: ConnectionTrait<'a>, diff --git a/src/lib.rs b/src/lib.rs index 83654499..3206cb2b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -266,10 +266,15 @@ mod database; mod docs; mod driver; +/// Module for the Entity type and operations pub mod entity; +/// Error types for all database operations pub mod error; +/// This module performs execution of queries on a Model or ActiveModel mod executor; +/// Holds types and methods to perform queries pub mod query; +/// Holds types that defines the schemas of an Entity pub mod schema; #[doc(hidden)] #[cfg(feature = "macros")] diff --git a/src/query/combine.rs b/src/query/combine.rs index c03906ea..a3dcc275 100644 --- a/src/query/combine.rs +++ b/src/query/combine.rs @@ -7,6 +7,7 @@ use sea_query::{Alias, ColumnRef, Iden, Order, SeaRc, SelectExpr, SelectStatemen macro_rules! select_def { ( $ident: ident, $str: expr ) => { + /// Implements the traits [Iden] and [IdenStatic] for a type #[derive(Debug, Clone, Copy)] pub struct $ident; @@ -54,6 +55,7 @@ where self } + /// Selects and Entity and returns it together with the Entity from `Self` pub fn select_also(mut self, _: F) -> SelectTwo where F: EntityTrait, @@ -62,6 +64,7 @@ where SelectTwo::new(self.into_query()) } + /// Makes a SELECT operation in conjunction to another relation pub fn select_with(mut self, _: F) -> SelectTwoMany where F: EntityTrait, diff --git a/src/query/delete.rs b/src/query/delete.rs index e5cefdef..c7df0c7d 100644 --- a/src/query/delete.rs +++ b/src/query/delete.rs @@ -5,9 +5,11 @@ use crate::{ use core::marker::PhantomData; use sea_query::{DeleteStatement, IntoIden}; +/// Defines the structure for a delete operation #[derive(Clone, Debug)] pub struct Delete; +/// Perform a delete operation on a model #[derive(Clone, Debug)] pub struct DeleteOne where @@ -17,6 +19,7 @@ where pub(crate) model: A, } +/// Perform a delete operation on multiple models #[derive(Clone, Debug)] pub struct DeleteMany where diff --git a/src/query/helper.rs b/src/query/helper.rs index bf762fc9..46f8c895 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -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 there is a group by clause, but some columns don't have aggregate functions // 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 { + #[allow(missing_docs)] type QueryStatement; + /// Add the select SQL statement fn query(&mut self) -> &mut SelectStatement; /// Clear the selection list @@ -164,9 +167,12 @@ pub trait QuerySelect: Sized { } // LINT: when the column does not appear in tables selected from +/// Performs ORDER BY operations pub trait QueryOrder: Sized { + #[allow(missing_docs)] type QueryStatement: OrderedStatement; + /// Add the query to perform an ORDER BY operation fn query(&mut self) -> &mut SelectStatement; /// Add an order_by expression @@ -234,9 +240,12 @@ pub trait QueryOrder: Sized { } // LINT: when the column does not appear in tables selected from +/// Perform a FILTER opertation on a statement pub trait QueryFilter: Sized { + #[allow(missing_docs)] type QueryStatement: ConditionalStatement; + /// Add the query to perform a FILTER on fn query(&mut self) -> &mut Self::QueryStatement; /// Add an AND WHERE expression @@ -372,6 +381,7 @@ pub trait QueryFilter: Sized { self } + /// Perform a check to determine table belongs to a Model through it's name alias fn belongs_to_tbl_alias(mut self, model: &M, tbl_alias: &str) -> Self where M: ModelTrait, diff --git a/src/query/insert.rs b/src/query/insert.rs index f7f77d7d..9d4d6ce5 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -5,6 +5,7 @@ use crate::{ use core::marker::PhantomData; use sea_query::{Alias, Expr, InsertStatement, ValueTuple}; +/// Performs INSERT operations on a ActiveModel #[derive(Debug)] pub struct Insert where @@ -106,6 +107,7 @@ where Self::new().add_many(models) } + /// Add a Model to Self #[allow(clippy::should_implement_trait)] pub fn add(mut self, m: M) -> Self where @@ -144,6 +146,7 @@ where self } + /// Add many Models to Self pub fn add_many(mut self, models: I) -> Self where M: IntoActiveModel, diff --git a/src/query/select.rs b/src/query/select.rs index 5e433e8a..06158be0 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -4,6 +4,7 @@ use core::marker::PhantomData; pub use sea_query::JoinType; use sea_query::{Alias, DynIden, Expr, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr}; +/// Defines a structure to perform select operations #[derive(Clone, Debug)] pub struct Select where @@ -13,6 +14,7 @@ where pub(crate) entity: PhantomData, } +/// Defines a structure to perform a SELECT operation on two Models #[derive(Clone, Debug)] pub struct SelectTwo where @@ -23,6 +25,7 @@ where pub(crate) entity: PhantomData<(E, F)>, } +/// Defines a structure to perform a SELECT operation on many Models #[derive(Clone, Debug)] pub struct SelectTwoMany where @@ -33,7 +36,9 @@ where pub(crate) entity: PhantomData<(E, F)>, } +/// Performs a conversion to [SimpleExpr] pub trait IntoSimpleExpr { + /// Method to perform the conversion fn into_simple_expr(self) -> SimpleExpr; } diff --git a/src/query/traits.rs b/src/query/traits.rs index f0045f52..0517cc64 100644 --- a/src/query/traits.rs +++ b/src/query/traits.rs @@ -1,7 +1,9 @@ use crate::{DbBackend, Statement}; use sea_query::QueryStatementBuilder; +/// Enforces a set of constraints to any type performing queries on a Model or ActiveModel pub trait QueryTrait { + /// Constrain the QueryStatement to [QueryStatementBuilder] trait type QueryStatement: QueryStatementBuilder; /// Get a mutable ref to the query builder diff --git a/src/query/update.rs b/src/query/update.rs index 89348229..d1b6b997 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -5,9 +5,11 @@ use crate::{ use core::marker::PhantomData; use sea_query::{Alias, Expr, IntoIden, SimpleExpr, UpdateStatement}; +/// Defines a structure to perform UPDATE query operations on a ActiveModel #[derive(Clone, Debug)] pub struct Update; +/// Defines an UPDATE operation on one ActiveModel #[derive(Clone, Debug)] pub struct UpdateOne where @@ -17,6 +19,7 @@ where pub(crate) model: A, } +/// Defines an UPDATE operation on multiple ActiveModels #[derive(Clone, Debug)] pub struct UpdateMany where @@ -182,6 +185,7 @@ impl UpdateMany where E: EntityTrait, { + /// Add the models to update to Self pub fn set(mut self, model: A) -> Self where A: ActiveModelTrait, @@ -195,6 +199,7 @@ where self } + /// Creates a [SimpleExpr] from a column pub fn col_expr(mut self, col: T, expr: SimpleExpr) -> Self where T: IntoIden, diff --git a/src/query/util.rs b/src/query/util.rs index 5fc88950..b23804f2 100644 --- a/src/query/util.rs +++ b/src/query/util.rs @@ -1,8 +1,11 @@ use crate::{database::*, QueryTrait, Statement}; +/// This structure provides debug capabilities #[derive(Debug)] pub struct DebugQuery<'a, Q, T> { + /// The query to debug pub query: &'a Q, + /// The value of the query pub value: T, } @@ -12,6 +15,7 @@ macro_rules! debug_query_build { where Q: QueryTrait, { + /// This macro builds a [Statement] when invoked pub fn build(&self) -> Statement { let func = $db_expr; let db_backend = func(self); diff --git a/src/schema/entity.rs b/src/schema/entity.rs index d99a41b9..c24a1385 100644 --- a/src/schema/entity.rs +++ b/src/schema/entity.rs @@ -8,6 +8,7 @@ use sea_query::{ }; impl Schema { + /// Creates Postgres enums from an Entity. See [TypeCreateStatement] for more details pub fn create_enum_from_entity(entity: E, db_backend: DbBackend) -> Vec where E: EntityTrait, @@ -15,6 +16,7 @@ impl Schema { create_enum_from_entity(entity, db_backend) } + /// Creates a table from an Entity. See [TableCreateStatement] for more details pub fn create_table_from_entity(entity: E, db_backend: DbBackend) -> TableCreateStatement where E: EntityTrait, diff --git a/src/schema/mod.rs b/src/schema/mod.rs index 1d05e679..3a5ce734 100644 --- a/src/schema/mod.rs +++ b/src/schema/mod.rs @@ -1,4 +1,5 @@ mod entity; +/// This structure defines a schema for a table #[derive(Debug)] pub struct Schema; diff --git a/src/util.rs b/src/util.rs index 20cc8eb3..9ffa1e4c 100644 --- a/src/util.rs +++ b/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] #[cfg(feature = "debug-print")] macro_rules! debug_print { @@ -5,7 +19,7 @@ macro_rules! debug_print { } #[macro_export] -// Non-debug version +/// Non-debug version #[cfg(not(feature = "debug-print"))] macro_rules! debug_print { ($( $args:expr ),*) => {