use std::path::StripPrefixError; use crate::BlogDb; impl BlogDb { // pub async fn cache_post(&self, id: i64, cacher: C) -> anyhow::Result<()> // where // C: Cacher + Send + 'static, // { // let post = self.get_post(id).await?; // let cached_page = // task::spawn_blocking(move || -> anyhow::Result { cacher.cache(post) }) // .await??; // await?? me?? me await?? // let slug = format!("blog/{id}"); // sqlx::query("REPLACE INTO pages (slug, content) VALUES (?, ?)") // .bind(slug) // .bind(cached_page) // .execute(&self.memory) // .await?; // Ok(()) // } // pub async fn add_page(&self, slug: S, content: T) -> anyhow::Result<()> where S: AsRef, T: AsRef, { let slug = prepare_slug(slug.as_ref()).await; sqlx::query("INSERT INTO pages (slug, content) VALUES (?, ?)") .bind(slug) .bind(content.as_ref()) .execute(&self.memory) .await?; Ok(()) } pub async fn get_page(&self, slug: S) -> anyhow::Result where S: AsRef, { let slug = prepare_slug_query(slug.as_ref()).await; let page: (String,) = sqlx::query_as("SELECT content FROM pages WHERE slug=?") .bind(slug) .fetch_one(&self.memory) .await?; Ok(page.0) } pub async fn update_page(&self, slug: S, content: T) -> anyhow::Result<()> where S: AsRef, T: AsRef, { let slug = prepare_slug(slug.as_ref()).await; sqlx::query("REPLACE INTO pages (slug, content) VALUES (?, ?)") .bind(slug) .bind(content.as_ref()) .execute(&self.memory) .await?; Ok(()) } pub async fn delete_page(&self, slug: S) -> anyhow::Result<()> where S: AsRef, { let slug = prepare_slug(slug.as_ref()).await; sqlx::query("DELETE FROM pages WHERE slug=?") .bind(slug) .execute(&self.memory) .await?; Ok(()) } pub async fn add_pages(&self, pages: P) -> anyhow::Result<()> where P: IntoIterator, S: AsRef, C: AsRef, { let pages = pages.into_iter(); for page in pages.into_iter() { let slug = prepare_slug(page.0.as_ref()).await; let content = page.1.as_ref(); let result: (String, String) = sqlx::query_as("REPLACE INTO pages (slug, content) VALUES (?,?) RETURNING *") .bind(slug) .bind(content) .fetch_one(&self.memory) .await?; } Ok(()) } pub async fn get_pages(&self) -> anyhow::Result> { let assets: Vec<(String, String)> = sqlx::query_as("SELECT * FROM assets") .fetch_all(&self.db) .await?; Ok(assets) } } /// Combine multiple patterns that match a page (e.g. `/blog/index.html` and `/blog/`) async fn prepare_slug<'a>(mut slug: &'a str) -> &str { if slug.ends_with(".html") { slug = slug.strip_suffix(".html").unwrap() } else if slug.ends_with("/index.html") { slug = slug.strip_suffix("/index.html").unwrap() } if slug.ends_with("/") { slug = slug.strip_suffix("/").unwrap() } slug } /// Combine multiple patterns that match a page (e.g. `/blog/index.html` and `/blog/`) async fn prepare_slug_query<'a>(mut slug: &'a str) -> &str { if slug.ends_with(".html") { slug = slug.strip_suffix(".html").unwrap() } else if slug.ends_with("/index.html") { slug = slug.strip_suffix("/index.html").unwrap() } if slug.ends_with("/") { slug = slug.strip_suffix("/").unwrap() } if slug == "" { slug = "index" } slug } #[cfg(test)] mod tests { use super::*; use crate::util::tests::*; use sqlx::SqlitePool; // struct PostCacher; // impl Cacher for PostCacher { // fn cache(&self, cacheable: Post) -> anyhow::Result { // Ok("cached page!".to_string()) // } // } // #[sqlx::test] // async fn cache(pool: SqlitePool) -> anyhow::Result<()> { // let (db, session_id, post) = init_and_add_post(pool).await?; // db.cache_post(post.id, PostCacher).await?; // Ok(()) // } }