From 894e8b40a44c0bf4d286459a39a845545d781686 Mon Sep 17 00:00:00 2001 From: eraden Date: Sat, 10 Jun 2023 22:48:33 +0200 Subject: [PATCH] Add constraint --- .../checkouts/m20230603_120814_checkouts.rs | 3 +- .../src/checkouts/m20230603_120815_items.rs | 91 ++++++++++- migration/src/lib.rs | 142 ++++++++++++++++++ 3 files changed, 231 insertions(+), 5 deletions(-) diff --git a/migration/src/checkouts/m20230603_120814_checkouts.rs b/migration/src/checkouts/m20230603_120814_checkouts.rs index 8bcfe10..de1a393 100644 --- a/migration/src/checkouts/m20230603_120814_checkouts.rs +++ b/migration/src/checkouts/m20230603_120814_checkouts.rs @@ -502,7 +502,8 @@ impl Migration { PaymentCollectionSession::PaymentSessionId, )) .to_owned(), - ); + ) + .await?; Ok(()) } /// ```sql diff --git a/migration/src/checkouts/m20230603_120815_items.rs b/migration/src/checkouts/m20230603_120815_items.rs index e779d2e..31b0abb 100644 --- a/migration/src/checkouts/m20230603_120815_items.rs +++ b/migration/src/checkouts/m20230603_120815_items.rs @@ -1,9 +1,10 @@ use sea_orm_migration::prelude::*; +use crate::constraint::Check; use crate::sea_orm::Iterable; use crate::{ - auto_uuid_not_null, create_type, drop_type, to_fk_name, to_pk2_name, ts_def_now_not_null, - DropTable, IntoColumnDef, + auto_uuid_not_null, create_constraint, create_type, drop_type, to_fk_name, to_pk2_name, + ts_def_now_not_null, AsIden, DropTable, IntoColumnDef, }; #[derive(DeriveMigrationName)] @@ -21,6 +22,7 @@ impl MigrationTrait for Migration { } impl Migration { + /// ```sql /// CREATE TABLE line_items /// ( /// id uuid NOT NULL, @@ -52,7 +54,26 @@ impl Migration { /// CONSTRAINT "CHK_91f40396d847f6ecfd9f752bf8" CHECK ((returned_quantity <= quantity)), /// CONSTRAINT "CHK_c61716c68f5ad5de2834c827d3" CHECK ((fulfilled_quantity <= quantity)) /// ); - /// + /// ``` + async fn create_line_items(&self, m: &SchemaManager<'_>) -> Result<(), DbErr> { + create_constraint( + m, + LineItem::LineItems, + Check::lower_eq(LineItem::ShippedQuantity, LineItem::FulfilledQuantity), + ) + .await?; + + create_constraint( + m, + LineItem::LineItems, + Check::greater(LineItem::Quantity, 0.iden()), + ) + .await?; + + Ok(()) + } + + /// ```sql /// CREATE TABLE line_item_adjustments /// ( /// id uuid NOT NULL, @@ -62,7 +83,12 @@ impl Migration { /// amount numeric NOT NULL, /// metadata jsonb /// ); - /// + /// ``` + async fn create_line_item_adjustments(&self, m: &SchemaManager<'_>) -> Result<(), DbErr> { + Ok(()) + } + + /// ```sql /// CREATE TABLE line_item_tax_lines /// ( /// id uuid NOT NULL, @@ -74,4 +100,61 @@ impl Migration { /// metadata jsonb, /// item_id uuid NOT NULL /// ); + /// ``` + async fn create_line_item_tax_lines(&self, m: &SchemaManager<'_>) -> Result<(), DbErr> { + Ok(()) + } +} + +#[derive(Iden)] +pub enum LineItem { + LineItems, + Id, + CartId, + OrderId, + SwapId, + Title, + Description, + Thumbnail, + IsGiftcard, + ShouldMerge, + AllowDiscounts, + HasShipping, + UnitPrice, + VariantId, + Quantity, + FulfilledQuantity, + ReturnedQuantity, + ShippedQuantity, + CreatedAt, + UpdatedAt, + Metadata, + ClaimOrderId, + IsReturn, + OriginalItemId, + OrderEditId, +} + +#[derive(Iden)] +pub enum LineItemAdjustment { + LineItemAdjustments, + Id, + ItemId, + Description, + DiscountId, + Amount, + Metadata, +} + +#[derive(Iden)] +pub enum LineItemTaxLine { + LineItemTaxLines, + Id, + Rate, + Name, + Code, + CreatedAt, + UpdatedAt, + Metadata, + ItemId, } diff --git a/migration/src/lib.rs b/migration/src/lib.rs index 076b9d2..b6d1964 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -1,3 +1,5 @@ +use std::fmt::{Display, Formatter, Pointer}; + pub use sea_orm_migration::prelude::*; pub mod carts; @@ -18,6 +20,8 @@ pub mod types; pub use types::*; +use crate::constraint::Check; + #[macro_export] macro_rules! ts_def_now_not_null { ($identifier: expr) => { @@ -109,3 +113,141 @@ fn to_snake(s: String) -> String { m }) } + +pub mod constraint { + use std::fmt::{Display, Formatter, Write}; + + use crate::{Constraint, Iden}; + + pub enum Check { + Lower(Box, Box), + LowerEq(Box, Box), + Eq(Box, Box), + GreaterEq(Box, Box), + Greater(Box, Box), + Or(Box, Box), + } + + impl Check { + pub fn or(self, r: Check) -> Check { + Check::Or(Box::new(self), Box::new(r)) + } + + pub fn constraint(self) -> Constraint { + Constraint::Check(self) + } + + pub fn to_name(&self) -> String { + match self { + Check::Lower(l, r) => format!("{}_lw_{}", l.to_string(), r.to_string()), + Check::LowerEq(l, r) => format!("{}_le_{}", l.to_string(), r.to_string()), + Check::Eq(l, r) => format!("{}_eq_{}", l.to_string(), r.to_string()), + Check::GreaterEq(l, r) => format!("{}_ge_{}", l.to_string(), r.to_string()), + Check::Greater(l, r) => format!("{}_g_{}", l.to_string(), r.to_string()), + Check::Or(l, r) => format!("{}_or_{}", l.to_name(), r.to_name()), + } + } + } + + impl Display for Check { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Check::Lower(l, r) => { + f.write_fmt(format_args!("{} < {}", l.to_string(), r.to_string())) + } + Check::LowerEq(l, r) => { + f.write_fmt(format_args!("{} <= {}", l.to_string(), r.to_string())) + } + Check::Eq(l, r) => { + f.write_fmt(format_args!("{} = {}", l.to_string(), r.to_string())) + } + Check::GreaterEq(l, r) => { + f.write_fmt(format_args!("{} >= {}", l.to_string(), r.to_string())) + } + Check::Greater(l, r) => { + f.write_fmt(format_args!("{} > {}", l.to_string(), r.to_string())) + } + Check::Or(l, r) => f.write_fmt(format_args!("({l}) OR ({r})")), + } + } + } + + impl Check { + pub fn lower(l: L, r: R) -> Check { + Check::Lower(Box::new(l), Box::new(r)) + } + pub fn lower_eq(l: L, r: R) -> Check { + Check::LowerEq(Box::new(l), Box::new(r)) + } + pub fn eq(l: L, r: R) -> Check { + Check::Eq(Box::new(l), Box::new(r)) + } + pub fn greater_eq(l: L, r: R) -> Check { + Check::GreaterEq(Box::new(l), Box::new(r)) + } + pub fn greater(l: L, r: R) -> Check { + Check::Greater(Box::new(l), Box::new(r)) + } + } +} + +pub struct CheckUSize(usize); + +impl Iden for CheckUSize { + fn unquoted(&self, s: &mut dyn Write) { + s.write_str(&format!("{}", self.0)); + } +} + +pub trait AsIden { + fn iden(self) -> I; +} + +impl AsIden for usize { + fn iden(self) -> CheckUSize { + CheckUSize(self) + } +} + +pub enum Constraint { + Check(Check), +} + +impl Constraint { + fn to_name(&self) -> String { + match self { + Constraint::Check(check) => format!("ck_{}", check.to_name()), + } + } +} + +impl From for Constraint { + fn from(value: Check) -> Self { + Self::Check(value) + } +} + +impl Display for Constraint { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Constraint::Check(check) => f.write_fmt(format_args!("CHECK {check}")), + } + } +} + +async fn create_constraint>( + m: &SchemaManager<'_>, + table: T, + c: C, +) -> Result<(), DbErr> { + let c = c.into(); + m.get_connection() + .execute_unprepared(&format!( + "ALTER TABLE {} ADD CONSTRAINT {} {}", + table.to_string(), + c.to_name(), + c + )) + .await; + Ok(()) +}