From 75809d821dd8dce0efce95fc2ee4863a8b45b068 Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Wed, 30 Sep 2020 07:37:18 -0700 Subject: [PATCH] FEAT: Can save a new page. Automagically includes its root note. --- server/nm-store/Cargo.toml | 1 + server/nm-store/src/lib.rs | 34 ++++++++++------ server/nm-store/src/sql/insert_one_page.sql | 8 ++++ server/nm-store/src/sql/select_one_page.sql | 2 +- server/nm-store/src/store.rs | 43 ++++++++++++++++++--- 5 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 server/nm-store/src/sql/insert_one_page.sql diff --git a/server/nm-store/Cargo.toml b/server/nm-store/Cargo.toml index 79522cf..d9b359b 100644 --- a/server/nm-store/Cargo.toml +++ b/server/nm-store/Cargo.toml @@ -11,6 +11,7 @@ readme = "./README.org" [dependencies] +friendly_id = "0.3.0" thiserror = "1.0.20" tokio = { version = "0.2.22", features = ["rt-threaded", "blocking"] } serde = { version = "1.0.116", features = ["derive"] } diff --git a/server/nm-store/src/lib.rs b/server/nm-store/src/lib.rs index bccef41..b1c4092 100644 --- a/server/nm-store/src/lib.rs +++ b/server/nm-store/src/lib.rs @@ -12,23 +12,24 @@ mod tests { async fn fresh_inmemory_database() -> NoteStore { let storagepool = NoteStore::new("sqlite://:memory:").await; - assert!(storagepool.is_ok()); + assert!(storagepool.is_ok(), "{:?}", storagepool); let storagepool = storagepool.unwrap(); - assert!(storagepool.reset_database().await.is_ok()); + let reset = storagepool.reset_database().await; + assert!(reset.is_ok(), "{:?}", reset); storagepool } #[tokio::test(threaded_scheduler)] async fn fetching_unfound_page_works() { let storagepool = fresh_inmemory_database().await; - let unfoundpage = storagepool.fetch_page("nonexistent-page").await; + let unfoundpage = storagepool.fetch_raw_page("nonexistent-page").await; assert!(unfoundpage.is_err()); } #[tokio::test(threaded_scheduler)] async fn fetching_unfound_note_works() { let storagepool = fresh_inmemory_database().await; - let unfoundnote = storagepool.fetch_note("nonexistent-note").await; + let unfoundnote = storagepool.fetch_raw_note("nonexistent-note").await; assert!(unfoundnote.is_err()); } @@ -36,9 +37,9 @@ mod tests { async fn cloning_storagepool_is_ok() { let storagepool = fresh_inmemory_database().await; let storagepool2 = storagepool.clone(); - let unfoundnote = storagepool2.fetch_note("nonexistent-note").await; + let unfoundnote = storagepool2.fetch_raw_note("nonexistent-note").await; assert!(unfoundnote.is_err()); - let unfoundnote = storagepool.fetch_note("nonexistent-note").await; + let unfoundnote = storagepool.fetch_raw_note("nonexistent-note").await; assert!(unfoundnote.is_err()); } @@ -46,16 +47,27 @@ mod tests { async fn can_save_a_note() { let storagepool = fresh_inmemory_database().await; let note_id = storagepool.insert_note("noteid", "notecontent", "note").await; - assert!(note_id.is_ok(), format!("note is not ok: {:?}", note_id)); + assert!(note_id.is_ok(), "{:?}", note_id); let note_id = note_id.unwrap(); assert!(note_id > 0); - let foundnote = storagepool.fetch_note("noteid").await; - assert!(foundnote.is_ok(), format!("foundnote is not ok: {:?}", foundnote)); + let foundnote = storagepool.fetch_raw_note("noteid").await; + assert!(foundnote.is_ok(), "{:?}", foundnote); let foundnote = foundnote.unwrap(); assert_eq!(foundnote.content, "notecontent"); assert_eq!(foundnote.notetype, "note"); } - - + + #[tokio::test(threaded_scheduler)] + async fn can_save_a_page() { + let storagepool = fresh_inmemory_database().await; + let page_id = storagepool.insert_page("pageid", "Test page").await; + assert!(page_id.is_ok(), "{:?}", page_id); + + let page = storagepool.fetch_raw_page("pageid").await; + assert!(page.is_ok(), "{:?}", page); + let page = page.unwrap(); + assert_eq!(page.title, "Test page"); + assert!(page.note_id > 0); + } } diff --git a/server/nm-store/src/sql/insert_one_page.sql b/server/nm-store/src/sql/insert_one_page.sql new file mode 100644 index 0000000..6142c5e --- /dev/null +++ b/server/nm-store/src/sql/insert_one_page.sql @@ -0,0 +1,8 @@ +INSERT INTO pages ( + slug, + title, + note_id, + creation_date, + updated_date, + lastview_date) +VALUES (?, ?, ?, ?, ?, ?); diff --git a/server/nm-store/src/sql/select_one_page.sql b/server/nm-store/src/sql/select_one_page.sql index 44840f9..c7599ce 100644 --- a/server/nm-store/src/sql/select_one_page.sql +++ b/server/nm-store/src/sql/select_one_page.sql @@ -1 +1 @@ -SELECT id, title, slug, note_id FROM pages WHERE slug=?; +SELECT id, title, slug, note_id, creation_date, updated_date, lastview_date, deleted_date FROM pages WHERE slug=?; diff --git a/server/nm-store/src/store.rs b/server/nm-store/src/store.rs index 6e78b75..a298886 100644 --- a/server/nm-store/src/store.rs +++ b/server/nm-store/src/store.rs @@ -1,12 +1,13 @@ use crate::errors::NoteStoreError; use crate::structs::{RawNote, RawPage}; +use friendly_id; use chrono; use sqlx; use sqlx::sqlite::SqlitePool; use std::sync::Arc; /// A handle to our Sqlite database. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct NoteStore(Arc); type NoteResult = core::result::Result; @@ -26,12 +27,12 @@ impl NoteStore { Ok(()) } - pub async fn fetch_page(&self, id: &str) -> SqlResult { + pub async fn fetch_raw_page(&self, id: &str) -> SqlResult { let select_one_page_sql = include_str!("sql/select_one_page.sql"); sqlx::query_as(select_one_page_sql).bind(&id).fetch_one(&*self.0).await } - pub async fn fetch_note(&self, id: &str) -> SqlResult { + pub async fn fetch_raw_note(&self, id: &str) -> SqlResult { let select_one_note_sql = include_str!("sql/select_one_note.sql"); sqlx::query_as(select_one_note_sql).bind(&id).fetch_one(&*self.0).await } @@ -43,10 +44,40 @@ impl NoteStore { .bind(&id) .bind(&content) .bind(¬etype) - .bind(&now) - .bind(&now) - .bind(&now) + .bind(&now).bind(&now).bind(&now) .execute(&*self.0).await? .last_insert_rowid()) } + + // TODO: We're returning the raw page with the raw note id, note + // the friendly ID. Is there a disconnect there? It's making me + // furiously to think. + pub async fn insert_page(&self, id: &str, title: &str) -> SqlResult { + let insert_one_note_sql = include_str!("sql/insert_one_note.sql"); + let insert_one_page_sql = include_str!("sql/insert_one_page.sql"); + let new_note_id = friendly_id::create(); + let now = chrono::Utc::now(); + + let mut tx = self.0.begin().await?; + + let note_id = sqlx::query(insert_one_note_sql) + .bind(&new_note_id) + .bind(&"") + .bind(&"page") + .bind(&now).bind(&now).bind(&now) + .execute(&mut tx).await? + .last_insert_rowid(); + + let page_id = sqlx::query(insert_one_page_sql) + .bind(&id) + .bind(&title) + .bind(¬e_id) + .bind(&now).bind(&now).bind(&now) + .execute(&mut tx).await? + .last_insert_rowid(); + + tx.commit().await?; + Ok(page_id) + } + }