Block adds & sellers, add metrics
This commit is contained in:
parent
57b1113cc3
commit
31e0920a50
36
Cargo.lock
generated
36
Cargo.lock
generated
@ -330,6 +330,21 @@ dependencies = [
|
|||||||
"syn 2.0.82",
|
"syn 2.0.82",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-web-prom"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56a34f1825c3ae06567a9d632466809bbf34963c86002e8921b64f32d48d289d"
|
||||||
|
dependencies = [
|
||||||
|
"actix-web",
|
||||||
|
"futures-core",
|
||||||
|
"log",
|
||||||
|
"pin-project-lite",
|
||||||
|
"prometheus",
|
||||||
|
"regex",
|
||||||
|
"strfmt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix_derive"
|
name = "actix_derive"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@ -1169,6 +1184,7 @@ dependencies = [
|
|||||||
"actix-rt",
|
"actix-rt",
|
||||||
"actix-session",
|
"actix-session",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
"actix-web-prom",
|
||||||
"askama",
|
"askama",
|
||||||
"askama_actix",
|
"askama_actix",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -3292,6 +3308,20 @@ dependencies = [
|
|||||||
"yansi",
|
"yansi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prometheus"
|
||||||
|
version = "0.13.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fnv",
|
||||||
|
"lazy_static",
|
||||||
|
"memchr",
|
||||||
|
"parking_lot",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ptr_meta"
|
name = "ptr_meta"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
@ -4650,6 +4680,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strfmt"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a8348af2d9fc3258c8733b8d9d8db2e56f54b2363a4b5b81585c7875ed65e65"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stringprep"
|
name = "stringprep"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -38,6 +38,7 @@ futures-core = "0.3.31"
|
|||||||
futures-util = "0.3.31"
|
futures-util = "0.3.31"
|
||||||
encoding_rs = "0.8.35"
|
encoding_rs = "0.8.35"
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
|
actix-web-prom = "0.9.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ use actix_session::{storage::RedisSessionStore, SessionMiddleware};
|
|||||||
use actix_web::cookie::Key;
|
use actix_web::cookie::Key;
|
||||||
use actix_web::{error, HttpResponse};
|
use actix_web::{error, HttpResponse};
|
||||||
use actix_web::{web::Data, App, HttpServer};
|
use actix_web::{web::Data, App, HttpServer};
|
||||||
|
use actix_web_prom::{PrometheusMetrics, PrometheusMetricsBuilder};
|
||||||
use sea_orm::Database;
|
use sea_orm::Database;
|
||||||
use serde_qs as qs;
|
use serde_qs as qs;
|
||||||
use serde_qs::actix::QsQueryConfig;
|
use serde_qs::actix::QsQueryConfig;
|
||||||
@ -116,12 +117,19 @@ async fn main() {
|
|||||||
Search(search_addr)
|
Search(search_addr)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let prometheus = PrometheusMetricsBuilder::new("api")
|
||||||
|
.endpoint("/metrics")
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Transform to data
|
// Transform to data
|
||||||
let search = Data::new(search);
|
let search = Data::new(search);
|
||||||
let admins = Data::new(admins);
|
let admins = Data::new(admins);
|
||||||
let db = Data::new(db);
|
let db = Data::new(db);
|
||||||
let redis = Data::new(redis);
|
let redis = Data::new(redis);
|
||||||
|
|
||||||
|
crate::routes::db_cleanup(db.clone());
|
||||||
|
|
||||||
let qs_config = QsQueryConfig::default()
|
let qs_config = QsQueryConfig::default()
|
||||||
.error_handler(|err, _req| {
|
.error_handler(|err, _req| {
|
||||||
// <- create custom error response
|
// <- create custom error response
|
||||||
@ -143,6 +151,7 @@ async fn main() {
|
|||||||
.cookie_name(SESSION_KEY.to_string())
|
.cookie_name(SESSION_KEY.to_string())
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
|
.wrap(prometheus.clone())
|
||||||
.app_data(qs_config.clone())
|
.app_data(qs_config.clone())
|
||||||
.app_data(admins.clone())
|
.app_data(admins.clone())
|
||||||
.app_data(db.clone())
|
.app_data(db.clone())
|
||||||
|
@ -1210,12 +1210,12 @@ async fn styles_css() -> HttpResponse {
|
|||||||
.body(include_str!("../assets/styles.css"))
|
.body(include_str!("../assets/styles.css"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn tmp_cleanup() {
|
fn tmp_cleanup() {
|
||||||
|
actix_rt::spawn(async {
|
||||||
let d = tokio::time::Duration::from_secs(10);
|
let d = tokio::time::Duration::from_secs(10);
|
||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(d).await;
|
tokio::time::sleep(d).await;
|
||||||
let _ = std::fs::create_dir_all("/tmp/assets/recipies/images");
|
let _ = std::fs::create_dir_all("/tmp/assets/recipies/images");
|
||||||
// tracing::info!("Starting files cleanup");
|
|
||||||
|
|
||||||
let Ok(mut dir) = tokio::fs::read_dir("/tmp/assets/recipies/images").await else {
|
let Ok(mut dir) = tokio::fs::read_dir("/tmp/assets/recipies/images").await else {
|
||||||
tracing::info!("Files cleanup failed. No tmp images dir");
|
tracing::info!("Files cleanup failed. No tmp images dir");
|
||||||
@ -1236,19 +1236,111 @@ async fn tmp_cleanup() {
|
|||||||
}
|
}
|
||||||
// tracing::info!("Files cleanup done");
|
// tracing::info!("Files cleanup done");
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn db_cleanup(db: Data<DatabaseConnection>) {
|
||||||
|
actix_rt::spawn(async move {
|
||||||
|
let d = tokio::time::Duration::from_secs(10);
|
||||||
|
loop {
|
||||||
|
let ids = Ingredients::find()
|
||||||
|
.join(
|
||||||
|
JoinType::Join,
|
||||||
|
entities::ingredients::Relation::RecipeIngredients.def(),
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
JoinType::Join,
|
||||||
|
entities::recipe_ingredients::Relation::Recipies.def(),
|
||||||
|
)
|
||||||
|
.select_only()
|
||||||
|
.column(entities::ingredients::Column::Id)
|
||||||
|
.column(entities::ingredients::Column::Name)
|
||||||
|
.column_as(
|
||||||
|
entities::recipe_ingredients::Column::RecipeId.count(),
|
||||||
|
"recipe_count",
|
||||||
|
)
|
||||||
|
.order_by_asc(entities::ingredients::Column::Name)
|
||||||
|
.group_by(entities::ingredients::Column::Id)
|
||||||
|
.into_model::<crate::types::ingredient_with_recipe_count::Model>()
|
||||||
|
.all(&**db)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| tracing::error!("Failed to load ingredients: {e}"))
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|record| matches!(record.recipe_count, None | Some(0)))
|
||||||
|
.map(|record| record.id)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let _ = Ingredients::delete_many()
|
||||||
|
.filter(entities::ingredients::Column::Id.is_in(ids))
|
||||||
|
.exec(&**db)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| {
|
||||||
|
tracing::error!("Failed clean up ingredients without recipies: {e}")
|
||||||
|
});
|
||||||
|
|
||||||
|
let ids = Tags::find()
|
||||||
|
.join(JoinType::Join, entities::tags::Relation::RecipeTags.def())
|
||||||
|
.join(
|
||||||
|
JoinType::Join,
|
||||||
|
entities::recipe_tags::Relation::Recipies.def(),
|
||||||
|
)
|
||||||
|
.select_only()
|
||||||
|
.column(entities::tags::Column::Id)
|
||||||
|
.column(entities::tags::Column::Name)
|
||||||
|
.column_as(
|
||||||
|
entities::recipe_tags::Column::RecipeId.count(),
|
||||||
|
"recipe_count",
|
||||||
|
)
|
||||||
|
.order_by_asc(entities::tags::Column::Name)
|
||||||
|
.group_by(entities::tags::Column::Id)
|
||||||
|
.into_model::<crate::types::tag_with_recipe_count::Model>()
|
||||||
|
.all(&**db)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| tracing::error!("Failed to load ingredients: {e}"))
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|record| matches!(record.recipe_count, None | Some(0)))
|
||||||
|
.map(|record| record.id)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let _ = Tags::delete_many()
|
||||||
|
.filter(entities::ingredients::Column::Id.is_in(ids))
|
||||||
|
.exec(&**db)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| tracing::error!("Failed clean up tags without recipies: {e}"));
|
||||||
|
tokio::time::sleep(d).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/app-ads.txt")]
|
||||||
|
pub async fn no_app_ads() -> HttpResponse {
|
||||||
|
HttpResponse::Ok().body("")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/ads.txt")]
|
||||||
|
pub async fn no_ads() -> HttpResponse {
|
||||||
|
HttpResponse::Ok().body("")
|
||||||
|
}
|
||||||
|
#[get("/sellers.json")]
|
||||||
|
pub async fn no_sellers() -> HttpResponse {
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.append_header(("Content-Type", "application/json"))
|
||||||
|
.body("{}")
|
||||||
|
}
|
||||||
|
#[get("/health")]
|
||||||
|
pub async fn health() -> HttpResponse {
|
||||||
|
HttpResponse::Ok().finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure(config: &mut actix_web::web::ServiceConfig) {
|
pub fn configure(config: &mut actix_web::web::ServiceConfig) {
|
||||||
actix_rt::spawn(tmp_cleanup());
|
tmp_cleanup();
|
||||||
|
|
||||||
config
|
config
|
||||||
.service(styles_css)
|
.service(styles_css)
|
||||||
.service(render_sign_in)
|
.service(render_sign_in)
|
||||||
.service(sign_in)
|
.service(sign_in)
|
||||||
.service(index_html)
|
|
||||||
.service(show)
|
|
||||||
.service(search_page)
|
.service(search_page)
|
||||||
.service(search_results)
|
.service(search_results)
|
||||||
.service(recipe_image_update)
|
|
||||||
.service(update_recipe)
|
.service(update_recipe)
|
||||||
.service(edit_recipe)
|
.service(edit_recipe)
|
||||||
.service(recipe_form)
|
.service(recipe_form)
|
||||||
@ -1258,5 +1350,12 @@ pub fn configure(config: &mut actix_web::web::ServiceConfig) {
|
|||||||
.service(ingredients_list)
|
.service(ingredients_list)
|
||||||
.service(by_tag)
|
.service(by_tag)
|
||||||
.service(tags_list)
|
.service(tags_list)
|
||||||
|
.service(recipe_image_update)
|
||||||
|
.service(show)
|
||||||
|
.service(index_html)
|
||||||
|
.service(no_app_ads)
|
||||||
|
.service(no_ads)
|
||||||
|
.service(no_sellers)
|
||||||
|
.service(health)
|
||||||
.service(Files::new("/assets", "./assets"));
|
.service(Files::new("/assets", "./assets"));
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ pub type User = String;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Ingredient {
|
pub struct Ingredient {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub qty: i32,
|
pub qty: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub unit: String,
|
pub unit: String,
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ pub fn parse_steps(s: &str) -> Result<Vec<(String, Option<String>)>, Error> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_ingredients(s: &str) -> Result<Vec<(String, Option<String>, i32)>, Error> {
|
pub fn parse_ingredients(s: &str) -> Result<Vec<(String, Option<String>, String)>, Error> {
|
||||||
s.lines()
|
s.lines()
|
||||||
.map(|s| s.trim())
|
.map(|s| s.trim())
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
@ -41,19 +41,13 @@ pub fn parse_ingredients(s: &str) -> Result<Vec<(String, Option<String>, i32)>,
|
|||||||
0 | 1 => return Err(InvalidIngeredientList),
|
0 | 1 => return Err(InvalidIngeredientList),
|
||||||
// no unit
|
// no unit
|
||||||
2 => {
|
2 => {
|
||||||
let qty = pieces
|
let qty = pieces.remove(0);
|
||||||
.remove(0)
|
Ok((pieces.join(" "), None, qty.to_string()))
|
||||||
.parse()
|
|
||||||
.map_err(|_| InvalidIngeredientList)?;
|
|
||||||
Ok((pieces.join(" "), None, qty))
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let qty = pieces
|
let qty = pieces.remove(0);
|
||||||
.remove(0)
|
|
||||||
.parse()
|
|
||||||
.map_err(|_| InvalidIngeredientList)?;
|
|
||||||
let unit = pieces.remove(0);
|
let unit = pieces.remove(0);
|
||||||
Ok((pieces.join(" "), Some(unit.to_string()), qty))
|
Ok((pieces.join(" "), Some(unit.to_string()), qty.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.11
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
|
#[sea_orm(unique)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.11
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.11
|
||||||
|
|
||||||
pub use super::ingredients::Entity as Ingredients;
|
pub use super::ingredients::Entity as Ingredients;
|
||||||
pub use super::recipe_ingredients::Entity as RecipeIngredients;
|
pub use super::recipe_ingredients::Entity as RecipeIngredients;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.11
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -9,7 +9,7 @@ pub struct Model {
|
|||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub ingredient_id: i32,
|
pub ingredient_id: i32,
|
||||||
pub qty: i32,
|
pub qty: String,
|
||||||
pub unit: String,
|
pub unit: String,
|
||||||
pub recipe_id: i32,
|
pub recipe_id: i32,
|
||||||
}
|
}
|
||||||
@ -20,16 +20,16 @@ pub enum Relation {
|
|||||||
belongs_to = "super::ingredients::Entity",
|
belongs_to = "super::ingredients::Entity",
|
||||||
from = "Column::IngredientId",
|
from = "Column::IngredientId",
|
||||||
to = "super::ingredients::Column::Id",
|
to = "super::ingredients::Column::Id",
|
||||||
on_update = "NoAction",
|
on_update = "Cascade",
|
||||||
on_delete = "NoAction"
|
on_delete = "Cascade"
|
||||||
)]
|
)]
|
||||||
Ingredients,
|
Ingredients,
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
belongs_to = "super::recipies::Entity",
|
belongs_to = "super::recipies::Entity",
|
||||||
from = "Column::RecipeId",
|
from = "Column::RecipeId",
|
||||||
to = "super::recipies::Column::Id",
|
to = "super::recipies::Column::Id",
|
||||||
on_update = "NoAction",
|
on_update = "Cascade",
|
||||||
on_delete = "NoAction"
|
on_delete = "Cascade"
|
||||||
)]
|
)]
|
||||||
Recipies,
|
Recipies,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.11
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -19,8 +19,8 @@ pub enum Relation {
|
|||||||
belongs_to = "super::recipies::Entity",
|
belongs_to = "super::recipies::Entity",
|
||||||
from = "Column::RecipeId",
|
from = "Column::RecipeId",
|
||||||
to = "super::recipies::Column::Id",
|
to = "super::recipies::Column::Id",
|
||||||
on_update = "NoAction",
|
on_update = "Cascade",
|
||||||
on_delete = "NoAction"
|
on_delete = "Cascade"
|
||||||
)]
|
)]
|
||||||
Recipies,
|
Recipies,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.11
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -18,16 +18,16 @@ pub enum Relation {
|
|||||||
belongs_to = "super::recipies::Entity",
|
belongs_to = "super::recipies::Entity",
|
||||||
from = "Column::RecipeId",
|
from = "Column::RecipeId",
|
||||||
to = "super::recipies::Column::Id",
|
to = "super::recipies::Column::Id",
|
||||||
on_update = "NoAction",
|
on_update = "Cascade",
|
||||||
on_delete = "NoAction"
|
on_delete = "Cascade"
|
||||||
)]
|
)]
|
||||||
Recipies,
|
Recipies,
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
belongs_to = "super::tags::Entity",
|
belongs_to = "super::tags::Entity",
|
||||||
from = "Column::TagId",
|
from = "Column::TagId",
|
||||||
to = "super::tags::Column::Id",
|
to = "super::tags::Column::Id",
|
||||||
on_update = "NoAction",
|
on_update = "Cascade",
|
||||||
on_delete = "NoAction"
|
on_delete = "Cascade"
|
||||||
)]
|
)]
|
||||||
Tags,
|
Tags,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.11
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.11
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
|
#[sea_orm(unique)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
pub use sea_orm_migration::prelude::*;
|
pub use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
mod m20220101_000001_create_table;
|
mod m20220101_000001_create_table;
|
||||||
|
mod m20220101_000002_change_quantity_type;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl MigratorTrait for Migrator {
|
impl MigratorTrait for Migrator {
|
||||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||||
vec![Box::new(m20220101_000001_create_table::Migration)]
|
vec![
|
||||||
|
Box::new(m20220101_000001_create_table::Migration),
|
||||||
|
Box::new(m20220101_000002_change_quantity_type::Migration),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
migration/src/m20220101_000002_change_quantity_type.rs
Normal file
41
migration/src/m20220101_000002_change_quantity_type.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.alter_table(
|
||||||
|
Table::alter()
|
||||||
|
.table(RecipeIngredient::RecipeIngredients)
|
||||||
|
.modify_column(ColumnDef::new(Alias::new("qty")).string().default("1"))
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.alter_table(
|
||||||
|
Table::alter()
|
||||||
|
.table(RecipeIngredient::RecipeIngredients)
|
||||||
|
.modify_column(ColumnDef::new(Alias::new("qty")).integer().default(1))
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
enum RecipeIngredient {
|
||||||
|
RecipeIngredients,
|
||||||
|
Id,
|
||||||
|
IngredientId,
|
||||||
|
Qty,
|
||||||
|
Unit,
|
||||||
|
RecipeId,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user