Skip to main content

corium_query/
entity.rs

1//! The lazy entity API: map-like navigation over EAVT.
2
3use corium_core::{AttrId, EntityId, IndexOrder, Keyword, Value};
4use corium_db::{Db, key_prefix};
5
6/// A lazy, map-like view of one entity. Nothing is read until asked for;
7/// each access is an index prefix scan against the underlying [`Db`] value.
8#[derive(Clone, Copy, Debug)]
9pub struct Entity<'a> {
10    db: &'a Db,
11    id: EntityId,
12}
13
14impl<'a> Entity<'a> {
15    /// Wraps an entity id over a database value.
16    #[must_use]
17    pub const fn new(db: &'a Db, id: EntityId) -> Self {
18        Self { db, id }
19    }
20
21    /// The entity id.
22    #[must_use]
23    pub const fn id(&self) -> EntityId {
24        self.id
25    }
26
27    /// The database value this entity reads from.
28    #[must_use]
29    pub const fn db(&self) -> &'a Db {
30        self.db
31    }
32
33    /// Values of an attribute (empty when absent).
34    #[must_use]
35    pub fn get(&self, attr: AttrId) -> Vec<Value> {
36        self.db.values(self.id, attr)
37    }
38
39    /// Values of an attribute by ident keyword.
40    #[must_use]
41    pub fn get_kw(&self, keyword: &Keyword) -> Vec<Value> {
42        self.db
43            .idents()
44            .entid(keyword)
45            .map(|attr| self.get(attr))
46            .unwrap_or_default()
47    }
48
49    /// Attributes present on this entity, in id order.
50    #[must_use]
51    pub fn keys(&self) -> Vec<AttrId> {
52        let prefix = key_prefix(IndexOrder::Eavt, Some(self.id), None, None);
53        let mut attrs: Vec<AttrId> = self
54            .db
55            .datoms_prefix(IndexOrder::Eavt, &prefix)
56            .map(|datom| datom.a)
57            .collect();
58        attrs.dedup();
59        attrs
60    }
61
62    /// Navigates a reference attribute to child entities.
63    #[must_use]
64    pub fn refs(&self, attr: AttrId) -> Vec<Entity<'a>> {
65        self.get(attr)
66            .into_iter()
67            .filter_map(|value| match value {
68                Value::Ref(child) => Some(Entity::new(self.db, child)),
69                _ => None,
70            })
71            .collect()
72    }
73
74    /// Reverse navigation: entities whose `attr` references this entity.
75    #[must_use]
76    pub fn reverse(&self, attr: AttrId) -> Vec<Entity<'a>> {
77        let value = Value::Ref(self.id);
78        let prefix = key_prefix(IndexOrder::Vaet, None, Some(attr), Some(&value));
79        self.db
80            .datoms_prefix(IndexOrder::Vaet, &prefix)
81            .map(|datom| Entity::new(self.db, datom.e))
82            .collect()
83    }
84}