1use std::any::Any;
2use std::cmp::Ordering;
3
4use gitql_ast::types::row::RowType;
5use gitql_ast::types::DataType;
6
7use crate::values::boolean::BoolValue;
8
9use super::base::Value;
10
11#[derive(Clone)]
12pub struct RowValue {
13 pub columns: Vec<Box<dyn Value>>,
14 pub row_type: RowType,
15}
16
17impl RowValue {
18 pub fn new(columns: Vec<Box<dyn Value>>, row_type: RowType) -> Self {
19 RowValue { columns, row_type }
20 }
21}
22
23impl Value for RowValue {
24 fn literal(&self) -> String {
25 let mut str = String::new();
26 str += "(";
27 for (pos, element) in self.columns.iter().enumerate() {
28 str += &element.literal();
29 if pos + 1 != self.columns.len() {
30 str += ", ";
31 }
32 }
33 str += ")";
34 str
35 }
36
37 fn equals(&self, other: &Box<dyn Value>) -> bool {
38 if let Some(other_row) = other.as_any().downcast_ref::<RowValue>() {
39 let data_type: Box<dyn DataType> = Box::new(other_row.row_type.clone());
40 if !self.row_type.equals(&data_type) {
41 return false;
42 }
43
44 let len = self.row_type.tuple.len();
45 for i in 0..len {
46 if !self.columns[i].eq(&other_row.columns[i]) {
47 return false;
48 }
49 }
50
51 return true;
52 }
53 false
54 }
55
56 fn compare(&self, _other: &Box<dyn Value>) -> Option<Ordering> {
57 None
58 }
59
60 fn data_type(&self) -> Box<dyn DataType> {
61 Box::new(self.row_type.clone())
62 }
63
64 fn as_any(&self) -> &dyn Any {
65 self
66 }
67
68 fn eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
69 if other.as_any().downcast_ref::<RowValue>().is_none() {
70 return Err("Unexpected type to perform `=` with".to_string());
71 }
72 Ok(Box::new(BoolValue::new(self.equals(other))))
73 }
74
75 fn bang_eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
76 if other.as_any().downcast_ref::<RowValue>().is_none() {
77 return Err("Unexpected type to perform `!=` with".to_string());
78 }
79 Ok(Box::new(BoolValue::new(!self.equals(other))))
80 }
81}