wip
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
parent
6fb0d5f1b6
commit
3a6db03ac1
|
@ -1,4 +1,4 @@
|
||||||
use crate::addressing::Address;
|
use crate::addressing::{Address, Addressable};
|
||||||
use crate::entry::InvariantEntry;
|
use crate::entry::InvariantEntry;
|
||||||
use crate::hash::{LargeMultihash, UpMultihash};
|
use crate::hash::{LargeMultihash, UpMultihash};
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ pub const ATTR_KEY: &str = "KEY";
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref HIER_ROOT_INVARIANT: InvariantEntry = InvariantEntry {
|
pub static ref HIER_ROOT_INVARIANT: InvariantEntry = InvariantEntry {
|
||||||
attribute: String::from(ATTR_KEY),
|
attribute: String::from(ATTR_KEY),
|
||||||
value: "HIER_ROOT".into(),
|
value: "HIER_ROOT".address().unwrap().into(),
|
||||||
};
|
};
|
||||||
pub static ref HIER_ROOT_ADDR: Address = HIER_ROOT_INVARIANT.entity().unwrap();
|
pub static ref HIER_ROOT_ADDR: Address = HIER_ROOT_INVARIANT.entity().unwrap();
|
||||||
pub static ref TYPE_HASH_ADDRESS: Address =
|
pub static ref TYPE_HASH_ADDRESS: Address =
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::addressing::Address;
|
use crate::addressing::{Address, Addressable};
|
||||||
use crate::error::UpEndError;
|
use crate::error::UpEndError;
|
||||||
use crate::hash::{b58_decode, sha256hash, AsMultihash, AsMultihashError, UpMultihash};
|
use crate::hash::{b58_decode, sha256hash, AsMultihash, AsMultihashError, UpMultihash};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
|
@ -28,11 +28,9 @@ pub struct InvariantEntry {
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(tag = "t", content = "c")]
|
#[serde(tag = "t", content = "c")]
|
||||||
pub enum EntryValue {
|
pub enum EntryValue {
|
||||||
String(String),
|
|
||||||
Number(f64),
|
|
||||||
Address(Address),
|
Address(Address),
|
||||||
|
Number(f64),
|
||||||
Null,
|
Null,
|
||||||
Invalid,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Entry {
|
impl Default for Entry {
|
||||||
|
@ -68,7 +66,7 @@ impl InvariantEntry {
|
||||||
.write_all(self.attribute.as_bytes())
|
.write_all(self.attribute.as_bytes())
|
||||||
.map_err(UpEndError::from_any)?;
|
.map_err(UpEndError::from_any)?;
|
||||||
entity
|
entity
|
||||||
.write_all(self.value.to_string()?.as_bytes())
|
.write_all(self.value.to_string().as_bytes())
|
||||||
.map_err(UpEndError::from_any)?;
|
.map_err(UpEndError::from_any)?;
|
||||||
Ok(Address::Hash(
|
Ok(Address::Hash(
|
||||||
sha256hash(entity.into_inner()).map_err(UpEndError::from_any)?,
|
sha256hash(entity.into_inner()).map_err(UpEndError::from_any)?,
|
||||||
|
@ -92,12 +90,7 @@ impl AsMultihash for Entry {
|
||||||
.as_slice(),
|
.as_slice(),
|
||||||
)?;
|
)?;
|
||||||
result.write_all(self.attribute.as_bytes())?;
|
result.write_all(self.attribute.as_bytes())?;
|
||||||
result.write_all(
|
result.write_all(self.value.to_string().as_bytes())?;
|
||||||
self.value
|
|
||||||
.to_string()
|
|
||||||
.map_err(|e| AsMultihashError(e.to_string()))?
|
|
||||||
.as_bytes(),
|
|
||||||
)?;
|
|
||||||
sha256hash(result.get_ref())
|
sha256hash(result.get_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,27 +104,25 @@ impl AsMultihash for InvariantEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntryValue {
|
impl EntryValue {
|
||||||
pub fn to_string(&self) -> Result<String, UpEndError> {
|
pub fn to_string(&self) -> String {
|
||||||
let (type_char, content) = match self {
|
let (type_char, content) = match self {
|
||||||
EntryValue::String(value) => ('S', value.to_owned()),
|
|
||||||
EntryValue::Number(n) => ('N', n.to_string()),
|
|
||||||
EntryValue::Address(address) => ('O', address.to_string()),
|
EntryValue::Address(address) => ('O', address.to_string()),
|
||||||
|
EntryValue::Number(n) => ('N', n.to_string()),
|
||||||
EntryValue::Null => ('X', "".to_string()),
|
EntryValue::Null => ('X', "".to_string()),
|
||||||
EntryValue::Invalid => return Err(UpEndError::CannotSerializeInvalid),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(format!("{}{}", type_char, content))
|
format!("{}{}", type_char, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn guess_from<S: AsRef<str>>(string: S) -> Self {
|
pub fn guess_from<S: AsRef<str>>(string: S) -> Result<Self, UpEndError> {
|
||||||
let string = string.as_ref();
|
let string = string.as_ref();
|
||||||
match string.parse::<f64>() {
|
match string.parse::<f64>() {
|
||||||
Ok(num) => EntryValue::Number(num),
|
Ok(num) => Ok(EntryValue::Number(num)),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
if let Ok(url) = Url::parse(string) {
|
if let Ok(url) = Url::parse(string) {
|
||||||
EntryValue::Address(Address::Url(url))
|
Ok(EntryValue::Address(Address::Url(url)))
|
||||||
} else {
|
} else {
|
||||||
EntryValue::String(string.to_string())
|
Ok(EntryValue::Address(string.address()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,34 +130,32 @@ impl EntryValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::str::FromStr for EntryValue {
|
impl std::str::FromStr for EntryValue {
|
||||||
type Err = std::convert::Infallible;
|
type Err = UpEndError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
if s.len() < 2 {
|
if s.len() < 2 {
|
||||||
match s.chars().next() {
|
match s.chars().next() {
|
||||||
Some('S') => Ok(EntryValue::String("".into())),
|
|
||||||
Some('X') => Ok(EntryValue::Null),
|
Some('X') => Ok(EntryValue::Null),
|
||||||
_ => Ok(EntryValue::Invalid),
|
_ => Err(UpEndError::EntryValueInvalid(s.to_string())),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (type_char, content) = s.split_at(1);
|
let (type_char, content) = s.split_at(1);
|
||||||
match (type_char, content) {
|
match (type_char, content) {
|
||||||
("S", content) => Ok(EntryValue::String(String::from(content))),
|
|
||||||
("N", content) => {
|
("N", content) => {
|
||||||
if let Ok(n) = content.parse::<f64>() {
|
if let Ok(n) = content.parse::<f64>() {
|
||||||
Ok(EntryValue::Number(n))
|
Ok(EntryValue::Number(n))
|
||||||
} else {
|
} else {
|
||||||
Ok(EntryValue::Invalid)
|
Err(UpEndError::EntryValueInvalid(s.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("O", content) => {
|
("O", content) => {
|
||||||
if let Ok(addr) = b58_decode(content).and_then(|v| Address::decode(&v)) {
|
if let Ok(addr) = b58_decode(content).and_then(|v| Address::decode(&v)) {
|
||||||
Ok(EntryValue::Address(addr))
|
Ok(EntryValue::Address(addr))
|
||||||
} else {
|
} else {
|
||||||
Ok(EntryValue::Invalid)
|
Err(UpEndError::EntryValueInvalid(s.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Ok(EntryValue::Invalid),
|
_ => Err(UpEndError::EntryValueInvalid(s.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,27 +171,13 @@ impl std::fmt::Display for EntryValue {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let (entry_type, entry_value) = match self {
|
let (entry_type, entry_value) = match self {
|
||||||
EntryValue::Address(address) => ("ADDRESS", address.to_string()),
|
EntryValue::Address(address) => ("ADDRESS", address.to_string()),
|
||||||
EntryValue::String(string) => ("STRING", string.to_owned()),
|
|
||||||
EntryValue::Number(n) => ("NUMBER", n.to_string()),
|
EntryValue::Number(n) => ("NUMBER", n.to_string()),
|
||||||
EntryValue::Null => ("NULL", "NULL".to_string()),
|
EntryValue::Null => ("NULL", "NULL".to_string()),
|
||||||
EntryValue::Invalid => ("INVALID", "INVALID".to_string()),
|
|
||||||
};
|
};
|
||||||
write!(f, "{}: {}", entry_type, entry_value)
|
write!(f, "{}: {}", entry_type, entry_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for EntryValue {
|
|
||||||
fn from(str: &str) -> Self {
|
|
||||||
Self::String(str.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for EntryValue {
|
|
||||||
fn from(str: String) -> Self {
|
|
||||||
Self::String(str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<f64> for EntryValue {
|
impl From<f64> for EntryValue {
|
||||||
fn from(num: f64) -> Self {
|
fn from(num: f64) -> Self {
|
||||||
Self::Number(num)
|
Self::Number(num)
|
||||||
|
@ -221,28 +196,28 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_value_from_to_string() -> Result<(), UpEndError> {
|
fn test_value_from_to_string() -> Result<(), UpEndError> {
|
||||||
let entry = EntryValue::String("hello".to_string());
|
let entry = EntryValue::Address("hello".address().unwrap());
|
||||||
let encoded = entry.to_string()?;
|
let encoded = entry.to_string();
|
||||||
let decoded = encoded.parse::<EntryValue>().unwrap();
|
let decoded = encoded.parse::<EntryValue>().unwrap();
|
||||||
assert_eq!(entry, decoded);
|
assert_eq!(entry, decoded);
|
||||||
|
|
||||||
let entry = EntryValue::Number(1337.93);
|
let entry = EntryValue::Number(1337.93);
|
||||||
let encoded = entry.to_string()?;
|
let encoded = entry.to_string();
|
||||||
let decoded = encoded.parse::<EntryValue>().unwrap();
|
let decoded = encoded.parse::<EntryValue>().unwrap();
|
||||||
assert_eq!(entry, decoded);
|
assert_eq!(entry, decoded);
|
||||||
|
|
||||||
let entry = EntryValue::Address(Address::Url(Url::parse("https://upend.dev").unwrap()));
|
let entry = EntryValue::Address(Address::Url(Url::parse("https://upend.dev").unwrap()));
|
||||||
let encoded = entry.to_string()?;
|
let encoded = entry.to_string();
|
||||||
let decoded = encoded.parse::<EntryValue>().unwrap();
|
let decoded = encoded.parse::<EntryValue>().unwrap();
|
||||||
assert_eq!(entry, decoded);
|
assert_eq!(entry, decoded);
|
||||||
|
|
||||||
let entry = EntryValue::String("".to_string());
|
let entry = EntryValue::Address("".address().unwrap());
|
||||||
let encoded = entry.to_string()?;
|
let encoded = entry.to_string();
|
||||||
let decoded = encoded.parse::<EntryValue>().unwrap();
|
let decoded = encoded.parse::<EntryValue>().unwrap();
|
||||||
assert_eq!(entry, decoded);
|
assert_eq!(entry, decoded);
|
||||||
|
|
||||||
let entry = EntryValue::Null;
|
let entry = EntryValue::Null;
|
||||||
let encoded = entry.to_string()?;
|
let encoded = entry.to_string();
|
||||||
let decoded = encoded.parse::<EntryValue>().unwrap();
|
let decoded = encoded.parse::<EntryValue>().unwrap();
|
||||||
assert_eq!(entry, decoded);
|
assert_eq!(entry, decoded);
|
||||||
|
|
||||||
|
@ -251,7 +226,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_into() {
|
fn test_into() {
|
||||||
assert_eq!(EntryValue::String(String::from("UPEND")), "UPEND".into());
|
|
||||||
assert_eq!(EntryValue::Number(1337.93), 1337.93.into());
|
assert_eq!(EntryValue::Number(1337.93), 1337.93.into());
|
||||||
let addr = Address::Url(Url::parse("https://upend.dev").unwrap());
|
let addr = Address::Url(Url::parse("https://upend.dev").unwrap());
|
||||||
assert_eq!(EntryValue::Address(addr.clone()), addr.into());
|
assert_eq!(EntryValue::Address(addr.clone()), addr.into());
|
||||||
|
@ -260,15 +234,15 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_guess_value() {
|
fn test_guess_value() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EntryValue::guess_from("UPEND"),
|
EntryValue::guess_from("UPEND").unwrap(),
|
||||||
EntryValue::String("UPEND".into())
|
EntryValue::Address("UPEND".address().unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EntryValue::guess_from("1337.93"),
|
EntryValue::guess_from("1337.93").unwrap(),
|
||||||
EntryValue::Number(1337.93)
|
EntryValue::Number(1337.93)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EntryValue::guess_from("https://upend.dev"),
|
EntryValue::guess_from("https://upend.dev").unwrap(),
|
||||||
EntryValue::Address(Address::Url(Url::parse("https://upend.dev").unwrap()))
|
EntryValue::Address(Address::Url(Url::parse("https://upend.dev").unwrap()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
pub enum UpEndError {
|
pub enum UpEndError {
|
||||||
HashDecodeError(String),
|
HashDecodeError(String),
|
||||||
AddressParseError(String),
|
AddressParseError(String),
|
||||||
|
EntryValueInvalid(String),
|
||||||
AddressComponentsDecodeError(AddressComponentsDecodeError),
|
AddressComponentsDecodeError(AddressComponentsDecodeError),
|
||||||
CannotSerializeInvalid,
|
CannotSerializeInvalid,
|
||||||
QueryParseError(String),
|
QueryParseError(String),
|
||||||
|
@ -23,6 +24,7 @@ impl std::fmt::Display for UpEndError {
|
||||||
match self {
|
match self {
|
||||||
UpEndError::HashDecodeError(err) => format!("Could not decode hash: {err}"),
|
UpEndError::HashDecodeError(err) => format!("Could not decode hash: {err}"),
|
||||||
UpEndError::AddressParseError(err) => format!("Error parsing address: {err}"),
|
UpEndError::AddressParseError(err) => format!("Error parsing address: {err}"),
|
||||||
|
UpEndError::EntryValueInvalid(err) => format!("Invalid Entry value: {err}"),
|
||||||
UpEndError::AddressComponentsDecodeError(cde) => match cde {
|
UpEndError::AddressComponentsDecodeError(cde) => match cde {
|
||||||
AddressComponentsDecodeError::UnknownType(t) =>
|
AddressComponentsDecodeError::UnknownType(t) =>
|
||||||
format!("Unknown type: \"{t}\""),
|
format!("Unknown type: \"{t}\""),
|
||||||
|
@ -47,3 +49,9 @@ impl UpEndError {
|
||||||
UpEndError::Other(error.to_string())
|
UpEndError::Other(error.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<crate::hash::AsMultihashError> for UpEndError {
|
||||||
|
fn from(error: crate::hash::AsMultihashError) -> Self {
|
||||||
|
UpEndError::Other(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::addressing::Address;
|
use crate::addressing::{Address, Addressable};
|
||||||
use crate::entry::EntryValue;
|
use crate::entry::EntryValue;
|
||||||
use crate::error::UpEndError;
|
use crate::error::UpEndError;
|
||||||
use nonempty::NonEmpty;
|
use nonempty::NonEmpty;
|
||||||
|
@ -64,8 +64,28 @@ impl TryFrom<lexpr::Value> for EntryValue {
|
||||||
lexpr::Value::Number(num) => Ok(EntryValue::Number(num.as_f64().ok_or_else(|| {
|
lexpr::Value::Number(num) => Ok(EntryValue::Number(num.as_f64().ok_or_else(|| {
|
||||||
UpEndError::QueryParseError(format!("Error processing number ({num:?})."))
|
UpEndError::QueryParseError(format!("Error processing number ({num:?})."))
|
||||||
})?)),
|
})?)),
|
||||||
lexpr::Value::Char(chr) => Ok(EntryValue::String(chr.to_string())),
|
lexpr::Value::Char(chr) => Ok(EntryValue::Address(
|
||||||
lexpr::Value::String(str) => Ok(EntryValue::String(str.to_string())),
|
chr.to_string()
|
||||||
|
.address()
|
||||||
|
.map_err(|e| {
|
||||||
|
UpEndError::QueryParseError(format!(
|
||||||
|
"Error hashing character `{}`: {:}",
|
||||||
|
chr, e
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
|
lexpr::Value::String(str) => Ok(EntryValue::Address(
|
||||||
|
str.to_string()
|
||||||
|
.address()
|
||||||
|
.map_err(|e| {
|
||||||
|
UpEndError::QueryParseError(format!(
|
||||||
|
"Error hashing string `{}`: {:}",
|
||||||
|
str, e
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
lexpr::Value::Symbol(_) => Ok(EntryValue::Address(Address::try_from(value.clone())?)),
|
lexpr::Value::Symbol(_) => Ok(EntryValue::Address(Address::try_from(value.clone())?)),
|
||||||
_ => Err(UpEndError::QueryParseError(
|
_ => Err(UpEndError::QueryParseError(
|
||||||
"Value can only be a string, number or address.".into(),
|
"Value can only be a string, number or address.".into(),
|
||||||
|
@ -298,7 +318,7 @@ impl FromStr for Query {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::error::UpEndError;
|
use crate::{addressing::Addressable, error::UpEndError};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -377,7 +397,10 @@ mod test {
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
let values: Vec<EntryValue> = vec!["FOO".into(), "BAR".into()];
|
let values: Vec<EntryValue> = vec![
|
||||||
|
"FOO".address().unwrap().into(),
|
||||||
|
"BAR".address().unwrap().into(),
|
||||||
|
];
|
||||||
let query = r#"(matches ? ? (in "FOO" "BAR"))"#.parse::<Query>()?;
|
let query = r#"(matches ? ? (in "FOO" "BAR"))"#.parse::<Query>()?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
query,
|
query,
|
||||||
|
@ -400,7 +423,8 @@ mod test {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Invalid queries
|
// Invalid queries
|
||||||
let values: Vec<EntryValue> = vec!["FOO".into(), EntryValue::Number(1337.93)];
|
let values: Vec<EntryValue> =
|
||||||
|
vec!["FOO".address().unwrap().into(), EntryValue::Number(1337.93)];
|
||||||
let query = r#"(matches ? ? (in "FOO" 1337.93))"#.parse::<Query>()?;
|
let query = r#"(matches ? ? (in "FOO" 1337.93))"#.parse::<Query>()?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -412,7 +436,7 @@ mod test {
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
let values = vec![EntryValue::Number(1337.93), "FOO".into()];
|
let values = vec![EntryValue::Number(1337.93), "FOO".address().unwrap().into()];
|
||||||
let query = r#"(matches ? ? (in 1337.93 "FOO"))"#.parse::<Query>()?;
|
let query = r#"(matches ? ? (in 1337.93 "FOO"))"#.parse::<Query>()?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -698,7 +698,7 @@ pub async fn get_all_attributes(state: web::Data<State>) -> Result<HttpResponse,
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|e| {
|
.filter_map(|e| {
|
||||||
if e.attribute == ATTR_LABEL {
|
if e.attribute == ATTR_LABEL {
|
||||||
if let EntryValue::String(label) = e.value {
|
if let EntryValue::String(label) = e.value { // TODO
|
||||||
Some(label)
|
Some(label)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -197,11 +197,7 @@ fn to_sqlite_predicates(query: Query) -> Result<SqlResult, QueryExecutionError>
|
||||||
match &eq.value {
|
match &eq.value {
|
||||||
QueryComponent::Exact(q_value) => match q_value {
|
QueryComponent::Exact(q_value) => match q_value {
|
||||||
EntryValue::Number(n) => subqueries.push(Box::new(data::value_num.eq(*n))),
|
EntryValue::Number(n) => subqueries.push(Box::new(data::value_num.eq(*n))),
|
||||||
_ => subqueries.push(Box::new(data::value_str.eq(
|
_ => subqueries.push(Box::new(data::value_str.eq(q_value.to_string()))),
|
||||||
q_value.to_string().map_err(|e| {
|
|
||||||
QueryExecutionError(format!("failed producing sql: {e}"))
|
|
||||||
})?,
|
|
||||||
))),
|
|
||||||
},
|
},
|
||||||
QueryComponent::In(q_values) => {
|
QueryComponent::In(q_values) => {
|
||||||
let first = q_values.first().ok_or_else(|| {
|
let first = q_values.first().ok_or_else(|| {
|
||||||
|
@ -239,11 +235,7 @@ fn to_sqlite_predicates(query: Query) -> Result<SqlResult, QueryExecutionError>
|
||||||
string values! (Found {v})"
|
string values! (Found {v})"
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
v.to_string().map_err(|e| {
|
Ok(v.to_string())
|
||||||
QueryExecutionError(format!(
|
|
||||||
"failed producing sql: {e}"
|
|
||||||
))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<String>, QueryExecutionError>>()?,
|
.collect::<Result<Vec<String>, QueryExecutionError>>()?,
|
||||||
|
|
|
@ -48,7 +48,7 @@ impl TryFrom<&Entry> for models::Entry {
|
||||||
entity_searchable: match &e.entity {
|
entity_searchable: match &e.entity {
|
||||||
Address::Attribute(attr) => Some(attr.clone()),
|
Address::Attribute(attr) => Some(attr.clone()),
|
||||||
Address::Url(url) => Some(url.to_string()),
|
Address::Url(url) => Some(url.to_string()),
|
||||||
_ => None,
|
_ => None, // TODO
|
||||||
},
|
},
|
||||||
entity: e.entity.encode()?,
|
entity: e.entity.encode()?,
|
||||||
attribute: e.attribute.clone(),
|
attribute: e.attribute.clone(),
|
||||||
|
@ -66,7 +66,7 @@ impl TryFrom<&Entry> for models::Entry {
|
||||||
..base_entry
|
..base_entry
|
||||||
}),
|
}),
|
||||||
_ => Ok(models::Entry {
|
_ => Ok(models::Entry {
|
||||||
value_str: Some(e.value.to_string()?),
|
value_str: Some(e.value.to_string()),
|
||||||
value_num: None,
|
value_num: None,
|
||||||
..base_entry
|
..base_entry
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -6,7 +6,7 @@ use lru::LruCache;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use upend_base::addressing::Address;
|
use upend_base::addressing::{Address, Addressable};
|
||||||
use upend_base::constants::ATTR_LABEL;
|
use upend_base::constants::ATTR_LABEL;
|
||||||
use upend_base::constants::{ATTR_IN, HIER_ROOT_ADDR, HIER_ROOT_INVARIANT};
|
use upend_base::constants::{ATTR_IN, HIER_ROOT_ADDR, HIER_ROOT_INVARIANT};
|
||||||
use upend_base::entry::Entry;
|
use upend_base::entry::Entry;
|
||||||
|
@ -112,7 +112,7 @@ pub fn fetch_or_create_dir(
|
||||||
.query(Query::SingleQuery(QueryPart::Matches(PatternQuery {
|
.query(Query::SingleQuery(QueryPart::Matches(PatternQuery {
|
||||||
entity: QueryComponent::Variable(None),
|
entity: QueryComponent::Variable(None),
|
||||||
attribute: QueryComponent::Exact(ATTR_LABEL.into()),
|
attribute: QueryComponent::Exact(ATTR_LABEL.into()),
|
||||||
value: QueryComponent::Exact(String::from(directory.clone()).into()),
|
value: QueryComponent::Exact(String::from(directory.clone()).address()?.into()),
|
||||||
})))?
|
})))?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|e: Entry| e.entity);
|
.map(|e: Entry| e.entity);
|
||||||
|
@ -142,7 +142,7 @@ pub fn fetch_or_create_dir(
|
||||||
let directory_entry = Entry {
|
let directory_entry = Entry {
|
||||||
entity: new_directory_address.clone(),
|
entity: new_directory_address.clone(),
|
||||||
attribute: String::from(ATTR_LABEL),
|
attribute: String::from(ATTR_LABEL),
|
||||||
value: String::from(directory).into(),
|
value: String::from(directory).address()?.into(),
|
||||||
provenance: "SYSTEM FS".to_string(),
|
provenance: "SYSTEM FS".to_string(),
|
||||||
timestamp: chrono::Utc::now().naive_utc(),
|
timestamp: chrono::Utc::now().naive_utc(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -247,7 +247,7 @@ impl UpEndConnection {
|
||||||
|
|
||||||
let primary = data
|
let primary = data
|
||||||
.filter(entity.eq(object_address.encode()?))
|
.filter(entity.eq(object_address.encode()?))
|
||||||
.or_filter(value_str.eq(EntryValue::Address(object_address.clone()).to_string()?))
|
.or_filter(value_str.eq(EntryValue::Address(object_address.clone()).to_string()))
|
||||||
.load::<models::Entry>(&conn)?;
|
.load::<models::Entry>(&conn)?;
|
||||||
|
|
||||||
let entries = primary
|
let entries = primary
|
||||||
|
@ -287,7 +287,7 @@ impl UpEndConnection {
|
||||||
let matches = data
|
let matches = data
|
||||||
.filter(identity.eq(object_address.encode()?))
|
.filter(identity.eq(object_address.encode()?))
|
||||||
.or_filter(entity.eq(object_address.encode()?))
|
.or_filter(entity.eq(object_address.encode()?))
|
||||||
.or_filter(value_str.eq(EntryValue::Address(object_address).to_string()?));
|
.or_filter(value_str.eq(EntryValue::Address(object_address).to_string()));
|
||||||
|
|
||||||
Ok(diesel::delete(matches).execute(&conn)?)
|
Ok(diesel::delete(matches).execute(&conn)?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ macro_rules! upend_insert_val {
|
||||||
$db_connection.insert_entry(Entry {
|
$db_connection.insert_entry(Entry {
|
||||||
entity: $entity.clone(),
|
entity: $entity.clone(),
|
||||||
attribute: String::from($attribute),
|
attribute: String::from($attribute),
|
||||||
value: upend_base::entry::EntryValue::String(String::from($value)),
|
value: upend_base::entry::EntryValue::Address(String::from($value).address().unwrap()),
|
||||||
provenance: "SYSTEM INIT".to_string(),
|
provenance: "SYSTEM INIT".to_string(),
|
||||||
timestamp: chrono::Utc::now().naive_utc(),
|
timestamp: chrono::Utc::now().naive_utc(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -21,7 +21,7 @@ use std::sync::{Arc, Mutex, RwLock};
|
||||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||||
use std::{fs, iter};
|
use std::{fs, iter};
|
||||||
use tracing::{error, info, trace, warn};
|
use tracing::{error, info, trace, warn};
|
||||||
use upend_base::addressing::Address;
|
use upend_base::addressing::{Address, Addressable};
|
||||||
use upend_base::constants::{ATTR_ADDED, ATTR_BY, ATTR_IN, ATTR_LABEL, ATTR_OF, TYPE_HASH_ADDRESS};
|
use upend_base::constants::{ATTR_ADDED, ATTR_BY, ATTR_IN, ATTR_LABEL, ATTR_OF, TYPE_HASH_ADDRESS};
|
||||||
use upend_base::entry::Entry;
|
use upend_base::entry::Entry;
|
||||||
use upend_base::hash::{b58_encode, UpMultihash};
|
use upend_base::hash::{b58_encode, UpMultihash};
|
||||||
|
@ -410,12 +410,16 @@ impl FsStore {
|
||||||
timestamp: chrono::Utc::now().naive_utc(),
|
timestamp: chrono::Utc::now().naive_utc(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mime_entry = mime_type.map(|mime_type| Entry {
|
let mime_entry = mime_type.and_then(|mime_type| {
|
||||||
entity: blob_address.clone(),
|
mime_type.address().ok().and_then(|mime_type_address| {
|
||||||
attribute: FILE_MIME_KEY.to_string(),
|
Some(Entry {
|
||||||
value: mime_type.into(),
|
entity: blob_address.clone(),
|
||||||
provenance: "SYSTEM INIT".to_string(),
|
attribute: FILE_MIME_KEY.to_string(),
|
||||||
timestamp: chrono::Utc::now().naive_utc(),
|
value: mime_type_address.into(),
|
||||||
|
provenance: "SYSTEM INIT".to_string(),
|
||||||
|
timestamp: chrono::Utc::now().naive_utc(),
|
||||||
|
})
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let added_entry = Entry {
|
let added_entry = Entry {
|
||||||
|
@ -472,6 +476,7 @@ impl FsStore {
|
||||||
attribute: ATTR_LABEL.to_string(),
|
attribute: ATTR_LABEL.to_string(),
|
||||||
value: name
|
value: name
|
||||||
.unwrap_or_else(|| filename.as_os_str().to_string_lossy().to_string())
|
.unwrap_or_else(|| filename.as_os_str().to_string_lossy().to_string())
|
||||||
|
.address()?
|
||||||
.into(),
|
.into(),
|
||||||
provenance: "SYSTEM INIT".to_string(),
|
provenance: "SYSTEM INIT".to_string(),
|
||||||
timestamp: chrono::Utc::now().naive_utc(),
|
timestamp: chrono::Utc::now().naive_utc(),
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "upend_text"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/lib.rs"
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pulldown-cmark = "0.9.3"
|
||||||
|
serde = "1.0.188"
|
||||||
|
wasm-bindgen = "0.2.87"
|
||||||
|
wee_alloc = "0.4.5"
|
|
@ -0,0 +1,45 @@
|
||||||
|
use pulldown_cmark::{Options, Parser};
|
||||||
|
|
||||||
|
pub struct Annotation {
|
||||||
|
pub id: String,
|
||||||
|
pub body: String,
|
||||||
|
pub target: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MarkdownResult {
|
||||||
|
pub text: String,
|
||||||
|
pub annotations: Vec<Annotation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UpEndTextError(pub String);
|
||||||
|
|
||||||
|
impl std::fmt::Display for UpEndTextError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:#?}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn markdown_to_annotations(markdown: &str) -> Result<MarkdownResult, UpEndTextError> {
|
||||||
|
let mut options = Options::empty();
|
||||||
|
options.insert(Options::ENABLE_STRIKETHROUGH);
|
||||||
|
let parser = Parser::new_ext(markdown, options);
|
||||||
|
|
||||||
|
for ev in parser {
|
||||||
|
println!("{:?}", ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let markdown_input = "Hello world, this is a ~~complicated~~ *very simple* example.";
|
||||||
|
let result = markdown_to_annotations(markdown_input);
|
||||||
|
result.unwrap();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue