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