Skip to main content

terminus_store/layer/
simple_builder.rs

1//! builder frontend for constructing new layers
2//!
3//! `base` and `child` contain their own layer builders, but these are
4//! not very easy to use. They require one to first insert all new
5//! dictionary entries in sorted order, and then all numerical triple
6//! additions/removals in sorted order
7//!
8//! The layer builder implemented here will instead take triples in
9//! any format (numerical, string, or a mixture), store them in
10//! memory, then does the required sorting and id conversion on
11//! commit.
12use super::internal::*;
13use super::layer::*;
14use crate::storage::*;
15use std::collections::HashMap;
16use std::io;
17use std::pin::Pin;
18use std::sync::Arc;
19
20use futures::future::Future;
21
22use bitvec::prelude::*;
23
24/// A layer builder trait with no generic typing.
25///
26/// Lack of generic types allows layer builders with different storage
27/// backends to be handled by trait objects of this type.
28pub trait LayerBuilder: Send + Sync {
29    /// Returns the name of the layer being built
30    fn name(&self) -> [u32; 5];
31    /// Return the parent if it exists
32    fn parent(&self) -> Option<Arc<dyn Layer>>;
33    /// Add a string triple
34    fn add_value_triple(&mut self, triple: ValueTriple);
35    /// Add an id triple
36    fn add_id_triple(&mut self, triple: IdTriple);
37    /// Remove a string triple
38    fn remove_value_triple(&mut self, triple: ValueTriple);
39    /// Remove an id triple
40    fn remove_id_triple(&mut self, triple: IdTriple);
41    /// Commit the layer to storage
42    fn commit(self) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send>>;
43    /// Commit a boxed layer to storage
44    fn commit_boxed(self: Box<Self>) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send>>;
45}
46
47/// A layer builder
48///
49/// `SimpleLayerBuilder` provides methods for adding and removing
50/// triples, and for committing the layer builder to storage.
51#[derive(Clone)]
52pub struct SimpleLayerBuilder<F: 'static + FileLoad + FileStore + Clone> {
53    name: [u32; 5],
54    parent: Option<Arc<dyn Layer>>,
55    files: LayerFiles<F>,
56    id_additions: Vec<IdTriple>,
57    id_removals: Vec<IdTriple>,
58
59    nodes_values_map: HashMap<ObjectType, u64>,
60    predicates_map: HashMap<String, u64>,
61    nodes_values_map_count: usize,
62    predicates_map_count: usize,
63    node_count: usize,
64    pred_count: usize,
65    val_count: usize,
66}
67
68impl<F: 'static + FileLoad + FileStore + Clone> SimpleLayerBuilder<F> {
69    /// Construct a layer builder for a base layer
70    pub fn new(name: [u32; 5], files: BaseLayerFiles<F>) -> Self {
71        Self {
72            name,
73            parent: None,
74            files: LayerFiles::Base(files),
75            id_additions: Vec::with_capacity(0),
76            id_removals: Vec::with_capacity(0),
77
78            nodes_values_map: HashMap::new(),
79            predicates_map: HashMap::new(),
80            nodes_values_map_count: 0,
81            predicates_map_count: 0,
82            node_count: 0,
83            pred_count: 0,
84            val_count: 0,
85        }
86    }
87
88    /// Construct a layer builder for a child layer
89    pub fn from_parent(name: [u32; 5], parent: Arc<dyn Layer>, files: ChildLayerFiles<F>) -> Self {
90        let nodes_values_map_count = parent.node_and_value_count();
91        let predicates_map_count = parent.predicate_count();
92        Self {
93            name,
94            parent: Some(parent),
95            files: LayerFiles::Child(files),
96            id_additions: Vec::new(),
97            id_removals: Vec::new(),
98
99            nodes_values_map: HashMap::new(),
100            predicates_map: HashMap::new(),
101            nodes_values_map_count,
102            predicates_map_count,
103            node_count: 0,
104            pred_count: 0,
105            val_count: 0,
106        }
107    }
108
109    fn calculate_triple(&mut self, triple: ValueTriple) -> IdTriple {
110        let subject = ObjectType::Node(triple.subject);
111        let predicate = triple.predicate;
112        let object = triple.object;
113        let subject_id = if let Some(n) = self.nodes_values_map.get(&subject) {
114            *n
115        } else {
116            let node_id = if let Some(node_id) = self
117                .parent
118                .as_ref()
119                .and_then(|p| p.subject_id(subject.node_ref().unwrap()))
120            {
121                node_id
122            } else {
123                self.nodes_values_map_count += 1;
124                self.node_count += 1;
125                self.nodes_values_map_count as u64
126            };
127            self.nodes_values_map.insert(subject, node_id);
128
129            node_id
130        };
131
132        let predicate_id = if let Some(p) = self.predicates_map.get(&predicate) {
133            *p
134        } else {
135            let predicate_id = if let Some(predicate_id) = self
136                .parent
137                .as_ref()
138                .and_then(|p| p.predicate_id(&predicate))
139            {
140                predicate_id
141            } else {
142                self.predicates_map_count += 1;
143                self.pred_count += 1;
144                self.predicates_map_count as u64
145            };
146            self.predicates_map.insert(predicate, predicate_id);
147
148            predicate_id
149        };
150        let object_id = if let Some(o) = self.nodes_values_map.get(&object) {
151            *o
152        } else {
153            match object {
154                ObjectType::Node(n) => {
155                    let node_id = if let Some(node_id) = self
156                        .parent
157                        .as_ref()
158                        .and_then(|p| p.object_node_id(n.as_str()))
159                    {
160                        node_id
161                    } else {
162                        self.nodes_values_map_count += 1;
163                        self.node_count += 1;
164                        self.nodes_values_map_count as u64
165                    };
166                    self.nodes_values_map.insert(ObjectType::Node(n), node_id);
167
168                    node_id
169                }
170                ObjectType::Value(v) => {
171                    let value_id = if let Some(value_id) =
172                        self.parent.as_ref().and_then(|p| p.object_value_id(&v))
173                    {
174                        value_id
175                    } else {
176                        self.nodes_values_map_count += 1;
177                        self.val_count += 1;
178                        self.nodes_values_map_count as u64
179                    };
180                    self.nodes_values_map.insert(ObjectType::Value(v), value_id);
181
182                    value_id
183                }
184            }
185        };
186
187        IdTriple::new(subject_id, predicate_id, object_id)
188    }
189}
190
191impl<F: 'static + FileLoad + FileStore + Clone> LayerBuilder for SimpleLayerBuilder<F> {
192    fn name(&self) -> [u32; 5] {
193        self.name
194    }
195
196    fn parent(&self) -> Option<Arc<dyn Layer>> {
197        self.parent.clone()
198    }
199
200    fn add_value_triple(&mut self, addition: ValueTriple) {
201        let triple = self.calculate_triple(addition);
202        self.id_additions.push(triple);
203    }
204
205    fn add_id_triple(&mut self, triple: IdTriple) {
206        self.id_additions.push(triple);
207    }
208
209    fn remove_value_triple(&mut self, removal: ValueTriple) {
210        let triple = self.calculate_triple(removal);
211        self.id_removals.push(triple);
212    }
213
214    fn remove_id_triple(&mut self, triple: IdTriple) {
215        self.id_removals.push(triple);
216    }
217
218    fn commit(self) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send>> {
219        let SimpleLayerBuilder {
220            name: _,
221            parent,
222            files,
223            mut id_additions,
224            mut id_removals,
225
226            nodes_values_map,
227            predicates_map,
228            nodes_values_map_count: _,
229            predicates_map_count: _,
230            node_count,
231            pred_count,
232            val_count,
233        } = self;
234        let parent_node_value_offset = parent
235            .as_ref()
236            .map(|p| p.node_and_value_count())
237            .unwrap_or(0);
238        let parent_predicate_offset = parent.as_ref().map(|p| p.predicate_count()).unwrap_or(0);
239        // time to deduplicate!
240
241        id_additions.sort();
242        id_additions.dedup();
243        id_additions.shrink_to_fit();
244        id_removals.sort();
245        id_removals.dedup();
246        id_removals.shrink_to_fit();
247
248        // we now need to figure out noops.
249        let mut additions_it = id_additions.iter_mut().peekable();
250        let mut removals_it = id_removals.iter_mut().peekable();
251        loop {
252            let addition = additions_it.peek();
253            let removal = removals_it.peek();
254
255            // advance those iterators in order until we reach the end
256            if removal.is_none() {
257                break;
258            }
259            if addition.is_none() {
260                // loop over the remaining removals to nullify everything that should be a noop due to being out of range
261                for removal in removals_it {
262                    if removal.subject > parent_node_value_offset as u64
263                        || removal.predicate > parent_predicate_offset as u64
264                        || removal.object > parent_node_value_offset as u64
265                    {
266                        *removal = IdTriple::new(0, 0, 0);
267                    }
268                }
269                break;
270            }
271
272            if addition < removal {
273                additions_it.next();
274            } else if addition > removal {
275                let removal = removals_it.next().unwrap();
276                // we need to clear a potential noop
277                if removal.subject > parent_node_value_offset as u64
278                    || removal.predicate > parent_predicate_offset as u64
279                    || removal.object > parent_node_value_offset as u64
280                {
281                    *removal = IdTriple::new(0, 0, 0);
282                }
283            } else {
284                // same triple! make it zeroes to express a no-op without having to shift around triples
285                let addition = additions_it.next().unwrap();
286                let removal = removals_it.next().unwrap();
287                *addition = IdTriple::new(0, 0, 0);
288                *removal = IdTriple::new(0, 0, 0);
289            }
290        }
291
292        // some dict entries might now be unused. We need to do an existence check.
293        let mut node_value_existences = bitvec![0;node_count + val_count];
294        let mut predicate_existences = bitvec![0;pred_count];
295        for triple in id_additions.iter().chain(id_removals.iter()) {
296            if triple.subject > parent_node_value_offset as u64 {
297                node_value_existences
298                    .set(triple.subject as usize - parent_node_value_offset - 1, true);
299            }
300            if triple.predicate > parent_predicate_offset as u64 {
301                predicate_existences.set(
302                    triple.predicate as usize - parent_predicate_offset - 1,
303                    true,
304                );
305            }
306            if triple.object > parent_node_value_offset as u64 {
307                node_value_existences
308                    .set(triple.object as usize - parent_node_value_offset - 1, true);
309            }
310        }
311
312        // time to collect our dictionaries.
313        let mut nodes = Vec::with_capacity(node_count);
314        let mut predicates = Vec::with_capacity(pred_count);
315        let mut values = Vec::with_capacity(val_count);
316
317        for (entry, id) in nodes_values_map.into_iter() {
318            if id <= parent_node_value_offset as u64 {
319                // we don't care about these ids. they are already correct in the triples
320                continue;
321            }
322            if !node_value_existences[id as usize - parent_node_value_offset - 1] {
323                // while originally collected, in the end this entry was unused
324                continue;
325            }
326            match entry {
327                ObjectType::Node(n) => nodes.push((n, id)),
328                ObjectType::Value(v) => values.push((v, id)),
329            }
330        }
331        for (entry, id) in predicates_map.into_iter() {
332            if id <= parent_predicate_offset as u64 {
333                // we don't care about these ids. they are already correct in the triples
334                continue;
335            }
336            if !predicate_existences[id as usize - parent_predicate_offset - 1] {
337                // while originally collected, in the end this entry was unused
338                continue;
339            }
340
341            predicates.push((entry, id));
342        }
343
344        nodes.sort();
345        predicates.sort();
346        values.sort();
347
348        // build up conversion maps for converting the id triples to their final id
349        let mut node_value_id_map = vec![0_u64; node_count + val_count];
350        let mut predicate_id_map = vec![0_u64; pred_count];
351        for (new_id, (_, old_id)) in nodes.iter().enumerate() {
352            let mapped_old_id = *old_id as usize - parent_node_value_offset - 1;
353            node_value_id_map[mapped_old_id] = (new_id + parent_node_value_offset + 1) as u64;
354        }
355        for (new_id, (_, old_id)) in values.iter().enumerate() {
356            let mapped_old_id = *old_id as usize - parent_node_value_offset - 1;
357            node_value_id_map[mapped_old_id] =
358                (new_id + parent_node_value_offset + nodes.len() + 1) as u64;
359        }
360        for (new_id, (_, old_id)) in predicates.iter().enumerate() {
361            let mapped_old_id = *old_id as usize - parent_predicate_offset - 1;
362            predicate_id_map[mapped_old_id] = (new_id + parent_predicate_offset + 1) as u64;
363        }
364
365        // now we have to map all the additions and removals
366        for triple in id_additions.iter_mut().chain(id_removals.iter_mut()) {
367            if triple.subject > parent_node_value_offset as u64 {
368                let mapped_id = triple.subject as usize - parent_node_value_offset - 1;
369                triple.subject = node_value_id_map[mapped_id];
370            }
371            if triple.predicate > parent_predicate_offset as u64 {
372                let mapped_id = triple.predicate as usize - parent_predicate_offset - 1;
373                triple.predicate = predicate_id_map[mapped_id];
374            }
375            if triple.object > parent_node_value_offset as u64 {
376                let mapped_id = triple.object as usize - parent_node_value_offset - 1;
377                triple.object = node_value_id_map[mapped_id];
378            }
379        }
380        // and resort them
381        id_additions.sort();
382        id_removals.sort();
383
384        // great! everything is now in order. Let's stuff it into an actual builder
385        Box::pin(async {
386            match parent {
387                Some(parent) => {
388                    let files = files.into_child();
389                    let mut builder =
390                        ChildLayerFileBuilder::from_files(parent.clone(), &files).await?;
391
392                    builder.add_nodes(nodes.into_iter().map(|x| x.0));
393                    builder.add_predicates(predicates.into_iter().map(|x| x.0));
394                    builder.add_values(values.into_iter().map(|x| x.0));
395
396                    let mut builder = builder.into_phase2().await?;
397
398                    builder.add_id_triples(id_additions).await?;
399                    builder.remove_id_triples(id_removals).await?;
400
401                    builder.finalize().await
402                }
403                None => {
404                    // TODO almost same as above, should be more generic
405                    let files = files.into_base();
406                    let mut builder = BaseLayerFileBuilder::from_files(&files).await?;
407
408                    builder.add_nodes(nodes.into_iter().map(|x| x.0));
409                    builder.add_predicates(predicates.into_iter().map(|x| x.0));
410                    builder.add_values(values.into_iter().map(|x| x.0));
411
412                    let mut builder = builder.into_phase2().await?;
413
414                    builder.add_id_triples(id_additions).await?;
415
416                    builder.finalize().await
417                }
418            }
419        })
420    }
421
422    fn commit_boxed(self: Box<Self>) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send>> {
423        let builder = *self;
424        builder.commit()
425    }
426}
427
428#[cfg(test)]
429mod tests {
430    use super::*;
431    use crate::storage::memory::*;
432    use tdb_succinct::TdbDataType;
433
434    fn new_base_files() -> BaseLayerFiles<MemoryBackedStore> {
435        // TODO inline
436        base_layer_memory_files()
437    }
438
439    fn new_child_files() -> ChildLayerFiles<MemoryBackedStore> {
440        // TODO inline
441        child_layer_memory_files()
442    }
443
444    async fn example_base_layer() -> Arc<InternalLayer> {
445        let name = [1, 2, 3, 4, 5];
446        let files = new_base_files();
447        let mut builder = SimpleLayerBuilder::new(name, files.clone());
448
449        builder.add_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
450        builder.add_value_triple(ValueTriple::new_string_value("pig", "says", "oink"));
451        builder.add_value_triple(ValueTriple::new_string_value("duck", "says", "quack"));
452
453        builder.commit().await.unwrap();
454
455        let layer = BaseLayer::load_from_files(name, &files).await.unwrap();
456        Arc::new(layer.into())
457    }
458
459    #[tokio::test]
460    async fn simple_base_layer_construction() {
461        let layer = example_base_layer().await;
462
463        assert!(layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo")));
464        assert!(layer.value_triple_exists(&ValueTriple::new_string_value("pig", "says", "oink")));
465        assert!(layer.value_triple_exists(&ValueTriple::new_string_value("duck", "says", "quack")));
466    }
467
468    #[tokio::test]
469    async fn simple_child_layer_construction() {
470        let base_layer = example_base_layer().await;
471        let files = new_child_files();
472        let name = [0, 0, 0, 0, 0];
473        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
474
475        builder.add_value_triple(ValueTriple::new_string_value("horse", "says", "neigh"));
476        builder.add_value_triple(ValueTriple::new_node("horse", "likes", "cow"));
477        builder.remove_value_triple(ValueTriple::new_string_value("duck", "says", "quack"));
478
479        let child_layer = Arc::new(
480            async {
481                builder.commit().await?;
482
483                ChildLayer::load_from_files(name, base_layer, &files).await
484            }
485            .await
486            .unwrap(),
487        );
488
489        assert!(child_layer
490            .value_triple_exists(&ValueTriple::new_string_value("horse", "says", "neigh")));
491        assert!(child_layer.value_triple_exists(&ValueTriple::new_node("horse", "likes", "cow")));
492        assert!(
493            child_layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo"))
494        );
495        assert!(
496            child_layer.value_triple_exists(&ValueTriple::new_string_value("pig", "says", "oink"))
497        );
498        assert!(!child_layer
499            .value_triple_exists(&ValueTriple::new_string_value("duck", "says", "quack")));
500    }
501
502    #[tokio::test]
503    async fn multi_level_layers() {
504        let base_layer = example_base_layer().await;
505        let name2 = [0, 0, 0, 0, 0];
506        let files2 = new_child_files();
507        let mut builder =
508            SimpleLayerBuilder::from_parent(name2, base_layer.clone(), files2.clone());
509
510        builder.add_value_triple(ValueTriple::new_string_value("horse", "says", "neigh"));
511        builder.add_value_triple(ValueTriple::new_node("horse", "likes", "cow"));
512        builder.remove_value_triple(ValueTriple::new_string_value("duck", "says", "quack"));
513
514        builder.commit().await.unwrap();
515        let layer2: Arc<InternalLayer> = Arc::new(
516            ChildLayer::load_from_files(name2, base_layer, &files2)
517                .await
518                .unwrap()
519                .into(),
520        );
521
522        let name3 = [0, 0, 0, 0, 1];
523        let files3 = new_child_files();
524        builder = SimpleLayerBuilder::from_parent(name3, layer2.clone(), files3.clone());
525        builder.remove_value_triple(ValueTriple::new_node("horse", "likes", "cow"));
526        builder.add_value_triple(ValueTriple::new_node("horse", "likes", "pig"));
527        builder.add_value_triple(ValueTriple::new_string_value("duck", "says", "quack"));
528
529        builder.commit().await.unwrap();
530        let layer3: Arc<InternalLayer> = Arc::new(
531            ChildLayer::load_from_files(name3, layer2, &files3)
532                .await
533                .unwrap()
534                .into(),
535        );
536
537        let name4 = [0, 0, 0, 0, 1];
538        let files4 = new_child_files();
539        builder = SimpleLayerBuilder::from_parent(name4, layer3.clone(), files4.clone());
540        builder.remove_value_triple(ValueTriple::new_string_value("pig", "says", "oink"));
541        builder.add_value_triple(ValueTriple::new_node("cow", "likes", "horse"));
542        builder.commit().await.unwrap();
543        let layer4: Arc<InternalLayer> = Arc::new(
544            ChildLayer::load_from_files(name4, layer3, &files4)
545                .await
546                .unwrap()
547                .into(),
548        );
549
550        assert!(layer4.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo")));
551        assert!(layer4.value_triple_exists(&ValueTriple::new_string_value("duck", "says", "quack")));
552        assert!(
553            layer4.value_triple_exists(&ValueTriple::new_string_value("horse", "says", "neigh"))
554        );
555        assert!(layer4.value_triple_exists(&ValueTriple::new_node("horse", "likes", "pig")));
556        assert!(layer4.value_triple_exists(&ValueTriple::new_node("cow", "likes", "horse")));
557
558        assert!(!layer4.value_triple_exists(&ValueTriple::new_string_value("pig", "says", "oink")));
559        assert!(!layer4.value_triple_exists(&ValueTriple::new_node("horse", "likes", "cow")));
560    }
561
562    #[tokio::test]
563    async fn remove_and_add_same_triple_on_base_layer_is_noop() {
564        let files = new_base_files();
565        let name = [0, 0, 0, 0, 0];
566        let mut builder = SimpleLayerBuilder::new(name, files.clone());
567
568        builder.remove_value_triple(ValueTriple::new_string_value("crow", "says", "caw"));
569        builder.add_value_triple(ValueTriple::new_string_value("crow", "says", "caw"));
570
571        builder.commit().await.unwrap();
572        let base_layer: Arc<InternalLayer> = Arc::new(
573            BaseLayer::load_from_files(name, &files)
574                .await
575                .unwrap()
576                .into(),
577        );
578
579        assert!(
580            !base_layer.value_triple_exists(&ValueTriple::new_string_value("crow", "says", "caw"))
581        );
582    }
583
584    #[tokio::test]
585    async fn add_and_remove_same_triple_on_base_layer_is_noop() {
586        let files = new_base_files();
587        let name = [0, 0, 0, 0, 0];
588        let mut builder = SimpleLayerBuilder::new(name, files.clone());
589
590        builder.add_value_triple(ValueTriple::new_string_value("crow", "says", "caw"));
591        builder.remove_value_triple(ValueTriple::new_string_value("crow", "says", "caw"));
592
593        builder.commit().await.unwrap();
594        let base_layer: Arc<InternalLayer> = Arc::new(
595            BaseLayer::load_from_files(name, &files)
596                .await
597                .unwrap()
598                .into(),
599        );
600
601        assert!(
602            !base_layer.value_triple_exists(&ValueTriple::new_string_value("crow", "says", "caw"))
603        );
604    }
605
606    #[tokio::test]
607    async fn remove_and_add_same_existing_triple_on_child_layer_is_noop() {
608        let base_layer = example_base_layer().await;
609        let files = new_child_files();
610        let name = [0, 0, 0, 0, 0];
611        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
612
613        builder.remove_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
614        builder.add_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
615
616        builder.commit().await.unwrap();
617        let child_layer: Arc<InternalLayer> = Arc::new(
618            ChildLayer::load_from_files(name, base_layer, &files)
619                .await
620                .unwrap()
621                .into(),
622        );
623
624        assert!(
625            child_layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo"))
626        );
627    }
628
629    #[tokio::test]
630    async fn add_and_remove_same_existing_triple_on_child_layer_is_noop() {
631        let base_layer = example_base_layer().await;
632        let files = new_child_files();
633        let name = [0, 0, 0, 0, 0];
634        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
635
636        builder.add_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
637        builder.remove_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
638
639        builder.commit().await.unwrap();
640        let child_layer: Arc<InternalLayer> = Arc::new(
641            ChildLayer::load_from_files(name, base_layer, &files)
642                .await
643                .unwrap()
644                .into(),
645        );
646
647        assert!(
648            child_layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo"))
649        );
650    }
651
652    #[tokio::test]
653    async fn remove_and_add_same_nonexisting_triple_on_child_layer_is_noop() {
654        let base_layer = example_base_layer().await;
655        let files = new_child_files();
656        let name = [0, 0, 0, 0, 0];
657        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
658
659        builder.remove_value_triple(ValueTriple::new_string_value("crow", "says", "caw"));
660        builder.add_value_triple(ValueTriple::new_string_value("crow", "says", "caw"));
661
662        builder.commit().await.unwrap();
663        let child_layer: Arc<InternalLayer> = Arc::new(
664            ChildLayer::load_from_files(name, base_layer, &files)
665                .await
666                .unwrap()
667                .into(),
668        );
669
670        assert!(
671            !child_layer.value_triple_exists(&ValueTriple::new_string_value("crow", "says", "caw"))
672        );
673    }
674
675    #[tokio::test]
676    async fn add_and_remove_same_nonexisting_triple_on_child_layer_is_noop() {
677        let base_layer = example_base_layer().await;
678        let files = new_child_files();
679        let name = [0, 0, 0, 0, 0];
680        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
681
682        builder.add_value_triple(ValueTriple::new_string_value("crow", "says", "caw"));
683        builder.remove_value_triple(ValueTriple::new_string_value("crow", "says", "caw"));
684
685        builder.commit().await.unwrap();
686        let child_layer: Arc<InternalLayer> = Arc::new(
687            ChildLayer::load_from_files(name, base_layer, &files)
688                .await
689                .unwrap()
690                .into(),
691        );
692
693        assert!(
694            !child_layer.value_triple_exists(&ValueTriple::new_string_value("crow", "says", "caw"))
695        );
696    }
697
698    #[tokio::test]
699    async fn remove_and_add_same_triple_by_id_and_string_on_child_layer_is_noop() {
700        let base_layer = example_base_layer().await;
701        let files = new_child_files();
702        let name = [0, 0, 0, 0, 0];
703        let node_id = base_layer.subject_id("cow").unwrap();
704        let predicate_id = base_layer.predicate_id("says").unwrap();
705        let value_id = base_layer
706            .object_value_id(&String::make_entry(&"moo"))
707            .unwrap();
708        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
709
710        builder.remove_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
711        builder.add_id_triple(IdTriple::new(node_id, predicate_id, value_id));
712
713        builder.commit().await.unwrap();
714        let child_layer: Arc<InternalLayer> = Arc::new(
715            ChildLayer::load_from_files(name, base_layer, &files)
716                .await
717                .unwrap()
718                .into(),
719        );
720
721        assert!(
722            child_layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo"))
723        );
724    }
725
726    #[tokio::test]
727    async fn remove_and_add_same_triple_by_string_and_id_on_child_layer_is_noop() {
728        let base_layer = example_base_layer().await;
729        let files = new_child_files();
730        let name = [0, 0, 0, 0, 0];
731        let node_id = base_layer.subject_id("cow").unwrap();
732        let predicate_id = base_layer.predicate_id("says").unwrap();
733        let value_id = base_layer
734            .object_value_id(&String::make_entry(&"moo"))
735            .unwrap();
736        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
737
738        builder.remove_id_triple(IdTriple::new(node_id, predicate_id, value_id));
739        builder.add_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
740
741        builder.commit().await.unwrap();
742        let child_layer: Arc<InternalLayer> = Arc::new(
743            ChildLayer::load_from_files(name, base_layer, &files)
744                .await
745                .unwrap()
746                .into(),
747        );
748
749        assert!(
750            child_layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo"))
751        );
752    }
753
754    #[tokio::test]
755    async fn add_and_remove_same_triple_by_id_and_string_on_child_layer_is_noop() {
756        let base_layer = example_base_layer().await;
757        let files = new_child_files();
758        let name = [0, 0, 0, 0, 0];
759        let node_id = base_layer.subject_id("cow").unwrap();
760        let predicate_id = base_layer.predicate_id("says").unwrap();
761        let value_id = base_layer
762            .object_value_id(&String::make_entry(&"moo"))
763            .unwrap();
764        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
765
766        builder.add_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
767        builder.remove_id_triple(IdTriple::new(node_id, predicate_id, value_id));
768
769        builder.commit().await.unwrap();
770        let child_layer: Arc<InternalLayer> = Arc::new(
771            ChildLayer::load_from_files(name, base_layer, &files)
772                .await
773                .unwrap()
774                .into(),
775        );
776
777        assert!(
778            child_layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo"))
779        );
780    }
781
782    #[tokio::test]
783    async fn add_and_remove_same_triple_by_string_and_id_on_child_layer_is_noop() {
784        let base_layer = example_base_layer().await;
785        let files = new_child_files();
786        let name = [0, 0, 0, 0, 0];
787        let node_id = base_layer.subject_id("cow").unwrap();
788        let predicate_id = base_layer.predicate_id("says").unwrap();
789        let value_id = base_layer
790            .object_value_id(&String::make_entry(&"moo"))
791            .unwrap();
792        let mut builder = SimpleLayerBuilder::from_parent(name, base_layer.clone(), files.clone());
793
794        builder.add_id_triple(IdTriple::new(node_id, predicate_id, value_id));
795        builder.remove_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
796
797        builder.commit().await.unwrap();
798        let child_layer: Arc<InternalLayer> = Arc::new(
799            ChildLayer::load_from_files(name, base_layer, &files)
800                .await
801                .unwrap()
802                .into(),
803        );
804
805        assert!(
806            child_layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo"))
807        );
808    }
809}