finish renaming target/key/value to entity/attribute/value
parent
6e7cdd9887
commit
21e7ee7538
|
@ -10,13 +10,13 @@ VALUES ('version', '0.1.0');
|
|||
|
||||
CREATE TABLE files
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
hash BLOB NOT NULL,
|
||||
path VARCHAR NOT NULL,
|
||||
valid BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
added DATETIME NOT NULL,
|
||||
size BIGINT NOT NULL,
|
||||
mtime DATETIME NULL
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
hash BLOB NOT NULL,
|
||||
path VARCHAR NOT NULL,
|
||||
valid BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
added DATETIME NOT NULL,
|
||||
size BIGINT NOT NULL,
|
||||
mtime DATETIME NULL
|
||||
);
|
||||
|
||||
CREATE INDEX files_hash ON files (hash);
|
||||
|
@ -25,13 +25,13 @@ CREATE INDEX files_valid ON files (valid);
|
|||
|
||||
CREATE TABLE data
|
||||
(
|
||||
identity BLOB PRIMARY KEY NOT NULL,
|
||||
target BLOB NOT NULL,
|
||||
key VARCHAR NOT NULL,
|
||||
value VARCHAR NOT NULL,
|
||||
UNIQUE (target, key, value)
|
||||
identity BLOB PRIMARY KEY NOT NULL,
|
||||
entity BLOB NOT NULL,
|
||||
attribute VARCHAR NOT NULL,
|
||||
value VARCHAR NOT NULL,
|
||||
UNIQUE (entity, attribute, value)
|
||||
);
|
||||
|
||||
CREATE INDEX data_target ON data (target);
|
||||
CREATE INDEX data_key ON data (key);
|
||||
CREATE INDEX data_entity ON data (entity);
|
||||
CREATE INDEX data_attribute ON data (attribute);
|
||||
CREATE INDEX data_value ON data (value);
|
||||
|
|
137
src/database.rs
137
src/database.rs
|
@ -27,8 +27,8 @@ use std::time::Duration;
|
|||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Entry {
|
||||
pub target: Address,
|
||||
pub key: String,
|
||||
pub entity: Address,
|
||||
pub attribute: String,
|
||||
pub value: EntryValue,
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,8 @@ impl TryFrom<&models::Entry> for Entry {
|
|||
|
||||
fn try_from(e: &models::Entry) -> Result<Self, Self::Error> {
|
||||
Ok(Entry {
|
||||
target: Address::decode(&e.target)?,
|
||||
key: e.key.clone(),
|
||||
entity: Address::decode(&e.entity)?,
|
||||
attribute: e.attribute.clone(),
|
||||
value: e.value.parse().unwrap(),
|
||||
})
|
||||
}
|
||||
|
@ -54,15 +54,15 @@ impl TryFrom<&models::Entry> for Entry {
|
|||
|
||||
impl std::fmt::Display for Entry {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} | {} | {}", self.target, self.key, self.value)
|
||||
write!(f, "{} | {} | {}", self.entity, self.attribute, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hashable for Entry {
|
||||
fn hash(self: &Entry) -> Result<Hash> {
|
||||
let mut result = Cursor::new(vec![0u8; 0]);
|
||||
result.write_all(self.target.encode()?.as_slice())?;
|
||||
result.write_all(self.key.as_bytes())?;
|
||||
result.write_all(self.entity.encode()?.as_slice())?;
|
||||
result.write_all(self.attribute.as_bytes())?;
|
||||
result.write_all(self.value.to_string()?.as_bytes())?;
|
||||
Ok(hash(result.get_ref()))
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ pub fn retrieve_object<C: Connection<Backend = Sqlite>>(
|
|||
use crate::schema::data::dsl::*;
|
||||
|
||||
let matches = data
|
||||
.filter(target.eq(object_address.encode()?))
|
||||
.filter(entity.eq(object_address.encode()?))
|
||||
.or_filter(value.eq(EntryValue::Address(object_address).to_string()?))
|
||||
.load::<models::Entry>(connection)?;
|
||||
let entries = matches
|
||||
|
@ -223,7 +223,7 @@ pub fn bulk_retrieve_objects<C: Connection<Backend = Sqlite>>(
|
|||
|
||||
let matches = data
|
||||
.filter(
|
||||
target.eq_any(
|
||||
entity.eq_any(
|
||||
object_addresses
|
||||
.iter()
|
||||
.filter_map(|addr| addr.encode().ok()),
|
||||
|
@ -250,7 +250,7 @@ pub fn remove_object<C: Connection<Backend = Sqlite>>(
|
|||
|
||||
let matches = data
|
||||
.filter(identity.eq(object_address.encode()?))
|
||||
.or_filter(target.eq(object_address.encode()?))
|
||||
.or_filter(entity.eq(object_address.encode()?))
|
||||
.or_filter(value.eq(EntryValue::Address(object_address).to_string()?));
|
||||
|
||||
Ok(diesel::delete(matches).execute(connection)?)
|
||||
|
@ -462,68 +462,67 @@ impl TryFrom<&lexpr::Value> for Query {
|
|||
impl Query {
|
||||
fn to_sqlite_predicates(&self) -> Result<Box<Predicate>> {
|
||||
match self {
|
||||
Query::SingleQuery(qp) => match qp {
|
||||
QueryPart::Matches(eq) => {
|
||||
let mut subqueries: Vec<Box<Predicate>> = vec![];
|
||||
Query::SingleQuery(qp) => {
|
||||
match qp {
|
||||
QueryPart::Matches(eq) => {
|
||||
let mut subqueries: Vec<Box<Predicate>> = vec![];
|
||||
|
||||
match &eq.entity {
|
||||
QueryComponent::Exact(q_target) => {
|
||||
subqueries.push(Box::new(data::target.eq(q_target.encode()?)))
|
||||
}
|
||||
QueryComponent::In(q_targets) => {
|
||||
let targets: Result<Vec<_>, _> =
|
||||
q_targets.iter().map(|t| t.encode()).collect();
|
||||
subqueries.push(Box::new(data::target.eq_any(targets?)))
|
||||
}
|
||||
QueryComponent::Contains(_) => {
|
||||
return Err(anyhow!("Addresses cannot be queried alike."))
|
||||
}
|
||||
QueryComponent::Any => {}
|
||||
};
|
||||
|
||||
match &eq.attribute {
|
||||
QueryComponent::Exact(q_key) => {
|
||||
subqueries.push(Box::new(data::key.eq(q_key.clone())))
|
||||
}
|
||||
QueryComponent::In(q_keys) => {
|
||||
subqueries.push(Box::new(data::key.eq_any(q_keys.clone())))
|
||||
}
|
||||
QueryComponent::Contains(q_key) => {
|
||||
subqueries.push(Box::new(data::key.like(format!("%{}%", q_key))))
|
||||
}
|
||||
QueryComponent::Any => {}
|
||||
};
|
||||
|
||||
match &eq.value {
|
||||
QueryComponent::Exact(q_value) => {
|
||||
subqueries.push(Box::new(data::value.eq(q_value.to_string()?)))
|
||||
}
|
||||
QueryComponent::In(q_values) => {
|
||||
let values: Result<Vec<_>, _> =
|
||||
q_values.iter().map(|v| v.to_string()).collect();
|
||||
subqueries.push(Box::new(data::value.eq_any(values?)))
|
||||
}
|
||||
QueryComponent::Contains(q_value) => {
|
||||
subqueries.push(Box::new(data::value.like(format!("%{}%", q_value))))
|
||||
}
|
||||
QueryComponent::Any => {}
|
||||
};
|
||||
|
||||
match subqueries.len() {
|
||||
0 => Ok(Box::new(true.into_sql::<Bool>())),
|
||||
1 => Ok(subqueries.remove(0)),
|
||||
_ => {
|
||||
let mut result: Box<And<Box<Predicate>, Box<Predicate>>> =
|
||||
Box::new(And::new(subqueries.remove(0), subqueries.remove(0)));
|
||||
while !subqueries.is_empty() {
|
||||
result = Box::new(And::new(result, subqueries.remove(0)));
|
||||
match &eq.entity {
|
||||
QueryComponent::Exact(q_entity) => {
|
||||
subqueries.push(Box::new(data::entity.eq(q_entity.encode()?)))
|
||||
}
|
||||
QueryComponent::In(q_entities) => {
|
||||
let entities: Result<Vec<_>, _> =
|
||||
q_entities.iter().map(|t| t.encode()).collect();
|
||||
subqueries.push(Box::new(data::entity.eq_any(entities?)))
|
||||
}
|
||||
QueryComponent::Contains(_) => {
|
||||
return Err(anyhow!("Addresses cannot be queried alike."))
|
||||
}
|
||||
QueryComponent::Any => {}
|
||||
};
|
||||
|
||||
match &eq.attribute {
|
||||
QueryComponent::Exact(q_attribute) => {
|
||||
subqueries.push(Box::new(data::attribute.eq(q_attribute.clone())))
|
||||
}
|
||||
QueryComponent::In(q_attributes) => subqueries
|
||||
.push(Box::new(data::attribute.eq_any(q_attributes.clone()))),
|
||||
QueryComponent::Contains(q_attribute) => subqueries
|
||||
.push(Box::new(data::attribute.like(format!("%{}%", q_attribute)))),
|
||||
QueryComponent::Any => {}
|
||||
};
|
||||
|
||||
match &eq.value {
|
||||
QueryComponent::Exact(q_value) => {
|
||||
subqueries.push(Box::new(data::value.eq(q_value.to_string()?)))
|
||||
}
|
||||
QueryComponent::In(q_values) => {
|
||||
let values: Result<Vec<_>, _> =
|
||||
q_values.iter().map(|v| v.to_string()).collect();
|
||||
subqueries.push(Box::new(data::value.eq_any(values?)))
|
||||
}
|
||||
QueryComponent::Contains(q_value) => subqueries
|
||||
.push(Box::new(data::value.like(format!("%{}%", q_value)))),
|
||||
QueryComponent::Any => {}
|
||||
};
|
||||
|
||||
match subqueries.len() {
|
||||
0 => Ok(Box::new(true.into_sql::<Bool>())),
|
||||
1 => Ok(subqueries.remove(0)),
|
||||
_ => {
|
||||
let mut result: Box<And<Box<Predicate>, Box<Predicate>>> =
|
||||
Box::new(And::new(subqueries.remove(0), subqueries.remove(0)));
|
||||
while !subqueries.is_empty() {
|
||||
result = Box::new(And::new(result, subqueries.remove(0)));
|
||||
}
|
||||
Ok(Box::new(result))
|
||||
}
|
||||
Ok(Box::new(result))
|
||||
}
|
||||
}
|
||||
QueryPart::Type(_) => unimplemented!("Type queries are not yet implemented."),
|
||||
}
|
||||
QueryPart::Type(_) => unimplemented!("Type queries are not yet implemented."),
|
||||
},
|
||||
}
|
||||
Query::MultiQuery(mq) => {
|
||||
let subqueries: Result<Vec<Box<Predicate>>> = mq
|
||||
.queries
|
||||
|
@ -584,8 +583,8 @@ pub fn insert_entry<C: Connection<Backend = Sqlite>>(
|
|||
|
||||
let insert_entry = models::Entry {
|
||||
identity: entry.address()?.encode()?,
|
||||
target: entry.target.encode()?,
|
||||
key: entry.key,
|
||||
entity: entry.entity.encode()?,
|
||||
attribute: entry.attribute,
|
||||
value: entry.value.to_string()?,
|
||||
};
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ pub fn list_roots<C: Connection<Backend = Sqlite>>(connection: &C) -> Result<Vec
|
|||
|
||||
Ok(all_directories
|
||||
.into_iter()
|
||||
.filter(|entry| !directories_with_parents.contains(&entry.target))
|
||||
.filter(|entry| !directories_with_parents.contains(&entry.entity))
|
||||
.collect())
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ pub async fn list_directory<C: Connection<Backend = Sqlite>>(
|
|||
let entry_addresses = match path.0.len() {
|
||||
0 => list_roots(connection)?
|
||||
.into_iter()
|
||||
.map(|e| e.target)
|
||||
.map(|e| e.entity)
|
||||
.collect(),
|
||||
_ => {
|
||||
let resolved_path: Vec<Address> = resolve_path(connection, path, false)?;
|
||||
|
@ -182,7 +182,7 @@ pub async fn list_directory<C: Connection<Backend = Sqlite>>(
|
|||
|
||||
Ok(bulk_retrieve_objects(connection, entry_addresses)?
|
||||
.into_iter()
|
||||
.filter(|e| [DIR_KEY, FILENAME_KEY, FILE_IDENTITY_KEY].contains(&e.key.as_str()))
|
||||
.filter(|e| [DIR_KEY, FILENAME_KEY, FILE_IDENTITY_KEY].contains(&e.attribute.as_str()))
|
||||
.collect::<Vec<Entry>>())
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ pub fn fetch_or_create_dir<C: Connection<Backend = Sqlite>>(
|
|||
})),
|
||||
)?
|
||||
.into_iter()
|
||||
.map(|e: Entry| e.target)
|
||||
.map(|e: Entry| e.entity)
|
||||
.collect();
|
||||
|
||||
let valid_directories: Vec<Address> = match parent.clone() {
|
||||
|
@ -235,16 +235,16 @@ pub fn fetch_or_create_dir<C: Connection<Backend = Sqlite>>(
|
|||
if create {
|
||||
let new_directory_address = Address::UUID(Uuid::new_v4());
|
||||
let directory_entry = Entry {
|
||||
target: new_directory_address.clone(),
|
||||
key: String::from(DIR_KEY),
|
||||
entity: new_directory_address.clone(),
|
||||
attribute: String::from(DIR_KEY),
|
||||
value: dir_value,
|
||||
};
|
||||
let _ = insert_entry(connection, directory_entry)?;
|
||||
|
||||
if let Some(parent_addr) = parent {
|
||||
let has_entry = Entry {
|
||||
target: parent_addr,
|
||||
key: String::from(DIR_HAS_KEY),
|
||||
entity: parent_addr,
|
||||
attribute: String::from(DIR_HAS_KEY),
|
||||
value: EntryValue::Address(new_directory_address.clone()),
|
||||
};
|
||||
let _ = insert_entry(connection, has_entry)?;
|
||||
|
@ -456,8 +456,8 @@ fn _process_directory_entry<P: AsRef<Path>>(
|
|||
let file_address = Address::UUID(Uuid::new_v4());
|
||||
|
||||
let name_entry = Entry {
|
||||
target: file_address.clone(),
|
||||
key: FILENAME_KEY.to_string(),
|
||||
entity: file_address.clone(),
|
||||
attribute: FILENAME_KEY.to_string(),
|
||||
value: EntryValue::Value(Value::String(
|
||||
filename.as_os_str().to_string_lossy().to_string(),
|
||||
)),
|
||||
|
@ -465,16 +465,16 @@ fn _process_directory_entry<P: AsRef<Path>>(
|
|||
let _ = insert_entry(&connection, name_entry)?;
|
||||
|
||||
let identity_entry = Entry {
|
||||
target: file_address.clone(),
|
||||
key: FILE_IDENTITY_KEY.to_string(),
|
||||
entity: file_address.clone(),
|
||||
attribute: FILE_IDENTITY_KEY.to_string(),
|
||||
value: EntryValue::Address(Address::Hash(digest.clone())),
|
||||
};
|
||||
|
||||
let _ = insert_entry(&connection, identity_entry)?;
|
||||
|
||||
let dir_has_entry = Entry {
|
||||
target: parent_dir.clone(),
|
||||
key: DIR_HAS_KEY.to_string(),
|
||||
entity: parent_dir.clone(),
|
||||
attribute: DIR_HAS_KEY.to_string(),
|
||||
value: EntryValue::Address(file_address),
|
||||
};
|
||||
let _ = insert_entry(&connection, dir_has_entry)?;
|
||||
|
|
|
@ -29,7 +29,7 @@ pub struct NewFile {
|
|||
#[table_name = "data"]
|
||||
pub struct Entry {
|
||||
pub identity: Vec<u8>,
|
||||
pub target: Vec<u8>,
|
||||
pub key: String,
|
||||
pub entity: Vec<u8>,
|
||||
pub attribute: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
table! {
|
||||
data (identity) {
|
||||
identity -> Binary,
|
||||
target -> Binary,
|
||||
key -> Text,
|
||||
entity -> Binary,
|
||||
attribute -> Text,
|
||||
value -> Text,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue