// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. //! # Tree Layer //! //! This layer provides an interface between the storage layer and //! the outside world. It provides all of the basic logic, including //! the premise that a note without a parent is automatically //! made a child of the day's notepad. mod make_tree; mod structs; use chrono::{DateTime, Utc}; use nm_store::{NoteStore, NoteStoreError, NewNote}; use crate::structs::{Page, Note}; use crate::make_tree::{make_note_tree, make_backreferences}; #[derive(Debug)] pub struct Notesmachine(pub(crate) NoteStore); type Result = core::result::Result; pub fn make_page(foundtree: &Note, backreferences: Vec>) -> Page { Page { slug: foundtree.id, title: foundtree.content, creation_date: foundtree.creation_date, updated_date: foundtree.updated_date, lastview_date: foundtree.lastview_date, deleted_date: foundtree.deleted_date, notes: foundtree.children, backreferences: backreferences } } impl Notesmachine { pub async fn new(url: &str) -> Result { let notestore = NoteStore::new(url).await?; Ok(Notesmachine(notestore)) } pub async fn get_page_via_slug(&self, slug: &str) -> Result { let (rawtree, rawbackreferences) = self.0.get_kasten_by_slug(slug).await?; Ok(make_page(&make_note_tree(&rawtree), make_backreferences(&rawbackreferences))) } pub async fn get_page(&self, title: &str) -> Result { let (rawtree, rawbackreferences) = self.0.get_kasten_by_title(title).await?; Ok(make_page(&make_note_tree(&rawtree), make_backreferences(&rawbackreferences))) } // TODO: // You should be able to: // Add a note that has no parent (gets added to "today") // Add a note that specifies only the page (gets added to page/root) // Add a note that has no location (gets tacked onto the end of the above) // Add a note that specifies the date of creation. pub async fn add_note(&self, note: &NewNote) -> Result { let mut note = note.clone(); if note.parent_id.is_none() { let (parent, _) = self.get_today_page().await?; note.parent_id = parent.id; } Ok(self.0.add_note(¬e)) } // pub async fn reference_note(&self, note_id: &str, new_parent_id: &str, new_location: i64) -> Result<()> { // todo!(); // } // // pub async fn embed_note(&self, note_id: &str, new_parent_id: &str, new_location: i64) -> Result<()> { // todo!(); // } pub async fn move_note(&self, note_id: &str, old_parent_id: &str, new_parent_id: &str, location: i64) -> Result<()> { self.0.move_note(note_id, old_parent_id, new_parent_id, location) } pub async fn update_note(&self, note_id: &str, content: &str) -> Result<()> { self.0.update_note(note_id, content) } pub async fn delete_note(&self, note_id: &str) -> Result<()> { self.0.delete_note(note_id) } } // Private stuff impl Notesmachine { async fn get_today_page(&self) -> Result { let title = chrono::Utc::now().format("%F").to_string(); let (rawtree, _) = self.0.get_kasten_by_title(title).await?; Ok(rawtree.id) } } #[cfg(test)] mod tests { use super::*; use tokio; async fn fresh_inmemory_database() -> Notesmachine { let notesmachine = Notesmachine::new("sqlite://:memory:").await; assert!(notesmachine.is_ok(), "{:?}", notesmachine); let notesmachine = notesmachine.unwrap(); let reset = notesmachine.0.reset_database().await; assert!(reset.is_ok(), "{:?}", reset); notesmachine } #[tokio::test(threaded_scheduler)] async fn fetching_unfound_page_by_slug_works() { let notesmachine = fresh_inmemory_database().await; let unfoundpage = notesmachine.navigate_via_slug("nonexistent-slug").await; assert!(unfoundpage.is_err()); } #[tokio::test(threaded_scheduler)] async fn fetching_unfound_page_by_title_works() { let title = "Nonexistent Page"; let notesmachine = fresh_inmemory_database().await; let newpageresult = notesmachine.get_box(&title).await; assert!(newpageresult.is_ok(), "{:?}", newpageresult); let newpage = newpageresult.unwrap(); assert_eq!(newpage.title, title, "{:?}", newpage.title); assert_eq!(newpage.slug, "nonexistent-page", "{:?}", newpage.slug); assert_eq!(newpage.root_note.content, "", "{:?}", newpage.root_note.content); assert_eq!(newpage.root_note.notetype, "root", "{:?}", newpage.root_note.notetype); assert_eq!(newpage.root_note.children.len(), 0, "{:?}", newpage.root_note.children); } }