Skip to main content

linkrs_core/value/
value_def.rs

1//! Value Type Definition - Core Enum and Basic Methods
2
3use crate::DataSet;
4use crate::{
5    types::storage_ids::{EdgeId, VertexId},
6    types::DataType,
7    value::{
8        date_time::{DateTimeValue, DateValue, TimeValue},
9        decimal128::Decimal128Value,
10        geography::Geography,
11        interval::IntervalValue,
12        json::{Json, JsonB, JsonError},
13        list::List,
14        null::NullType,
15        uuid::UuidValue,
16        vector::VectorValue,
17    },
18    vertex_edge_path::{Edge, EdgeHeader, Path, Vertex},
19    ArrayTypeInfo, StructTypeInfo,
20};
21use compact_str::CompactString;
22use serde::{Deserialize, Serialize};
23use std::{
24    collections::{HashMap, HashSet},
25    hash::Hash,
26    sync::Arc,
27};
28
29/// Indicates values that can be stored in node/edge attributes
30/// Simplified design following PostgreSQL type system
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub enum Value {
33    Empty,
34    Null(NullType),
35    Bool(bool),
36    // Integer types: simplified to 3 types (aligned with PostgreSQL)
37    SmallInt(i16), // 2 bytes, corresponds to PostgreSQL smallint
38    Int(i32),      // 4 bytes, corresponds to PostgreSQL integer
39    BigInt(i64),   // 8 bytes, corresponds to PostgreSQL bigint
40    // Floating point types: 2 types (standard practice)
41    Float(f32),  // 4 bytes, single precision
42    Double(f64), // 8 bytes, double precision
43    Decimal128(Decimal128Value),
44    String(CompactString),
45    /// Fixed-length strings for optimized storage of short strings.
46    /// Content is always padded/truncated to the declared length, so the
47    /// length is derivable via `chars().count()`.
48    FixedString(String),
49    /// Binary data
50    Blob(Vec<u8>),
51    Date(DateValue),
52    Time(TimeValue),
53    DateTime(DateTimeValue),
54    Vertex(Box<Vertex>),
55    Edge(Box<Edge>),
56    EdgeHeader(Box<EdgeHeader>),
57    Path(Box<Path>),
58    List(Box<List>),
59    /// Map with generalized keys: any hashable `Value` (string keys remain
60    /// the common case; float keys use the normalized NaN/±0 hashing).
61    Map(Box<HashMap<Value, Value>>),
62    Set(Box<HashSet<Value>>),
63    Geography(Geography),
64    Vector(VectorValue),
65    DataSet(Box<DataSet>),
66
67    /// JSON type (text format)
68    Json(Box<Json>),
69    /// JSONB type (binary format)
70    JsonB(Box<JsonB>),
71    /// UUID type (16 bytes binary)
72    Uuid(UuidValue),
73    /// Interval type (PostgreSQL compatible)
74    Interval(IntervalValue),
75
76    /// Lightweight vertex ID reference (no heap allocation).
77    /// Used by expand fast path when only the vertex ID is needed
78    /// (e.g. count-only aggregation downstream).
79    VertexId(VertexId),
80    /// Lightweight edge ID reference (no heap allocation).
81    /// Used by expand fast path when only the edge ID is needed.
82    EdgeId(EdgeId),
83
84    /// STRUCT value: ordered named fields.
85    Struct(Box<StructValue>),
86    /// ARRAY value: element-homogeneous array.
87    Array(Box<ArrayValue>),
88}
89
90/// STRUCT value: ordered field table.
91#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
92pub struct StructValue {
93    pub fields: Vec<(String, Value)>,
94}
95
96/// ARRAY value: fixed-size array.
97#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
98pub struct ArrayValue {
99    pub values: Vec<Value>,
100}
101
102impl StructValue {
103    pub fn new(fields: Vec<(String, Value)>) -> Self {
104        Self { fields }
105    }
106}
107
108impl ArrayValue {
109    pub fn new(values: Vec<Value>) -> Self {
110        Self { values }
111    }
112}
113
114impl Value {
115    /// Create a string value from a string-like type.
116    ///
117    /// `CompactString` stores up to 22 bytes inline without heap allocation,
118    /// falling back to a heap-allocated `String` for longer content.
119    pub fn string(s: impl AsRef<str>) -> Self {
120        Value::String(CompactString::new(s.as_ref()))
121    }
122
123    /// Create a string value from an owned `String`.
124    pub fn string_from_owned(s: String) -> Self {
125        Value::String(CompactString::from(s))
126    }
127
128    /// Getting the type of value
129    pub fn get_type(&self) -> DataType {
130        match self {
131            Value::Empty => DataType::Empty,
132            Value::Null(_) => DataType::Null,
133            Value::Bool(_) => DataType::Bool,
134            Value::SmallInt(_) => DataType::SmallInt,
135            Value::Int(_) => DataType::Int,
136            Value::BigInt(_) => DataType::BigInt,
137            Value::Float(_) => DataType::Float,
138            Value::Double(_) => DataType::Double,
139            Value::Decimal128(_) => DataType::Decimal128,
140            Value::String(_) => DataType::String,
141            Value::FixedString(data) => DataType::FixedString(data.chars().count()),
142            Value::Blob(_) => DataType::Blob,
143            Value::Date(_) => DataType::Date,
144            Value::Time(_) => DataType::Time,
145            Value::DateTime(_) => DataType::DateTime,
146            Value::Vertex(_) => DataType::Vertex,
147            Value::Edge(_) | Value::EdgeHeader(_) => DataType::Edge,
148            Value::Path(_) => DataType::Path,
149            Value::List(l) => DataType::List(Box::new(Self::container_element_type(l.iter()))),
150            Value::Map(m) => DataType::Map(Box::new(Self::container_element_type(m.values()))),
151            Value::Set(s) => DataType::Set(Box::new(Self::container_element_type(s.iter()))),
152            Value::Geography(_) => DataType::Geography,
153            Value::Vector(v) => DataType::VectorDense(v.dimension()),
154            Value::DataSet(_) => DataType::DataSet,
155            Value::Json(_) => DataType::Json,
156            Value::JsonB(_) => DataType::JsonB,
157            Value::Uuid(_) => DataType::Uuid,
158            Value::Interval(_) => DataType::Interval,
159            Value::VertexId(_) => DataType::Vertex,
160            Value::EdgeId(_) => DataType::Edge,
161            Value::Struct(s) => DataType::Struct(Arc::new(StructTypeInfo::new(
162                s.fields
163                    .iter()
164                    .map(|(name, value)| (name.clone(), value.get_type()))
165                    .collect(),
166            ))),
167            Value::Array(a) => DataType::Array(Arc::new(ArrayTypeInfo::new(
168                a.values
169                    .first()
170                    .map(|v| v.get_type())
171                    .unwrap_or(DataType::Empty),
172                None,
173            ))),
174        }
175    }
176
177    /// Alias for get_type
178    pub fn data_type(&self) -> DataType {
179        self.get_type()
180    }
181
182    /// Common type of a container's elements.
183    ///
184    /// Folds `Value::get_type` over the element types with the numeric/temporal
185    /// promotion hierarchy. Returns `DataType::Empty` for an empty container
186    /// (the "untyped container" marker on the parameterized `List`/`Map`/`Set`
187    /// variants).
188    pub fn container_element_type<'a, I>(elements: I) -> DataType
189    where
190        I: IntoIterator<Item = &'a Value>,
191    {
192        let mut common = DataType::Empty;
193        for element in elements {
194            common = crate::type_system::TypeUtils::get_common_type(&common, &element.get_type());
195            if common == DataType::Empty {
196                break;
197            }
198        }
199        common
200    }
201
202    /// Check if the value is null
203    pub fn is_null(&self) -> bool {
204        matches!(self, Value::Null(_))
205    }
206
207    /// Check if the value is a numeric type
208    pub fn is_numeric(&self) -> bool {
209        matches!(
210            self,
211            Value::SmallInt(_)
212                | Value::Int(_)
213                | Value::BigInt(_)
214                | Value::Float(_)
215                | Value::Double(_)
216                | Value::Decimal128(_)
217        )
218    }
219
220    /// Check if the value is BadNull
221    pub fn is_bad_null(&self) -> bool {
222        use super::null::NullType;
223        matches!(
224            self,
225            Value::Null(NullType::BadData) | Value::Null(NullType::BadType)
226        )
227    }
228
229    /// Check if the value is empty
230    pub fn is_empty(&self) -> bool {
231        matches!(self, Value::Empty)
232    }
233
234    /// Get Boolean value
235    pub fn bool_value(&self) -> Option<bool> {
236        match self {
237            Value::Bool(b) => Some(*b),
238            _ => None,
239        }
240    }
241
242    /// Get String value
243    pub fn string_value(&self) -> Option<&str> {
244        match self {
245            Value::String(s) => Some(s),
246            Value::FixedString(data) => Some(data),
247            _ => None,
248        }
249    }
250
251    /// Get vector value as Vec<f32> from List of Float values or Vector type
252    pub fn as_vector(&self) -> Option<Vec<f32>> {
253        match self {
254            Value::Vector(vec) => Some(vec.to_dense()),
255            Value::List(list) => {
256                let vector: Option<Vec<f32>> = list
257                    .iter()
258                    .map(|v| match v {
259                        Value::Float(f) => Some(*f),
260                        Value::Double(f) => Some(*f as f32),
261                        Value::Int(i) => Some(*i as f32),
262                        Value::SmallInt(i) => Some(*i as f32),
263                        Value::BigInt(i) => Some(*i as f32),
264                        _ => None,
265                    })
266                    .collect();
267                vector
268            }
269            Value::Blob(blob) => {
270                if blob.len() % std::mem::size_of::<f32>() == 0 {
271                    let len = blob.len() / std::mem::size_of::<f32>();
272                    let mut vector = Vec::with_capacity(len);
273                    let ptr = blob.as_ptr() as *const f32;
274                    for i in 0..len {
275                        unsafe {
276                            vector.push(*ptr.add(i));
277                        }
278                    }
279                    Some(vector)
280                } else {
281                    None
282                }
283            }
284            _ => None,
285        }
286    }
287
288    /// Get reference to vector data (more efficient than as_vector)
289    pub fn as_vector_ref(&self) -> Option<&[f32]> {
290        match self {
291            Value::Vector(vec) => vec.as_dense(),
292            _ => None,
293        }
294    }
295
296    /// Create a new vector value
297    pub fn vector(data: Vec<f32>) -> Self {
298        Value::Vector(super::vector::VectorValue::dense(data))
299    }
300
301    /// Create a new sparse vector value
302    pub fn sparse_vector(indices: Vec<u32>, values: Vec<f32>) -> Self {
303        Value::Vector(super::vector::VectorValue::sparse(indices, values))
304    }
305
306    /// Create fixed-length string value (truncates or space-pads to `len`)
307    pub fn fixed_string(len: usize, data: String) -> Self {
308        let padded_data = if data.chars().count() > len {
309            data.chars().take(len).collect()
310        } else {
311            format!("{:<width$}", data, width = len)
312        };
313        Value::FixedString(padded_data)
314    }
315
316    /// Get the length of a fixed-length string
317    pub fn fixed_string_len(&self) -> Option<usize> {
318        match self {
319            Value::FixedString(data) => Some(data.chars().count()),
320            _ => None,
321        }
322    }
323
324    /// Compute the hash of the value
325    pub fn hash_value(&self) -> u64 {
326        use std::collections::hash_map::DefaultHasher;
327        use std::hash::Hasher;
328        let mut hasher = DefaultHasher::new();
329        self.hash(&mut hasher);
330        hasher.finish()
331    }
332
333    /// Estimate the memory usage of the value
334    pub fn estimated_size(&self) -> usize {
335        match self {
336            Value::Empty => std::mem::size_of::<Self>(),
337            Value::Null(_) => std::mem::size_of::<Self>(),
338            Value::Bool(_) => std::mem::size_of::<Self>(),
339            Value::SmallInt(_) => std::mem::size_of::<Self>(),
340            Value::Int(_) => std::mem::size_of::<Self>(),
341            Value::BigInt(_) => std::mem::size_of::<Self>(),
342            Value::Float(_) => std::mem::size_of::<Self>(),
343            Value::Double(_) => std::mem::size_of::<Self>(),
344            Value::Decimal128(_) => std::mem::size_of::<Self>(),
345            Value::String(s) => std::mem::size_of::<Self>() + s.len(),
346            Value::FixedString(data) => std::mem::size_of::<Self>() + data.len(),
347            Value::Blob(b) => std::mem::size_of::<Self>() + b.len(),
348            Value::Date(_) => std::mem::size_of::<Self>(),
349            Value::Time(_) => std::mem::size_of::<Self>(),
350            Value::DateTime(_) => std::mem::size_of::<Self>(),
351            Value::Vertex(v) => std::mem::size_of::<Self>() + v.estimated_size(),
352            Value::Edge(e) => std::mem::size_of::<Self>() + e.estimated_size(),
353            Value::EdgeHeader(h) => std::mem::size_of::<Self>() + h.estimated_size(),
354            Value::Path(p) => std::mem::size_of::<Self>() + p.estimated_size(),
355            Value::List(l) => std::mem::size_of::<Self>() + l.estimated_size(),
356            Value::Map(m) => {
357                let mut size = std::mem::size_of::<Self>();
358                size += m.capacity() * 8;
359                for (k, v) in m.as_ref() {
360                    size += k.estimated_size();
361                    size += v.estimated_size();
362                }
363                size
364            }
365            Value::Set(s) => {
366                let mut size = std::mem::size_of::<Self>();
367                size += s.capacity() * 8;
368                for v in s.as_ref() {
369                    size += v.estimated_size();
370                }
371                size
372            }
373            Value::Geography(g) => std::mem::size_of::<Self>() + g.estimated_size(),
374            Value::Vector(v) => std::mem::size_of::<Self>() + v.estimated_size(),
375            Value::DataSet(ds) => std::mem::size_of::<Self>() + ds.estimated_size(),
376            Value::Json(j) => std::mem::size_of::<Self>() + j.estimated_size(),
377            Value::JsonB(j) => std::mem::size_of::<Self>() + j.estimated_size(),
378            Value::Uuid(_) => std::mem::size_of::<Self>(),
379            Value::Interval(_) => std::mem::size_of::<Self>(),
380            Value::VertexId(_) => std::mem::size_of::<Self>(),
381            Value::EdgeId(_) => std::mem::size_of::<Self>(),
382            Value::Struct(s) => {
383                let mut size = std::mem::size_of::<Self>();
384                for (name, value) in &s.fields {
385                    size += name.len();
386                    size += value.estimated_size();
387                }
388                size
389            }
390            Value::Array(a) => {
391                let mut size = std::mem::size_of::<Self>();
392                for value in &a.values {
393                    size += value.estimated_size();
394                }
395                size
396            }
397        }
398    }
399
400    /// Create JSON value
401    pub fn json(text: &str) -> Result<Self, JsonError> {
402        Ok(Value::Json(Box::new(Json::parse(text)?)))
403    }
404
405    /// Create JSONB value
406    pub fn jsonb(text: &str) -> Result<Self, JsonError> {
407        Ok(Value::JsonB(Box::new(JsonB::parse(text)?)))
408    }
409
410    /// Create JSON value from serde_json::Value
411    pub fn from_json_value(value: serde_json::Value) -> Self {
412        Value::JsonB(Box::new(JsonB::from_value(value)))
413    }
414}
415
416impl Value {
417    /// Create a new List value (wraps in Box)
418    pub fn list(list: List) -> Self {
419        Value::List(Box::new(list))
420    }
421
422    /// Create a new Map value (wraps in Box).
423    pub fn map(map: HashMap<Value, Value>) -> Self {
424        Value::Map(Box::new(map))
425    }
426
427    /// Create a new Map value from string-keyed entries (the common case).
428    pub fn string_map<K: AsRef<str>>(map: impl IntoIterator<Item = (K, Value)>) -> Self {
429        Value::Map(Box::new(
430            map.into_iter()
431                .map(|(k, v)| (Value::string(k), v))
432                .collect(),
433        ))
434    }
435
436    /// Create a new Set value (wraps in Box)
437    pub fn set(set: HashSet<Value>) -> Self {
438        Value::Set(Box::new(set))
439    }
440
441    /// Create a new Edge value (wraps in Box)
442    pub fn edge(edge: Edge) -> Self {
443        Value::Edge(Box::new(edge))
444    }
445
446    /// Create a new edge header value (wraps in Box)
447    pub fn edge_header(header: EdgeHeader) -> Self {
448        Value::EdgeHeader(Box::new(header))
449    }
450
451    /// Create a new Path value (wraps in Box)
452    pub fn path(path: Path) -> Self {
453        Value::Path(Box::new(path))
454    }
455
456    /// Create a new DataSet value (wraps in Box)
457    pub fn dataset(dataset: DataSet) -> Self {
458        Value::DataSet(Box::new(dataset))
459    }
460
461    /// Create a new Struct value (wraps in Box).
462    pub fn struct_(fields: Vec<(String, Value)>) -> Self {
463        Value::Struct(Box::new(StructValue::new(fields)))
464    }
465
466    /// Create a new Array value (wraps in Box).
467    pub fn array(values: Vec<Value>) -> Self {
468        Value::Array(Box::new(ArrayValue::new(values)))
469    }
470}
471
472impl std::fmt::Display for Value {
473    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
474        match self {
475            Value::Empty => write!(f, "EMPTY"),
476            Value::Null(n) => write!(f, "NULL({:?})", n),
477            Value::Bool(b) => write!(f, "{}", b),
478            Value::SmallInt(i) => write!(f, "{}", i),
479            Value::Int(i) => write!(f, "{}", i),
480            Value::BigInt(i) => write!(f, "{}", i),
481            Value::Float(fl) => write!(f, "{}", fl),
482            Value::Double(fl) => write!(f, "{}", fl),
483            Value::Decimal128(d) => write!(f, "{}", d),
484            Value::String(s) => write!(f, "{}", s),
485            Value::FixedString(data) => {
486                write!(f, "\"{}\"[fixed:{}]", data, data.chars().count())
487            }
488            Value::Blob(b) => write!(f, "Blob({} bytes)", b.len()),
489            Value::Date(d) => write!(f, "{:04}-{:02}-{:02}", d.year, d.month, d.day),
490            Value::Time(t) => write!(
491                f,
492                "{:02}:{:02}:{:02}.{:06}",
493                t.hour, t.minute, t.sec, t.microsec
494            ),
495            Value::DateTime(dt) => write!(
496                f,
497                "{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:06}",
498                dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.sec, dt.microsec
499            ),
500            Value::Vertex(v) => write!(f, "Vertex({:?})", v.vid()),
501            Value::Edge(e) => write!(f, "Edge({:?} -> {:?})", e.src(), e.dst()),
502            Value::EdgeHeader(h) => write!(
503                f,
504                "EdgeHeader({:?} -> {:?}, {}, {})",
505                h.src(),
506                h.dst(),
507                h.edge_type(),
508                h.ranking()
509            ),
510            Value::Path(p) => write!(f, "Path({:?})", p),
511            Value::List(list) => {
512                write!(f, "[")?;
513                for (i, item) in list.iter().enumerate() {
514                    if i > 0 {
515                        write!(f, ", ")?;
516                    }
517                    write!(f, "{}", item)?;
518                }
519                write!(f, "]")
520            }
521            Value::Map(map) => {
522                write!(f, "{{")?;
523                for (i, (k, v)) in map.iter().enumerate() {
524                    if i > 0 {
525                        write!(f, ", ")?;
526                    }
527                    write!(f, "{}: {}", k, v)?;
528                }
529                write!(f, "}}")
530            }
531            Value::Set(set) => {
532                write!(f, "{{")?;
533                for (i, item) in set.iter().enumerate() {
534                    if i > 0 {
535                        write!(f, ", ")?;
536                    }
537                    write!(f, "{}", item)?;
538                }
539                write!(f, "}}")
540            }
541            Value::Geography(g) => write!(f, "{}", g),
542            Value::Vector(v) => write!(f, "{}", v),
543            Value::DataSet(ds) => write!(f, "DataSet({} rows)", ds.row_count()),
544            Value::Json(j) => write!(f, "Json({})", j.as_str()),
545            Value::JsonB(j) => write!(f, "JsonB({})", j.to_json_string()),
546            Value::Uuid(u) => write!(f, "Uuid({})", u),
547            Value::Interval(i) => write!(f, "Interval({})", i),
548            Value::VertexId(vid) => write!(f, "VertexId({:?})", vid),
549            Value::EdgeId(eid) => write!(f, "EdgeId({:?})", eid),
550            Value::Struct(s) => {
551                write!(f, "{{")?;
552                for (i, (name, value)) in s.fields.iter().enumerate() {
553                    if i > 0 {
554                        write!(f, ", ")?;
555                    }
556                    write!(f, "{}: {}", name, value)?;
557                }
558                write!(f, "}}")
559            }
560            Value::Array(a) => {
561                write!(f, "[")?;
562                for (i, value) in a.values.iter().enumerate() {
563                    if i > 0 {
564                        write!(f, ", ")?;
565                    }
566                    write!(f, "{}", value)?;
567                }
568                write!(f, "]")
569            }
570        }
571    }
572}