diff --git a/Cargo.toml b/Cargo.toml index f08bda2..ad0bd34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 "] 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"} diff --git a/nextgraph/src/tests/orm.rs b/nextgraph/src/tests/orm.rs index 5678973..c172c2e 100644 --- a/nextgraph/src/tests/orm.rs +++ b/nextgraph/src/tests/orm.rs @@ -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 . + + + 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; } diff --git a/ng-verifier/src/orm/add_remove_triples.rs b/ng-verifier/src/orm/add_remove_triples.rs index 1b374c1..2e94255 100644 --- a/ng-verifier/src/orm/add_remove_triples.rs +++ b/ng-verifier/src/orm/add_remove_triples.rs @@ -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, - // predicate_schema_iri: &String, - // tracked_subjects: &'a mut HashMap>>>, - // ) -> Result>, 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); } } } diff --git a/ng-verifier/src/orm/mod.rs b/ng-verifier/src/orm/mod.rs index a368598..475306f 100644 --- a/ng-verifier/src/orm/mod.rs +++ b/ng-verifier/src/orm/mod.rs @@ -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 = 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, Vec)> = 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); } } diff --git a/ng-verifier/src/orm/types.rs b/ng-verifier/src/orm/types.rs index 23fdaf5..ac8721d 100644 --- a/ng-verifier/src/orm/types.rs +++ b/ng-verifier/src/orm/types.rs @@ -57,6 +57,10 @@ pub struct OrmTrackedSubjectChange { pub subject_iri: String, /// Predicates that were changed. pub predicates: HashMap, + /// 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 { diff --git a/ng-verifier/src/orm/validation.rs b/ng-verifier/src/orm/validation.rs index 6129743..35e47c1 100644 --- a/ng-verifier/src/orm/validation.rs +++ b/ng-verifier/src/orm/validation.rs @@ -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; }