refactor!: Unify groups, tags, types (on the backend)
parent
7ee69a0388
commit
8bf75a7c9e
|
@ -1,28 +1,16 @@
|
|||
use crate::addressing::Address;
|
||||
use crate::database::entry::InvariantEntry;
|
||||
|
||||
pub const TYPE_TYPE_VAL: &str = "TYPE";
|
||||
pub const TYPE_BASE_ATTR: &str = "TYPE";
|
||||
pub const TYPE_HAS_ATTR: &str = "TYPE_HAS";
|
||||
// pub const TYPE_ATTR_REQUIRED: &str = "TYPE_ATTR_REQUIRED";
|
||||
|
||||
pub const IS_OF_TYPE_ATTR: &str = "IS";
|
||||
|
||||
pub const HIER_TYPE_VAL: &str = "HIER";
|
||||
pub const HIER_HAS_ATTR: &str = "HAS";
|
||||
pub const IS_OF_ATTR: &str = "OF";
|
||||
pub const ATTR_BY_ATTR: &str = "BY";
|
||||
|
||||
pub const LABEL_ATTR: &str = "LBL";
|
||||
pub const ADDED_ATTR: &str = "ADDED";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref TYPE_INVARIANT: InvariantEntry = InvariantEntry {
|
||||
attribute: String::from(TYPE_BASE_ATTR),
|
||||
value: TYPE_TYPE_VAL.into(),
|
||||
pub static ref HIER_ROOT_INVARIANT: InvariantEntry = InvariantEntry {
|
||||
attribute: String::from(IS_OF_ATTR),
|
||||
value: "HIER_ROOT".into(),
|
||||
};
|
||||
pub static ref TYPE_ADDR: Address = TYPE_INVARIANT.entity().unwrap();
|
||||
pub static ref HIER_INVARIANT: InvariantEntry = InvariantEntry {
|
||||
attribute: String::from(TYPE_BASE_ATTR),
|
||||
value: HIER_TYPE_VAL.into(),
|
||||
};
|
||||
pub static ref HIER_ADDR: Address = HIER_INVARIANT.entity().unwrap();
|
||||
pub static ref HIER_ROOT_ADDR: Address = HIER_ROOT_INVARIANT.entity().unwrap();
|
||||
}
|
||||
|
|
|
@ -6,13 +6,12 @@ use lru::LruCache;
|
|||
use tracing::trace;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::addressing::{Address, Addressable};
|
||||
use crate::database::constants::{
|
||||
HIER_ADDR, HIER_HAS_ATTR, HIER_INVARIANT, IS_OF_TYPE_ATTR, LABEL_ATTR, TYPE_ADDR, TYPE_HAS_ATTR,
|
||||
};
|
||||
use crate::database::entry::{Entry, EntryValue};
|
||||
use crate::addressing::Address;
|
||||
use crate::database::constants::LABEL_ATTR;
|
||||
use crate::database::entry::Entry;
|
||||
use crate::database::lang::{PatternQuery, Query, QueryComponent, QueryPart};
|
||||
|
||||
use super::constants::{HIER_ROOT_ADDR, HIER_ROOT_INVARIANT, IS_OF_ATTR};
|
||||
use super::UpEndConnection;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
|
@ -77,47 +76,14 @@ impl std::fmt::Display for UHierPath {
|
|||
}
|
||||
}
|
||||
|
||||
trait PointerEntries {
|
||||
fn extract_pointers(&self) -> Vec<(Address, Address)>;
|
||||
}
|
||||
|
||||
impl PointerEntries for Vec<Entry> {
|
||||
fn extract_pointers(&self) -> Vec<(Address, Address)> {
|
||||
self.iter()
|
||||
.filter_map(|e| {
|
||||
if let EntryValue::Address(address) = &e.value {
|
||||
Some((e.address().unwrap(), address.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_roots(connection: &UpEndConnection) -> Result<Vec<Address>> {
|
||||
let all_directories: Vec<Entry> =
|
||||
connection.query(Query::SingleQuery(QueryPart::Matches(PatternQuery {
|
||||
entity: QueryComponent::Variable(None),
|
||||
attribute: QueryComponent::Exact(IS_OF_TYPE_ATTR.into()),
|
||||
value: QueryComponent::Exact(HIER_ADDR.clone().into()),
|
||||
})))?;
|
||||
|
||||
// TODO: this is horrible
|
||||
let directories_with_parents: Vec<Address> = connection
|
||||
Ok(connection
|
||||
.query(Query::SingleQuery(QueryPart::Matches(PatternQuery {
|
||||
entity: QueryComponent::Variable(None),
|
||||
attribute: QueryComponent::Exact(HIER_HAS_ATTR.into()),
|
||||
value: QueryComponent::Variable(None),
|
||||
attribute: QueryComponent::Exact(IS_OF_ATTR.into()),
|
||||
value: QueryComponent::Exact((*HIER_ROOT_ADDR).clone().into()),
|
||||
})))?
|
||||
.extract_pointers()
|
||||
.into_iter()
|
||||
.map(|(_, val)| val)
|
||||
.collect();
|
||||
|
||||
Ok(all_directories
|
||||
.into_iter()
|
||||
.filter(|entry| !directories_with_parents.contains(&entry.entity))
|
||||
.map(|e| e.entity)
|
||||
.collect())
|
||||
}
|
||||
|
@ -154,13 +120,12 @@ pub fn fetch_or_create_dir(
|
|||
let parent_has: Vec<Address> = match parent.clone() {
|
||||
Some(parent) => connection
|
||||
.query(Query::SingleQuery(QueryPart::Matches(PatternQuery {
|
||||
entity: QueryComponent::Exact(parent),
|
||||
attribute: QueryComponent::Exact(HIER_HAS_ATTR.into()),
|
||||
value: QueryComponent::Variable(None),
|
||||
entity: QueryComponent::Variable(None),
|
||||
attribute: QueryComponent::Exact(IS_OF_ATTR.into()),
|
||||
value: QueryComponent::Exact(parent.into()),
|
||||
})))?
|
||||
.extract_pointers()
|
||||
.into_iter()
|
||||
.map(|(_, val)| val)
|
||||
.map(|e| e.entity)
|
||||
.collect(),
|
||||
None => list_roots(connection)?,
|
||||
};
|
||||
|
@ -173,14 +138,6 @@ pub fn fetch_or_create_dir(
|
|||
0 => {
|
||||
if create {
|
||||
let new_directory_address = Address::Uuid(Uuid::new_v4());
|
||||
let type_entry = Entry {
|
||||
entity: new_directory_address.clone(),
|
||||
attribute: String::from(IS_OF_TYPE_ATTR),
|
||||
value: HIER_ADDR.clone().into(),
|
||||
provenance: "SYSTEM FS".to_string(),
|
||||
timestamp: chrono::Utc::now().naive_utc(),
|
||||
};
|
||||
connection.insert_entry(type_entry)?;
|
||||
|
||||
let directory_entry = Entry {
|
||||
entity: new_directory_address.clone(),
|
||||
|
@ -191,16 +148,23 @@ pub fn fetch_or_create_dir(
|
|||
};
|
||||
connection.insert_entry(directory_entry)?;
|
||||
|
||||
if let Some(parent) = parent {
|
||||
let has_entry = Entry {
|
||||
entity: parent,
|
||||
attribute: String::from(HIER_HAS_ATTR),
|
||||
value: new_directory_address.clone().into(),
|
||||
connection.insert_entry(if let Some(parent) = parent {
|
||||
Entry {
|
||||
entity: new_directory_address.clone(),
|
||||
attribute: String::from(IS_OF_ATTR),
|
||||
value: parent.into(),
|
||||
provenance: "SYSTEM FS".to_string(),
|
||||
timestamp: chrono::Utc::now().naive_utc(),
|
||||
};
|
||||
connection.insert_entry(has_entry)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Entry {
|
||||
entity: new_directory_address.clone(),
|
||||
attribute: String::from(IS_OF_ATTR),
|
||||
value: HIER_ROOT_ADDR.clone().into(),
|
||||
provenance: "SYSTEM FS".to_string(),
|
||||
timestamp: chrono::Utc::now().naive_utc(),
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(new_directory_address)
|
||||
} else {
|
||||
|
@ -269,10 +233,8 @@ pub fn resolve_path_cached(
|
|||
}
|
||||
|
||||
pub fn initialize_hier(connection: &UpEndConnection) -> Result<()> {
|
||||
connection.insert_entry(Entry::try_from(&*HIER_INVARIANT)?)?;
|
||||
upend_insert_addr!(connection, HIER_ADDR, IS_OF_TYPE_ATTR, TYPE_ADDR)?;
|
||||
upend_insert_val!(connection, HIER_ADDR, TYPE_HAS_ATTR, HIER_HAS_ATTR)?;
|
||||
upend_insert_val!(connection, HIER_ADDR, LABEL_ATTR, "Group")?;
|
||||
connection.insert_entry(Entry::try_from(&*HIER_ROOT_INVARIANT)?)?;
|
||||
upend_insert_val!(connection, HIER_ROOT_ADDR, LABEL_ATTR, "Hierarchy Root")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,6 @@ pub mod lang;
|
|||
|
||||
use crate::addressing::{Address, Addressable};
|
||||
use crate::common::build;
|
||||
use crate::database::constants::{
|
||||
IS_OF_TYPE_ATTR, LABEL_ATTR, TYPE_ADDR, TYPE_HAS_ATTR, TYPE_INVARIANT, TYPE_TYPE_VAL,
|
||||
};
|
||||
use crate::database::engine::execute;
|
||||
use crate::database::entry::{Entry, EntryValue, ImmutableEntry};
|
||||
use crate::database::inner::models;
|
||||
|
@ -161,13 +158,6 @@ impl UpEndDatabase {
|
|||
},
|
||||
)?;
|
||||
|
||||
trace!("Initializing types...");
|
||||
connection.insert_entry(Entry::try_from(&*TYPE_INVARIANT)?)?;
|
||||
upend_insert_addr!(connection, TYPE_ADDR, IS_OF_TYPE_ATTR, TYPE_ADDR)?;
|
||||
upend_insert_val!(connection, TYPE_ADDR, TYPE_HAS_ATTR, TYPE_HAS_ATTR)?;
|
||||
upend_insert_val!(connection, TYPE_ADDR, TYPE_HAS_ATTR, TYPE_TYPE_VAL)?;
|
||||
upend_insert_val!(connection, TYPE_ADDR, LABEL_ATTR, "UpEnd Type")?;
|
||||
|
||||
initialize_hier(&connection)?;
|
||||
|
||||
Ok(OpenResult { db, new })
|
||||
|
@ -378,6 +368,8 @@ impl UpEndConnection {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::database::constants::LABEL_ATTR;
|
||||
|
||||
use super::*;
|
||||
use tempfile::TempDir;
|
||||
|
||||
|
|
|
@ -2,11 +2,8 @@ use self::db::files;
|
|||
|
||||
use super::{Blob, StoreError, UpStore, UpdatePathOutcome};
|
||||
use crate::addressing::Address;
|
||||
use crate::database::constants::{
|
||||
ADDED_ATTR, HIER_HAS_ATTR, IS_OF_TYPE_ATTR, LABEL_ATTR, TYPE_ADDR, TYPE_BASE_ATTR,
|
||||
TYPE_HAS_ATTR,
|
||||
};
|
||||
use crate::database::entry::{Entry, InvariantEntry};
|
||||
use crate::database::constants::{ADDED_ATTR, ATTR_BY_ATTR, IS_OF_ATTR, LABEL_ATTR};
|
||||
use crate::database::entry::Entry;
|
||||
use crate::database::hierarchies::{
|
||||
resolve_path, resolve_path_cached, ResolveCache, UHierPath, UNode,
|
||||
};
|
||||
|
@ -24,7 +21,7 @@ use lru::LruCache;
|
|||
use rayon::prelude::*;
|
||||
use serde_json::json;
|
||||
use std::borrow::Borrow;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::convert::TryInto;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Component, Path};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
@ -35,19 +32,9 @@ use walkdir::WalkDir;
|
|||
|
||||
mod db;
|
||||
|
||||
const BLOB_TYPE: &str = "BLOB";
|
||||
const ALIAS_KEY: &str = "ALIAS";
|
||||
pub const FILE_MIME_KEY: &str = "FILE_MIME";
|
||||
const FILE_SIZE_KEY: &str = "FILE_SIZE";
|
||||
|
||||
lazy_static! {
|
||||
static ref BLOB_TYPE_INVARIANT: InvariantEntry = InvariantEntry {
|
||||
attribute: String::from(TYPE_BASE_ATTR),
|
||||
value: BLOB_TYPE.into(),
|
||||
};
|
||||
static ref BLOB_TYPE_ADDR: Address = BLOB_TYPE_INVARIANT.entity().unwrap();
|
||||
}
|
||||
|
||||
pub struct FsStore {
|
||||
path: PathBuf,
|
||||
pool: r2d2::Pool<ConnectionManager<SqliteConnection>>,
|
||||
|
@ -116,14 +103,6 @@ impl FsStore {
|
|||
let db = db.borrow();
|
||||
let upconnection = db.connection()?;
|
||||
|
||||
// Initialize types, etc...
|
||||
debug!("Initializing DB types.");
|
||||
upconnection.insert_entry(Entry::try_from(&*BLOB_TYPE_INVARIANT)?)?;
|
||||
upend_insert_addr!(upconnection, BLOB_TYPE_ADDR, IS_OF_TYPE_ATTR, TYPE_ADDR)?;
|
||||
upend_insert_val!(upconnection, BLOB_TYPE_ADDR, TYPE_HAS_ATTR, FILE_SIZE_KEY)?;
|
||||
upend_insert_val!(upconnection, BLOB_TYPE_ADDR, TYPE_HAS_ATTR, FILE_MIME_KEY)?;
|
||||
upend_insert_val!(upconnection, BLOB_TYPE_ADDR, LABEL_ATTR, "Data Blob")?;
|
||||
|
||||
// Walk through the vault, find all paths
|
||||
debug!("Traversing vault directory");
|
||||
let absolute_dir_path = fs::canonicalize(&*self.path)?;
|
||||
|
@ -411,14 +390,6 @@ impl FsStore {
|
|||
let blob_address = Address::Hash(hash);
|
||||
|
||||
// Metadata
|
||||
let type_entry = Entry {
|
||||
entity: blob_address.clone(),
|
||||
attribute: String::from(IS_OF_TYPE_ATTR),
|
||||
value: BLOB_TYPE_ADDR.clone().into(),
|
||||
provenance: "SYSTEM INIT".to_string(),
|
||||
timestamp: chrono::Utc::now().naive_utc(),
|
||||
};
|
||||
|
||||
let size_entry = Entry {
|
||||
entity: blob_address.clone(),
|
||||
attribute: FILE_SIZE_KEY.to_string(),
|
||||
|
@ -467,7 +438,6 @@ impl FsStore {
|
|||
// Insert all
|
||||
let file_count = self.insert_file(new_file)?;
|
||||
|
||||
connection.insert_entry_immutable(type_entry)?;
|
||||
connection.insert_entry_immutable(size_entry)?;
|
||||
if file_count == 1 {
|
||||
connection.insert_entry_immutable(added_entry)?;
|
||||
|
@ -477,9 +447,9 @@ impl FsStore {
|
|||
}
|
||||
|
||||
let dir_has_entry = Entry {
|
||||
entity: parent_dir.clone(),
|
||||
attribute: HIER_HAS_ATTR.to_string(),
|
||||
value: blob_address.clone().into(),
|
||||
entity: blob_address.clone(),
|
||||
attribute: IS_OF_ATTR.to_string(),
|
||||
value: parent_dir.clone().into(),
|
||||
provenance: "SYSTEM INIT".to_string(),
|
||||
timestamp: chrono::Utc::now().naive_utc(),
|
||||
};
|
||||
|
@ -498,7 +468,7 @@ impl FsStore {
|
|||
|
||||
let alias_entry = Entry {
|
||||
entity: dir_has_entry_addr,
|
||||
attribute: ALIAS_KEY.to_string(),
|
||||
attribute: ATTR_BY_ATTR.to_string(),
|
||||
value: label_entry_addr.into(),
|
||||
provenance: "SYSTEM INIT".to_string(),
|
||||
timestamp: chrono::Utc::now().naive_utc(),
|
||||
|
|
|
@ -45,7 +45,9 @@
|
|||
|
||||
$: ({ entity, entityInfo, error, revalidate } = useEntity(address));
|
||||
|
||||
$: allTypeAddresses = ($entity?.attr["IS"] || []).map((attr) => attr.value.c);
|
||||
$: allTypeAddresses = ($entity?.attr["OF"] || [])
|
||||
.filter((attr) => attr.value.t == "Address")
|
||||
.map((attr) => attr.value.c);
|
||||
|
||||
$: allTypeEntries = query(
|
||||
`(matches (in ${allTypeAddresses.map((addr) => `@${addr}`).join(" ")}) ? ?)`
|
||||
|
|
Loading…
Reference in New Issue