refactor!: Unify groups, tags, types (on the backend)

feat/type-attributes
Tomáš Mládek 2023-06-09 13:33:36 +02:00
parent 7ee69a0388
commit 8bf75a7c9e
5 changed files with 46 additions and 132 deletions

View File

@ -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();
}

View File

@ -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(())
}

View File

@ -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;

View File

@ -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(),

View File

@ -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(" ")}) ? ?)`