remove list_hier, retrieve_object retrieves attrs of attrs, rework /api/hier

feat/vaults
Tomáš Mládek 2021-12-17 23:04:35 +01:00
parent 1194a4439e
commit e0a603d154
4 changed files with 82 additions and 94 deletions

View File

@ -15,7 +15,7 @@ use crate::database::constants::{
};
use crate::database::entry::{Entry, EntryValue};
use crate::database::lang::{EntryQuery, Query, QueryComponent, QueryPart};
use crate::database::{bulk_retrieve_objects, insert_entry, query, DbPool};
use crate::database::{insert_entry, query, DbPool};
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct UNode(String);
@ -37,14 +37,14 @@ impl UNode {
}
#[derive(Debug, Clone, PartialEq)]
pub struct UPath(pub Vec<UNode>);
pub struct UHierPath(pub Vec<UNode>);
impl std::str::FromStr for UPath {
impl std::str::FromStr for UHierPath {
type Err = anyhow::Error;
fn from_str(string: &str) -> Result<Self, Self::Err> {
if string.is_empty() {
Ok(UPath(vec![]))
Ok(UHierPath(vec![]))
} else {
let result: Result<Vec<UNode>> = string
.trim_end_matches('/')
@ -52,7 +52,7 @@ impl std::str::FromStr for UPath {
.map(|part| UNode::new(String::from(part)))
.collect();
Ok(UPath(result?))
Ok(UHierPath(result?))
}
}
}
@ -63,7 +63,7 @@ impl std::fmt::Display for UNode {
}
}
impl std::fmt::Display for UPath {
impl std::fmt::Display for UHierPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
@ -77,11 +77,11 @@ impl std::fmt::Display for UPath {
}
}
trait EntryList {
trait PointerEntries {
fn extract_pointers(&self) -> Vec<(Address, Address)>;
}
impl EntryList for Vec<Entry> {
impl PointerEntries for Vec<Entry> {
fn extract_pointers(&self) -> Vec<(Address, Address)> {
self.iter()
.filter_map(|e| {
@ -95,7 +95,7 @@ impl EntryList for Vec<Entry> {
}
}
pub fn list_orphans<C: Connection<Backend = Sqlite>>(connection: &C) -> Result<Vec<Address>> {
pub fn list_roots<C: Connection<Backend = Sqlite>>(connection: &C) -> Result<Vec<Address>> {
let all_directories: Vec<Entry> = query(
connection,
Query::SingleQuery(QueryPart::Matches(EntryQuery {
@ -125,34 +125,6 @@ pub fn list_orphans<C: Connection<Backend = Sqlite>>(connection: &C) -> Result<V
.collect())
}
pub async fn list_path<C: Connection<Backend = Sqlite>>(
connection: &C,
path: &UPath,
) -> Result<Vec<Entry>> {
let resolved_path: Vec<Address> = resolve_path(connection, path, false)?;
let entry_addresses = match resolved_path.last() {
Some(last) => query(
connection,
Query::SingleQuery(QueryPart::Matches(EntryQuery {
entity: QueryComponent::Exact(last.clone()),
attribute: QueryComponent::Exact(HIER_HAS_ATTR.to_string()),
value: QueryComponent::Any,
})),
)?
.extract_pointers()
.into_iter()
.map(|(addr, val)| [addr, val])
.flatten()
.collect(),
None => list_orphans(connection)?,
};
Ok(bulk_retrieve_objects(connection, entry_addresses)?
.into_iter()
// .filter(|e| [DIR_KEY, FILENAME_KEY, FILE_IDENTITY_KEY].contains(&e.attribute.as_str()))
.collect::<Vec<Entry>>())
}
lazy_static! {
static ref FETCH_CREATE_LOCK: Mutex<()> = Mutex::new(());
}
@ -199,7 +171,7 @@ pub fn fetch_or_create_dir<C: Connection<Backend = Sqlite>>(
.into_iter()
.map(|(_, val)| val)
.collect(),
None => list_orphans(connection)?,
None => list_roots(connection)?,
};
let valid_directories: Vec<Address> = matching_directories
@ -248,7 +220,7 @@ pub fn fetch_or_create_dir<C: Connection<Backend = Sqlite>>(
pub fn resolve_path<C: Connection<Backend = Sqlite>>(
connection: &C,
path: &UPath,
path: &UHierPath,
create: bool,
) -> Result<Vec<Address>> {
let mut result: Vec<Address> = vec![];
@ -272,7 +244,7 @@ pub type ResolveCache = LruCache<(Option<Address>, UNode), Address>;
pub fn resolve_path_cached<C: Connection<Backend = Sqlite>>(
connection: &C,
path: &UPath,
path: &UHierPath,
create: bool,
cache: &Arc<Mutex<ResolveCache>>,
) -> Result<Vec<Address>> {
@ -326,7 +298,7 @@ mod tests {
#[test]
fn test_path_codec() {
let path = UPath(vec![
let path = UHierPath(vec![
UNode("top".to_string()),
UNode("foo".to_string()),
UNode("bar".to_string()),
@ -336,7 +308,7 @@ mod tests {
let str_path = path.to_string();
assert!(!str_path.is_empty());
let decoded_path: Result<UPath> = str_path.parse();
let decoded_path: Result<UHierPath> = str_path.parse();
assert!(decoded_path.is_ok());
assert_eq!(path, decoded_path.unwrap());
@ -344,13 +316,13 @@ mod tests {
#[test]
fn test_path_validation() {
let valid_path: Result<UPath> = "a/b/c/d/e/f/g".parse();
let valid_path: Result<UHierPath> = "a/b/c/d/e/f/g".parse();
assert!(valid_path.is_ok());
let invalid_path: Result<UPath> = "a/b/c//d/e/f/g".parse();
let invalid_path: Result<UHierPath> = "a/b/c//d/e/f/g".parse();
assert!(invalid_path.is_err());
let invalid_path: Result<UPath> = "a//b/c//d/e/f///g".parse();
let invalid_path: Result<UHierPath> = "a//b/c//d/e/f///g".parse();
assert!(invalid_path.is_err());
}
@ -386,7 +358,7 @@ mod tests {
assert!(baz_result.is_ok());
let baz_result = baz_result.unwrap();
let orphans = list_orphans(&open_result.pool.get().unwrap());
let orphans = list_roots(&open_result.pool.get().unwrap());
assert!(orphans.is_ok());
assert_eq!(orphans.unwrap().len(), 2);

View File

@ -9,7 +9,7 @@ pub mod hierarchies;
pub mod inner;
pub mod lang;
use crate::addressing::Address;
use crate::addressing::{Address, Addressable};
use crate::database::constants::{IS_OF_TYPE_ATTR, TYPE_ADDR, TYPE_HAS_ATTR, TYPE_INVARIANT};
use crate::database::entry::{Entry, EntryValue};
use crate::database::inner::models;
@ -118,43 +118,35 @@ pub fn retrieve_object<C: Connection<Backend = Sqlite>>(
) -> Result<Vec<Entry>> {
use crate::database::inner::schema::data::dsl::*;
let matches = data
let primary = data
.filter(entity.eq(object_address.encode()?))
.or_filter(value.eq(EntryValue::Address(object_address).to_string()?))
.load::<models::Entry>(connection)?;
let entries = matches
let entries = primary
.iter()
.map(Entry::try_from)
.filter_map(Result::ok)
.collect();
.collect::<Result<Vec<Entry>>>()?;
Ok(entries)
}
pub fn bulk_retrieve_objects<C: Connection<Backend = Sqlite>>(
connection: &C,
object_addresses: Vec<Address>,
) -> Result<Vec<Entry>> {
use crate::database::inner::schema::data::dsl::*;
let matches = data
let secondary = data
.filter(
entity.eq_any(
object_addresses
entries
.iter()
.filter_map(|addr| addr.encode().ok()),
.map(|e| e.address())
.filter_map(Result::ok)
.map(|addr| addr.encode())
.collect::<Result<Vec<Vec<u8>>>>()?,
),
)
// .or_filter(value.eq(EntryValue::Address(object_address).to_str()?))
.load::<models::Entry>(connection)?;
let entries = matches
let secondary_entries = secondary
.iter()
.map(Entry::try_from)
.filter_map(Result::ok)
.collect();
.collect::<Result<Vec<Entry>>>()?;
Ok(entries)
Ok([entries, secondary_entries].concat())
}
pub fn remove_object<C: Connection<Backend = Sqlite>>(

View File

@ -9,7 +9,7 @@ use crate::database::constants::{
HIER_HAS_ATTR, IS_OF_TYPE_ATTR, TYPE_ADDR, TYPE_BASE_ATTR, TYPE_HAS_ATTR,
};
use crate::database::entry::{Entry, EntryValue, InvariantEntry};
use crate::database::hierarchies::{resolve_path_cached, ResolveCache, UNode, UPath};
use crate::database::hierarchies::{resolve_path_cached, ResolveCache, UNode, UHierPath};
use crate::database::inner::models;
use crate::database::{
file_set_valid, file_update_mtime, insert_entry, insert_file, retrieve_all_files, DbPool,
@ -350,7 +350,7 @@ fn _process_directory_entry<P: AsRef<Path>>(
let components = normalized_path.components().collect::<Vec<Component>>();
let (filename, dir_path) = components.split_last().unwrap();
let upath = UPath(
let upath = UHierPath(
iter::once(UNode::new("NATIVE").unwrap())
.chain(dir_path.iter().map(|component| {
UNode::new(component.as_os_str().to_string_lossy().to_string()).unwrap()

View File

@ -1,6 +1,6 @@
use crate::addressing::{Address, Addressable};
use crate::database::entry::{Entry, InEntry};
use crate::database::hierarchies::{list_path, UPath};
use crate::database::hierarchies::{list_roots, resolve_path, UHierPath};
use crate::database::lang::Query;
use crate::database::{
get_latest_files, insert_entry, query, remove_object, retrieve_file, retrieve_object, DbPool,
@ -84,34 +84,36 @@ pub async fn get_query(
Ok(HttpResponse::Ok().json(&result))
}
trait EntriesAsHash {
fn as_hash(&self) -> Result<HashMap<String, &Entry>>;
}
impl EntriesAsHash for Vec<Entry> {
fn as_hash(&self) -> Result<HashMap<String, &Entry>> {
let mut result: HashMap<String, &Entry> = HashMap::new();
for entry in self {
result.insert(encode(entry.address()?.encode()?), entry);
}
Ok(result)
}
}
#[get("/api/obj/{address_str}")]
pub async fn get_object(
state: web::Data<State>,
address_str: web::Path<String>,
) -> Result<HttpResponse, Error> {
let connection = state.db_pool.get().map_err(ErrorInternalServerError)?;
let response: Result<Vec<Entry>> = retrieve_object(
let result: Vec<Entry> = retrieve_object(
&connection,
Address::decode(&decode(address_str.into_inner()).map_err(ErrorBadRequest)?)
.map_err(ErrorBadRequest)?,
);
)
.map_err(ErrorInternalServerError)?;
debug!("{:?}", response);
let mut result: HashMap<String, Entry> = HashMap::new();
for entry in response.map_err(error::ErrorInternalServerError)? {
result.insert(
encode(
entry
.address()
.map_err(ErrorInternalServerError)?
.encode()
.map_err(ErrorInternalServerError)?,
),
entry,
);
}
Ok(HttpResponse::Ok().json(result))
debug!("{:?}", result);
Ok(HttpResponse::Ok().json(result.as_hash().map_err(ErrorInternalServerError)?))
}
const MAX_SIZE: usize = 1_000_000;
@ -172,13 +174,35 @@ pub async fn list_hier(
path: web::Path<String>,
) -> Result<HttpResponse, Error> {
let connection = state.db_pool.get().map_err(ErrorInternalServerError)?;
let upath: UPath = path.into_inner().parse().map_err(ErrorBadRequest)?;
let upath: UHierPath = path.into_inner().parse().map_err(ErrorBadRequest)?;
trace!("Listing path \"{}\"", upath);
let entries: Vec<Entry> = list_path(&connection, &upath)
.await
.map_err(ErrorNotFound)?; // todo: 500 if actual error occurs
Ok(HttpResponse::Ok().json(entries))
let (addr, data) = if upath.0.is_empty() {
(
None,
list_roots(&connection)
.map_err(ErrorInternalServerError)?
.into_iter()
.map(|root| {
retrieve_object(&connection, root)
})
.collect::<Result<Vec<Vec<Entry>>>>().map_err(ErrorInternalServerError)?
.concat(),
)
} else {
// todo: 500 if actual error occurs
let path = resolve_path(&connection, &upath, false).map_err(ErrorNotFound)?;
let last = path.last().unwrap().clone();
(
Some(last.clone()),
retrieve_object(&connection, last).map_err(ErrorInternalServerError)?,
)
};
Ok(HttpResponse::Ok().json(json!({
"addr": addr,
"data": data
})))
}
#[post("/api/refresh")]