From 7b5c69cc505c55096d84f4fb70762ca5252170de Mon Sep 17 00:00:00 2001 From: Myrddin Dundragon Date: Fri, 29 Aug 2025 19:09:05 -0400 Subject: [PATCH] [#2] Refactored and added SQLX schema files. --- ...e46f85218872afb759b07d5aa217309555b99.json | 12 +++ ...21aa67599591bcbc9671d31c6ed90aded502d.json | 12 +++ ...4325d06de1327c453945128ce2e0a1edf510d.json | 12 +++ ...b10ac982c6fdcd30e6d089a1d140210c9b11a.json | 12 +++ ...4bf5cbd7028ca60047a869de25e7931920190.json | 12 +++ ...03b81fe2f78bb0b317c75d9af6266c6ad6d55.json | 12 +++ ...9bbf3838edfc2e9ce27e6a6661505e5b936e2.json | 12 +++ ...4cc5bf969e512b9fb6b589bd09504317363c0.json | 20 +++++ ...62b293515e469653452750ed9e5424be00320.json | 12 +++ ...e4e230b99d780768c96de7966fbee252e7565.json | 12 +++ ...b7800e68e1e7311c16ea07d9e50904b40e817.json | 12 +++ ...b29c65de57982428e1a6f45579638b6c7442a.json | 12 +++ examples/generate_database.rs | 20 +++-- src/adventurer.rs | 27 +++--- src/database.rs | 87 ++++++++++++------- src/lib.rs | 4 +- src/tale.rs | 6 +- 17 files changed, 242 insertions(+), 54 deletions(-) create mode 100644 .sqlx/query-0f58e58ff3bcda95267629c8dbde46f85218872afb759b07d5aa217309555b99.json create mode 100644 .sqlx/query-2b2ddeb7ea1690d809f237afc8d21aa67599591bcbc9671d31c6ed90aded502d.json create mode 100644 .sqlx/query-40a4dcf62e6741b1e2b669469704325d06de1327c453945128ce2e0a1edf510d.json create mode 100644 .sqlx/query-50d891dc85cb19ce33378ced606b10ac982c6fdcd30e6d089a1d140210c9b11a.json create mode 100644 .sqlx/query-5bbbe0b55b0e8a775165a59c2344bf5cbd7028ca60047a869de25e7931920190.json create mode 100644 .sqlx/query-63586c7d68985fedfb450a942ad03b81fe2f78bb0b317c75d9af6266c6ad6d55.json create mode 100644 .sqlx/query-67c82ddcbec08a947ef28a28a439bbf3838edfc2e9ce27e6a6661505e5b936e2.json create mode 100644 .sqlx/query-b1fa9c554e3fe18b4117a314c644cc5bf969e512b9fb6b589bd09504317363c0.json create mode 100644 .sqlx/query-c32d614137f871a3f603c57e99d62b293515e469653452750ed9e5424be00320.json create mode 100644 .sqlx/query-e448c3365fa62303d143b2ed04ee4e230b99d780768c96de7966fbee252e7565.json create mode 100644 .sqlx/query-ec49fe1746763238c7ead570da9b7800e68e1e7311c16ea07d9e50904b40e817.json create mode 100644 .sqlx/query-ee6075930ca151fc036d2797b96b29c65de57982428e1a6f45579638b6c7442a.json diff --git a/.sqlx/query-0f58e58ff3bcda95267629c8dbde46f85218872afb759b07d5aa217309555b99.json b/.sqlx/query-0f58e58ff3bcda95267629c8dbde46f85218872afb759b07d5aa217309555b99.json new file mode 100644 index 0000000..3614b7b --- /dev/null +++ b/.sqlx/query-0f58e58ff3bcda95267629c8dbde46f85218872afb759b07d5aa217309555b99.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT OR IGNORE INTO tale_tags (tale_slug, tag_id)\n VALUES (?1, ?2)", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "0f58e58ff3bcda95267629c8dbde46f85218872afb759b07d5aa217309555b99" +} diff --git a/.sqlx/query-2b2ddeb7ea1690d809f237afc8d21aa67599591bcbc9671d31c6ed90aded502d.json b/.sqlx/query-2b2ddeb7ea1690d809f237afc8d21aa67599591bcbc9671d31c6ed90aded502d.json new file mode 100644 index 0000000..31591d3 --- /dev/null +++ b/.sqlx/query-2b2ddeb7ea1690d809f237afc8d21aa67599591bcbc9671d31c6ed90aded502d.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT OR REPLACE INTO tavern (key, value) VALUES ('title', ?1)", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "2b2ddeb7ea1690d809f237afc8d21aa67599591bcbc9671d31c6ed90aded502d" +} diff --git a/.sqlx/query-40a4dcf62e6741b1e2b669469704325d06de1327c453945128ce2e0a1edf510d.json b/.sqlx/query-40a4dcf62e6741b1e2b669469704325d06de1327c453945128ce2e0a1edf510d.json new file mode 100644 index 0000000..a395326 --- /dev/null +++ b/.sqlx/query-40a4dcf62e6741b1e2b669469704325d06de1327c453945128ce2e0a1edf510d.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT OR REPLACE INTO adventurers (\n handle, name, profile, image, blurb\n ) VALUES (?1, ?2, ?3, ?4, ?5)", + "describe": { + "columns": [], + "parameters": { + "Right": 5 + }, + "nullable": [] + }, + "hash": "40a4dcf62e6741b1e2b669469704325d06de1327c453945128ce2e0a1edf510d" +} diff --git a/.sqlx/query-50d891dc85cb19ce33378ced606b10ac982c6fdcd30e6d089a1d140210c9b11a.json b/.sqlx/query-50d891dc85cb19ce33378ced606b10ac982c6fdcd30e6d089a1d140210c9b11a.json new file mode 100644 index 0000000..9533c63 --- /dev/null +++ b/.sqlx/query-50d891dc85cb19ce33378ced606b10ac982c6fdcd30e6d089a1d140210c9b11a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "CREATE TABLE IF NOT EXISTS tags (\n id INTEGER PRIMARY KEY,\n name TEXT NOT NULL UNIQUE\n )", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "50d891dc85cb19ce33378ced606b10ac982c6fdcd30e6d089a1d140210c9b11a" +} diff --git a/.sqlx/query-5bbbe0b55b0e8a775165a59c2344bf5cbd7028ca60047a869de25e7931920190.json b/.sqlx/query-5bbbe0b55b0e8a775165a59c2344bf5cbd7028ca60047a869de25e7931920190.json new file mode 100644 index 0000000..ad2e2fc --- /dev/null +++ b/.sqlx/query-5bbbe0b55b0e8a775165a59c2344bf5cbd7028ca60047a869de25e7931920190.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT OR IGNORE INTO tags (name) VALUES (?1)", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "5bbbe0b55b0e8a775165a59c2344bf5cbd7028ca60047a869de25e7931920190" +} diff --git a/.sqlx/query-63586c7d68985fedfb450a942ad03b81fe2f78bb0b317c75d9af6266c6ad6d55.json b/.sqlx/query-63586c7d68985fedfb450a942ad03b81fe2f78bb0b317c75d9af6266c6ad6d55.json new file mode 100644 index 0000000..05fc672 --- /dev/null +++ b/.sqlx/query-63586c7d68985fedfb450a942ad03b81fe2f78bb0b317c75d9af6266c6ad6d55.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "CREATE TABLE IF NOT EXISTS tales (\n slug TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n author TEXT NOT NULL,\n summary TEXT NOT NULL,\n publish_date TEXT NOT NULL,\n content TEXT NOT NULL\n )", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "63586c7d68985fedfb450a942ad03b81fe2f78bb0b317c75d9af6266c6ad6d55" +} diff --git a/.sqlx/query-67c82ddcbec08a947ef28a28a439bbf3838edfc2e9ce27e6a6661505e5b936e2.json b/.sqlx/query-67c82ddcbec08a947ef28a28a439bbf3838edfc2e9ce27e6a6661505e5b936e2.json new file mode 100644 index 0000000..930feff --- /dev/null +++ b/.sqlx/query-67c82ddcbec08a947ef28a28a439bbf3838edfc2e9ce27e6a6661505e5b936e2.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "CREATE TABLE IF NOT EXISTS adventurers (\n handle TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n profile TEXT NOT NULL,\n image TEXT NOT NULL,\n blurb TEXT NOT NULL\n )", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "67c82ddcbec08a947ef28a28a439bbf3838edfc2e9ce27e6a6661505e5b936e2" +} diff --git a/.sqlx/query-b1fa9c554e3fe18b4117a314c644cc5bf969e512b9fb6b589bd09504317363c0.json b/.sqlx/query-b1fa9c554e3fe18b4117a314c644cc5bf969e512b9fb6b589bd09504317363c0.json new file mode 100644 index 0000000..12570b2 --- /dev/null +++ b/.sqlx/query-b1fa9c554e3fe18b4117a314c644cc5bf969e512b9fb6b589bd09504317363c0.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT id FROM tags WHERE name = ?1", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true + ] + }, + "hash": "b1fa9c554e3fe18b4117a314c644cc5bf969e512b9fb6b589bd09504317363c0" +} diff --git a/.sqlx/query-c32d614137f871a3f603c57e99d62b293515e469653452750ed9e5424be00320.json b/.sqlx/query-c32d614137f871a3f603c57e99d62b293515e469653452750ed9e5424be00320.json new file mode 100644 index 0000000..af00ef8 --- /dev/null +++ b/.sqlx/query-c32d614137f871a3f603c57e99d62b293515e469653452750ed9e5424be00320.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "CREATE TABLE IF NOT EXISTS tale_tags (\n tale_slug TEXT,\n tag_id INTEGER,\n FOREIGN KEY(tale_slug) REFERENCES tales(slug),\n FOREIGN KEY(tag_id) REFERENCES tags(id),\n UNIQUE(tale_slug, tag_id)\n )", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "c32d614137f871a3f603c57e99d62b293515e469653452750ed9e5424be00320" +} diff --git a/.sqlx/query-e448c3365fa62303d143b2ed04ee4e230b99d780768c96de7966fbee252e7565.json b/.sqlx/query-e448c3365fa62303d143b2ed04ee4e230b99d780768c96de7966fbee252e7565.json new file mode 100644 index 0000000..c30f805 --- /dev/null +++ b/.sqlx/query-e448c3365fa62303d143b2ed04ee4e230b99d780768c96de7966fbee252e7565.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT OR REPLACE INTO tales (\n slug, title, author, summary, publish_date, content\n ) VALUES (?1, ?2, ?3, ?4, ?5, ?6)", + "describe": { + "columns": [], + "parameters": { + "Right": 6 + }, + "nullable": [] + }, + "hash": "e448c3365fa62303d143b2ed04ee4e230b99d780768c96de7966fbee252e7565" +} diff --git a/.sqlx/query-ec49fe1746763238c7ead570da9b7800e68e1e7311c16ea07d9e50904b40e817.json b/.sqlx/query-ec49fe1746763238c7ead570da9b7800e68e1e7311c16ea07d9e50904b40e817.json new file mode 100644 index 0000000..d230b56 --- /dev/null +++ b/.sqlx/query-ec49fe1746763238c7ead570da9b7800e68e1e7311c16ea07d9e50904b40e817.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "CREATE TABLE IF NOT EXISTS tavern (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "ec49fe1746763238c7ead570da9b7800e68e1e7311c16ea07d9e50904b40e817" +} diff --git a/.sqlx/query-ee6075930ca151fc036d2797b96b29c65de57982428e1a6f45579638b6c7442a.json b/.sqlx/query-ee6075930ca151fc036d2797b96b29c65de57982428e1a6f45579638b6c7442a.json new file mode 100644 index 0000000..109e41f --- /dev/null +++ b/.sqlx/query-ee6075930ca151fc036d2797b96b29c65de57982428e1a6f45579638b6c7442a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT OR REPLACE INTO tavern (key, value) VALUES ('description', ?1)", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "ee6075930ca151fc036d2797b96b29c65de57982428e1a6f45579638b6c7442a" +} diff --git a/examples/generate_database.rs b/examples/generate_database.rs index 38d5cfd..af19c7d 100644 --- a/examples/generate_database.rs +++ b/examples/generate_database.rs @@ -1,24 +1,28 @@ use std::path::{Path, PathBuf}; use chrono::NaiveDate; -use tavern::{Adventurer, Database, FrontMatter, Tale, Tavern}; +use tavern::{Adventurer, Database, Legend, Lore, Tale, Tavern}; #[cfg(feature = "publisher")] fn generate_tavern() -> Tavern { - let author: Adventurer = - Adventurer { name: String::from("Jason Smith"), - handle: String::from("myrddin"), + let legend: Legend = Legend + { profile: String::from("https://cybermages.tech/about/myrddin"), image: String::from("https://cybermages.tech/about/myrddin/pic"), blurb: String::from("I love code!") }; - let fm: FrontMatter = - FrontMatter { title: String::from("Test post"), + let author: Adventurer = + Adventurer { name: String::from("Jason Smith"), + handle: String::from("myrddin"), + legend }; + + let lore: Lore = + Lore { title: String::from("Test post"), slug: String::from("test_post"), author: author.handle.clone(), summary: String::from("The Moon is made of cheese!"), @@ -30,8 +34,8 @@ fn generate_tavern() -> Tavern 10, 41) .unwrap() }; - let tale: Tale = Tale { front_matter: fm, - content: PathBuf::from("posts/test_post.md") }; + let tale: Tale = Tale { lore, + story: PathBuf::from("posts/test_post.md") }; // Create a dummy posts directory and file for this example to work diff --git a/src/adventurer.rs b/src/adventurer.rs index 6136d66..987c83d 100644 --- a/src/adventurer.rs +++ b/src/adventurer.rs @@ -1,6 +1,20 @@ use serde::{Deserialize, Serialize}; +/// +#[derive(Deserialize, Serialize)] +pub struct Legend +{ + /// A link to the adventurer's profile (e.g., personal website, GitHub, + /// etc.). + pub profile: String, + /// A URL or path to an image representing the adventurer (e.g., avatar or + /// portrait). + pub image: String, + + /// A short descriptive text or tagline about the adventurer. + pub blurb: String +} /// Represents an author or contributor of a tale. /// @@ -16,16 +30,9 @@ pub struct Adventurer /// mentions). pub handle: String, - /// A link to the adventurer's profile (e.g., personal website, GitHub, - /// etc.). - pub profile: String, - - /// A URL or path to an image representing the adventurer (e.g., avatar or - /// portrait). - pub image: String, - - /// A short descriptive text or tagline about the adventurer. - pub blurb: String + /// + #[serde(flatten)] + pub legend: Legend } diff --git a/src/database.rs b/src/database.rs index 8cd0fcd..eab167a 100644 --- a/src/database.rs +++ b/src/database.rs @@ -7,14 +7,14 @@ use sqlx::{Error, Result}; #[cfg(not(feature = "publisher"))] use sqlx::Row; -use crate::adventurer::Adventurer; +use crate::adventurer::{Adventurer, Legend}; use crate::tale::Tale; #[cfg(feature = "publisher")] use crate::converter::Converter; #[cfg(not(feature = "publisher"))] -use crate::tale::FrontMatter; +use crate::tale::Lore; @@ -136,7 +136,7 @@ impl Database -> Result<(), Box> { // Convert the tales content from Markdown to HTML. - let markdown_content = std::fs::read_to_string(&tale.content)?; + let markdown_content = std::fs::read_to_string(&tale.story)?; let html_content: String = Converter::markdown_to_html(&markdown_content); // Start a transaction. @@ -147,18 +147,18 @@ impl Database "INSERT OR REPLACE INTO tales ( slug, title, author, summary, publish_date, content ) VALUES (?1, ?2, ?3, ?4, ?5, ?6)", - tale.front_matter.slug, - tale.front_matter.title, - tale.front_matter.author, - tale.front_matter.summary, - tale.front_matter.publish_date, + tale.lore.slug, + tale.lore.title, + tale.lore.author, + tale.lore.summary, + tale.lore.publish_date, html_content ).execute(&mut *tx) // Pass mutable reference to the transaction .await?; // Store the tags. // For each tag ... - for tag_name in &tale.front_matter.tags + for tag_name in &tale.lore.tags { // Insert a new tag, ignore if it already exists. sqlx::query!("INSERT OR IGNORE INTO tags (name) VALUES (?1)", @@ -176,7 +176,7 @@ impl Database sqlx::query!( "INSERT OR IGNORE INTO tale_tags (tale_slug, tag_id) VALUES (?1, ?2)", - tale.front_matter.slug, + tale.lore.slug, id ).execute(&mut *tx) // Pass mutable reference to the transaction .await?; @@ -202,9 +202,9 @@ impl Database ) VALUES (?1, ?2, ?3, ?4, ?5)", adventurer.handle, adventurer.name, - adventurer.profile, - adventurer.image, - adventurer.blurb + adventurer.legend.profile, + adventurer.legend.image, + adventurer.legend.blurb ).execute(&mut *tx) .await?; @@ -242,7 +242,7 @@ impl Database #[cfg(not(feature = "publisher"))] pub async fn get_tales_summary(&self, categories: &[String]) - -> Result> + -> Result> { let mut tales = Vec::new(); @@ -292,7 +292,7 @@ impl Database let publish_date = chrono::NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%dT%H:%M:%S") .map_err(|e| sqlx::Error::Decode(e.into()))?; - tales.push(FrontMatter { title: row.try_get("title")?, + tales.push(Lore { title: row.try_get("title")?, slug: row.try_get("slug")?, summary: row.try_get("summary")?, author: row.try_get("author")?, @@ -336,15 +336,15 @@ impl Database let publish_date = chrono::NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%dT%H:%M:%S") .map_err(|e| Error::Decode(e.into()))?; - let front_matter = FrontMatter { title: row.try_get("title")?, + let lore = Lore { title: row.try_get("title")?, slug: row.try_get("slug")?, summary: row.try_get("summary")?, author: row.try_get("author")?, publish_date, tags }; - Ok(Some(Tale { front_matter, - content: row.try_get("content")? })) + Ok(Some(Tale { lore, + story: row.try_get("content")? })) } else { @@ -358,22 +358,47 @@ impl Database { let mut tx = self.pool.begin().await?; - let adventurer = sqlx::query_as!( - Adventurer, - "SELECT - handle AS 'handle!', - name AS 'name!', - profile AS 'profile!', - image AS 'image!', - blurb AS 'blurb!' - FROM adventurers - WHERE handle = ?1", - handle - ).fetch_optional(&mut *tx) // Use transaction here - .await?; + let legend = sqlx::query_as!( + Legend, + "SELECT + profile AS profile, + image AS image, + blurb AS blurb + FROM adventurers + WHERE handle = ?1", + handle +) +.fetch_optional(&mut *tx) +.await?; + +let hero = sqlx::query!( + "SELECT + name, + handle AS 'handle!' + FROM adventurers + WHERE handle = ?1", + handle +) +.fetch_optional(&mut *tx) +.await?; tx.commit().await?; + let adventurer = match (hero, legend) + { + (Some(h), Some(l)) => + { + Some(Adventurer + { + name: h.name, + handle: h.handle, + legend: l, + }) + } + + _ => { None } + }; + Ok(adventurer) } } diff --git a/src/lib.rs b/src/lib.rs index 73dec19..1e86806 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,8 +12,8 @@ mod tavern; -pub use crate::adventurer::Adventurer; +pub use crate::adventurer::{Adventurer, Legend}; pub use crate::database::Database; pub use crate::info::{get_name, get_version}; -pub use crate::tale::{FrontMatter, Tale}; +pub use crate::tale::{Lore, Tale}; pub use crate::tavern::Tavern; diff --git a/src/tale.rs b/src/tale.rs index 1080636..758eae1 100644 --- a/src/tale.rs +++ b/src/tale.rs @@ -20,7 +20,7 @@ pub type Markdown = String; /// This includes details such as the title, author, summary, and /// associated tags. #[derive(Deserialize, Serialize)] -pub struct FrontMatter +pub struct Lore { /// The title of the tale. pub title: String, @@ -49,8 +49,8 @@ pub struct Tale { /// Metadata of the post. #[serde(flatten)] - pub front_matter: FrontMatter, + pub lore: Lore, /// The file path to the Markdown content of the tale. - pub content: Markdown + pub story: Markdown }