feat(indexer): get multiple claims value and various others

This commit is contained in:
Matthieu Bessat 2024-01-06 23:19:34 +01:00
parent 6c6e096287
commit 8f1b67cfd9
12 changed files with 132 additions and 32 deletions

7
Cargo.lock generated
View file

@ -578,6 +578,12 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "indoc"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
[[package]]
name = "inotify"
version = "0.9.6"
@ -910,6 +916,7 @@ dependencies = [
"chrono-tz",
"clap",
"fully_pub",
"indoc",
"notify",
"reqwest",
"serde",

View file

@ -18,6 +18,7 @@ chrono = { version = "0.4.26", features = ["serde"] }
notify = "6.0.1"
anyhow = "1.0.75"
chrono-tz = "0.8.4"
indoc = "2"
[dependencies.uuid]
version = "1.4.1"

View file

@ -1,5 +0,0 @@
// impl From<io::Error> for CliError {
// fn from(error: io::Error) -> Self {
// CliError::IoError(error)
// }
// }

View file

@ -5,6 +5,7 @@ pub mod parse_extractor;
pub mod models;
pub mod labels;
pub mod read;
pub mod filter;
#[cfg(test)]
mod test_parse_extractor;

View file

@ -96,7 +96,7 @@ struct EntryContainer {
parsed_entry: PEntry,
/// the final interpreted Entry, more pratical to work with, if you have only data query
pure_entry: Option<Entry>,
pure_entry: Entry,
/// a reference to the file that originally contained this entry
source_file_id: Uuid
@ -127,6 +127,8 @@ struct LanguageLabels {
/// functions to work with pure entry
/// get claims matching a property search string from a pure_entry
pub fn get_entry_claims<'a>(pure_entry: &'a Entry, property_str: &str) -> Vec<&'a EntryClaim> {
pure_entry.claims
.iter()

View file

@ -5,10 +5,12 @@ use anyhow::{Result, anyhow};
use crate::pdel_parser::{PEntry, PEntryValue, ParseOutput, PEntryClaim, PFunction, PFunctionArgument, UnresolvedReference};
use crate::database::models::{Entry, EntryValue, EntryClaim, Property};
pub fn get_claim_value<'a>(entry: &'a PEntry, target_property: &str) -> Option<&'a PEntryValue> {
/// to work with parsed entry
pub fn get_claim_values<'a>(entry: &'a PEntry, target_property: &str) -> Vec<&'a PEntryValue> {
entry.claims.p.iter()
.find(|claim| claim.p.property.p == target_property)
.filter(|claim| claim.p.property.p == target_property)
.map(|claim| &claim.p.value_container.p.value.p)
.collect()
}
pub fn get_pure_property(property_locator: &String) -> Property {
@ -124,10 +126,17 @@ pub fn get_pure_value(parsed_value: &PEntryValue) -> Result<EntryValue> {
let l = naive_dt.and_local_timezone(Paris).unwrap().with_timezone(&Utc);
EntryValue::Time(l)
},
_ => unimplemented!()
"VaultEntry" => {
let entry_path: String = func.arguments.iter().nth(0).map(|x| &x.p)
.map(get_argument_value)
.ok_or(anyhow!("Cannot get argument"))?
.try_into().map_err(|_| anyhow!("Entry path argument is not String"))?;
EntryValue::String(format!("vault_entry://{}", entry_path))
}
_ => return Err(anyhow!("Encountered unsupported function {:?}", func.name.p))
}
},
_ => unimplemented!()
_ => return Err(anyhow!("Entry value type not supported by extractor {:?}", parsed_value))
})
}

View file

@ -1,17 +1,16 @@
use std::io::BufReader;
use anyhow::Result;
use std::fs::File;
use crate::unwrap_or_return;
use super::models::Notebook;
use super::NotebookContext;
#[derive(Debug)]
pub enum ReadErr {
CannotReadDB
}
pub fn read_db(context: &NotebookContext) -> Result<Notebook, ReadErr> {
let db_file = unwrap_or_return!(
File::open(&context.database_path()),

View file

@ -29,8 +29,8 @@ fn test_transform_into_pure_value_with_globe_coordinate() {
/// util function
/// TODO: move it to appropriate place in the code tree
fn format_date(time: DateTime<Utc>, format: &str) -> String {
time.naive_local().date().format(format).to_string()
fn format_datum(time: DateTime<Utc>, format: &str) -> String {
time.naive_local().format(format).to_string()
}
#[test]
@ -48,9 +48,9 @@ fn test_transform_into_pure_value_with_datum_date() {
unreachable!()
};
assert_eq!(format_date(time, "%Y"), "2023");
assert_eq!(format_date(time, "%m"), "11");
assert_eq!(format_date(time, "%d"), "19"); // 19 instead of 20 because we are in UTC+1
assert_eq!(format_datum(time, "%Y"), "2023");
assert_eq!(format_datum(time, "%m"), "11");
assert_eq!(format_datum(time, "%d"), "19"); // 19 instead of 20 because we are in UTC+1
}
#[test]
@ -67,10 +67,11 @@ fn test_transform_into_pure_value_with_datum_datetime() {
let EntryValue::Time(time) = pure_value else {
unreachable!()
};
dbg!("wow {:?}", pure_value);
assert_eq!(format_date(time, "%d"), "19");
assert_eq!(format_date(time, "%H"), "10"); // UTC+1
assert_eq!(format_date(time, "%M"), "55");
assert_eq!(format_datum(time, "%d"), "19");
assert_eq!(format_datum(time, "%H"), "10"); // UTC+1
assert_eq!(format_datum(time, "%M"), "55");
}
#[test]

View file

@ -1,17 +1,20 @@
use crate::database::NotebookContext;
use crate::database::models::{Notebook, EntryContainer, SourceFile};
use crate::database::parse_extractor::{get_pure_entry, get_claim_value};
use std::path::Path;
use std::fs;
use crate::pdel_parser::parse_wrapper;
use crate::pdel_parser::markdown::parse_markdown;
use crate::pdel_parser::{ParseOutput, PEntry};
use bincode::serialize;
use std::fs::File;
// import the write trait (not directly used)
use std::io::Write;
use crate::unwrap_or_return;
use uuid::Uuid;
use anyhow::{Result, anyhow};
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use std::io::Read;
mod reference_resolver;
@ -19,12 +22,16 @@ mod reference_resolver;
#[cfg(test)]
mod test_reference_resolver;
#[cfg(test)]
mod test_indexer;
#[derive(Debug)]
pub enum IndexingErr {
CannotOpen,
IoErr,
ParseErr
ParseErr,
ExtractErr(anyhow::Error)
}
#[derive(Debug)]
@ -37,28 +44,41 @@ struct IndexingResult {
/// # Arguments
///
/// * `file_id` - the id that you known
///
/// - parse entry
/// - check for existing id
/// - if id missing add the code
/// - reparse
/// - extract the pure entry
fn index_file(file_path: &Path, file_id: Uuid) -> Result<IndexingResult, IndexingErr> {
// keep an existing id or get a new one
// or use the git id?
let mut entries_containers: Vec<EntryContainer> = vec![];
let contents = fs::read_to_string(file_path)
.expect("Should be able to read the file, there is something wrong with it");
let source_file = SourceFile {
id: file_id,
path: file_path.to_path_buf(),
};
let res = parse_wrapper(parse_markdown, &contents);
match res {
Ok(pout) => {
// if add_id_on_entry(&source_file, &pout) {
// return index_file(file_path, file_id);
// }
for entry in pout.p {
let pure_entry = get_pure_entry(&entry).map_err(|e| IndexingErr::ExtractErr(e))?;
entries_containers.push(EntryContainer {
source_file_id: file_id,
pure_entry,
parsed_entry: entry,
pure_entry: None
})
}
Ok(IndexingResult {
files: vec![SourceFile {
id: file_id,
path: file_path.to_path_buf(),
}],
files: vec![],
entries: entries_containers
})
},
@ -105,7 +125,6 @@ fn index_dir(dir_path: &Path) -> Result<IndexingResult, IndexingErr> {
// we preparsed the entites, now going to link them
// TODO: index into a graph db? IndraDB or sqlite?
//
// for each entity, index the names into the table,
// then check if the names that is referenced in the entry are valid
// if valid, replace them with actual id (or pointer) of the referenced entry
@ -118,6 +137,43 @@ fn index_dir(dir_path: &Path) -> Result<IndexingResult, IndexingErr> {
})
}
use crate::database::models::get_entry_claims;
/// Will add ids on entries that don't have an id yet
/// we need to manipulate the file and write it back
/// we act directly on the file system and write the file
/// return Result True if id were missing False if not
/// we have here a function to only work on one entry at the time to allow for more flexibility in
/// the testing
fn add_id_on_entry(input_entry_code: String, pout: ParseOutput<PEntry>) -> Result<(Uuid, String)> {
// let mut f = File::open(&source_file.path).map_err(|e| anyhow!("Failed to open file: {e:?}"))?;
// if get_claim_value(&pout.p, "id").len() >= 1 {
// return Result<
// }
// detected missing id
// generate new id
let id = Uuid::new_v4();
// add the id as String
let id_claim_pdel_code = format!(" id: {:?},\n", id.to_string());
// let first_claim = pout.p.claims.p.iter().nth(0).ok_or(anyhow!("Expected at least one claim"))?;
// // open file
// let mut code = String::new();
let mut code = input_entry_code;
// println!("{:?}", &code.as_str()[(pout.p.claims.start_loc)..(pout.p.claims.start_loc+10)]);
// TODO: have good whitespace aligment
// detect { and then
// detect whitespace alignment
// right now, +3 is arbitrary (to handle 4 spaces identation)
code.insert_str(pout.p.claims.start_loc+3, &id_claim_pdel_code);
// get the cursor position at the begining of the entries claims
// append the code
// for now we won't have the issue of macro expansion because we will append before !labels
Ok((id, code))
}
fn index_notebook(path: &Path) -> Result<Notebook, IndexingErr>
{
let index_res = match index_dir(path) {

View file

@ -0,0 +1,29 @@
use crate::indexer::add_id_on_entry;
use crate::pdel_parser::parse_entry;
use indoc::{indoc, formatdoc};
#[test]
fn test_add_id_on_entry() {
let entry_code = indoc! {r#"
@Entry {
foo: "bar",
foo2: "bar",
}
"#}.to_string();
let res = parse_entry(&entry_code, 0);
let pout = res.unwrap();
let res = add_id_on_entry(entry_code, pout);
assert!(res.is_ok());
let (uuid, out_code) = res.unwrap();
let expected_output_code = formatdoc! {r#"
@Entry {{
id: "{uuid}",
foo: "bar",
foo2: "bar",
}}
"#}.to_string();
assert_eq!(out_code, expected_output_code);
}

View file

@ -2,7 +2,7 @@ use super::*;
use crate::pdel_parser::PEntryValue;
use crate::pdel_parser::values::container::parse_entry_value_container;
use crate::pdel_parser::parse_wrapper;
use crate::database::parse_extractor::get_claim_value;
use crate::database::parse_extractor::get_claim_values;
#[test]
fn test_parse_simple_entry() {
@ -98,9 +98,9 @@ fn test_parse_with_labels() {
assert!(res.is_ok(), "{:?}", res);
let pout = res.unwrap();
let claims = &pout.p.claims.p;
assert!(get_claim_value(&pout.p, &"name").is_some());
assert!(get_claim_value(&pout.p, &"description").is_some());
assert!(get_claim_value(&pout.p, &"alias").is_some());
assert!(get_claim_values(&pout.p, &"name").len() == 2);
assert!(get_claim_values(&pout.p, &"description").len() == 2);
assert!(get_claim_values(&pout.p, &"alias").len() == 1);
assert_eq!(claims[2].p.property.p, "name");
assert_eq!(claims[2].p.value_container.p.value.p, PEntryValue::String("Douglas Adams".to_string()));
}