use query_engine::chase::materialize; use query_engine::chase::rule::RuleBuilder; use query_engine::frontend::Session; use query_engine::{Atom, Instance, Term, chase}; #[test] fn existential_trigger_stays_inactive_when_head_is_already_satisfied() { let instance: Instance = vec![ Atom::new("Person", vec![Term::constant("alice")]), Atom::new( "HasSSN", vec![Term::constant("alice"), Term::constant("known")], ), ] .into_iter() .collect(); let rule = RuleBuilder::new() .when("Person", vec![Term::var("X")]) .then("HasSSN", vec![Term::var("X"), Term::var("Y")]) .build(); let result = chase(instance, &[rule]); assert!(result.terminated); assert_eq!(result.steps, 0); assert_eq!(result.instance.facts_for_predicate("HasSSN").len(), 1); } #[test] fn fresh_nulls_skip_existing_input_null_ids() { let instance: Instance = vec![ Atom::new("Seed", vec![Term::null(0)]), Atom::new("Person", vec![Term::constant("alice")]), ] .into_iter() .collect(); let rule = RuleBuilder::new() .when("Person", vec![Term::var("X")]) .then("HasSSN", vec![Term::var("X"), Term::var("Y")]) .build(); let result = chase(instance, &[rule]); assert!(result.terminated); assert_eq!(result.instance.facts_for_predicate("HasSSN").len(), 1); let fact = result.instance.facts_for_predicate("HasSSN")[0]; assert!(matches!(fact.terms[1], Term::Null(id) if id > 0)); } #[test] fn frontend_materialization_respects_existing_existential_witnesses() { let mut session = Session::new(); let output = session .execute_script( "fact Person(alice).\n\ fact HasSSN(alice, known).\n\ rule Person(?X) -> HasSSN(?X, ?Y).\n\ run.\n\ query HasSSN(alice, ?Y)?", ) .unwrap(); assert!(output.contains("1 row(s)")); assert!(output.contains("?Y = known")); assert!(!output.contains("⊥")); } #[test] fn frontend_materialization_starts_after_existing_null_ids() { let instance: Instance = vec![ Atom::new("Seed", vec![Term::null(7)]), Atom::new("Employee", vec![Term::constant("alice")]), ] .into_iter() .collect(); let rule = RuleBuilder::new() .when("Employee", vec![Term::var("X")]) .then("WorksIn", vec![Term::var("X"), Term::var("Dept")]) .build(); let state = materialize(instance, &[rule]); assert!(state.result.terminated); assert_eq!( state.result.instance.facts_for_predicate("WorksIn").len(), 1 ); let fact = state.result.instance.facts_for_predicate("WorksIn")[0]; assert!(matches!(fact.terms[1], Term::Null(id) if id > 7)); }