Skip to content

Commit

Permalink
feat: add recipe ingredient draft entity
Browse files Browse the repository at this point in the history
This is used for external recipes which can not assign an ingredient to a specific step.
  • Loading branch information
Toromyx committed Feb 8, 2024
1 parent de5d351 commit 4098f41
Show file tree
Hide file tree
Showing 25 changed files with 598 additions and 5 deletions.
8 changes: 8 additions & 0 deletions docs/architecture/database/schema.puml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ entity "Recipe Step Ingredient" as recipe_step_ingredient {
}
recipe_step_ingredient }o--|| "recipe_id" recipe

entity "Recipe Ingredient Draft" as recipe_ingredient_draft {
id: INTEGER
--
order: INTEGER
text: TEXT
}
recipe_ingredient_draft }o--|| "recipe_id" recipe

entity "Recipe Step Ingredient Draft" as recipe_step_ingredient_draft {
id: INTEGER
--
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/command/entity.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod ingredient;
pub mod recipe;
pub mod recipe_file;
pub mod recipe_ingredient_draft;
pub mod recipe_step;
pub mod recipe_step_ingredient;
pub mod recipe_step_ingredient_draft;
Expand Down
56 changes: 56 additions & 0 deletions src-tauri/src/command/entity/recipe_ingredient_draft.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use crate::{
command::error::{CommandError, CommandError::NotFound},
entity::recipe_ingredient_draft::Model,
entity_crud::{
recipe_ingredient_draft::{
RecipeIngredientDraftCondition, RecipeIngredientDraftCreate, RecipeIngredientDraftCrud,
RecipeIngredientDraftFilter, RecipeIngredientDraftUpdate,
},
EntityCrudTrait,
},
};

#[tauri::command]
pub async fn entity_create_recipe_ingredient_draft(
create: RecipeIngredientDraftCreate,
) -> Result<i64, CommandError> {
let id = RecipeIngredientDraftCrud::create(create).await?;
Ok(id)
}

#[tauri::command]
pub async fn entity_read_recipe_ingredient_draft(id: i64) -> Result<Model, CommandError> {
let model_option = RecipeIngredientDraftCrud::read(id).await?;
let model = model_option.ok_or(NotFound)?;
Ok(model)
}

#[tauri::command]
pub async fn entity_update_recipe_ingredient_draft(
update: RecipeIngredientDraftUpdate,
) -> Result<(), CommandError> {
RecipeIngredientDraftCrud::update(update).await?;
Ok(())
}

#[tauri::command]
pub async fn entity_delete_recipe_ingredient_draft(id: i64) -> Result<(), CommandError> {
RecipeIngredientDraftCrud::delete(id).await?;
Ok(())
}

#[tauri::command]
pub async fn entity_list_recipe_ingredient_draft(
filter: RecipeIngredientDraftFilter,
) -> Result<Vec<i64>, CommandError> {
let list = RecipeIngredientDraftCrud::list(filter).await?;
Ok(list)
}

#[tauri::command]
pub async fn entity_count_recipe_ingredient_draft(
condition: Option<RecipeIngredientDraftCondition>,
) -> Result<i64, CommandError> {
let count = RecipeIngredientDraftCrud::count(condition).await?;
Ok(count)
}
12 changes: 12 additions & 0 deletions src-tauri/src/command/external_recipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
entity_crud::{
recipe::{RecipeCreate, RecipeCrud},
recipe_file::{RecipeFileCreate, RecipeFileCreateUri, RecipeFileCrud},
recipe_ingredient_draft::{RecipeIngredientDraftCreate, RecipeIngredientDraftCrud},
recipe_step::{RecipeStepCreate, RecipeStepCrud},
recipe_step_ingredient_draft::{
RecipeStepIngredientDraftCreate, RecipeStepIngredientDraftCrud,
Expand All @@ -18,6 +19,17 @@ pub async fn external_recipe(url: String) -> Result<i64, CommandError> {
name: external_recipe.name,
})
.await?;
for (i, ingredient) in external_recipe.ingredients.into_iter().enumerate() {
tokio::spawn(async move {
RecipeIngredientDraftCrud::create(RecipeIngredientDraftCreate {
order: (i + 1) as i64,
text: ingredient,
recipe_id,
})
.await
.unwrap();
});
}
for (i, step) in external_recipe.steps.into_iter().enumerate() {
tokio::spawn(async move {
let recipe_step_id = RecipeStepCrud::create(RecipeStepCreate {
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod ingredient;
pub mod recipe;
pub mod recipe_file;
pub mod recipe_ingredient_draft;
pub mod recipe_step;
pub mod recipe_step_ingredient;
pub mod recipe_step_ingredient_draft;
Expand Down
41 changes: 41 additions & 0 deletions src-tauri/src/entity/recipe_ingredient_draft.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! This module implements the recipe ingredient draft entity.
//!
//! See [`Model`] for more information.
use sea_orm::entity::prelude::*;
use serde::Serialize;

/// This struct represents a recipe ingredient draft.
///
/// Just like [`super::recipe_step_ingredient::Model`] it is not yet split up into quantity, unit, and does not include a reference to an [`super::ingredient::Model`].
/// But in contrast to [`super::recipe_step_ingredient::Model`] this entity is related to the recipe directly because a [`super::recipe_step::Model`] could not be determined.
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "recipe_ingredient_draft")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i64,
pub order: i64,
pub text: String,
pub recipe_id: i64,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::recipe::Entity",
from = "Column::RecipeId",
to = "super::recipe::Column::Id",
on_update = "NoAction",
on_delete = "Cascade"
)]
Recipe,
}

impl Related<super::recipe::Entity> for Entity {
fn to() -> RelationDef {
Relation::Recipe.def()
}
}

impl ActiveModelBehavior for ActiveModel {}
1 change: 1 addition & 0 deletions src-tauri/src/entity_crud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{database, window::get_window};
pub mod ingredient;
pub mod recipe;
pub mod recipe_file;
pub mod recipe_ingredient_draft;
pub mod recipe_step;
pub mod recipe_step_ingredient;
pub mod recipe_step_ingredient_draft;
Expand Down
122 changes: 122 additions & 0 deletions src-tauri/src/entity_crud/recipe_ingredient_draft.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//! This module implements [`EntityCrudTrait`] for [`crate::entity::recipe_ingredient_draft`].
use sea_orm::{
sea_query::IntoCondition,
ActiveValue::{NotSet, Set, Unchanged},
ColumnTrait, Condition, DeriveIntoActiveModel, IntoActiveModel, QueryOrder, Select,
};
use serde::Deserialize;

use crate::{
entity::recipe_ingredient_draft::{ActiveModel, Column, Entity, Model, PrimaryKey, Relation},
entity_crud::{EntityCrudTrait, Filter, Order, OrderBy},
event::channel::{
ENTITY_ACTION_CREATED_RECIPE_INGREDIENT_DRAFT,
ENTITY_ACTION_DELETED_RECIPE_INGREDIENT_DRAFT,
ENTITY_ACTION_UPDATED_RECIPE_INGREDIENT_DRAFT,
},
};

#[derive(Debug, Deserialize, DeriveIntoActiveModel)]
#[serde(rename_all = "camelCase")]
pub struct RecipeIngredientDraftCreate {
pub order: i64,
pub text: String,
pub recipe_id: i64,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RecipeIngredientDraftUpdate {
pub id: i64,
pub order: Option<i64>,
pub text: Option<String>,
}

impl IntoActiveModel<ActiveModel> for RecipeIngredientDraftUpdate {
fn into_active_model(self) -> ActiveModel {
ActiveModel {
id: Unchanged(self.id),
order: match self.order {
Some(order) => Set(order),
_ => NotSet,
},
text: match self.text {
Some(text) => Set(text),
_ => NotSet,
},
recipe_id: NotSet,
}
}
}

pub type RecipeIngredientDraftFilter =
Filter<RecipeIngredientDraftCondition, RecipeIngredientDraftOrderBy>;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RecipeIngredientDraftCondition {
pub recipe_id: Option<i64>,
}

impl IntoCondition for RecipeIngredientDraftCondition {
fn into_condition(self) -> Condition {
Condition::all().add_option(
self.recipe_id
.map(|recipe_id| Column::RecipeId.eq(recipe_id)),
)
}
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum RecipeIngredientDraftOrderBy {
Order(Order),
}

impl OrderBy for RecipeIngredientDraftOrderBy {
type Entity = Entity;

fn add(self, select: Select<Self::Entity>) -> Select<Self::Entity> {
match self {
RecipeIngredientDraftOrderBy::Order(order) => {
select.order_by(Column::Order, order.into())
}
}
}
}

pub struct RecipeIngredientDraftCrud {}

impl EntityCrudTrait for RecipeIngredientDraftCrud {
type Entity = Entity;
type Model = Model;
type ActiveModel = ActiveModel;
type Column = Column;
type Relation = Relation;
type PrimaryKey = PrimaryKey;
type EntityCreate = RecipeIngredientDraftCreate;
type EntityUpdate = RecipeIngredientDraftUpdate;
type EntityCondition = RecipeIngredientDraftCondition;
type EntityOrderBy = RecipeIngredientDraftOrderBy;

fn primary_key_value(model: &Model) -> i64 {
model.id
}

fn primary_key_colum() -> Column {
Column::Id
}

fn entity_action_created_channel() -> &'static str {
ENTITY_ACTION_CREATED_RECIPE_INGREDIENT_DRAFT
}

fn entity_action_updated_channel() -> &'static str {
ENTITY_ACTION_UPDATED_RECIPE_INGREDIENT_DRAFT
}

fn entity_action_deleted_channel() -> &'static str {
ENTITY_ACTION_DELETED_RECIPE_INGREDIENT_DRAFT
}
}
7 changes: 7 additions & 0 deletions src-tauri/src/event/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ pub const ENTITY_ACTION_CREATED_RECIPE: &str = "ENTITY_ACTION_CREATED_RECIPE";
pub const ENTITY_ACTION_UPDATED_RECIPE: &str = "ENTITY_ACTION_UPDATED_RECIPE";
pub const ENTITY_ACTION_DELETED_RECIPE: &str = "ENTITY_ACTION_DELETED_RECIPE";

pub const ENTITY_ACTION_CREATED_RECIPE_INGREDIENT_DRAFT: &str =
"ENTITY_ACTION_CREATED_RECIPE_INGREDIENT_DRAFT";
pub const ENTITY_ACTION_UPDATED_RECIPE_INGREDIENT_DRAFT: &str =
"ENTITY_ACTION_UPDATED_RECIPE_INGREDIENT_DRAFT";
pub const ENTITY_ACTION_DELETED_RECIPE_INGREDIENT_DRAFT: &str =
"ENTITY_ACTION_DELETED_RECIPE_INGREDIENT_DRAFT";

pub const ENTITY_ACTION_CREATED_RECIPE_FILE: &str = "ENTITY_ACTION_CREATED_RECIPE_FILE";
pub const ENTITY_ACTION_UPDATED_RECIPE_FILE: &str = "ENTITY_ACTION_UPDATED_RECIPE_FILE";
pub const ENTITY_ACTION_DELETED_RECIPE_FILE: &str = "ENTITY_ACTION_DELETED_RECIPE_FILE";
Expand Down
5 changes: 3 additions & 2 deletions src-tauri/src/external_recipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ pub mod knusperstuebchen;
pub mod pinterest;
pub mod sallys_welt;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ExternalRecipe {
pub name: String,
pub ingredients: Vec<String>,
pub steps: Vec<ExternalRecipeStep>,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ExternalRecipeStep {
pub ingredients: Vec<String>,
Expand Down
8 changes: 6 additions & 2 deletions src-tauri/src/external_recipe/knusperstuebchen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl ExternalRecipeGetterTrait for ExternalRecipeGetter {
description: String::from(""),
files: vec![pdf_anchor_element.get_attribute("href").await?],
}],
..Default::default()
}),
Some(recipe_element) => {
let name_element = recipe_element.select(".ERSName").await?.unwrap();
Expand Down Expand Up @@ -67,6 +68,7 @@ impl ExternalRecipeGetterTrait for ExternalRecipeGetter {
pdf_anchor_element.get_attribute("href").await?,
],
}],
..Default::default()
})
}
}
Expand Down Expand Up @@ -95,12 +97,12 @@ mod tests {
external_recipe: ExternalRecipe {
name: String::from("Apfel-Mazarin-Kuchen"),
steps: vec![ExternalRecipeStep {
ingredients: vec![],
description: String::from(""),
files: vec![String::from(
"https://knusperstuebchen.net/wp-content/uploads/2014/09/Apfel-Mazarin-Kuchen.pdf",
)],
..Default::default()
}],
..Default::default()
},
},
ExpectedGet {
Expand Down Expand Up @@ -150,6 +152,7 @@ mod tests {
),
],
}],
..Default::default()
},
},
ExpectedGet {
Expand Down Expand Up @@ -197,6 +200,7 @@ mod tests {
),
],
}],
..Default::default()
},
},
]
Expand Down
4 changes: 3 additions & 1 deletion src-tauri/src/external_recipe/pinterest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ impl ExternalRecipeGetterTrait for ExternalRecipeGetter {
.map(|block| block.video_data.video_list.video.url)
.collect(),
}],
..Default::default()
}),
PinterestRelayPinQueryData::External(data) => {
let external_recipe = crate::external_recipe::get(data.link).await?;
Expand All @@ -147,7 +148,7 @@ impl ExternalRecipeGetterTrait for ExternalRecipeGetter {
vec![pin_it_uri_match(), pinterest_uri_match()]
}
}

/*
#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down Expand Up @@ -199,3 +200,4 @@ mod tests {
}
}
}
*/
1 change: 1 addition & 0 deletions src-tauri/src/external_recipe/sallys_welt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ impl ExternalRecipeGetterTrait for ExternalRecipeGetter {
Ok(ExternalRecipe {
name: dom.select("h1").await?.unwrap().text_content().await?,
steps,
..Default::default()
})
}

Expand Down
Loading

0 comments on commit 4098f41

Please sign in to comment.