typedb_driver/concept/
mod.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20use std::fmt::{Debug, Display, Formatter};
21
22use chrono::{DateTime, NaiveDate, NaiveDateTime};
23
24pub use self::{
25    instance::{Attribute, Entity, Relation},
26    type_::{AttributeType, EntityType, RelationType, RoleType},
27    value::{Value, ValueType},
28};
29use crate::{
30    concept::value::{Decimal, Duration, Struct, TimeZone},
31    IID,
32};
33
34pub mod instance;
35pub mod type_;
36pub mod value;
37
38/// The fundamental TypeQL object.
39#[derive(Clone, PartialEq)]
40pub enum Concept {
41    EntityType(EntityType),
42    RelationType(RelationType),
43    RoleType(RoleType),
44    AttributeType(AttributeType),
45
46    Entity(Entity),
47    Relation(Relation),
48    Attribute(Attribute),
49
50    Value(Value),
51}
52
53#[derive(Clone, PartialEq)]
54pub enum ConceptCategory {
55    EntityType,
56    RelationType,
57    RoleType,
58    AttributeType,
59    Entity,
60    Relation,
61    Attribute,
62    Value,
63}
64
65impl ConceptCategory {
66    pub const fn name(&self) -> &'static str {
67        match self {
68            ConceptCategory::EntityType => "EntityType",
69            ConceptCategory::RelationType => "RelationType",
70            ConceptCategory::RoleType => "RoleType",
71            ConceptCategory::AttributeType => "AttributeType",
72            ConceptCategory::Entity => "Entity",
73            ConceptCategory::Relation => "Relation",
74            ConceptCategory::Attribute => "Attribute",
75            ConceptCategory::Value => "Value",
76        }
77    }
78}
79
80impl Display for ConceptCategory {
81    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
82        Debug::fmt(self, f)
83    }
84}
85
86impl Debug for ConceptCategory {
87    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
88        write!(f, "{}", self.name())
89    }
90}
91
92impl Concept {
93    pub(crate) const UNKNOWN_LABEL: &'static str = "unknown";
94
95    /// Retrieves the unique id (IID) of this Concept.
96    /// If this is an Entity or Relation Instance, returns the IID of the instance.
97    /// Otherwise, returns None.
98    pub fn try_get_iid(&self) -> Option<&IID> {
99        match self {
100            Self::Entity(entity) => Some(&entity.iid),
101            Self::Relation(relation) => Some(&relation.iid),
102            _ => None,
103        }
104    }
105
106    /// Retrieves the label of this Concept.
107    /// If this is an Instance, returns the label of the type of this instance ("unknown" if type fetching is disabled).
108    /// If this is a Value, returns the label of the value type of the value.
109    /// If this is a Type, returns the label of the type.
110    pub fn get_label(&self) -> &str {
111        self.try_get_label().unwrap_or(Self::UNKNOWN_LABEL)
112    }
113
114    /// Retrieves the optional label of the concept.
115    /// If this is an Instance, returns the label of the type of this instance (None if type fetching is disabled).
116    /// If this is a Value, returns the label of the value type of the value.
117    /// If this is a Type, returns the label of the type.
118    pub fn try_get_label(&self) -> Option<&str> {
119        match self {
120            Self::EntityType(entity_type) => Some(entity_type.label()),
121            Self::RelationType(relation_type) => Some(relation_type.label()),
122            Self::AttributeType(attribute_type) => Some(attribute_type.label()),
123            Self::RoleType(role_type) => Some(role_type.label()),
124            Self::Entity(entity) => entity.type_().map(|type_| type_.label()),
125            Self::Relation(relation) => relation.type_().map(|type_| type_.label()),
126            Self::Attribute(attribute) => attribute.type_().map(|type_| type_.label()),
127            Self::Value(value) => Some(value.get_type_name()),
128        }
129    }
130
131    /// Retrieves the label of the value type of the concept, if it exists.
132    /// If this is an Attribute Instance, returns the label of the value of this instance.
133    /// If this is a Value, returns the label of the value.
134    /// If this is an Attribute Type, returns the label of the value type that the schema permits for the attribute type, if one is defined.
135    /// Otherwise, returns None.
136    pub fn try_get_value_label(&self) -> Option<&str> {
137        match self {
138            Self::AttributeType(attribute_type) => attribute_type.value_type().map(|value_type| value_type.name()),
139            Self::Attribute(attribute) => Some(attribute.value.get_type_name()),
140            Self::Value(value) => Some(value.get_type_name()),
141            _ => None,
142        }
143    }
144
145    /// Retrieves the value type enum of the concept, if it exists.
146    /// If this is an Attribute Instance, returns the value type of the value of this instance.
147    /// If this is a Value, returns the value type of the value.
148    /// If this is an Attribute Type, returns value type that the schema permits for the attribute type, if one is defined.
149    /// Otherwise, returns None.
150    pub fn try_get_value_type(&self) -> Option<ValueType> {
151        match self {
152            Self::AttributeType(attribute_type) => attribute_type.value_type().cloned(),
153            Self::Attribute(attribute) => Some(attribute.value.get_type()),
154            Self::Value(value) => Some(value.get_type()),
155            _ => None,
156        }
157    }
158
159    /// Retrieves the value of this Concept, if it exists.
160    /// If this is an Attribute Instance, returns the value of this instance.
161    /// If this a Value, returns the value.
162    /// Otherwise, returns empty.
163    pub fn try_get_value(&self) -> Option<&Value> {
164        match self {
165            Self::Attribute(attribute) => Some(&attribute.value),
166            Self::Value(value) => Some(value),
167            _ => None,
168        }
169    }
170
171    /// Retrieves the boolean value of this Concept, if it exists.
172    /// If this is a boolean-valued Attribute Instance, returns the boolean value of this instance.
173    /// If this a boolean-valued Value, returns the boolean value.
174    /// Otherwise, returns None.
175    pub fn try_get_boolean(&self) -> Option<bool> {
176        self.try_get_value().map(|value| value.get_boolean()).flatten()
177    }
178
179    /// Retrieves the integer value of this Concept, if it exists.
180    /// If this is an integer-valued Attribute Instance, returns the integer value of this instance.
181    /// If this an integer-valued Value, returns the integer value.
182    /// Otherwise, returns None.
183    pub fn try_get_integer(&self) -> Option<i64> {
184        self.try_get_value().map(|value| value.get_integer()).flatten()
185    }
186
187    /// Retrieves the double value of this Concept, if it exists.
188    /// If this is a double-valued Attribute Instance, returns the double value of this instance.
189    /// If this a double-valued Value, returns the double value.
190    /// Otherwise, returns None.
191    pub fn try_get_double(&self) -> Option<f64> {
192        self.try_get_value().map(|value| value.get_double()).flatten()
193    }
194
195    /// Retrieves the fixed-decimal value of this Concept, if it exists.
196    /// If this is a fixed-decimal valued Attribute Instance, returns the fixed-decimal value of this instance.
197    /// If this a fixed-decimal valued Value, returns the fixed-decimal value.
198    /// Otherwise, returns None.
199    pub fn try_get_decimal(&self) -> Option<Decimal> {
200        self.try_get_value().map(|value| value.get_decimal()).flatten()
201    }
202
203    /// Retrieves the string value of this Concept, if it exists.
204    /// If this is a string-valued Attribute Instance, returns the string value of this instance.
205    /// If this a string-valued Value, returns the string value.
206    /// Otherwise, returns None.
207    pub fn try_get_string(&self) -> Option<&str> {
208        self.try_get_value().map(|value| value.get_string()).flatten()
209    }
210
211    /// Retrieves the date value of this Concept, if it exists.
212    /// If this is a date-valued Attribute Instance, returns the date value of this instance.
213    /// If this a date-valued Value, returns the date value.
214    /// Otherwise, returns None.
215    pub fn try_get_date(&self) -> Option<NaiveDate> {
216        self.try_get_value().map(|value| value.get_date()).flatten()
217    }
218
219    /// Retrieves the datetime value of this Concept, if it exists.
220    /// If this is a datetime-valued Attribute Instance, returns the datetime value of this instance.
221    /// If this a datetime-valued Value, returns the datetime value.
222    /// Otherwise, returns None.
223    pub fn try_get_datetime(&self) -> Option<NaiveDateTime> {
224        self.try_get_value().map(|value| value.get_datetime()).flatten()
225    }
226
227    /// Retrieves the timezoned-datetime value of this Concept, if it exists.
228    /// If this is a timezoned-datetime valued Attribute Instance, returns the timezoned-datetime value of this instance.
229    /// If this a timezoned-datetime valued Value, returns the timezoned-datetime value.
230    /// Otherwise, returns None.
231    pub fn try_get_datetime_tz(&self) -> Option<DateTime<TimeZone>> {
232        self.try_get_value().map(|value| value.get_datetime_tz()).flatten()
233    }
234
235    /// Retrieves the duration value of this Concept, if it exists.
236    /// If this is a duration-valued Attribute Instance, returns the duration value of this instance.
237    /// If this a duration-valued Value, returns the duration value.
238    /// Otherwise, returns None.
239    pub fn try_get_duration(&self) -> Option<Duration> {
240        self.try_get_value().map(|value| value.get_duration()).flatten()
241    }
242
243    /// Retrieves the struct value of this Concept, if it exists.
244    /// If this is a struct-valued Attribute Instance, returns the struct value of this instance.
245    /// If this a struct-valued Value, returns the struct value.
246    /// Otherwise, returns None.
247    pub fn try_get_struct(&self) -> Option<&Struct> {
248        self.try_get_value().map(|value| value.get_struct()).flatten()
249    }
250
251    /// Retrieves the category of this Concept.
252    pub fn get_category(&self) -> ConceptCategory {
253        match self {
254            Self::EntityType(_) => ConceptCategory::EntityType,
255            Self::RelationType(_) => ConceptCategory::RelationType,
256            Self::RoleType(_) => ConceptCategory::RoleType,
257            Self::AttributeType(_) => ConceptCategory::AttributeType,
258            Self::Entity(_) => ConceptCategory::Entity,
259            Self::Relation(_) => ConceptCategory::Relation,
260            Self::Attribute(_) => ConceptCategory::Attribute,
261            Self::Value(_) => ConceptCategory::Value,
262        }
263    }
264
265    /// Check if this Concept represents a Type from the schema of the database.
266    /// These are exactly: Entity Types, Relation Types, Role Types, and Attribute Types
267    ///
268    /// Equivalent to:
269    /// ```
270    /// concept.is_entity_type() || concept.is_relation_type() || concept.is_role_type() || concept.is_attribute_type()
271    /// ```
272    pub fn is_type(&self) -> bool {
273        match self {
274            Self::EntityType(_) | Self::RelationType(_) | Self::RoleType(_) | Self::AttributeType(_) => true,
275            _ => false,
276        }
277    }
278
279    /// Check if this Concept represents an Entity Type from the schema of the database
280    pub fn is_entity_type(&self) -> bool {
281        matches!(self.get_category(), ConceptCategory::EntityType)
282    }
283
284    /// Check if this Concept represents a Relation Type from the schema of the database
285    pub fn is_relation_type(&self) -> bool {
286        matches!(self.get_category(), ConceptCategory::RelationType)
287    }
288
289    /// Check if this Concept represents a Role Type from the schema of the database
290    pub fn is_role_type(&self) -> bool {
291        matches!(self.get_category(), ConceptCategory::RoleType)
292    }
293
294    /// Check if this Concept represents an Attribute Type from the schema of the database
295    pub fn is_attribute_type(&self) -> bool {
296        matches!(self.get_category(), ConceptCategory::AttributeType)
297    }
298
299    /// Check if this Concept represents a stored database instance from the database.
300    /// These are exactly: Entity, Relation, and Attribute
301    ///
302    /// Equivalent to:
303    /// ```
304    /// concept.is_entity() || concept.is_relation() ||  concept.is_attribute()
305    /// ```
306    pub fn is_instance(&self) -> bool {
307        match self {
308            Self::Entity(_) | Self::Relation(_) | Self::Attribute(_) => true,
309            _ => false,
310        }
311    }
312
313    /// Check if this Concept represents an Entity instance from the database
314    pub fn is_entity(&self) -> bool {
315        matches!(self.get_category(), ConceptCategory::Entity)
316    }
317
318    /// Check if this Concept represents an Relation instance from the database
319    pub fn is_relation(&self) -> bool {
320        matches!(self.get_category(), ConceptCategory::Relation)
321    }
322
323    /// Check if this Concept represents an Attribute instance from the database
324    pub fn is_attribute(&self) -> bool {
325        matches!(self.get_category(), ConceptCategory::Attribute)
326    }
327
328    /// Check if this Concept represents a Value returned by the database
329    pub fn is_value(&self) -> bool {
330        matches!(self.get_category(), ConceptCategory::Value)
331    }
332
333    /// Check if this Concept holds a boolean as an AttributeType, an Attribute, or a Value
334    pub fn is_boolean(&self) -> bool {
335        matches!(self.try_get_value_type(), Some(ValueType::Boolean))
336    }
337
338    /// Check if this Concept holds an integer as an AttributeType, an Attribute, or a Value
339    pub fn is_integer(&self) -> bool {
340        matches!(self.try_get_value_type(), Some(ValueType::Integer))
341    }
342
343    /// Check if this Concept holds a fixed-decimal as an AttributeType, an Attribute, or a Value
344    pub fn is_decimal(&self) -> bool {
345        matches!(self.try_get_value_type(), Some(ValueType::Decimal))
346    }
347
348    /// Check if this Concept holds a double as an AttributeType, an Attribute, or a Value
349    pub fn is_double(&self) -> bool {
350        matches!(self.try_get_value_type(), Some(ValueType::Double))
351    }
352
353    /// Check if this Concept holds a string as an AttributeType, an Attribute, or a Value
354    pub fn is_string(&self) -> bool {
355        matches!(self.try_get_value_type(), Some(ValueType::String))
356    }
357
358    /// Check if this Concept holds a date as an AttributeType, an Attribute, or a Value
359    pub fn is_date(&self) -> bool {
360        matches!(self.try_get_value_type(), Some(ValueType::Date))
361    }
362
363    /// Check if this Concept holds a datetime as an AttributeType, an Attribute, or a Value
364    pub fn is_datetime(&self) -> bool {
365        matches!(self.try_get_value_type(), Some(ValueType::Datetime))
366    }
367
368    /// Check if this Concept holds a timezoned-datetime as an AttributeType, an Attribute, or a Value
369    pub fn is_datetime_tz(&self) -> bool {
370        matches!(self.try_get_value_type(), Some(ValueType::DatetimeTZ))
371    }
372
373    /// Check if this Concept holds a duration as an AttributeType, an Attribute, or a Value
374    pub fn is_duration(&self) -> bool {
375        matches!(self.try_get_value_type(), Some(ValueType::Duration))
376    }
377
378    /// Check if this Concept holds a struct as an AttributeType, an Attribute, or a Value
379    pub fn is_struct(&self) -> bool {
380        matches!(self.try_get_value_type(), Some(ValueType::Struct(_)))
381    }
382}
383
384impl Display for Concept {
385    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
386        Debug::fmt(self, f)
387    }
388}
389
390impl Debug for Concept {
391    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
392        if self.is_type() {
393            write!(f, "{}({})", self.get_category(), self.get_label())
394        } else {
395            write!(f, "{}({}", self.get_category(), self.get_label())?;
396            if self.try_get_iid().is_some() {
397                write!(f, ": {}", self.try_get_iid().unwrap())?;
398                if self.try_get_value().is_some() {
399                    write!(f, ", {}", self.try_get_value().unwrap())?;
400                }
401            } else if self.try_get_value().is_some() {
402                write!(f, ": {}", self.try_get_value().unwrap())?;
403            } else {
404                // shouldn't be reachable?
405            }
406            write!(f, ")")
407        }
408    }
409}
410
411/// Kind represents the base of a defined type to describe its capabilities.
412/// For example, "define entity person;" defines a type "person" of a kind "entity".
413#[derive(Copy, Clone, Hash, PartialEq, Eq)]
414pub enum Kind {
415    Entity,
416    Attribute,
417    Relation,
418    Role,
419}
420
421impl Kind {
422    pub const fn name(&self) -> &'static str {
423        match self {
424            Kind::Entity => "entity",
425            Kind::Attribute => "attribute",
426            Kind::Relation => "relation",
427            Kind::Role => "relation:role",
428        }
429    }
430}
431
432impl Debug for Kind {
433    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
434        write!(f, "Kind[{}]", self.name())
435    }
436}
437
438impl Display for Kind {
439    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
440        write!(f, "{}", self.name())
441    }
442}