initial seed
This commit is contained in:
178
src/seed.rs
Normal file
178
src/seed.rs
Normal file
@@ -0,0 +1,178 @@
|
||||
//! Catalog seed data — run via `cargo loco seed`.
|
||||
|
||||
use loco_rs::prelude::*;
|
||||
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set};
|
||||
|
||||
use crate::{
|
||||
models::_entities::{categories, products},
|
||||
shared::slug::slugify,
|
||||
};
|
||||
|
||||
// -- Categories -----------------------------------------------------------
|
||||
|
||||
struct CategorySeed {
|
||||
name: &'static str,
|
||||
description: &'static str,
|
||||
position: i32,
|
||||
}
|
||||
|
||||
const CATEGORIES: &[CategorySeed] = &[
|
||||
CategorySeed {
|
||||
name: "Electronics",
|
||||
description: "Audio, computing, and smart devices",
|
||||
position: 0,
|
||||
},
|
||||
CategorySeed {
|
||||
name: "Accessories",
|
||||
description: "Cables, adapters, cases, and everyday essentials",
|
||||
position: 1,
|
||||
},
|
||||
CategorySeed {
|
||||
name: "Home & Office",
|
||||
description: "Ergonomic furniture, lighting, and desk organization",
|
||||
position: 2,
|
||||
},
|
||||
];
|
||||
|
||||
// -- Products -------------------------------------------------------------
|
||||
|
||||
struct ProductSeed {
|
||||
name: &'static str,
|
||||
description: &'static str,
|
||||
price_cents: i64,
|
||||
stock: i32,
|
||||
category_slug: &'static str,
|
||||
sku: Option<&'static str>,
|
||||
}
|
||||
|
||||
const PRODUCTS: &[ProductSeed] = &[
|
||||
ProductSeed {
|
||||
name: "Wireless Headphones",
|
||||
description: "Over-ear Bluetooth headphones with active noise cancelling, 30-hour battery life, and plush memory-foam cushions.",
|
||||
price_cents: 7_999,
|
||||
stock: 25,
|
||||
category_slug: "electronics",
|
||||
sku: Some("WH-1000"),
|
||||
},
|
||||
ProductSeed {
|
||||
name: "Mechanical Keyboard",
|
||||
description: "Tenkeyless mechanical keyboard with hot-swappable switches, per-key RGB backlight, and a detachable USB-C cable.",
|
||||
price_cents: 12_999,
|
||||
stock: 15,
|
||||
category_slug: "electronics",
|
||||
sku: Some("MK-TKL-RGB"),
|
||||
},
|
||||
ProductSeed {
|
||||
name: "USB-C Hub",
|
||||
description: "7-in-1 USB-C hub with HDMI 4K output, 100 W power delivery pass-through, SD card reader, and three USB-A 3.2 ports.",
|
||||
price_cents: 3_499,
|
||||
stock: 40,
|
||||
category_slug: "accessories",
|
||||
sku: Some("USBC-HUB7"),
|
||||
},
|
||||
ProductSeed {
|
||||
name: "Laptop Stand",
|
||||
description: "Adjustable aluminium laptop stand with ventilated surface. Supports laptops from 10\u{201d} to 17\u{201d}.",
|
||||
price_cents: 4_999,
|
||||
stock: 30,
|
||||
category_slug: "accessories",
|
||||
sku: Some("LS-ALU-01"),
|
||||
},
|
||||
ProductSeed {
|
||||
name: "Desk Lamp",
|
||||
description: "LED desk lamp with 5 colour temperatures, stepless brightness control, and a flexible gooseneck arm.",
|
||||
price_cents: 3_999,
|
||||
stock: 20,
|
||||
category_slug: "home-office",
|
||||
sku: Some("DL-5CT"),
|
||||
},
|
||||
ProductSeed {
|
||||
name: "Ergonomic Mouse",
|
||||
description: "Vertical wireless ergonomic mouse with 6 buttons, adjustable DPI up to 4 000, and a sculpted thumb rest.",
|
||||
price_cents: 5_999,
|
||||
stock: 18,
|
||||
category_slug: "electronics",
|
||||
sku: Some("EM-VW-01"),
|
||||
},
|
||||
ProductSeed {
|
||||
name: "Webcam Privacy Cover",
|
||||
description: "Ultra-thin sliding webcam cover compatible with laptops, tablets, and external monitors. Pack of 3.",
|
||||
price_cents: 599,
|
||||
stock: 100,
|
||||
category_slug: "accessories",
|
||||
sku: Some("WPC-3PK"),
|
||||
},
|
||||
ProductSeed {
|
||||
name: "Cable Organizer Set",
|
||||
description: "Silicone cable management kit with 6 magnetic clips, 4 velcro straps, and an under-desk cable tray.",
|
||||
price_cents: 1_299,
|
||||
stock: 50,
|
||||
category_slug: "home-office",
|
||||
sku: Some("COS-MAG"),
|
||||
},
|
||||
];
|
||||
|
||||
// -- Public API -----------------------------------------------------------
|
||||
|
||||
/// Insert starter categories and products. Called from the `seed()` hook.
|
||||
pub async fn seed_catalog(ctx: &AppContext) -> Result<()> {
|
||||
for cat in CATEGORIES {
|
||||
let slug = slugify(cat.name);
|
||||
let exists = categories::Entity::find()
|
||||
.filter(categories::Column::Slug.eq(&slug))
|
||||
.one(&ctx.db)
|
||||
.await?
|
||||
.is_some();
|
||||
if exists {
|
||||
continue;
|
||||
}
|
||||
categories::ActiveModel {
|
||||
name: Set(cat.name.to_string()),
|
||||
slug: Set(slug),
|
||||
description: Set(Some(cat.description.to_string())),
|
||||
position: Set(cat.position),
|
||||
published: Set(true),
|
||||
..Default::default()
|
||||
}
|
||||
.insert(&ctx.db)
|
||||
.await?;
|
||||
}
|
||||
|
||||
for item in PRODUCTS {
|
||||
let product_slug = slugify(item.name);
|
||||
let exists = products::Entity::find()
|
||||
.filter(products::Column::Slug.eq(&product_slug))
|
||||
.one(&ctx.db)
|
||||
.await?
|
||||
.is_some();
|
||||
if exists {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cat_slug = slugify(item.category_slug);
|
||||
let category = categories::Entity::find()
|
||||
.filter(categories::Column::Slug.eq(&cat_slug))
|
||||
.one(&ctx.db)
|
||||
.await?;
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
|
||||
products::ActiveModel {
|
||||
name: Set(item.name.to_string()),
|
||||
slug: Set(product_slug),
|
||||
description: Set(Some(item.description.to_string())),
|
||||
price_cents: Set(item.price_cents),
|
||||
currency: Set("EUR".to_string()),
|
||||
sku: Set(item.sku.map(|s| s.to_string())),
|
||||
stock: Set(item.stock),
|
||||
published: Set(true),
|
||||
published_at: Set(Some(now.into())),
|
||||
category_id: Set(category.map(|c| c.id)),
|
||||
..Default::default()
|
||||
}
|
||||
.insert(&ctx.db)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user