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;
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 IID,
31 concept::value::{Decimal, Duration, Struct, TimeZone},
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 fmt::Display for ConceptCategory {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 fmt::Debug::fmt(self, f)
83 }
84}
85
86impl fmt::Debug for ConceptCategory {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> 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().and_then(|value| value.get_boolean())
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().and_then(|value| value.get_integer())
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().and_then(|value| value.get_double())
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().and_then(|value| value.get_decimal())
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().and_then(|value| value.get_string())
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().and_then(|value| value.get_date())
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().and_then(|value| value.get_datetime())
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().and_then(|value| value.get_datetime_tz())
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().and_then(|value| value.get_duration())
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().and_then(|value| value.get_struct())
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 matches!(self, Self::EntityType(_) | Self::RelationType(_) | Self::RoleType(_) | Self::AttributeType(_))
274 }
275
276 /// Check if this Concept represents an Entity Type from the schema of the database
277 pub fn is_entity_type(&self) -> bool {
278 matches!(self.get_category(), ConceptCategory::EntityType)
279 }
280
281 /// Check if this Concept represents a Relation Type from the schema of the database
282 pub fn is_relation_type(&self) -> bool {
283 matches!(self.get_category(), ConceptCategory::RelationType)
284 }
285
286 /// Check if this Concept represents a Role Type from the schema of the database
287 pub fn is_role_type(&self) -> bool {
288 matches!(self.get_category(), ConceptCategory::RoleType)
289 }
290
291 /// Check if this Concept represents an Attribute Type from the schema of the database
292 pub fn is_attribute_type(&self) -> bool {
293 matches!(self.get_category(), ConceptCategory::AttributeType)
294 }
295
296 /// Check if this Concept represents a stored database instance from the database.
297 /// These are exactly: Entity, Relation, and Attribute
298 ///
299 /// Equivalent to:
300 /// ```
301 /// concept.is_entity() || concept.is_relation() || concept.is_attribute()
302 /// ```
303 pub fn is_instance(&self) -> bool {
304 matches!(self, Self::Entity(_) | Self::Relation(_) | Self::Attribute(_))
305 }
306
307 /// Check if this Concept represents an Entity instance from the database
308 pub fn is_entity(&self) -> bool {
309 matches!(self.get_category(), ConceptCategory::Entity)
310 }
311
312 /// Check if this Concept represents an Relation instance from the database
313 pub fn is_relation(&self) -> bool {
314 matches!(self.get_category(), ConceptCategory::Relation)
315 }
316
317 /// Check if this Concept represents an Attribute instance from the database
318 pub fn is_attribute(&self) -> bool {
319 matches!(self.get_category(), ConceptCategory::Attribute)
320 }
321
322 /// Check if this Concept represents a Value returned by the database
323 pub fn is_value(&self) -> bool {
324 matches!(self.get_category(), ConceptCategory::Value)
325 }
326
327 /// Check if this Concept holds a boolean as an AttributeType, an Attribute, or a Value
328 pub fn is_boolean(&self) -> bool {
329 matches!(self.try_get_value_type(), Some(ValueType::Boolean))
330 }
331
332 /// Check if this Concept holds an integer as an AttributeType, an Attribute, or a Value
333 pub fn is_integer(&self) -> bool {
334 matches!(self.try_get_value_type(), Some(ValueType::Integer))
335 }
336
337 /// Check if this Concept holds a fixed-decimal as an AttributeType, an Attribute, or a Value
338 pub fn is_decimal(&self) -> bool {
339 matches!(self.try_get_value_type(), Some(ValueType::Decimal))
340 }
341
342 /// Check if this Concept holds a double as an AttributeType, an Attribute, or a Value
343 pub fn is_double(&self) -> bool {
344 matches!(self.try_get_value_type(), Some(ValueType::Double))
345 }
346
347 /// Check if this Concept holds a string as an AttributeType, an Attribute, or a Value
348 pub fn is_string(&self) -> bool {
349 matches!(self.try_get_value_type(), Some(ValueType::String))
350 }
351
352 /// Check if this Concept holds a date as an AttributeType, an Attribute, or a Value
353 pub fn is_date(&self) -> bool {
354 matches!(self.try_get_value_type(), Some(ValueType::Date))
355 }
356
357 /// Check if this Concept holds a datetime as an AttributeType, an Attribute, or a Value
358 pub fn is_datetime(&self) -> bool {
359 matches!(self.try_get_value_type(), Some(ValueType::Datetime))
360 }
361
362 /// Check if this Concept holds a timezoned-datetime as an AttributeType, an Attribute, or a Value
363 pub fn is_datetime_tz(&self) -> bool {
364 matches!(self.try_get_value_type(), Some(ValueType::DatetimeTZ))
365 }
366
367 /// Check if this Concept holds a duration as an AttributeType, an Attribute, or a Value
368 pub fn is_duration(&self) -> bool {
369 matches!(self.try_get_value_type(), Some(ValueType::Duration))
370 }
371
372 /// Check if this Concept holds a struct as an AttributeType, an Attribute, or a Value
373 pub fn is_struct(&self) -> bool {
374 matches!(self.try_get_value_type(), Some(ValueType::Struct(_)))
375 }
376}
377
378impl fmt::Display for Concept {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 fmt::Debug::fmt(self, f)
381 }
382}
383
384impl fmt::Debug for Concept {
385 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386 if self.is_type() {
387 write!(f, "{}({})", self.get_category(), self.get_label())
388 } else {
389 write!(f, "{}({}", self.get_category(), self.get_label())?;
390 if self.try_get_iid().is_some() {
391 write!(f, ": {}", self.try_get_iid().unwrap())?;
392 if self.try_get_value().is_some() {
393 write!(f, ", {}", self.try_get_value().unwrap())?;
394 }
395 } else if self.try_get_value().is_some() {
396 write!(f, ": {}", self.try_get_value().unwrap())?;
397 } else {
398 // shouldn't be reachable?
399 }
400 write!(f, ")")
401 }
402 }
403}
404
405/// Kind represents the base of a defined type to describe its capabilities.
406/// For example, "define entity person;" defines a type "person" of a kind "entity".
407#[repr(C)]
408#[derive(Copy, Clone, Hash, PartialEq, Eq)]
409pub enum Kind {
410 Entity,
411 Attribute,
412 Relation,
413 Role,
414}
415
416impl Kind {
417 pub const fn name(&self) -> &'static str {
418 match self {
419 Kind::Entity => "entity",
420 Kind::Attribute => "attribute",
421 Kind::Relation => "relation",
422 Kind::Role => "relation:role",
423 }
424 }
425}
426
427impl fmt::Debug for Kind {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 write!(f, "Kind[{}]", self.name())
430 }
431}
432
433impl fmt::Display for Kind {
434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435 write!(f, "{}", self.name())
436 }
437}