Documetation for the entity module

This commit is contained in:
Charles Chege 2021-10-29 10:39:16 +03:00
parent 817e9bdd23
commit db098d1a03
10 changed files with 148 additions and 0 deletions

View File

@ -5,6 +5,7 @@ use async_trait::async_trait;
use sea_query::{Nullable, ValueTuple}; use sea_query::{Nullable, ValueTuple};
use std::fmt::Debug; use std::fmt::Debug;
/// Defines a value from an ActiveModel and its state
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct ActiveValue<V> pub struct ActiveValue<V>
where where
@ -14,6 +15,7 @@ where
state: ActiveValueState, state: ActiveValueState,
} }
/// Defines a set operation on an [ActiveValue]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn Set<V>(v: V) -> ActiveValue<V> pub fn Set<V>(v: V) -> ActiveValue<V>
where where
@ -22,6 +24,7 @@ where
ActiveValue::set(v) ActiveValue::set(v)
} }
/// Defines an unset operation on an [ActiveValue]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn Unset<V>(_: Option<bool>) -> ActiveValue<V> pub fn Unset<V>(_: Option<bool>) -> ActiveValue<V>
where where
@ -30,6 +33,7 @@ where
ActiveValue::unset() ActiveValue::unset()
} }
// Defines the state of an [ActiveValue]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum ActiveValueState { enum ActiveValueState {
Set, Set,
@ -51,22 +55,31 @@ where
ActiveValue::unchanged(value) ActiveValue::unchanged(value)
} }
/// Enforces a set of constraints on any type performing an Create, Update or Delete operation
#[async_trait] #[async_trait]
pub trait ActiveModelTrait: Clone + Debug { pub trait ActiveModelTrait: Clone + Debug {
/// Enforce the type to the constraints of the [EntityTrait]
type Entity: EntityTrait; type Entity: EntityTrait;
/// Get a mutable [ActiveValue] from an ActiveModel
fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>; fn take(&mut self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
/// Get a immutable [ActiveValue] from an ActiveModel
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>; fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> ActiveValue<Value>;
/// Set the Value into an ActiveModel
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value); fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
/// Set the state of an [ActiveValue] to the Unset state
fn unset(&mut self, c: <Self::Entity as EntityTrait>::Column); fn unset(&mut self, c: <Self::Entity as EntityTrait>::Column);
/// Check the state of a [ActiveValue]
fn is_unset(&self, c: <Self::Entity as EntityTrait>::Column) -> bool; fn is_unset(&self, c: <Self::Entity as EntityTrait>::Column) -> bool;
/// The default implementation of the ActiveModel
fn default() -> Self; fn default() -> Self;
/// Get the primary key of the ActiveModel
#[allow(clippy::question_mark)] #[allow(clippy::question_mark)]
fn get_primary_key_value(&self) -> Option<ValueTuple> { fn get_primary_key_value(&self) -> Option<ValueTuple> {
let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter(); let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
@ -103,6 +116,7 @@ pub trait ActiveModelTrait: Clone + Debug {
} }
} }
/// Perform an `INSERT` operation on the ActiveModel
async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr> async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
where where
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>, <Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
@ -121,6 +135,7 @@ pub trait ActiveModelTrait: Clone + Debug {
ActiveModelBehavior::after_save(am, true) ActiveModelBehavior::after_save(am, true)
} }
/// Perform the `UPDATE` operation on an ActiveModel
async fn update<'a, C>(self, db: &'a C) -> Result<Self, DbErr> async fn update<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
where where
Self: ActiveModelBehavior + 'a, Self: ActiveModelBehavior + 'a,
@ -170,6 +185,7 @@ pub trait ActiveModelTrait: Clone + Debug {
} }
} }
/// Enforce a set of constraints to a override the ActiveModel behavior
/// Behaviors for users to override /// Behaviors for users to override
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait ActiveModelBehavior: ActiveModelTrait { pub trait ActiveModelBehavior: ActiveModelTrait {
@ -199,10 +215,12 @@ pub trait ActiveModelBehavior: ActiveModelTrait {
} }
} }
/// Enforce constraints for conversion to an ActiveModel
pub trait IntoActiveModel<A> pub trait IntoActiveModel<A>
where where
A: ActiveModelTrait, A: ActiveModelTrait,
{ {
/// Method to call to perform the conversion
fn into_active_model(self) -> A; fn into_active_model(self) -> A;
} }
@ -215,10 +233,12 @@ where
} }
} }
/// Constraints to perform the conversion of a type into an [ActiveValue]
pub trait IntoActiveValue<V> pub trait IntoActiveValue<V>
where where
V: Into<Value>, V: Into<Value>,
{ {
/// Method to perform the conversion
fn into_active_value(self) -> ActiveValue<V>; fn into_active_value(self) -> ActiveValue<V>;
} }
@ -296,6 +316,7 @@ impl<V> ActiveValue<V>
where where
V: Into<Value>, V: Into<Value>,
{ {
/// Set the value of an [ActiveValue] and also set its state to `ActiveValueState::Set`
pub fn set(value: V) -> Self { pub fn set(value: V) -> Self {
Self { Self {
value: Some(value), value: Some(value),
@ -303,6 +324,7 @@ where
} }
} }
/// Check if the state of an [ActiveValue] is `ActiveValueState::Set` which returns true
pub fn is_set(&self) -> bool { pub fn is_set(&self) -> bool {
matches!(self.state, ActiveValueState::Set) matches!(self.state, ActiveValueState::Set)
} }
@ -314,10 +336,14 @@ where
} }
} }
/// Check if the status of the [ActiveValue] is `ActiveValueState::Unchanged`
/// which returns `true` if it is
pub fn is_unchanged(&self) -> bool { pub fn is_unchanged(&self) -> bool {
matches!(self.state, ActiveValueState::Unchanged) matches!(self.state, ActiveValueState::Unchanged)
} }
/// Set the `value` field of the ActiveModel to [Option::None] and the
/// `state` field to `ActiveValueState::Unset`
pub fn unset() -> Self { pub fn unset() -> Self {
Self { Self {
value: None, value: None,
@ -325,23 +351,30 @@ where
} }
} }
/// Check if the state of an [ActiveValue] is `ActiveValueState::Unset`
/// which returns true if it is
pub fn is_unset(&self) -> bool { pub fn is_unset(&self) -> bool {
matches!(self.state, ActiveValueState::Unset) matches!(self.state, ActiveValueState::Unset)
} }
/// Get the mutable value of the `value` field of an [ActiveValue]
/// also setting it's state to `ActiveValueState::Unset`
pub fn take(&mut self) -> Option<V> { pub fn take(&mut self) -> Option<V> {
self.state = ActiveValueState::Unset; self.state = ActiveValueState::Unset;
self.value.take() self.value.take()
} }
/// Get an owned value of the `value` field of the [ActiveValue]
pub fn unwrap(self) -> V { pub fn unwrap(self) -> V {
self.value.unwrap() self.value.unwrap()
} }
/// Check is a [Value] exists or not
pub fn into_value(self) -> Option<Value> { pub fn into_value(self) -> Option<Value> {
self.value.map(Into::into) self.value.map(Into::into)
} }
/// Wrap the [Value] into a `ActiveValue<Value>`
pub fn into_wrapped_value(self) -> ActiveValue<Value> { pub fn into_wrapped_value(self) -> ActiveValue<Value> {
match self.state { match self.state {
ActiveValueState::Set => ActiveValue::set(self.into_value().unwrap()), ActiveValueState::Set => ActiveValue::set(self.into_value().unwrap()),

View File

@ -7,21 +7,28 @@ use sea_query::{Alias, Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef};
pub use sea_strum::IntoEnumIterator as Iterable; pub use sea_strum::IntoEnumIterator as Iterable;
use std::fmt::Debug; use std::fmt::Debug;
/// Ensure the identifier for an Entity can be converted to a static str
pub trait IdenStatic: Iden + Copy + Debug + 'static { pub trait IdenStatic: Iden + Copy + Debug + 'static {
/// Method to call to get the static string identity
fn as_str(&self) -> &str; fn as_str(&self) -> &str;
} }
/// Enforces the naming of an entity to a set of constraints
pub trait EntityName: IdenStatic + Default { pub trait EntityName: IdenStatic + Default {
/// Method to get the name for the schema, defaults to [Option::None] if not set
fn schema_name(&self) -> Option<&str> { fn schema_name(&self) -> Option<&str> {
None None
} }
/// Get the name of the table
fn table_name(&self) -> &str; fn table_name(&self) -> &str;
/// Get the name of the module from the invoking `self.table_name()`
fn module_name(&self) -> &str { fn module_name(&self) -> &str {
self.table_name() self.table_name()
} }
/// Get the [TableRef] from invoking the `self.schema_name()`
fn table_ref(&self) -> TableRef { fn table_ref(&self) -> TableRef {
match self.schema_name() { match self.schema_name() {
Some(schema) => (Alias::new(schema).into_iden(), self.into_iden()).into_table_ref(), Some(schema) => (Alias::new(schema).into_iden(), self.into_iden()).into_table_ref(),
@ -43,14 +50,19 @@ pub trait EntityName: IdenStatic + Default {
/// - Update: `update`, `update_*` /// - Update: `update`, `update_*`
/// - Delete: `delete`, `delete_*` /// - Delete: `delete`, `delete_*`
pub trait EntityTrait: EntityName { pub trait EntityTrait: EntityName {
#[allow(missing_docs)]
type Model: ModelTrait<Entity = Self> + FromQueryResult; type Model: ModelTrait<Entity = Self> + FromQueryResult;
#[allow(missing_docs)]
type Column: ColumnTrait; type Column: ColumnTrait;
#[allow(missing_docs)]
type Relation: RelationTrait; type Relation: RelationTrait;
#[allow(missing_docs)]
type PrimaryKey: PrimaryKeyTrait + PrimaryKeyToColumn<Column = Self::Column>; type PrimaryKey: PrimaryKeyTrait + PrimaryKeyToColumn<Column = Self::Column>;
/// Check if the relation belongs to an Entity
fn belongs_to<R>(related: R) -> RelationBuilder<Self, R> fn belongs_to<R>(related: R) -> RelationBuilder<Self, R>
where where
R: EntityTrait, R: EntityTrait,
@ -58,6 +70,7 @@ pub trait EntityTrait: EntityName {
RelationBuilder::new(RelationType::HasOne, Self::default(), related, false) RelationBuilder::new(RelationType::HasOne, Self::default(), related, false)
} }
/// Check if the entity has at least one relation
fn has_one<R>(_: R) -> RelationBuilder<Self, R> fn has_one<R>(_: R) -> RelationBuilder<Self, R>
where where
R: EntityTrait + Related<Self>, R: EntityTrait + Related<Self>,
@ -65,6 +78,7 @@ pub trait EntityTrait: EntityName {
RelationBuilder::from_rel(RelationType::HasOne, R::to().rev(), true) RelationBuilder::from_rel(RelationType::HasOne, R::to().rev(), true)
} }
/// Chech if the Entity has many relations
fn has_many<R>(_: R) -> RelationBuilder<Self, R> fn has_many<R>(_: R) -> RelationBuilder<Self, R>
where where
R: EntityTrait + Related<Self>, R: EntityTrait + Related<Self>,

View File

@ -2,6 +2,7 @@ use crate::{EntityName, IdenStatic, Iterable};
use sea_query::{DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value}; use sea_query::{DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value};
use std::str::FromStr; use std::str::FromStr;
/// Defines a Column for an Entity
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct ColumnDef { pub struct ColumnDef {
pub(crate) col_type: ColumnType, pub(crate) col_type: ColumnType,
@ -10,34 +11,62 @@ pub struct ColumnDef {
pub(crate) indexed: bool, pub(crate) indexed: bool,
} }
/// The type of column as defined in the SQL format
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum ColumnType { pub enum ColumnType {
/// `CHAR` type of specified fixed length
Char(Option<u32>), Char(Option<u32>),
/// `STRING` type for variable string length
String(Option<u32>), String(Option<u32>),
/// `TEXT` type used for large pieces of string data and stored out of row in case size is too big
Text, Text,
/// `TINYINT` useful for storing one byte of data (range of 0-255)
TinyInteger, TinyInteger,
/// `SMALLINT` data type stores small whole numbers that range from 32,767 to 32,767
SmallInteger, SmallInteger,
/// `INTEGER` data types hold numbers that are whole, or without a decimal point
Integer, Integer,
/// `BIGINT` is a 64-bit representation of an integer taking up 8 bytes of storage and
/// ranging from -2^63 (-9,223,372,036,854,775,808) to 2^63 (9,223,372,036,854,775,807).
BigInteger, BigInteger,
/// `FLOAT` an approximate-number data type, where values range cannot be represented exactly.
Float, Float,
/// `DOUBLE` is a normal-size floating point number where the
/// total number of digits is specified in size.
Double, Double,
/// `DECIMAL` type store numbers that have fixed precision and scale
Decimal(Option<(u32, u32)>), Decimal(Option<(u32, u32)>),
/// `DATETIME` type is used for values that contain both date and time parts.
DateTime, DateTime,
/// `TIMESTAMP` is a temporal data type that holds the combination of date and time.
Timestamp, Timestamp,
/// `TIMESTAMP WITH TIME ZONE` (or `TIMESTAMPTZ`) data type stores 8-byte
/// date values that include timestamp and time zone information in UTC format.
TimestampWithTimeZone, TimestampWithTimeZone,
/// `TIME` data type defines a time of a day based on 24-hour clock
Time, Time,
/// `DATE` data type stores the calendar date
Date, Date,
/// `BINARY` data types contain byte strings—a sequence of octets or bytes.
Binary, Binary,
/// `BOOLEAN` is the result of a comparison operator
Boolean, Boolean,
/// `MONEY` data type handles monetary data
Money(Option<(u32, u32)>), Money(Option<(u32, u32)>),
/// `JSON` represents the JavaScript Object Notation type
Json, Json,
/// JSON binary format is structured in the way that permits the server to search for
/// values within the JSON document directly by key or array index, which is very fast.
JsonBinary, JsonBinary,
/// A custom implementation of a data type
Custom(String), Custom(String),
/// A Universally Unique IDentifier that is specified in RFC 4122
Uuid, Uuid,
} }
macro_rules! bind_oper { macro_rules! bind_oper {
( $op: ident ) => { ( $op: ident ) => {
#[allow(missing_docs)]
fn $op<V>(&self, v: V) -> SimpleExpr fn $op<V>(&self, v: V) -> SimpleExpr
where where
V: Into<Value>, V: Into<Value>,
@ -58,6 +87,7 @@ macro_rules! bind_func_no_params {
macro_rules! bind_vec_func { macro_rules! bind_vec_func {
( $func: ident ) => { ( $func: ident ) => {
#[allow(missing_docs)]
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn $func<V, I>(&self, v: I) -> SimpleExpr fn $func<V, I>(&self, v: I) -> SimpleExpr
where where
@ -72,6 +102,7 @@ macro_rules! bind_vec_func {
macro_rules! bind_subquery_func { macro_rules! bind_subquery_func {
( $func: ident ) => { ( $func: ident ) => {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
#[allow(missing_docs)]
fn $func(&self, s: SelectStatement) -> SimpleExpr { fn $func(&self, s: SelectStatement) -> SimpleExpr {
Expr::tbl(self.entity_name(), *self).$func(s) Expr::tbl(self.entity_name(), *self).$func(s)
} }
@ -81,14 +112,18 @@ macro_rules! bind_subquery_func {
// LINT: when the operand value does not match column type // LINT: when the operand value does not match column type
/// Wrapper of the identically named method in [`sea_query::Expr`] /// Wrapper of the identically named method in [`sea_query::Expr`]
pub trait ColumnTrait: IdenStatic + Iterable + FromStr { pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
#[allow(missing_docs)]
type EntityName: EntityName; type EntityName: EntityName;
/// Define a column for an Entity
fn def(&self) -> ColumnDef; fn def(&self) -> ColumnDef;
/// Get the name of the entity the column belongs to
fn entity_name(&self) -> DynIden { fn entity_name(&self) -> DynIden {
SeaRc::new(Self::EntityName::default()) as DynIden SeaRc::new(Self::EntityName::default()) as DynIden
} }
/// get the name of the entity the column belongs to
fn as_column_ref(&self) -> (DynIden, DynIden) { fn as_column_ref(&self) -> (DynIden, DynIden) {
(self.entity_name(), SeaRc::new(*self) as DynIden) (self.entity_name(), SeaRc::new(*self) as DynIden)
} }
@ -221,6 +256,7 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
bind_func_no_params!(is_null); bind_func_no_params!(is_null);
bind_func_no_params!(is_not_null); bind_func_no_params!(is_not_null);
/// Perform an operation if the column is null
fn if_null<V>(&self, v: V) -> SimpleExpr fn if_null<V>(&self, v: V) -> SimpleExpr
where where
V: Into<Value>, V: Into<Value>,
@ -236,6 +272,7 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
} }
impl ColumnType { impl ColumnType {
/// instantiate a new [ColumnDef]
pub fn def(self) -> ColumnDef { pub fn def(self) -> ColumnDef {
ColumnDef { ColumnDef {
col_type: self, col_type: self,
@ -247,20 +284,24 @@ impl ColumnType {
} }
impl ColumnDef { impl ColumnDef {
/// Marks the column as `UNIQUE`
pub fn unique(mut self) -> Self { pub fn unique(mut self) -> Self {
self.unique = true; self.unique = true;
self self
} }
/// Mark the column as nullable
pub fn null(self) -> Self { pub fn null(self) -> Self {
self.nullable() self.nullable()
} }
/// Mark the column as nullable
pub fn nullable(mut self) -> Self { pub fn nullable(mut self) -> Self {
self.null = true; self.null = true;
self self
} }
/// Set the `indexed` field to `true`
pub fn indexed(mut self) -> Self { pub fn indexed(mut self) -> Self {
self.indexed = true; self.indexed = true;
self self

View File

@ -2,10 +2,14 @@ use crate::{ColumnTrait, EntityTrait, IdenStatic};
use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc}; use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc};
use std::fmt; use std::fmt;
/// Defines an operation for an Entity
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Identity { pub enum Identity {
/// Performs one operation
Unary(DynIden), Unary(DynIden),
/// Performs two operations
Binary(DynIden, DynIden), Binary(DynIden, DynIden),
/// Performs three operations
Ternary(DynIden, DynIden, DynIden), Ternary(DynIden, DynIden, DynIden),
} }
@ -28,14 +32,18 @@ impl Iden for Identity {
} }
} }
/// Performs a conversion into an [Identity]
pub trait IntoIdentity { pub trait IntoIdentity {
/// Method to perform the conversion
fn into_identity(self) -> Identity; fn into_identity(self) -> Identity;
} }
/// Check the [Identity] of an Entity
pub trait IdentityOf<E> pub trait IdentityOf<E>
where where
E: EntityTrait, E: EntityTrait,
{ {
/// Method to call to perform this check
fn identity_of(self) -> Identity; fn identity_of(self) -> Identity;
} }

View File

@ -3,15 +3,21 @@ use crate::{
}; };
use sea_query::{Alias, IntoIden, JoinType, SeaRc}; use sea_query::{Alias, IntoIden, JoinType, SeaRc};
/// Same as [RelationDef]
pub type LinkDef = RelationDef; pub type LinkDef = RelationDef;
/// A set of constraints for links between Entities
pub trait Linked { pub trait Linked {
#[allow(missing_docs)]
type FromEntity: EntityTrait; type FromEntity: EntityTrait;
#[allow(missing_docs)]
type ToEntity: EntityTrait; type ToEntity: EntityTrait;
/// Link for an Entity
fn link(&self) -> Vec<LinkDef>; fn link(&self) -> Vec<LinkDef>;
/// Find all the Entities that are linked to the Entity
fn find_linked(&self) -> Select<Self::ToEntity> { fn find_linked(&self) -> Select<Self::ToEntity> {
let mut select = Select::new(); let mut select = Select::new();
for (i, rel) in self.link().into_iter().rev().enumerate() { for (i, rel) in self.link().into_iter().rev().enumerate() {

View File

@ -4,6 +4,7 @@ mod column;
mod identity; mod identity;
mod link; mod link;
mod model; mod model;
/// Re-export common types from the entity
pub mod prelude; pub mod prelude;
mod primary_key; mod primary_key;
mod relation; mod relation;

View File

@ -5,13 +5,18 @@ use crate::{
pub use sea_query::Value; pub use sea_query::Value;
use std::fmt::Debug; use std::fmt::Debug;
/// A set of constraints for a Model
pub trait ModelTrait: Clone + Send + Debug { pub trait ModelTrait: Clone + Send + Debug {
#[allow(missing_docs)]
type Entity: EntityTrait; type Entity: EntityTrait;
/// Get the [Value] of a column from an Entity
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> Value; fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> Value;
/// Set the [Value] of a column in an Entity
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value); fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
/// Find related Models
fn find_related<R>(&self, _: R) -> Select<R> fn find_related<R>(&self, _: R) -> Select<R>
where where
R: EntityTrait, R: EntityTrait,
@ -20,6 +25,7 @@ pub trait ModelTrait: Clone + Send + Debug {
<Self::Entity as Related<R>>::find_related().belongs_to(self) <Self::Entity as Related<R>>::find_related().belongs_to(self)
} }
/// Find linked Models
fn find_linked<L>(&self, l: L) -> Select<L::ToEntity> fn find_linked<L>(&self, l: L) -> Select<L::ToEntity>
where where
L: Linked<FromEntity = Self::Entity>, L: Linked<FromEntity = Self::Entity>,
@ -29,9 +35,13 @@ pub trait ModelTrait: Clone + Send + Debug {
} }
} }
/// A set of constraints for implementing a [QueryResult]
pub trait FromQueryResult: Sized { pub trait FromQueryResult: Sized {
/// Instantiate a Model from a [QueryResult]
fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr>; fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr>;
/// Transform the error from instantiating a Model from a [QueryResult]
/// and converting it to an [Option]
fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result<Option<Self>, DbErr> { fn from_query_result_optional(res: &QueryResult, pre: &str) -> Result<Option<Self>, DbErr> {
Ok(Self::from_query_result(res, pre).ok()) Ok(Self::from_query_result(res, pre).ok())
} }

View File

@ -23,6 +23,7 @@ pub use chrono::NaiveTime as Time;
#[cfg(feature = "with-chrono")] #[cfg(feature = "with-chrono")]
pub use chrono::NaiveDateTime as DateTime; pub use chrono::NaiveDateTime as DateTime;
/// Handles the time and dates
#[cfg(feature = "with-chrono")] #[cfg(feature = "with-chrono")]
pub type DateTimeWithTimeZone = chrono::DateTime<chrono::FixedOffset>; pub type DateTimeWithTimeZone = chrono::DateTime<chrono::FixedOffset>;

View File

@ -4,7 +4,9 @@ use sea_query::{FromValueTuple, IntoValueTuple};
use std::fmt::Debug; use std::fmt::Debug;
//LINT: composite primary key cannot auto increment //LINT: composite primary key cannot auto increment
/// A set of constraints to be used to define a Primary Key
pub trait PrimaryKeyTrait: IdenStatic + Iterable { pub trait PrimaryKeyTrait: IdenStatic + Iterable {
#[allow(missing_docs)]
type ValueType: Sized type ValueType: Sized
+ Send + Send
+ Debug + Debug
@ -14,14 +16,19 @@ pub trait PrimaryKeyTrait: IdenStatic + Iterable {
+ TryGetableMany + TryGetableMany
+ TryFromU64; + TryFromU64;
/// Method to call to perform `AUTOINCREMENT` operation on a Primary Kay
fn auto_increment() -> bool; fn auto_increment() -> bool;
} }
/// How to map a Primary Key to a column
pub trait PrimaryKeyToColumn { pub trait PrimaryKeyToColumn {
#[allow(missing_docs)]
type Column: ColumnTrait; type Column: ColumnTrait;
/// Method to map a primary key to a column in an Entity
fn into_column(self) -> Self::Column; fn into_column(self) -> Self::Column;
/// Method to map a primary key from a column in an Entity
fn from_column(col: Self::Column) -> Option<Self> fn from_column(col: Self::Column) -> Option<Self>
where where
Self: Sized; Self: Sized;

View File

@ -3,45 +3,68 @@ use core::marker::PhantomData;
use sea_query::{JoinType, TableRef}; use sea_query::{JoinType, TableRef};
use std::fmt::Debug; use std::fmt::Debug;
/// Defines the type of relationship
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum RelationType { pub enum RelationType {
/// An Entity has one relationship
HasOne, HasOne,
/// An Entity has many relationships
HasMany, HasMany,
} }
/// Action to perform on a foreign key whenever there are changes
/// to an ActiveModel
pub type ForeignKeyAction = sea_query::ForeignKeyAction; pub type ForeignKeyAction = sea_query::ForeignKeyAction;
/// Constraints a type to implement the trait to create a relationship
pub trait RelationTrait: Iterable + Debug + 'static { pub trait RelationTrait: Iterable + Debug + 'static {
/// The method to call
fn def(&self) -> RelationDef; fn def(&self) -> RelationDef;
} }
/// Checks if Entities are related
pub trait Related<R> pub trait Related<R>
where where
R: EntityTrait, R: EntityTrait,
{ {
/// Check if an entity is related to another entity
fn to() -> RelationDef; fn to() -> RelationDef;
/// Check if an entity is related through another entity
fn via() -> Option<RelationDef> { fn via() -> Option<RelationDef> {
None None
} }
/// Find related Entities
fn find_related() -> Select<R> { fn find_related() -> Select<R> {
Select::<R>::new().join_join_rev(JoinType::InnerJoin, Self::to(), Self::via()) Select::<R>::new().join_join_rev(JoinType::InnerJoin, Self::to(), Self::via())
} }
} }
/// Defines a relationship
#[derive(Debug)] #[derive(Debug)]
pub struct RelationDef { pub struct RelationDef {
/// The type of relationship defined in [RelationType]
pub rel_type: RelationType, pub rel_type: RelationType,
/// Reference from another Entity
pub from_tbl: TableRef, pub from_tbl: TableRef,
/// Reference to another ENtity
pub to_tbl: TableRef, pub to_tbl: TableRef,
/// Reference to from a Column
pub from_col: Identity, pub from_col: Identity,
/// Reference to another column
pub to_col: Identity, pub to_col: Identity,
/// Defines the owner of the Relation
pub is_owner: bool, pub is_owner: bool,
/// Defines an operation to be performed on a Foreign Key when a
/// `DELETE` Operation is performed
pub on_delete: Option<ForeignKeyAction>, pub on_delete: Option<ForeignKeyAction>,
/// Defines an operation to be performed on a Foreign Key when a
/// `UPDATE` Operation is performed
pub on_update: Option<ForeignKeyAction>, pub on_update: Option<ForeignKeyAction>,
} }
/// Defines a helper to build a relation
#[derive(Debug)] #[derive(Debug)]
pub struct RelationBuilder<E, R> pub struct RelationBuilder<E, R>
where where
@ -108,6 +131,7 @@ where
} }
} }
/// Build a relationship from an Entity
pub fn from<T>(mut self, identifier: T) -> Self pub fn from<T>(mut self, identifier: T) -> Self
where where
T: IdentityOf<E>, T: IdentityOf<E>,
@ -116,6 +140,7 @@ where
self self
} }
/// Build a relationship to an Entity
pub fn to<T>(mut self, identifier: T) -> Self pub fn to<T>(mut self, identifier: T) -> Self
where where
T: IdentityOf<R>, T: IdentityOf<R>,
@ -124,11 +149,13 @@ where
self self
} }
/// An operation to perform on a foreign key when a delete operation occurs
pub fn on_delete(mut self, action: ForeignKeyAction) -> Self { pub fn on_delete(mut self, action: ForeignKeyAction) -> Self {
self.on_delete = Some(action); self.on_delete = Some(action);
self self
} }
/// An operation to perform on a foreign key when an update operation occurs
pub fn on_update(mut self, action: ForeignKeyAction) -> Self { pub fn on_update(mut self, action: ForeignKeyAction) -> Self {
self.on_update = Some(action); self.on_update = Some(action);
self self