REFACTOR: Dry'ing out the insert_new_note feature.
Since both `insert_page` and `insert_note` need to insert a note, having that code twice in the same block was annoying, especially since discovering that my oh-so-clever use of `include_str!` precludes me from using the `query!` macros, which want the strings included *before* doing analysis. All that wrestling with the Transaction type turned out to be much simpler when I was able to just devolve it into an Executor.
This commit is contained in:
parent
75809d821d
commit
1565fef001
|
@ -12,9 +12,9 @@ mod tests {
|
||||||
|
|
||||||
async fn fresh_inmemory_database() -> NoteStore {
|
async fn fresh_inmemory_database() -> NoteStore {
|
||||||
let storagepool = NoteStore::new("sqlite://:memory:").await;
|
let storagepool = NoteStore::new("sqlite://:memory:").await;
|
||||||
assert!(storagepool.is_ok(), "{:?}", storagepool);
|
assert!(storagepool.is_ok(), "{:?}", storagepool);
|
||||||
let storagepool = storagepool.unwrap();
|
let storagepool = storagepool.unwrap();
|
||||||
let reset = storagepool.reset_database().await;
|
let reset = storagepool.reset_database().await;
|
||||||
assert!(reset.is_ok(), "{:?}", reset);
|
assert!(reset.is_ok(), "{:?}", reset);
|
||||||
storagepool
|
storagepool
|
||||||
}
|
}
|
||||||
|
@ -45,29 +45,29 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test(threaded_scheduler)]
|
#[tokio::test(threaded_scheduler)]
|
||||||
async fn can_save_a_note() {
|
async fn can_save_a_note() {
|
||||||
let storagepool = fresh_inmemory_database().await;
|
let storagepool = fresh_inmemory_database().await;
|
||||||
let note_id = storagepool.insert_note("noteid", "notecontent", "note").await;
|
let note_id = storagepool.insert_note("noteid", "notecontent", "note").await;
|
||||||
assert!(note_id.is_ok(), "{:?}", note_id);
|
assert!(note_id.is_ok(), "{:?}", note_id);
|
||||||
let note_id = note_id.unwrap();
|
let note_id = note_id.unwrap();
|
||||||
assert!(note_id > 0);
|
assert!(note_id > 0);
|
||||||
|
|
||||||
let foundnote = storagepool.fetch_raw_note("noteid").await;
|
let foundnote = storagepool.fetch_raw_note("noteid").await;
|
||||||
assert!(foundnote.is_ok(), "{:?}", foundnote);
|
assert!(foundnote.is_ok(), "{:?}", foundnote);
|
||||||
let foundnote = foundnote.unwrap();
|
let foundnote = foundnote.unwrap();
|
||||||
assert_eq!(foundnote.content, "notecontent");
|
assert_eq!(foundnote.content, "notecontent");
|
||||||
assert_eq!(foundnote.notetype, "note");
|
assert_eq!(foundnote.notetype, "note");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(threaded_scheduler)]
|
#[tokio::test(threaded_scheduler)]
|
||||||
async fn can_save_a_page() {
|
async fn can_save_a_page() {
|
||||||
let storagepool = fresh_inmemory_database().await;
|
let storagepool = fresh_inmemory_database().await;
|
||||||
let page_id = storagepool.insert_page("pageid", "Test page").await;
|
let page_id = storagepool.insert_page("pageid", "Test page").await;
|
||||||
assert!(page_id.is_ok(), "{:?}", page_id);
|
assert!(page_id.is_ok(), "{:?}", page_id);
|
||||||
|
|
||||||
let page = storagepool.fetch_raw_page("pageid").await;
|
let page = storagepool.fetch_raw_page("pageid").await;
|
||||||
assert!(page.is_ok(), "{:?}", page);
|
assert!(page.is_ok(), "{:?}", page);
|
||||||
let page = page.unwrap();
|
let page = page.unwrap();
|
||||||
assert_eq!(page.title, "Test page");
|
assert_eq!(page.title, "Test page");
|
||||||
assert!(page.note_id > 0);
|
assert!(page.note_id > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::errors::NoteStoreError;
|
use crate::errors::NoteStoreError;
|
||||||
use crate::structs::{RawNote, RawPage};
|
use crate::structs::{RawNote, RawPage};
|
||||||
use friendly_id;
|
|
||||||
use chrono;
|
use chrono;
|
||||||
|
use friendly_id;
|
||||||
use sqlx;
|
use sqlx;
|
||||||
use sqlx::sqlite::SqlitePool;
|
use sqlx::sqlite::SqlitePool;
|
||||||
|
use sqlx::{sqlite::Sqlite, Executor};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// A handle to our Sqlite database.
|
/// A handle to our Sqlite database.
|
||||||
|
@ -13,6 +14,24 @@ pub struct NoteStore(Arc<SqlitePool>);
|
||||||
type NoteResult<T> = core::result::Result<T, NoteStoreError>;
|
type NoteResult<T> = core::result::Result<T, NoteStoreError>;
|
||||||
type SqlResult<T> = sqlx::Result<T>;
|
type SqlResult<T> = sqlx::Result<T>;
|
||||||
|
|
||||||
|
async fn insert_note<'e, E>(executor: E, id: &str, content: &str, notetype: &str) -> SqlResult<i64>
|
||||||
|
where
|
||||||
|
E: 'e + Executor<'e, Database = Sqlite>,
|
||||||
|
{
|
||||||
|
let insert_one_note_sql = include_str!("sql/insert_one_note.sql");
|
||||||
|
let now = chrono::Utc::now();
|
||||||
|
Ok(sqlx::query(insert_one_note_sql)
|
||||||
|
.bind(&id)
|
||||||
|
.bind(&content)
|
||||||
|
.bind(¬etype)
|
||||||
|
.bind(&now)
|
||||||
|
.bind(&now)
|
||||||
|
.bind(&now)
|
||||||
|
.execute(executor)
|
||||||
|
.await?
|
||||||
|
.last_insert_rowid())
|
||||||
|
}
|
||||||
|
|
||||||
impl NoteStore {
|
impl NoteStore {
|
||||||
pub async fn new(url: &str) -> NoteResult<Self> {
|
pub async fn new(url: &str) -> NoteResult<Self> {
|
||||||
let pool = SqlitePool::connect(url).await?;
|
let pool = SqlitePool::connect(url).await?;
|
||||||
|
@ -37,47 +56,34 @@ impl NoteStore {
|
||||||
sqlx::query_as(select_one_note_sql).bind(&id).fetch_one(&*self.0).await
|
sqlx::query_as(select_one_note_sql).bind(&id).fetch_one(&*self.0).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn insert_note(&self, id: &str, content: &str, notetype: &str) -> SqlResult<i64> {
|
pub async fn insert_note(&self, id: &str, content: &str, notetype: &str) -> SqlResult<i64> {
|
||||||
let insert_one_note_sql = include_str!("sql/insert_one_note.sql");
|
insert_note(&*self.0, id, content, notetype).await
|
||||||
let now = chrono::Utc::now();
|
}
|
||||||
Ok(sqlx::query(insert_one_note_sql)
|
|
||||||
.bind(&id)
|
|
||||||
.bind(&content)
|
|
||||||
.bind(¬etype)
|
|
||||||
.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
|
// 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
|
// the friendly ID. Is there a disconnect there? It's making me
|
||||||
// furiously to think.
|
// furiously to think.
|
||||||
pub async fn insert_page(&self, id: &str, title: &str) -> SqlResult<i64> {
|
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 insert_one_page_sql = include_str!("sql/insert_one_page.sql");
|
|
||||||
let new_note_id = friendly_id::create();
|
let new_note_id = friendly_id::create();
|
||||||
let now = chrono::Utc::now();
|
let now = chrono::Utc::now();
|
||||||
|
|
||||||
let mut tx = self.0.begin().await?;
|
let mut tx = self.0.begin().await?;
|
||||||
|
|
||||||
let note_id = sqlx::query(insert_one_note_sql)
|
let note_id = insert_note(&mut tx, &new_note_id, &"", &"page").await?;
|
||||||
.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)
|
let page_id = sqlx::query(insert_one_page_sql)
|
||||||
.bind(&id)
|
.bind(&id)
|
||||||
.bind(&title)
|
.bind(&title)
|
||||||
.bind(¬e_id)
|
.bind(¬e_id)
|
||||||
.bind(&now).bind(&now).bind(&now)
|
.bind(&now)
|
||||||
.execute(&mut tx).await?
|
.bind(&now)
|
||||||
.last_insert_rowid();
|
.bind(&now)
|
||||||
|
.execute(&mut tx)
|
||||||
tx.commit().await?;
|
.await?
|
||||||
Ok(page_id)
|
.last_insert_rowid();
|
||||||
}
|
|
||||||
|
|
||||||
|
tx.commit().await?;
|
||||||
|
Ok(page_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue