qualia_core_db/query/
temporal_scrub.rs1use crate::git_bridge::DagStore;
6use crate::NQuin;
7
8pub fn replay_to_state<'a, F>(dag: &'a DagStore, as_of_ms: u64, resolver: F) -> Vec<NQuin>
12where
13 F: Fn([u8; 32]) -> Option<Vec<NQuin>>,
14{
15 let mut state = Vec::new();
16
17 for (node, _) in dag.nodes().iter().filter(|(n, _)| n.timestamp <= as_of_ms) {
19 if let Some(mutations) = resolver(node.quins_merkle) {
20 for quin in mutations {
21 state.push(quin);
22 }
23 }
24 }
25
26 state
27}
28
29pub fn frame_diff_hints<'a, F>(
33 dag: &'a DagStore,
34 t0: u64,
35 t1: u64,
36 resolver: F,
37) -> (Vec<NQuin>, Vec<NQuin>)
38where
39 F: Fn([u8; 32]) -> Option<Vec<NQuin>>,
40{
41 let mut added = Vec::new();
42 let mut removed = Vec::new();
43
44 let min_t = t0.min(t1);
49 let max_t = t0.max(t1);
50
51 for (node, _) in dag.nodes().iter() {
52 if node.timestamp > min_t && node.timestamp <= max_t {
53 if let Some(mutations) = resolver(node.quins_merkle) {
54 for quin in mutations {
55 if t1 >= t0 {
56 added.push(quin); } else {
58 removed.push(quin); }
60 }
61 }
62 }
63 }
64
65 (added, removed)
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn test_replay_to_state() {
74 let mut dag = DagStore::new();
75 let q1 = NQuin {
76 subject: 1,
77 predicate: 2,
78 object: 3,
79 context: 0,
80 metadata: 0,
81 parity: 0,
82 };
83 let q2 = NQuin {
84 subject: 4,
85 predicate: 5,
86 object: 6,
87 context: 0,
88 metadata: 0,
89 parity: 0,
90 };
91
92 dag.commit_node([0u8; 32], &[q1.clone()], 123, 1000, "commit1");
93 dag.commit_node([0u8; 32], &[q2.clone()], 123, 2000, "commit2");
94
95 let resolver = |merkle: [u8; 32]| -> Option<Vec<NQuin>> {
96 if merkle == crate::git_bridge::quins_merkle(&[q1.clone()]) {
97 Some(vec![q1.clone()])
98 } else if merkle == crate::git_bridge::quins_merkle(&[q2.clone()]) {
99 Some(vec![q2.clone()])
100 } else {
101 None
102 }
103 };
104
105 let state_at_1500 = replay_to_state(&dag, 1500, &resolver);
106 assert_eq!(state_at_1500.len(), 1);
107 assert_eq!(state_at_1500[0].subject, 1);
108
109 let state_at_2500 = replay_to_state(&dag, 2500, &resolver);
110 assert_eq!(state_at_2500.len(), 2);
111 }
112
113 #[test]
114 fn test_frame_diff_hints() {
115 let mut dag = DagStore::new();
116 let q1 = NQuin {
117 subject: 1,
118 predicate: 2,
119 object: 3,
120 context: 0,
121 metadata: 0,
122 parity: 0,
123 };
124 let q2 = NQuin {
125 subject: 4,
126 predicate: 5,
127 object: 6,
128 context: 0,
129 metadata: 0,
130 parity: 0,
131 };
132
133 dag.commit_node([0u8; 32], &[q1.clone()], 123, 1000, "commit1");
134 dag.commit_node([0u8; 32], &[q2.clone()], 123, 2000, "commit2");
135
136 let resolver = |merkle: [u8; 32]| -> Option<Vec<NQuin>> {
137 if merkle == crate::git_bridge::quins_merkle(&[q1.clone()]) {
138 Some(vec![q1.clone()])
139 } else if merkle == crate::git_bridge::quins_merkle(&[q2.clone()]) {
140 Some(vec![q2.clone()])
141 } else {
142 None
143 }
144 };
145
146 let (added, removed) = frame_diff_hints(&dag, 1500, 2500, &resolver);
148 assert_eq!(added.len(), 1);
149 assert_eq!(added[0].subject, 4);
150 assert_eq!(removed.len(), 0);
151
152 let (added, removed) = frame_diff_hints(&dag, 2500, 1500, &resolver);
154 assert_eq!(added.len(), 0);
155 assert_eq!(removed.len(), 1);
156 assert_eq!(removed[0].subject, 4);
157 }
158}