1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// SPDX-FileCopyrightText: 2021 Lutris Engineering, Inc
// SPDX-License-Identifier: BlueOak-1.0.0 OR BSD-2-Clause-Patent
// SPDX-FileContributor: Piper McCorkle <piper@lutris.engineering>
use std::cmp::Ordering;
use crate::{builtin_idents, storage::Storage, Database, Datom, QueryError, Value, ID};
/**
An un-resolved entity [ID], which can be used to resolve entities by
[ident](crate::builtin_idents::ident) or
[unique](crate::builtin_idents::unique) attribute
*/
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum EID {
/// A resolved entity [ID]
Resolved(ID),
/// Resolve an entity by its [ident](crate::builtin_idents::ident)
Ident(String),
/// Resolve an entity by a static
/// [ident](crate::builtin_idents::ident)
InternedIdent(&'static str),
/// Resolve an entity by a [unique](crate::builtin_idents::unique)
/// attribute
Unique(
/// [unique](crate::builtin_idents::unique) attribute
Box<Self>,
/// Value
Value,
),
}
fn by_t(a: &Datom, b: &Datom) -> Ordering {
a.t.cmp(&b.t)
}
impl EID {
/**
Create an [EID] to resolve an entity by a
[unique](crate::builtin_idents::unique) attribute
*/
pub fn unique(eid: Self, val: Value) -> Self {
Self::Unique(eid.into(), val)
}
/// Resolve this [EID] into its [ID] according to a [Database]
pub fn resolve<'c, S: Storage>(&self, db: &Database<'c, S>) -> Result<ID, QueryError> {
match self {
Self::Resolved(id) => Ok(*id),
Self::Ident(ident_str) => {
if let Some(entity) = builtin_idents::BUILTIN_ENTITIES_BY_IDENT.get(ident_str) {
if let Some(Value::ID(id)) = entity.get(&builtin_idents::ID) {
return Ok(id.to_owned());
}
}
let ident_val = Value::from(ident_str.as_str());
db.datoms_for_attribute_value(builtin_idents::IDENT, ident_val)?
.max_by(by_t)
.map(|datom| datom.entity)
.ok_or_else(|| QueryError::UnresolvedEID(self.clone()))
}
Self::InternedIdent(ident_str) => Self::Ident(ident_str.to_string()).resolve(db),
Self::Unique(attr_eid, val) => {
let attr_id = attr_eid.resolve(db)?;
db.datoms_for_attribute_value(attr_id, val.to_owned())?
.max_by(by_t)
.map(|datom| datom.entity)
.ok_or_else(|| QueryError::UnresolvedEID(self.clone()))
}
}
}
}
impl From<ID> for EID {
fn from(id: ID) -> Self {
Self::Resolved(id)
}
}
impl From<String> for EID {
fn from(ident: String) -> Self {
Self::Ident(ident)
}
}
impl From<&'static str> for EID {
fn from(ident: &'static str) -> Self {
Self::InternedIdent(ident)
}
}