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}