diff --git a/contracts/axone-cognitarium/src/contract.rs b/contracts/axone-cognitarium/src/contract.rs index fdb1a43a..4b1c2902 100644 --- a/contracts/axone-cognitarium/src/contract.rs +++ b/contracts/axone-cognitarium/src/contract.rs @@ -121,13 +121,8 @@ pub mod execute { None => QueryPlan::empty_plan(), }; - let query_engine = QueryEngine::new(deps.storage); - let delete_templates = query_engine.make_triple_templates( - &plan, - &prefix_map, - delete, - plan_builder.cached_namespaces(), - )?; + let query_engine = QueryEngine::new(deps.storage, plan_builder.cached_namespaces()); + let delete_templates = query_engine.make_triple_templates(&plan, &prefix_map, delete)?; let triples = if r#where.is_none() { let empty_vars = ResolvedVariables::with_capacity(0); @@ -205,7 +200,7 @@ pub mod query { PlanBuilder::new(deps.storage, &prefix_map, None).with_limit(count as usize); let plan = plan_builder.build_plan(&query.r#where)?; - QueryEngine::new(deps.storage) + QueryEngine::new(deps.storage, plan_builder.cached_namespaces()) .select(plan, query.select) .and_then(|res| util::map_select_solutions(deps, res, plan_builder.cached_namespaces())) } @@ -356,7 +351,7 @@ pub mod util { res: SelectResults<'_>, ns_cache: Vec, ) -> StdResult { - let mut ns_resolver: NamespaceResolver = ns_cache.into(); + let mut ns_solver = NamespaceResolver::new(deps.storage, ns_cache); let mut id_issuer = IdentifierIssuer::new("b", 0u128); let mut bindings: Vec> = vec![]; @@ -365,17 +360,7 @@ pub mod util { let resolved = vars .into_iter() .map(|(name, var)| -> StdResult<(String, Value)> { - Ok(( - name, - var.as_value( - &mut |ns_key| { - let res = ns_resolver.resolve_from_key(deps.storage, ns_key); - res.and_then(NamespaceResolver::none_as_error_middleware) - .map(|ns| ns.value) - }, - &mut id_issuer, - )?, - )) + Ok((name, var.as_value(&mut ns_solver, &mut id_issuer)?)) }) .collect::>>()?; bindings.push(resolved); @@ -401,13 +386,8 @@ pub mod util { .with_limit(store.limits.max_query_limit as usize); let plan = plan_builder.build_plan(&r#where)?; - let atoms = QueryEngine::new(storage) - .construct_atoms( - plan, - &prefix_map, - construct, - plan_builder.cached_namespaces(), - )? + let atoms = QueryEngine::new(storage, plan_builder.cached_namespaces()) + .construct_atoms(plan, &prefix_map, construct)? .collect::>>()?; let out: Vec = Vec::default(); diff --git a/contracts/axone-cognitarium/src/querier/engine.rs b/contracts/axone-cognitarium/src/querier/engine.rs index fd98d45a..6b95d18f 100644 --- a/contracts/axone-cognitarium/src/querier/engine.rs +++ b/contracts/axone-cognitarium/src/querier/engine.rs @@ -5,7 +5,9 @@ use crate::querier::mapper::{iri_as_node, literal_as_object}; use crate::querier::plan::{PatternValue, QueryNode, QueryPlan}; use crate::querier::variable::{ResolvedVariable, ResolvedVariables}; use crate::rdf::Atom; -use crate::state::{triples, Namespace, NamespaceResolver, Object, Predicate, Subject, Triple}; +use crate::state::{ + triples, Namespace, NamespaceResolver, NamespaceSolver, Object, Predicate, Subject, Triple, +}; use crate::{rdf, state}; use axone_rdf::normalize::IdentifierIssuer; use cosmwasm_std::{Order, StdError, StdResult, Storage}; @@ -16,6 +18,7 @@ use std::rc::Rc; pub struct QueryEngine<'a> { storage: &'a dyn Storage, + ns_cache: Vec, } pub struct SelectResults<'a> { @@ -24,8 +27,8 @@ pub struct SelectResults<'a> { } impl<'a> QueryEngine<'a> { - pub fn new(storage: &'a dyn Storage) -> Self { - Self { storage } + pub fn new(storage: &'a dyn Storage, ns_cache: Vec) -> Self { + Self { storage, ns_cache } } pub fn select( @@ -59,7 +62,6 @@ impl<'a> QueryEngine<'a> { plan: QueryPlan, prefixes: &HashMap, templates: Vec<(VarOrNode, VarOrNamedNode, VarOrNodeOrLiteral)>, - ns_cache: Vec, ) -> StdResult> { let templates = templates .into_iter() @@ -68,7 +70,7 @@ impl<'a> QueryEngine<'a> { Ok(ResolvedAtomIterator::new( self.storage, - ns_cache.into(), + self.ns_cache.clone().into(), IdentifierIssuer::new("b", 0u128), self.eval_plan(plan), templates, @@ -88,28 +90,17 @@ impl<'a> QueryEngine<'a> { plan: &QueryPlan, prefixes: &HashMap, templates: Either, Vec>, - ns_cache: Vec, ) -> StdResult> { - let mut ns_resolver: NamespaceResolver = ns_cache.into(); + let mut ns_resolver = NamespaceResolver::new(self.storage, self.ns_cache.clone()); match templates { Left(tpl) => tpl .into_iter() - .map(|t| { - TripleTemplate::try_new(self.storage, &mut ns_resolver, plan, prefixes, Left(t)) - }) + .map(|t| TripleTemplate::try_new(&mut ns_resolver, plan, prefixes, Left(t))) .collect::>>(), Right(tpl) => tpl .into_iter() - .map(|t| { - TripleTemplate::try_new( - self.storage, - &mut ns_resolver, - plan, - prefixes, - Right(t), - ) - }) + .map(|t| TripleTemplate::try_new(&mut ns_resolver, plan, prefixes, Right(t))) .collect::>>(), } } @@ -182,6 +173,26 @@ impl<'a> QueryEngine<'a> { type ResolvedVariablesIterator<'a> = Box> + 'a>; +impl<'a> Iterator for FilterIterator<'a> { + type Item = StdResult; + + fn next(&mut self) -> Option { + match self.upstream.next()? { + Ok(vars) => match self.expr.evaluate(&vars, &mut self.ns_resolver) { + Ok(t) => { + if t.as_bool() { + Some(Ok(vars)) + } else { + None + } + } + Err(e) => Some(Err(e)), + }, + Err(e) => Some(Err(e)), + } + } +} + struct ForLoopJoinIterator<'a> { left: ResolvedVariablesIterator<'a>, right: Rc ResolvedVariablesIterator<'a> + 'a>, @@ -592,8 +603,7 @@ pub type TripleTemplateNoBlankNode = (VarOrNamedNode, VarOrNamedNode, VarOrNamed impl TripleTemplate { fn try_new( - storage: &dyn Storage, - ns_resolver: &mut NamespaceResolver, + ns_solver: &mut dyn NamespaceSolver, plan: &QueryPlan, prefixes: &HashMap, template: Either, @@ -604,9 +614,9 @@ impl TripleTemplate { }; Ok(TripleTemplate { - subject: Self::build_subject_template(storage, ns_resolver, plan, prefixes, s_tpl)?, - predicate: Self::build_predicate_template(storage, ns_resolver, plan, prefixes, p_tpl)?, - object: Self::build_object_template(storage, ns_resolver, plan, prefixes, o_tpl)?, + subject: Self::build_subject_template(ns_solver, plan, prefixes, s_tpl)?, + predicate: Self::build_predicate_template(ns_solver, plan, prefixes, p_tpl)?, + object: Self::build_object_template(ns_solver, plan, prefixes, o_tpl)?, }) } @@ -667,8 +677,7 @@ impl TripleTemplate { } fn build_subject_template( - storage: &dyn Storage, - ns_resolver: &mut NamespaceResolver, + ns_solver: &mut dyn NamespaceSolver, plan: &QueryPlan, prefixes: &HashMap, value: Either, @@ -686,19 +695,13 @@ impl TripleTemplate { ))?, ), Left(VarOrNode::Node(Node::NamedNode(iri))) | Right(VarOrNamedNode::NamedNode(iri)) => { - Left(Subject::Named(iri_as_node( - ns_resolver, - storage, - prefixes, - iri, - )?)) + Left(Subject::Named(iri_as_node(ns_solver, prefixes, iri)?)) } }) } fn build_predicate_template( - storage: &dyn Storage, - ns_resolver: &mut NamespaceResolver, + ns_solver: &mut dyn NamespaceSolver, plan: &QueryPlan, prefixes: &HashMap, value: VarOrNamedNode, @@ -707,15 +710,12 @@ impl TripleTemplate { VarOrNamedNode::Variable(v) => Right(plan.get_var_index(v.as_str()).ok_or( StdError::generic_err("Selected variable not found in query"), )?), - VarOrNamedNode::NamedNode(iri) => { - Left(iri_as_node(ns_resolver, storage, prefixes, iri)?) - } + VarOrNamedNode::NamedNode(iri) => Left(iri_as_node(ns_solver, prefixes, iri)?), }) } fn build_object_template( - storage: &dyn Storage, - ns_resolver: &mut NamespaceResolver, + ns_solver: &mut dyn NamespaceSolver, plan: &QueryPlan, prefixes: &HashMap, value: Either, @@ -733,22 +733,18 @@ impl TripleTemplate { ))?, ), Left(VarOrNodeOrLiteral::Node(Node::NamedNode(iri))) - | Right(VarOrNamedNodeOrLiteral::NamedNode(iri)) => Left(Object::Named(iri_as_node( - ns_resolver, - storage, - prefixes, - iri, - )?)), + | Right(VarOrNamedNodeOrLiteral::NamedNode(iri)) => { + Left(Object::Named(iri_as_node(ns_solver, prefixes, iri)?)) + } Left(VarOrNodeOrLiteral::Literal(l)) | Right(VarOrNamedNodeOrLiteral::Literal(l)) => { - Left(literal_as_object(ns_resolver, storage, prefixes, l)?) + Left(literal_as_object(ns_solver, prefixes, l)?) } }) } } pub struct ResolvedAtomIterator<'a> { - storage: &'a dyn Storage, - ns_resolver: NamespaceResolver, + ns_resolver: NamespaceResolver<'a>, id_issuer: IdentifierIssuer, upstream_iter: ResolvedVariablesIterator<'a>, templates: Vec, @@ -758,14 +754,13 @@ pub struct ResolvedAtomIterator<'a> { impl<'a> ResolvedAtomIterator<'a> { pub fn new( storage: &'a dyn Storage, - ns_resolver: NamespaceResolver, + ns_cache: Vec, id_issuer: IdentifierIssuer, upstream_iter: ResolvedVariablesIterator<'a>, templates: Vec, ) -> Self { Self { - storage, - ns_resolver, + ns_resolver: NamespaceResolver::new(storage, ns_cache.into()), id_issuer, upstream_iter, templates, @@ -794,12 +789,7 @@ impl<'a> Iterator for ResolvedAtomIterator<'a> { } Ok(vars) => { for res in self.templates.iter().map(|template| { - template.resolve( - self.storage, - &mut self.ns_resolver, - &mut self.id_issuer, - &vars, - ) + template.resolve(&mut self.ns_resolver, &mut self.id_issuer, &vars) }) { match res { Ok(Some(atom)) => self.buffer.push_back(Ok(atom)), @@ -853,28 +843,21 @@ impl AtomTemplate { pub fn resolve( &self, - storage: &dyn Storage, - ns_resolver: &mut NamespaceResolver, + ns_solver: &mut dyn NamespaceSolver, id_issuer: &mut IdentifierIssuer, vars: &ResolvedVariables, ) -> StdResult> { - let resolve_ns_fn = &mut |ns_key| { - let res = ns_resolver.resolve_from_key(storage, ns_key); - res.and_then(NamespaceResolver::none_as_error_middleware) - .map(|ns| ns.value) - }; - - let subject = match self.resolve_atom_subject(resolve_ns_fn, id_issuer, vars)? { + let subject = match self.resolve_atom_subject(ns_solver, id_issuer, vars)? { Some(s) => s, None => return Ok(None), }; - let property = match self.resolve_atom_property(resolve_ns_fn, vars)? { + let property = match self.resolve_atom_property(ns_solver, vars)? { Some(p) => p, None => return Ok(None), }; - let value = match self.resolve_atom_value(resolve_ns_fn, id_issuer, vars)? { + let value = match self.resolve_atom_value(ns_solver, id_issuer, vars)? { Some(v) => v, None => return Ok(None), }; @@ -886,22 +869,19 @@ impl AtomTemplate { })) } - fn resolve_atom_subject( + fn resolve_atom_subject( &self, - resolve_ns_fn: &mut F, + ns_solver: &mut dyn NamespaceSolver, id_issuer: &mut IdentifierIssuer, vars: &ResolvedVariables, - ) -> StdResult> - where - F: FnMut(u128) -> StdResult, - { + ) -> StdResult> { Self::resolve_atom_term( &self.subject, ResolvedVariable::as_subject, vars, &mut |value| { Ok(match value { - Subject::Named(n) => rdf::Subject::NamedNode(n.as_iri(resolve_ns_fn)?), + Subject::Named(n) => rdf::Subject::NamedNode(n.as_iri(ns_solver)?), Subject::Blank(n) => rdf::Subject::BlankNode( id_issuer.get_str_or_issue(n.to_string()).to_string(), ), @@ -911,39 +891,33 @@ impl AtomTemplate { ) } - fn resolve_atom_property( + fn resolve_atom_property( &self, - resolve_ns_fn: &mut F, + ns_solver: &mut dyn NamespaceSolver, vars: &ResolvedVariables, - ) -> StdResult> - where - F: FnMut(u128) -> StdResult, - { + ) -> StdResult> { Self::resolve_atom_term( &self.property, ResolvedVariable::as_predicate, vars, - &mut |value| value.as_iri(resolve_ns_fn).map(rdf::Property), + &mut |value| value.as_iri(ns_solver).map(rdf::Property), "predicate", ) } - fn resolve_atom_value( + fn resolve_atom_value( &self, - resolve_ns_fn: &mut F, + ns_solver: &mut dyn NamespaceSolver, id_issuer: &mut IdentifierIssuer, vars: &ResolvedVariables, - ) -> StdResult> - where - F: FnMut(u128) -> StdResult, - { + ) -> StdResult> { Self::resolve_atom_term( &self.value, ResolvedVariable::as_object, vars, &mut |value| { Ok(match value { - Object::Named(n) => rdf::Value::NamedNode(n.as_iri(resolve_ns_fn)?), + Object::Named(n) => rdf::Value::NamedNode(n.as_iri(ns_solver)?), Object::Blank(n) => { rdf::Value::BlankNode(id_issuer.get_str_or_issue(n.to_string()).to_string()) } @@ -953,7 +927,7 @@ impl AtomTemplate { rdf::Value::LiteralLang(value, language) } state::Literal::Typed { value, datatype } => { - rdf::Value::LiteralDatatype(value, datatype.as_iri(resolve_ns_fn)?) + rdf::Value::LiteralDatatype(value, datatype.as_iri(ns_solver)?) } }, }) @@ -1226,7 +1200,7 @@ mod test { ]; for case in cases { - let engine = QueryEngine::new(&deps.storage); + let engine = QueryEngine::new(&deps.storage, vec![]); assert_eq!( engine.select(case.plan, case.selection).and_then(|res| Ok(( res.head.clone(), @@ -1369,7 +1343,7 @@ mod test { }, ]; - let engine = QueryEngine::new(&deps.storage); + let engine = QueryEngine::new(&deps.storage, vec![]); for case in cases { assert_eq!(engine.eval_plan(case.plan).count(), case.expects); } diff --git a/contracts/axone-cognitarium/src/querier/mapper.rs b/contracts/axone-cognitarium/src/querier/mapper.rs index ac353dbc..2a05f859 100644 --- a/contracts/axone-cognitarium/src/querier/mapper.rs +++ b/contracts/axone-cognitarium/src/querier/mapper.rs @@ -1,13 +1,12 @@ use crate::msg::{Literal, IRI}; use crate::state; -use crate::state::{NamespaceResolver, Object}; +use crate::state::{NamespaceSolver, Object}; use axone_rdf::uri::{expand_uri, explode_iri}; -use cosmwasm_std::{StdResult, Storage}; +use cosmwasm_std::StdResult; use std::collections::HashMap; pub fn literal_as_object( - ns_resolver: &mut NamespaceResolver, - storage: &dyn Storage, + ns_solver: &mut dyn NamespaceSolver, prefixes: &HashMap, literal: Literal, ) -> StdResult { @@ -18,14 +17,13 @@ pub fn literal_as_object( } Literal::TypedValue { value, datatype } => state::Literal::Typed { value, - datatype: iri_as_node(ns_resolver, storage, prefixes, datatype)?, + datatype: iri_as_node(ns_solver, prefixes, datatype)?, }, })) } pub fn iri_as_node( - ns_resolver: &mut NamespaceResolver, - storage: &dyn Storage, + ns_solver: &mut dyn NamespaceSolver, prefixes: &HashMap, iri: IRI, ) -> StdResult { @@ -35,12 +33,16 @@ pub fn iri_as_node( } .and_then(|iri| explode_iri(&iri)) .and_then(|(ns_key, v)| { - ns_resolver - .resolve_from_val(storage, ns_key) - .and_then(NamespaceResolver::none_as_error_middleware) - .map(|ns| state::Node { - namespace: ns.key, - value: v, - }) + ns_solver.resolve_from_val(ns_key).map(|ns| state::Node { + namespace: ns.key, + value: v, + }) }) } + +pub fn iri_as_string(iri: IRI, prefixes: &HashMap) -> StdResult { + match iri { + IRI::Prefixed(prefixed) => expand_uri(&prefixed, prefixes), + IRI::Full(full) => Ok(full), + } +} diff --git a/contracts/axone-cognitarium/src/querier/plan_builder.rs b/contracts/axone-cognitarium/src/querier/plan_builder.rs index 970508b1..fae1bfb9 100644 --- a/contracts/axone-cognitarium/src/querier/plan_builder.rs +++ b/contracts/axone-cognitarium/src/querier/plan_builder.rs @@ -1,13 +1,14 @@ use crate::msg::{Node, TriplePattern, VarOrNamedNode, VarOrNode, VarOrNodeOrLiteral, WhereClause}; use crate::querier::mapper::{iri_as_node, literal_as_object}; use crate::querier::plan::{PatternValue, PlanVariable, QueryNode, QueryPlan}; -use crate::state::{HasCachedNamespaces, Namespace, NamespaceResolver, Object, Predicate, Subject}; -use cosmwasm_std::{StdError, StdResult, Storage}; +use crate::state::{ + HasCachedNamespaces, Namespace, NamespaceQuerier, NamespaceResolver, Object, Predicate, Subject, +}; +use cosmwasm_std::{StdResult, Storage}; use std::collections::HashMap; pub struct PlanBuilder<'a> { - storage: &'a dyn Storage, - ns_resolver: NamespaceResolver, + ns_resolver: NamespaceResolver<'a>, prefixes: &'a HashMap, variables: Vec, limit: Option, @@ -21,8 +22,7 @@ impl<'a> PlanBuilder<'a> { ns_cache: Option>, ) -> Self { Self { - storage, - ns_resolver: ns_cache.map_or_else(NamespaceResolver::new, Into::into), + ns_resolver: NamespaceResolver::new(storage, ns_cache.unwrap_or(vec![]).into()), prefixes, variables: Vec::new(), skip: None, @@ -133,7 +133,7 @@ impl<'a> PlanBuilder<'a> { value.lookup_bound_variable(&mut |v| bound_variables.push(v)); Some(value) } - Err(err) if NamespaceResolver::is_ns_not_found_error(&err) => None, + Err(err) if NamespaceQuerier::is_ns_not_found_error(&err) => None, _ => Some(pattern_res?), }) } @@ -145,7 +145,7 @@ impl<'a> PlanBuilder<'a> { PatternValue::BlankVariable(self.resolve_blank_variable(b)) } VarOrNode::Node(Node::NamedNode(iri)) => PatternValue::Constant(Subject::Named( - iri_as_node(&mut self.ns_resolver, self.storage, self.prefixes, iri)?, + iri_as_node(&mut self.ns_resolver, self.prefixes, iri)?, )), }) } @@ -156,12 +156,9 @@ impl<'a> PlanBuilder<'a> { ) -> StdResult> { Ok(match value { VarOrNamedNode::Variable(v) => PatternValue::Variable(self.resolve_basic_variable(v)), - VarOrNamedNode::NamedNode(iri) => PatternValue::Constant(iri_as_node( - &mut self.ns_resolver, - self.storage, - self.prefixes, - iri, - )?), + VarOrNamedNode::NamedNode(iri) => { + PatternValue::Constant(iri_as_node(&mut self.ns_resolver, self.prefixes, iri)?) + } }) } @@ -176,20 +173,12 @@ impl<'a> PlanBuilder<'a> { VarOrNodeOrLiteral::Node(Node::BlankNode(b)) => { PatternValue::BlankVariable(self.resolve_blank_variable(b)) } - VarOrNodeOrLiteral::Node(Node::NamedNode(iri)) => { - PatternValue::Constant(Object::Named(iri_as_node( - &mut self.ns_resolver, - self.storage, - self.prefixes, - iri, - )?)) + VarOrNodeOrLiteral::Node(Node::NamedNode(iri)) => PatternValue::Constant( + Object::Named(iri_as_node(&mut self.ns_resolver, self.prefixes, iri)?), + ), + VarOrNodeOrLiteral::Literal(l) => { + PatternValue::Constant(literal_as_object(&mut self.ns_resolver, self.prefixes, l)?) } - VarOrNodeOrLiteral::Literal(l) => PatternValue::Constant(literal_as_object( - &mut self.ns_resolver, - self.storage, - self.prefixes, - l, - )?), }) } diff --git a/contracts/axone-cognitarium/src/querier/variable.rs b/contracts/axone-cognitarium/src/querier/variable.rs index af90d28c..d3458d91 100644 --- a/contracts/axone-cognitarium/src/querier/variable.rs +++ b/contracts/axone-cognitarium/src/querier/variable.rs @@ -1,5 +1,5 @@ use crate::msg::{Value, IRI}; -use crate::state::{Literal, Object, Predicate, Subject}; +use crate::state::{Literal, NamespaceSolver, Object, Predicate, Subject}; use axone_rdf::normalize::IdentifierIssuer; use cosmwasm_std::StdResult; @@ -49,10 +49,11 @@ impl ResolvedVariable { }) } - pub fn as_value(&self, ns_fn: &mut F, id_issuer: &mut IdentifierIssuer) -> StdResult - where - F: FnMut(u128) -> StdResult, - { + pub fn as_value( + &self, + ns_fn: &mut dyn NamespaceSolver, + id_issuer: &mut IdentifierIssuer, + ) -> StdResult { Ok(match self { ResolvedVariable::Subject(subject) => match subject { Subject::Named(named) => named.as_iri(ns_fn).map(|iri| Value::URI { @@ -149,7 +150,7 @@ impl ResolvedVariables { #[cfg(test)] mod tests { use super::*; - use crate::state::{Literal, Node}; + use crate::state::{Literal, Namespace, Node}; use cosmwasm_std::StdError; #[test] @@ -206,11 +207,26 @@ mod tests { } } - fn ns(i: u128) -> StdResult { - match i { - 0 => Ok("foo".to_string()), - 1 => Ok("bar".to_string()), - _ => Err(StdError::generic_err("namespace not found")), + struct TestNamespaceSolver; + impl NamespaceSolver for TestNamespaceSolver { + fn resolve_from_key(&mut self, key: u128) -> StdResult { + match key { + 0 => Ok(Namespace { + key: 0, + value: "foo".to_string(), + counter: 1, + }), + 1 => Ok(Namespace { + key: 1, + value: "bar".to_string(), + counter: 1, + }), + _ => Err(StdError::generic_err("namespace not found")), + } + } + + fn resolve_from_val(&mut self, _value: String) -> StdResult { + Err(StdError::generic_err("namespace not found")) } } @@ -294,8 +310,9 @@ mod tests { ]; let mut id_issuer = IdentifierIssuer::new("b", 0u128); + let mut ns_solver = TestNamespaceSolver; for (var, expected) in cases { - assert_eq!(var.as_value(&mut ns, &mut id_issuer), expected) + assert_eq!(var.as_value(&mut ns_solver, &mut id_issuer), expected) } } diff --git a/contracts/axone-cognitarium/src/state/namespaces.rs b/contracts/axone-cognitarium/src/state/namespaces.rs index 24129e06..5568cdd3 100644 --- a/contracts/axone-cognitarium/src/state/namespaces.rs +++ b/contracts/axone-cognitarium/src/state/namespaces.rs @@ -41,15 +41,15 @@ pub fn namespaces<'a>() -> IndexedMap> { ) } -/// [NamespaceResolver] is a [Namespace] querying service allowing to resolve namespaces either by +/// [NamespaceQuerier] is a [Namespace] querying service allowing to resolve namespaces either by /// namespace's value or namespace's internal state key. It implements a two way indexed in-memory /// cache to mitigate state access. -pub struct NamespaceResolver { +pub struct NamespaceQuerier { by_val: BTreeMap>>, by_key: BTreeMap>>, } -impl NamespaceResolver { +impl NamespaceQuerier { pub fn new() -> Self { Self { by_key: BTreeMap::new(), @@ -138,7 +138,7 @@ impl NamespaceResolver { } } -impl Default for NamespaceResolver { +impl Default for NamespaceQuerier { fn default() -> Self { Self::new() } @@ -154,7 +154,7 @@ pub trait HasCachedNamespaces { fn clear_cache(&mut self); } -impl HasCachedNamespaces for NamespaceResolver { +impl HasCachedNamespaces for NamespaceQuerier { fn cached_namespaces(&self) -> Vec { self.by_key .iter() @@ -168,9 +168,9 @@ impl HasCachedNamespaces for NamespaceResolver { } } -impl From> for NamespaceResolver { +impl From> for NamespaceQuerier { fn from(value: Vec) -> Self { - let mut resolver = NamespaceResolver::new(); + let mut resolver = NamespaceQuerier::new(); for ns in value { resolver.insert(ns); } @@ -179,12 +179,55 @@ impl From> for NamespaceResolver { } } +pub trait NamespaceSolver { + fn resolve_from_key(&mut self, key: u128) -> StdResult; + fn resolve_from_val(&mut self, value: String) -> StdResult; +} + +pub struct NamespaceResolver<'a> { + storage: &'a dyn Storage, + ns_querier: NamespaceQuerier, +} + +impl<'a> NamespaceResolver<'a> { + pub fn new(storage: &'a dyn Storage, ns_cache: Vec) -> Self { + Self { + storage, + ns_querier: ns_cache.into(), + } + } +} + +impl<'a> NamespaceSolver for NamespaceResolver<'a> { + fn resolve_from_key(&mut self, key: u128) -> StdResult { + self.ns_querier + .resolve_from_key(self.storage, key) + .and_then(NamespaceQuerier::none_as_error_middleware) + } + + fn resolve_from_val(&mut self, value: String) -> StdResult { + self.ns_querier + .resolve_from_val(self.storage, value) + .and_then(NamespaceQuerier::none_as_error_middleware) + } +} + +impl<'a> HasCachedNamespaces for NamespaceResolver<'a> { + fn cached_namespaces(&self) -> Vec { + self.ns_querier.cached_namespaces() + } + + fn clear_cache(&mut self) { + self.ns_querier.clear_cache() + } +} + /// Allow to batch write operations on [Namespace] taking care of the [NAMESPACE_KEY_INCREMENT], it -/// manages insertions/deletions as well as counting references. It internally use a [NamespaceResolver] +/// manages insertions/deletions as well as counting references. It internally use a [NamespaceQuerier] /// as a cache of new/removed/modified namespaces, to finally apply writing to the state when /// calling [Self::flush]. pub struct NamespaceBatchService { - ns_resolver: NamespaceResolver, + ns_resolver: NamespaceQuerier, ns_key_inc: u128, ns_count_diff: i128, } @@ -192,7 +235,7 @@ pub struct NamespaceBatchService { impl NamespaceBatchService { pub fn new(storage: &dyn Storage) -> StdResult { Ok(Self { - ns_resolver: NamespaceResolver::new(), + ns_resolver: NamespaceQuerier::new(), ns_key_inc: NAMESPACE_KEY_INCREMENT.load(storage)?, ns_count_diff: 0, }) diff --git a/contracts/axone-cognitarium/src/state/triples.rs b/contracts/axone-cognitarium/src/state/triples.rs index aa62b1fd..f3bb7593 100644 --- a/contracts/axone-cognitarium/src/state/triples.rs +++ b/contracts/axone-cognitarium/src/state/triples.rs @@ -1,3 +1,4 @@ +use crate::state::NamespaceSolver; use blake3::Hash; use cosmwasm_std::StdResult; use cw_storage_plus::{Index, IndexList, IndexedMap, MultiIndex}; @@ -150,11 +151,8 @@ impl Node { key } - pub fn as_iri(&self, ns_fn: &mut F) -> StdResult - where - F: FnMut(u128) -> StdResult, - { - Ok(ns_fn(self.namespace)? + &self.value) + pub fn as_iri(&self, ns_solver: &mut dyn NamespaceSolver) -> StdResult { + Ok(ns_solver.resolve_from_key(self.namespace)?.value + &self.value) } } diff --git a/contracts/axone-cognitarium/src/storer/engine.rs b/contracts/axone-cognitarium/src/storer/engine.rs index 105989b6..fa165416 100644 --- a/contracts/axone-cognitarium/src/storer/engine.rs +++ b/contracts/axone-cognitarium/src/storer/engine.rs @@ -1,7 +1,7 @@ use crate::error::StoreError; use crate::state::{ - triples, Literal, NamespaceBatchService, Node, Object, Store, Subject, Triple, - BLANK_NODE_IDENTIFIER_COUNTER, BLANK_NODE_SIZE, STORE, + triples, Literal, NamespaceBatchService, NamespaceQuerier, Node, Object, Store, Subject, + Triple, BLANK_NODE_IDENTIFIER_COUNTER, BLANK_NODE_SIZE, STORE, }; use crate::ContractError; use axone_rdf::normalize::IdentifierIssuer; @@ -280,15 +280,10 @@ impl<'a> StoreEngine<'a> { } fn node_size(&mut self, node: &Node) -> StdResult { - if let Some(ns) = self - .ns_batch_svc - .resolve_from_key(self.storage, node.namespace)? - { - return Ok(ns.value.len() + node.value.len()); - } - - // Should never happen as in its use the namespace should be already cached. - Err(StdError::not_found("Namespace")) + self.ns_batch_svc + .resolve_from_key(self.storage, node.namespace) + .and_then(NamespaceQuerier::none_as_error_middleware) + .map(|ns| ns.value.len() + node.value.len()) } fn object_size(&mut self, object: &Object) -> StdResult {