As cool as the ParentId/NoteId thing was, it didn't feel zero-abstraction,

and it was starting to prove to be clutter.  Maybe it's a mistake to
downtype them to a common type, but I don't think there was that much
risk here.
This commit is contained in:
Elf M. Sternberg 2020-11-12 13:33:27 -08:00
parent 8a83d802d3
commit 013ca18c62
2 changed files with 66 additions and 77 deletions

View File

@ -35,8 +35,9 @@ lazy_static! {
); );
} }
lazy_static! { lazy_static! {
static ref SELECT_NOTES_BACKREFENCING_PAGE_SQL: &'static str = static ref SELECT_NOTES_BACKREFERENCING_PAGE_SQL: &'static str =
include_str!("sql/select_notes_backreferencing_page.sql"); include_str!("sql/select_notes_backreferencing_page.sql");
} }
@ -63,6 +64,20 @@ where
// |_|\___|\__\__|_||_| |_|\_\__,_/__/\__\___|_||_| // |_|\___|\__\__|_||_| |_|\_\__,_/__/\__\___|_||_|
// //
// The next three functions are essentially the same, although the internal
// SQL operations are quite different between the first two and the last.
async fn select_object_by_query<'a, E>(executor: E, query: &str, field: &str) -> SqlResult<Vec<Note>>
where
E: Executor<'a, Database = Sqlite>,
{
let r: Vec<RowNote> = sqlx::query_as(query)
.bind(field)
.fetch_all(executor)
.await?;
Ok(r.into_iter().map(|z| Note::from(z)).collect())
}
// Select the requested page via its id. This is fairly rare; // Select the requested page via its id. This is fairly rare;
// pages should usually be picked up via their title, but if you're // pages should usually be picked up via their title, but if you're
// navigating to an instance, this is how you specify the page in a // navigating to an instance, this is how you specify the page in a
@ -72,15 +87,11 @@ where
// //
// Recommended: Clients should update the URL whenever changing // Recommended: Clients should update the URL whenever changing
// page. // page.
pub(crate) async fn select_page_by_slug<'a, E>(executor: E, slug: &NoteId) -> SqlResult<Vec<Note>> pub(crate) async fn select_page_by_slug<'a, E>(executor: E, slug: &str) -> SqlResult<Vec<Note>>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
let r: Vec<RowNote> = sqlx::query_as(&SELECT_PAGE_BY_ID_SQL) select_object_by_query(executor, &SELECT_PAGE_BY_ID_SQL, &slug).await
.bind(&**slug)
.fetch_all(executor)
.await?;
Ok(r.into_iter().map(|z| Note::from(z)).collect())
} }
// Fetch the page by title. The return value is an array of Note // Fetch the page by title. The return value is an array of Note
@ -90,11 +101,7 @@ pub(crate) async fn select_page_by_title<'a, E>(executor: E, title: &str) -> Sql
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
let r: Vec<RowNote> = sqlx::query_as(&SELECT_PAGE_BY_TITLE_SQL) select_object_by_query(executor, &SELECT_PAGE_BY_TITLE_SQL, &title).await
.bind(&title)
.fetch_all(executor)
.await?;
Ok(r.into_iter().map(|z| Note::from(z)).collect())
} }
// Fetch all backreferences to a page. The return value is an array // Fetch all backreferences to a page. The return value is an array
@ -103,16 +110,12 @@ where
// they want to display that collection. // they want to display that collection.
pub(crate) async fn select_backreferences_for_page<'a, E>( pub(crate) async fn select_backreferences_for_page<'a, E>(
executor: E, executor: E,
page_id: &NoteId, page_id: &str,
) -> SqlResult<Vec<Note>> ) -> SqlResult<Vec<Note>>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
let r: Vec<RowNote> = sqlx::query_as(&SELECT_NOTES_BACKREFENCING_PAGE_SQL) select_object_by_query(executor, &SELECT_NOTES_BACKREFERENCING_PAGE_SQL, &page_id).await
.bind(&**page_id)
.fetch_all(executor)
.await?;
Ok(r.into_iter().map(|z| Note::from(z)).collect())
} }
// ___ _ ___ _ _ _ // ___ _ ___ _ _ _
@ -275,8 +278,8 @@ where
pub(crate) async fn select_note_to_note_relationship<'a, E>( pub(crate) async fn select_note_to_note_relationship<'a, E>(
executor: E, executor: E,
parent_id: &ParentId, parent_id: &str,
note_id: &NoteId, note_id: &str,
) -> SqlResult<NoteRelationship> ) -> SqlResult<NoteRelationship>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
@ -288,8 +291,8 @@ where
"LIMIT 1" "LIMIT 1"
); );
let s: NoteRelationshipRow = sqlx::query_as(get_note_to_note_relationship_sql) let s: NoteRelationshipRow = sqlx::query_as(get_note_to_note_relationship_sql)
.bind(&**parent_id) .bind(parent_id)
.bind(&**note_id) .bind(note_id)
.fetch_one(executor) .fetch_one(executor)
.await?; .await?;
Ok(NoteRelationship::from(s)) Ok(NoteRelationship::from(s))
@ -303,8 +306,8 @@ where
pub(crate) async fn insert_note_to_note_relationship<'a, E>( pub(crate) async fn insert_note_to_note_relationship<'a, E>(
executor: E, executor: E,
parent_id: &ParentId, parent_id: &str,
note_id: &NoteId, note_id: &str,
location: i64, location: i64,
kind: &RelationshipKind, kind: &RelationshipKind,
) -> SqlResult<()> ) -> SqlResult<()>
@ -317,10 +320,10 @@ where
); );
let _ = sqlx::query(insert_note_to_note_relationship_sql) let _ = sqlx::query(insert_note_to_note_relationship_sql)
.bind(&**parent_id) .bind(parent_id)
.bind(&**note_id) .bind(note_id)
.bind(&location) .bind(&location)
.bind(&kind.to_string()) .bind(kind.to_string())
.execute(executor) .execute(executor)
.await?; .await?;
Ok(()) Ok(())
@ -328,7 +331,7 @@ where
pub(crate) async fn make_room_for_new_note<'a, E>( pub(crate) async fn make_room_for_new_note<'a, E>(
executor: E, executor: E,
parent_id: &ParentId, parent_id: &str,
location: i64, location: i64,
) -> SqlResult<()> ) -> SqlResult<()>
where where
@ -342,7 +345,7 @@ where
let _ = sqlx::query(make_room_for_new_note_sql) let _ = sqlx::query(make_room_for_new_note_sql)
.bind(&location) .bind(&location)
.bind(&**parent_id) .bind(parent_id)
.execute(executor) .execute(executor)
.await?; .await?;
Ok(()) Ok(())
@ -350,7 +353,7 @@ where
pub(crate) async fn determine_max_child_location_for_note<'a, E>( pub(crate) async fn determine_max_child_location_for_note<'a, E>(
executor: E, executor: E,
note_id: &ParentId, note_id: &str,
comp_loc: Option<i64>, comp_loc: Option<i64>,
) -> SqlResult<i64> ) -> SqlResult<i64>
where where
@ -365,7 +368,7 @@ where
pub(crate) async fn assert_max_child_location_for_note<'a, E>( pub(crate) async fn assert_max_child_location_for_note<'a, E>(
executor: E, executor: E,
note_id: &ParentId, note_id: &str,
) -> SqlResult<i64> ) -> SqlResult<i64>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
@ -374,7 +377,7 @@ where
"SELECT MAX(location) AS count FROM note_relationships WHERE parent_id = ?;"; "SELECT MAX(location) AS count FROM note_relationships WHERE parent_id = ?;";
let count: RowCount = sqlx::query_as(assert_max_child_location_for_note_sql) let count: RowCount = sqlx::query_as(assert_max_child_location_for_note_sql)
.bind(&**note_id) .bind(note_id)
.fetch_one(executor) .fetch_one(executor)
.await?; .await?;
@ -389,8 +392,8 @@ where
pub(crate) async fn insert_bulk_note_to_page_relationships<'a, E>( pub(crate) async fn insert_bulk_note_to_page_relationships<'a, E>(
executor: E, executor: E,
note_id: &NoteId, note_id: &str,
references: &[NoteId], references: &[String],
) -> SqlResult<()> ) -> SqlResult<()>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
@ -408,7 +411,7 @@ where
let mut request = sqlx::query(&insert_note_page_references_sql); let mut request = sqlx::query(&insert_note_page_references_sql);
for reference in references { for reference in references {
request = request.bind(&**note_id).bind(&**reference); request = request.bind(note_id).bind(reference);
} }
request.execute(executor).await.map(|_| ()) request.execute(executor).await.map(|_| ())
@ -416,7 +419,7 @@ where
pub(crate) async fn delete_bulk_note_to_page_relationships<'a, E>( pub(crate) async fn delete_bulk_note_to_page_relationships<'a, E>(
executor: E, executor: E,
note_id: &NoteId, note_id: &str,
) -> SqlResult<()> ) -> SqlResult<()>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
@ -424,7 +427,7 @@ where
let delete_note_to_page_relationship_sql = let delete_note_to_page_relationship_sql =
"DELETE FROM note_page_relationships WHERE and note_id = ?;"; "DELETE FROM note_page_relationships WHERE and note_id = ?;";
let _ = sqlx::query(delete_note_to_page_relationship_sql) let _ = sqlx::query(delete_note_to_page_relationship_sql)
.bind(&**note_id) .bind(note_id)
.execute(executor) .execute(executor)
.await?; .await?;
Ok(()) Ok(())
@ -487,8 +490,8 @@ where
pub(crate) async fn delete_note_to_note_relationship<'a, E>( pub(crate) async fn delete_note_to_note_relationship<'a, E>(
executor: E, executor: E,
parent_id: &ParentId, parent_id: &str,
note_id: &NoteId, note_id: &str,
) -> SqlResult<()> ) -> SqlResult<()>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
@ -499,8 +502,8 @@ where
); );
let count = sqlx::query(delete_note_to_note_relationship_sql) let count = sqlx::query(delete_note_to_note_relationship_sql)
.bind(&**parent_id) .bind(parent_id)
.bind(&**note_id) .bind(note_id)
.execute(executor) .execute(executor)
.await? .await?
.rows_affected(); .rows_affected();
@ -513,7 +516,7 @@ where
pub(crate) async fn delete_note_to_page_relationships<'a, E>( pub(crate) async fn delete_note_to_page_relationships<'a, E>(
executor: E, executor: E,
note_id: &NoteId, note_id: &str,
) -> SqlResult<()> ) -> SqlResult<()>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
@ -527,20 +530,20 @@ where
} }
let _ = sqlx::query(&DELETE_NOTE_TO_PAGE_RELATIONSHIPS_SQL) let _ = sqlx::query(&DELETE_NOTE_TO_PAGE_RELATIONSHIPS_SQL)
.bind(&**note_id) .bind(note_id)
.execute(executor) .execute(executor)
.await?; .await?;
Ok(()) Ok(())
} }
pub(crate) async fn delete_note<'a, E>(executor: E, note_id: &NoteId) -> SqlResult<()> pub(crate) async fn delete_note<'a, E>(executor: E, note_id: &str) -> SqlResult<()>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
let delete_note_sql = "DELETE FROM notes WHERE note_id = ?"; let delete_note_sql = "DELETE FROM notes WHERE note_id = ?";
let count = sqlx::query(delete_note_sql) let count = sqlx::query(delete_note_sql)
.bind(&**note_id) .bind(note_id)
.execute(executor) .execute(executor)
.await? .await?
.rows_affected(); .rows_affected();
@ -556,7 +559,7 @@ where
// sequential. // sequential.
pub(crate) async fn close_hole_for_deleted_note<'a, E>( pub(crate) async fn close_hole_for_deleted_note<'a, E>(
executor: E, executor: E,
parent_id: &ParentId, parent_id: &str,
location: i64, location: i64,
) -> SqlResult<()> ) -> SqlResult<()>
where where
@ -570,7 +573,7 @@ where
let _ = sqlx::query(close_hole_for_deleted_note_sql) let _ = sqlx::query(close_hole_for_deleted_note_sql)
.bind(&location) .bind(&location)
.bind(&**parent_id) .bind(parent_id)
.execute(executor) .execute(executor)
.await?; .await?;
Ok(()) Ok(())
@ -584,7 +587,7 @@ where
pub(crate) async fn validate_or_generate_all_found_references( pub(crate) async fn validate_or_generate_all_found_references(
txi: &mut Transaction<'_, Sqlite>, txi: &mut Transaction<'_, Sqlite>,
references: &[String] references: &[String]
) -> SqlResult<Vec<NoteId>> { ) -> SqlResult<Vec<String>> {
let mut tx = txi.begin().await?; let mut tx = txi.begin().await?;
let found_references = let found_references =
@ -597,8 +600,8 @@ pub(crate) async fn validate_or_generate_all_found_references(
} }
let _ = bulk_insert_notes(&mut tx, &new_page).await?; let _ = bulk_insert_notes(&mut tx, &new_page).await?;
let mut all_reference_ids: Vec<NoteId> = found_references.iter().map(|r| NoteId(r.id.clone())).collect(); let mut all_reference_ids: Vec<String> = found_references.iter().map(|r| r.id.clone()).collect();
all_reference_ids.append(&mut new_page.iter().map(|r| NoteId(r.id.clone())).collect()); all_reference_ids.append(&mut new_page.iter().map(|r| r.id.clone()).collect());
tx.commit().await?; tx.commit().await?;
Ok(all_reference_ids) Ok(all_reference_ids)
} }
@ -611,14 +614,14 @@ pub(crate) async fn validate_or_generate_all_found_references(
// The dreaded miscellaneous! // The dreaded miscellaneous!
pub(crate) async fn count_existing_note_relationships<'a, E>(executor: E, note_id: &NoteId) -> SqlResult<i64> pub(crate) async fn count_existing_note_relationships<'a, E>(executor: E, note_id: &str) -> SqlResult<i64>
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
let count_existing_note_relationships_sql = let count_existing_note_relationships_sql =
"SELECT COUNT(*) as count FROM note_relationships WHERE note_id = ?;"; "SELECT COUNT(*) as count FROM note_relationships WHERE note_id = ?;";
let count: RowCount = sqlx::query_as(&count_existing_note_relationships_sql) let count: RowCount = sqlx::query_as(&count_existing_note_relationships_sql)
.bind(&**note_id) .bind(note_id)
.fetch_one(executor) .fetch_one(executor)
.await?; .await?;
Ok(count.count) Ok(count.count)

View File

@ -93,20 +93,18 @@ impl NoteStore {
/// this use case says that in the event of a failure to find the /// this use case says that in the event of a failure to find the
/// requested page, return a basic NotFound. /// requested page, return a basic NotFound.
pub async fn get_page_by_slug(&self, slug: &str) -> NoteResult<(Vec<Note>, Vec<Note>)> { pub async fn get_page_by_slug(&self, slug: &str) -> NoteResult<(Vec<Note>, Vec<Note>)> {
let page = select_page_by_slug(&*self.0, &NoteId(slug.to_string())).await?; let page = select_page_by_slug(&*self.0, slug).await?;
if page.is_empty() { if page.is_empty() {
return Err(NoteStoreError::NotFound); return Err(NoteStoreError::NotFound);
} }
let note_id = NoteId(page[0].id.clone()); let note_id = &page[0].id;
Ok(( let backreferences = select_backreferences_for_page(&*self.0, &note_id).await?;
page, Ok((page, backreferences))
select_backreferences_for_page(&*self.0, &note_id).await?,
))
} }
/// Fetch page by title /// Fetch page by title
///
/// The most common use case: the user is navigating by requesting /// The most common use case: the user is navigating by requesting
/// a page. The page either exists or it doesn't. If it /// a page. The page either exists or it doesn't. If it
/// doesn't, we go out and make it. Since we know it doesn't exist, /// doesn't, we go out and make it. Since we know it doesn't exist,
@ -119,11 +117,9 @@ impl NoteStore {
let page = select_page_by_title(&*self.0, title).await?; let page = select_page_by_title(&*self.0, title).await?;
if page.len() > 0 { if page.len() > 0 {
let note_id = NoteId(page[0].id.clone()); let note_id = &page[0].id;
return Ok(( let backreferences = select_backreferences_for_page(&*self.0, &note_id).await?;
page, return Ok((page, backreferences));
select_backreferences_for_page(&*self.0, &note_id).await?,
));
} }
// Sanity check! // Sanity check!
@ -149,14 +145,8 @@ impl NoteStore {
parent_id: &str, parent_id: &str,
location: Option<i64>, location: Option<i64>,
) -> NoteResult<String> { ) -> NoteResult<String> {
let new_id = self let kind = RelationshipKind::Direct;
.insert_note( let new_id = self.insert_note(note, parent_id, location, kind).await?;
note,
&ParentId(parent_id.to_string()),
location,
RelationshipKind::Direct,
)
.await?;
Ok(new_id) Ok(new_id)
} }
@ -170,10 +160,6 @@ impl NoteStore {
) -> NoteResult<()> { ) -> NoteResult<()> {
let mut tx = self.0.begin().await?; let mut tx = self.0.begin().await?;
let old_parent_id = ParentId(old_parent_id.to_string());
let new_parent_id = ParentId(new_parent_id.to_string());
let note_id = NoteId(note_id.to_string());
let old_note = select_note_to_note_relationship(&mut tx, &old_parent_id, &note_id).await?; let old_note = select_note_to_note_relationship(&mut tx, &old_parent_id, &note_id).await?;
let old_note_location = old_note.location; let old_note_location = old_note.location;
let old_note_kind = old_note.kind; let old_note_kind = old_note.kind;
@ -239,7 +225,7 @@ impl NoteStore {
async fn insert_note( async fn insert_note(
&self, &self,
note: &NewNote, note: &NewNote,
parent_id: &ParentId, parent_id: &str,
location: Option<i64>, location: Option<i64>,
kind: RelationshipKind, kind: RelationshipKind,
) -> NoteResult<String> { ) -> NoteResult<String> {