feat/orm
Laurin Weger 1 week ago
parent 82de4660f3
commit 35dc5e2c93
No known key found for this signature in database
GPG Key ID: 9B372BB0B792770F
  1. 33
      Cargo.toml
  2. 444
      nextgraph/src/tests/orm.rs
  3. 33
      ng-verifier/src/orm/add_remove_triples.rs
  4. 78
      ng-verifier/src/orm/mod.rs
  5. 4
      ng-verifier/src/orm/types.rs
  6. 65
      ng-verifier/src/orm/validation.rs

@ -12,7 +12,7 @@ members = [
"sdk/ng-sdk-js",
"ng-oxigraph",
]
default-members = [ "nextgraph" ]
default-members = ["nextgraph"]
[workspace.package]
version = "0.1.2"
@ -23,10 +23,31 @@ authors = ["Niko PLP <niko@nextgraph.org>"]
repository = "https://git.nextgraph.org/NextGraph/nextgraph-rs"
homepage = "https://nextgraph.org"
keywords = [
"crdt","dapp","decentralized","e2ee","local-first","p2p","semantic-web","eventual-consistency","json-ld","markdown",
"ocap","vc","offline-first","p2p-network","collaboration","privacy-protection","rdf","rich-text-editor","self-hosted",
"sparql","byzantine-fault-tolerance",
"web3", "graph-database", "database","triplestore"
"crdt",
"dapp",
"decentralized",
"e2ee",
"local-first",
"p2p",
"semantic-web",
"eventual-consistency",
"json-ld",
"markdown",
"ocap",
"vc",
"offline-first",
"p2p-network",
"collaboration",
"privacy-protection",
"rdf",
"rich-text-editor",
"self-hosted",
"sparql",
"byzantine-fault-tolerance",
"web3",
"graph-database",
"database",
"triplestore",
]
documentation = "https://docs.nextgraph.org/"
@ -35,7 +56,7 @@ lto = true
opt-level = 's'
[profile.dev]
opt-level = 2
opt-level = 1
[patch.crates-io]
# tauri = { git = "https://github.com/simonhyll/tauri.git", branch="fix/ipc-mixup"}

@ -12,8 +12,8 @@ use crate::tests::create_or_open_wallet::create_or_open_wallet;
use async_std::stream::StreamExt;
use ng_net::app_protocol::{AppResponse, AppResponseV0, NuriV0};
use ng_net::orm::{
BasicType, OrmSchemaDataType, OrmSchemaLiteralType, OrmSchemaPredicate, OrmSchemaShape,
OrmShapeType,
BasicType, OrmSchema, OrmSchemaDataType, OrmSchemaLiteralType, OrmSchemaPredicate,
OrmSchemaShape, OrmShapeType,
};
use ng_verifier::orm::utils::shape_type_to_sparql;
@ -69,222 +69,7 @@ INSERT DATA {
.await
.expect("SPARQL update failed");
// Define the ORM schema
let mut schema = HashMap::new();
schema.insert(
"http://example.org/TestObject||http://example.org/anotherObject".to_string(),
Arc::new(OrmSchemaShape {
iri: "http://example.org/TestObject||http://example.org/anotherObject".to_string(),
predicates: vec![
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::string,
literals: None,
shape: None,
}],
iri: "http://example.org/prop1".to_string(),
readablePredicate: "prop1".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
}],
iri: "http://example.org/prop2".to_string(),
readablePredicate: "prop2".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
],
}),
);
schema.insert(
"http://example.org/TestObject".to_string(),
Arc::new(OrmSchemaShape {
iri: "http://example.org/TestObject".to_string(),
predicates: vec![
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::literal,
literals: Some(vec![BasicType::Str(
"http://example.org/TestObject".to_string(),
)]),
shape: None,
}],
iri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type".to_string(),
readablePredicate: "type".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: Some(true),
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::string,
literals: None,
shape: None,
}],
iri: "http://example.org/stringValue".to_string(),
readablePredicate: "stringValue".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
}],
iri: "http://example.org/numValue".to_string(),
readablePredicate: "numValue".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::boolean,
literals: None,
shape: None,
}],
iri: "http://example.org/boolValue".to_string(),
readablePredicate: "boolValue".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
}],
iri: "http://example.org/arrayValue".to_string(),
readablePredicate: "arrayValue".to_string(),
maxCardinality: -1,
minCardinality: 0,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::shape,
literals: None,
shape: Some(
"http://example.org/TestObject||http://example.org/objectValue"
.to_string(),
),
}],
iri: "http://example.org/objectValue".to_string(),
readablePredicate: "objectValue".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::shape,
literals: None,
shape: Some(
"http://example.org/TestObject||http://example.org/anotherObject"
.to_string(),
),
}],
iri: "http://example.org/anotherObject".to_string(),
readablePredicate: "anotherObject".to_string(),
maxCardinality: -1,
minCardinality: 0,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![
OrmSchemaDataType {
valType: OrmSchemaLiteralType::string,
literals: None,
shape: None,
},
OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
},
],
iri: "http://example.org/numOrStr".to_string(),
readablePredicate: "numOrStr".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::literal,
literals: Some(vec![
BasicType::Str("lit1".to_string()),
BasicType::Str("lit2".to_string()),
]),
shape: None,
}],
iri: "http://example.org/lit1Or2".to_string(),
readablePredicate: "lit1Or2".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
],
}),
);
schema.insert(
"http://example.org/TestObject||http://example.org/objectValue".to_string(),
Arc::new(OrmSchemaShape {
iri: "http://example.org/TestObject||http://example.org/objectValue".to_string(),
predicates: vec![
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::string,
literals: None,
shape: None,
}],
iri: "http://example.org/nestedString".to_string(),
readablePredicate: "nestedString".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
}],
iri: "http://example.org/nestedNum".to_string(),
readablePredicate: "nestedNum".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
}],
iri: "http://example.org/nestedArray".to_string(),
readablePredicate: "nestedArray".to_string(),
maxCardinality: -1,
minCardinality: 0,
extra: None,
}),
],
}),
);
let schema = create_big_schema();
let shape_type = OrmShapeType {
schema,
shape: "http://example.org/TestObject".to_string(),
@ -581,6 +366,29 @@ INSERT DATA {
ex:lit1Or2 "lit1" ;
ex:unrelated "some value" ;
ex:anotherUnrelated 4242 .
<urn:test:obj2> a ex:TestObject ;
ex:stringValue "hello world #2" ;
ex:numValue 422 ;
ex:boolValue false ;
ex:arrayValue 4,5,6 ;
ex:objectValue [
ex:nestedString "nested2" ;
ex:nestedNum 72 ;
ex:nestedArray 7,8,9
] ;
ex:anotherObject [
ex:prop1 "one2" ;
ex:prop2 12
], [
ex:prop1 "two2" ;
ex:prop2 22
] ;
ex:numOrStr 4 ;
ex:lit1Or2 "lit2" ;
ex:unrelated "some value2" ;
ex:anotherUnrelated 42422 .
}
"#
.to_string();
@ -590,8 +398,47 @@ INSERT DATA {
.expect("SPARQL update failed");
// Define the ORM schema
let mut schema = HashMap::new();
let schema = create_big_schema();
let shape_type = OrmShapeType {
schema,
shape: "http://example.org/TestObject".to_string(),
};
log_info!("starting orm test");
let nuri = NuriV0::new_from(&doc_nuri).expect("parse nuri");
let (mut receiver, cancel_fn) = orm_start(nuri, shape_type, session_id)
.await
.expect("orm_start");
log_info!("orm_start called");
// TODO: remove this call to cancel_fn()
cancel_fn();
// TODO : change the data with sparql_query
while let Some(app_response) = receiver.next().await {
let orm_json = match app_response {
AppResponse::V0(v) => match v {
AppResponseV0::OrmInitial(json) => Some(json),
_ => None,
},
}
.unwrap();
log_info!("ORM JSON arrived\n: {:?}", orm_json);
// TODO: after we got what we wanted, call cancel_fn, otherwise the test never ends.
}
//
}
fn create_big_schema() -> OrmSchema {
// Define the ORM schema
let mut schema: OrmSchema = HashMap::new();
// Base shape
schema.insert(
"http://example.org/TestObject".to_string(),
Arc::new(OrmSchemaShape {
@ -659,6 +506,36 @@ INSERT DATA {
minCardinality: 0,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::shape,
literals: None,
shape: Some(
"http://example.org/TestObject||http://example.org/objectValue"
.to_string(),
),
}],
iri: "http://example.org/objectValue".to_string(),
readablePredicate: "objectValue".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::shape,
literals: None,
shape: Some(
"http://example.org/TestObject||http://example.org/anotherObject"
.to_string(),
),
}],
iri: "http://example.org/anotherObject".to_string(),
readablePredicate: "anotherObject".to_string(),
maxCardinality: -1,
minCardinality: 0,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![
OrmSchemaDataType {
@ -679,14 +556,18 @@ INSERT DATA {
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::literal,
literals: Some(vec![
BasicType::Str("lit1".to_string()),
BasicType::Str("lit2".to_string()),
]),
shape: None,
}],
dataTypes: vec![
OrmSchemaDataType {
valType: OrmSchemaLiteralType::literal,
literals: Some(vec![BasicType::Str("lit1".to_string())]),
shape: None,
},
OrmSchemaDataType {
valType: OrmSchemaLiteralType::literal,
literals: Some(vec![BasicType::Str("lit2".to_string())]),
shape: None,
},
],
iri: "http://example.org/lit1Or2".to_string(),
readablePredicate: "lit1Or2".to_string(),
maxCardinality: 1,
@ -697,36 +578,85 @@ INSERT DATA {
}),
);
let shape_type = OrmShapeType {
schema,
shape: "http://example.org/TestObject".to_string(),
};
log_info!("starting orm test");
let nuri = NuriV0::new_from(&doc_nuri).expect("parse nuri");
let (mut receiver, cancel_fn) = orm_start(nuri, shape_type, session_id)
.await
.expect("orm_start");
log_info!("orm_start called");
// TODO: remove this call to cancel_fn()
cancel_fn();
// TODO : change the data with sparql_query
while let Some(app_response) = receiver.next().await {
let orm_json = match app_response {
AppResponse::V0(v) => match v {
AppResponseV0::OrmInitial(json) => Some(json),
_ => None,
},
}
.unwrap();
// a nested shape (http://example.org/anotherObject)
schema.insert(
"http://example.org/TestObject||http://example.org/anotherObject".to_string(),
Arc::new(OrmSchemaShape {
iri: "http://example.org/TestObject||http://example.org/anotherObject".to_string(),
predicates: vec![
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::string,
literals: None,
shape: None,
}],
iri: "http://example.org/prop1".to_string(),
readablePredicate: "prop1".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
}],
iri: "http://example.org/prop2".to_string(),
readablePredicate: "prop2".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
],
}),
);
log_info!("ORM JSON arrived\n: {:?}", orm_json);
// another nested shape (http://example.org/objectValue)
schema.insert(
"http://example.org/TestObject||http://example.org/objectValue".to_string(),
Arc::new(OrmSchemaShape {
iri: "http://example.org/TestObject||http://example.org/objectValue".to_string(),
predicates: vec![
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::string,
literals: None,
shape: None,
}],
iri: "http://example.org/nestedString".to_string(),
readablePredicate: "nestedString".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
}],
iri: "http://example.org/nestedNum".to_string(),
readablePredicate: "nestedNum".to_string(),
maxCardinality: 1,
minCardinality: 1,
extra: None,
}),
Arc::new(OrmSchemaPredicate {
dataTypes: vec![OrmSchemaDataType {
valType: OrmSchemaLiteralType::number,
literals: None,
shape: None,
}],
iri: "http://example.org/nestedArray".to_string(),
readablePredicate: "nestedArray".to_string(),
maxCardinality: -1,
minCardinality: 0,
extra: None,
}),
],
}),
);
// TODO: after we got what we wanted, call cancel_fn, otherwise the test never ends.
}
//
return schema;
}

@ -27,27 +27,6 @@ pub fn add_remove_triples(
orm_subscription: &mut OrmSubscription,
subject_changes: &mut OrmTrackedSubjectChange,
) -> Result<(), VerifierError> {
// fn get_tracked_predicate<'a>(
// subject_iri: &str,
// shape: &Arc<OrmSchemaShape>,
// predicate_schema_iri: &String,
// tracked_subjects: &'a mut HashMap<String, HashMap<String, Arc<RwLock<OrmTrackedSubject>>>>,
// ) -> Result<Arc<RwLock<OrmTrackedPredicate>>, VerifierError> {
// let tracked_shapes_for_subject = tracked_subjects
// .get_mut(&subject_iri.to_string())
// .ok_or(VerifierError::OrmSubjectNotFound)?;
// let subject = tracked_shapes_for_subject
// .get_mut(&shape.iri)
// .ok_or(VerifierError::OrmSubjectNotFound)?;
// Ok(subject
// .read()
// .unwrap()
// .tracked_predicates
// .get(predicate_schema_iri)
// .ok_or(VerifierError::OrmPredicateNotFound)?
// .clone())
// }
// Helper to get/create tracked subjects
fn get_or_create_tracked_subject<'a>(
subject_iri: &str,
@ -91,8 +70,8 @@ pub fn add_remove_triples(
let tracked_subject_lock =
get_or_create_tracked_subject(subject_iri, &shape, tracked_subjects);
let mut tracked_subject = tracked_subject_lock.write().unwrap();
log_debug!("lock acquired on tracked_subject");
// Add tracked predicate or increase cardinality
// log_debug!("lock acquired on tracked_subject");
// Add get tracked predicate.
let tracked_predicate_lock = tracked_subject
.tracked_predicates
.entry(predicate_schema.iri.clone())
@ -106,7 +85,7 @@ pub fn add_remove_triples(
});
{
let mut tracked_predicate = tracked_predicate_lock.write().unwrap();
log_debug!("lock acquired on tracked_predicate");
// log_debug!("lock acquired on tracked_predicate");
tracked_predicate.current_cardinality += 1;
// Keep track of the changed values too.
@ -216,7 +195,7 @@ pub fn add_remove_triples(
// Remove obj_val from current_literals in-place
current_literals.retain(|val| *val != val_removed);
} else {
tracked_predicate.current_literals = Some(vec![val_removed]);
panic!("tracked_predicate.current_literals must not be None.");
}
} else if tracked_predicate
.schema
@ -244,7 +223,7 @@ pub fn add_remove_triples(
// Remove link to children
tracked_predicate
.tracked_children
.retain(|c| *obj_iri != c.read().unwrap().subject_iri);
.retain(|ts| *obj_iri != ts.read().unwrap().subject_iri);
for shape_iri in shapes_to_process {
// Get or create object's tracked subject struct.
@ -255,7 +234,7 @@ pub fn add_remove_triples(
.write()
.unwrap()
.parents
.remove(obj_iri);
.remove(subject_iri);
}
}
}

@ -58,7 +58,7 @@ impl Verifier {
//let base = NuriV0::repo_id(&repo.id);
let nuri_str = nuri.as_ref().map(|s| s.as_str());
log_debug!("querying construct\n{}\n{}\n\n", nuri_str.unwrap(), query);
log_debug!("querying construct\n{}\n{}\n", nuri_str.unwrap(), query);
let parsed =
Query::parse(&query, nuri_str).map_err(|e| NgError::OxiGraphError(e.to_string()))?;
@ -67,17 +67,19 @@ impl Verifier {
.map_err(|e| NgError::OxiGraphError(e.to_string()))?;
match results {
QueryResults::Graph(triples) => {
let mut results = vec![];
let mut result_triples: Vec<Triple> = vec![];
for t in triples {
match t {
Err(e) => {
log_err!("{}", e.to_string());
return Err(NgError::SparqlError(e.to_string()));
}
Ok(triple) => results.push(triple),
Ok(triple) => {
result_triples.push(triple);
}
}
}
Ok(results)
Ok(result_triples)
}
_ => return Err(NgError::InvalidResponse),
}
@ -138,21 +140,18 @@ impl Verifier {
// First in, last out stack to keep track of objects to validate (nested objects first). Strings are object IRIs.
let mut shape_validation_queue: Vec<(Arc<OrmSchemaShape>, Vec<String>)> = vec![];
// Add root shape for first validation run.
let root_shape_iri = root_shape.iri.clone();
shape_validation_queue.push((root_shape, vec![]));
// Process queue of shapes and subjects to validate.
// For a given shape, we evaluate every subject against that shape.
while let Some((shape, objects_to_validate)) = shape_validation_queue.pop() {
// Collect triples relevant for validation.
log_debug!(
"process_changes_for_shape_and_session triples_added: {:?}",
triples_added
);
let added_triples_by_subject =
group_by_subject_for_shape(&shape, triples_added, &objects_to_validate);
let removed_triples_by_subject =
group_by_subject_for_shape(&shape, triples_removed, &objects_to_validate);
let all_modified_subjects: HashSet<&SubjectIri> = added_triples_by_subject
let modified_subject_iris: HashSet<&SubjectIri> = added_triples_by_subject
.keys()
.chain(removed_triples_by_subject.keys())
.collect();
@ -162,7 +161,7 @@ impl Verifier {
.get_mut(nuri)
.unwrap()
.iter_mut()
.find(|sub| sub.session_id == session_id && sub.shape_type.shape == shape.iri)
.find(|sub| sub.session_id == session_id && sub.shape_type.shape == root_shape_iri)
.unwrap();
// Variable to collect nested objects that need validation.
@ -170,9 +169,9 @@ impl Verifier {
HashMap::new();
// For each subject, add/remove triples and validate.
log_debug!("all_modified_subjects: {:?}", all_modified_subjects);
log_debug!("all_modified_subjects: {:?}", modified_subject_iris);
for subject_iri in all_modified_subjects {
for subject_iri in modified_subject_iris {
let triples_added_for_subj = added_triples_by_subject
.get(subject_iri)
.map(|v| v.as_slice())
@ -190,22 +189,31 @@ impl Verifier {
.or_insert_with(|| OrmTrackedSubjectChange {
subject_iri: subject_iri.clone(),
predicates: HashMap::new(),
data_applied: false,
});
// Apply all triples for that subject to the tracked (shape, subject) pair.
// Record the changes.
{
log_debug!("add_remove_triples for subject {subject_iri}");
if let Err(e) = add_remove_triples(
shape.clone(),
subject_iri,
triples_added_for_subj,
triples_removed_for_subj,
&mut orm_subscription,
change,
) {
log_err!("apply_changes_from_triples add/remove error: {:?}", e);
panic!();
if !change.data_applied {
log_debug!(
"Adding triples to change tracker for subject {}",
subject_iri
);
if let Err(e) = add_remove_triples(
shape.clone(),
subject_iri,
triples_added_for_subj,
triples_removed_for_subj,
&mut orm_subscription,
change,
) {
log_err!("apply_changes_from_triples add/remove error: {:?}", e);
panic!();
}
change.data_applied = true;
} else {
log_debug!("not applying triples again for subject {subject_iri}");
}
let validity = {
@ -240,8 +248,11 @@ impl Verifier {
// Now, we queue all non-evaluated objects
for (shape_iri, objects_to_eval) in &nested_objects_to_eval {
let orm_subscription =
self.get_first_orm_subscription_for(nuri, Some(&shape.iri), Some(&session_id));
let orm_subscription = self.get_first_orm_subscription_for(
nuri,
Some(&root_shape_iri),
Some(&session_id),
);
// Extract schema and shape Arc before mutable borrow
let schema = orm_subscription.shape_type.schema.clone();
let shape_arc = schema.get(shape_iri).unwrap().clone();
@ -526,16 +537,18 @@ impl Verifier {
let mut return_vals: Value = Value::Array(vec![]);
let return_val_vec = return_vals.as_array_mut().unwrap();
log_debug!(
"Tracked subjects:\n{:?}\n",
orm_subscription.tracked_subjects,
);
// log_debug!(
// "Tracked subjects:\n{:?}\n",
// orm_subscription.tracked_subjects,
// );
// For each valid change struct, we build an orm object.
// The way we get the changes from the tracked subjects is a bit hacky, sorry.
for (subject_iri, tracked_subjects_by_shape) in &orm_subscription.tracked_subjects {
if let Some(tracked_subject) = tracked_subjects_by_shape.get(&shape_type.shape) {
log_info!("changes for : {:?}\n{:?}", tracked_subject, changes);
if tracked_subject.read().unwrap().valid == OrmTrackedSubjectValidity::Valid {
let ts = tracked_subject.read().unwrap();
log_info!("changes for: {:?} valid: {:?}\n", ts.subject_iri, ts.valid);
if ts.valid == OrmTrackedSubjectValidity::Valid {
if let Some(change) = changes
.get(&shape_type.shape)
.and_then(|subject_iri_to_ts| subject_iri_to_ts.get(subject_iri).clone())
@ -546,7 +559,8 @@ impl Verifier {
root_shape,
&orm_subscription.tracked_subjects,
);
log_debug!("Materialized change:\n{:?}\ninto:\n{:?}", change, new_val);
// TODO: For some reason, this log statement causes a panic.
// log_debug!("Materialized change:\n{:?}\ninto:\n{:?}", change, new_val);
return_val_vec.push(new_val);
}
}

@ -57,6 +57,10 @@ pub struct OrmTrackedSubjectChange {
pub subject_iri: String,
/// Predicates that were changed.
pub predicates: HashMap<String, OrmTrackedPredicateChanges>,
/// If the new triples have been added to the tracked predicates
/// (values_added / values_removed) already. This is to prevent
/// double-application.
pub data_applied: bool,
}
#[derive(Debug)]
pub struct OrmTrackedPredicateChanges {

@ -13,6 +13,7 @@ use std::collections::HashSet;
use crate::orm::types::*;
use crate::verifier::*;
use ng_net::orm::*;
use ng_repo::log::*;
impl Verifier {
/// Check the validity of a subject and update affecting tracked subjects' validity.
@ -54,9 +55,8 @@ impl Verifier {
{
// We need to fetch the subject's current state:
// We have new parents but were previously not recording changes.
// Return the subject_iri with `needs_fetch` set to true.
return vec![(s_change.subject_iri.clone(), shape.iri.clone(), true)];
// TODO
}
}
@ -97,6 +97,14 @@ impl Verifier {
// Check 4.1) Cardinality
if count < p_schema.minCardinality {
log_debug!(
"[VALIDATION] Invalid: minCardinality not met | predicate: {:?} | count: {} | min: {} | schema: {:?} | changed: {:?}",
p_schema.iri,
count,
p_schema.minCardinality,
shape.iri,
p_change
);
set_validity(&mut new_validity, OrmTrackedSubjectValidity::Invalid);
if count <= 0 {
// If cardinality is 0, we can remove the tracked predicate.
@ -108,6 +116,14 @@ impl Verifier {
&& p_schema.maxCardinality != -1
&& p_schema.extra != Some(true)
{
log_debug!(
"[VALIDATION] Invalid: maxCardinality exceeded | predicate: {:?} | count: {} | max: {} | schema: {:?} | changed: {:?}",
p_schema.iri,
count,
p_schema.maxCardinality,
shape.iri,
p_change
);
// If cardinality is too high and no extra allowed, invalid.
set_validity(&mut new_validity, OrmTrackedSubjectValidity::Invalid);
break;
@ -146,6 +162,12 @@ impl Verifier {
},
);
if !some_valid {
log_debug!(
"[VALIDATION] Invalid: required literals missing | predicate: {:?} | schema: {:?} | changed: {:?}",
p_schema.iri,
shape.iri,
p_change
);
set_validity(&mut new_validity, OrmTrackedSubjectValidity::Invalid);
}
// Check 4.4) Nested shape correct.
@ -184,11 +206,36 @@ impl Verifier {
});
if counts.1 > 0 && p_schema.extra != Some(true) {
// If we have at least one invalid nested object and no extra allowed, invalid.
log_debug!(
"[VALIDATION] Invalid: nested invalid child | predicate: {:?} | schema: {:?} | changed: {:?}",
p_schema.iri,
shape.iri,
p_change
);
// If we have at least one invalid nested object
// and no extra (in this case this means invalid) allowed, invalid.
set_validity(&mut new_validity, OrmTrackedSubjectValidity::Invalid);
break;
} else if counts.0 > p_schema.maxCardinality && p_schema.maxCardinality != -1 {
log_debug!(
"[VALIDATION] Too many valid children: | predicate: {:?} | schema: {:?} | changed: {:?}",
p_schema.iri,
shape.iri,
p_change
);
// If there are more valid children than what's allowed, break.
set_validity(&mut new_validity, OrmTrackedSubjectValidity::Invalid);
break;
} else if counts.0 < p_schema.minCardinality {
// If we have not enough valid nested objects, invalid.
} else if counts.0 + counts.2 + counts.3 < p_schema.minCardinality {
log_debug!(
"[VALIDATION] Invalid: not enough nested children | predicate: {:?} | valid_count: {} | min: {} | schema: {:?} | changed: {:?}",
p_schema.iri,
counts.0,
p_schema.minCardinality,
shape.iri,
p_change
);
// If we don't have enough nested objects, invalid.
set_validity(&mut new_validity, OrmTrackedSubjectValidity::Invalid);
break;
} else if counts.3 > 0 {
@ -251,6 +298,14 @@ impl Verifier {
}),
};
if !matches {
log_debug!(
"[VALIDATION] Invalid: value type mismatch | predicate: {:?} | value: {:?} | allowed_types: {:?} | schema: {:?} | changed: {:?}",
p_schema.iri,
val_added,
allowed_types,
shape.iri,
p_change
);
set_validity(&mut new_validity, OrmTrackedSubjectValidity::Invalid);
break;
}

Loading…
Cancel
Save