FEAT: Can save a new page. Automagically includes its root note.

This commit is contained in:
Elf M. Sternberg 2020-09-30 07:37:18 -07:00
parent 6bc8b0e911
commit 75809d821d
5 changed files with 70 additions and 18 deletions

View File

@ -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"] }

View File

@ -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);
}
}

View File

@ -0,0 +1,8 @@
INSERT INTO pages (
slug,
title,
note_id,
creation_date,
updated_date,
lastview_date)
VALUES (?, ?, ?, ?, ?, ?);

View File

@ -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=?;

View File

@ -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<SqlitePool>);
type NoteResult<T> = core::result::Result<T, NoteStoreError>;
@ -26,12 +27,12 @@ impl NoteStore {
Ok(())
}
pub async fn fetch_page(&self, id: &str) -> SqlResult<RawPage> {
pub async fn fetch_raw_page(&self, id: &str) -> SqlResult<RawPage> {
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<RawNote> {
pub async fn fetch_raw_note(&self, id: &str) -> SqlResult<RawNote> {
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(&notetype)
.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<i64> {
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(&note_id)
.bind(&now).bind(&now).bind(&now)
.execute(&mut tx).await?
.last_insert_rowid();
tx.commit().await?;
Ok(page_id)
}
}