mz_expr/scalar/func/impls/
map.rs1use std::fmt;
11
12use itertools::Itertools;
13use mz_expr_derive::sqlfunc;
14use mz_repr::{Datum, DatumMap, RowArena, SqlColumnType, SqlScalarType};
15use serde::{Deserialize, Serialize};
16
17use crate::scalar::func::{LazyUnaryFunc, stringify_datum};
18use crate::{Eval, EvalError};
19
20#[derive(
21 Ord,
22 PartialOrd,
23 Clone,
24 Debug,
25 Eq,
26 PartialEq,
27 Serialize,
28 Deserialize,
29 Hash
30)]
31pub struct CastMapToString {
32 pub ty: SqlScalarType,
33}
34
35impl LazyUnaryFunc for CastMapToString {
36 fn eval<'a>(
37 &'a self,
38 datums: &[Datum<'a>],
39 temp_storage: &'a RowArena,
40 a: &'a impl Eval,
41 ) -> Result<Datum<'a>, EvalError> {
42 let a = a.eval(datums, temp_storage)?;
43 if a.is_null() {
44 return Ok(Datum::Null);
45 }
46 let mut buf = String::new();
47 stringify_datum(&mut buf, a, &self.ty)?;
48 Ok(Datum::String(temp_storage.push_string(buf)))
49 }
50
51 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
52 SqlScalarType::String.nullable(input_type.nullable)
53 }
54
55 fn propagates_nulls(&self) -> bool {
56 true
57 }
58
59 fn introduces_nulls(&self) -> bool {
60 false
61 }
62
63 fn preserves_uniqueness(&self) -> bool {
64 true
65 }
66
67 fn inverse(&self) -> Option<crate::UnaryFunc> {
68 None
70 }
71
72 fn is_monotone(&self) -> bool {
73 false
74 }
75
76 fn is_eliminable_cast(&self) -> bool {
77 false
78 }
79}
80
81impl fmt::Display for CastMapToString {
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 f.write_str("maptostr")
84 }
85}
86
87#[sqlfunc(sqlname = "map_length")]
88fn map_length<'a>(a: DatumMap<'a>) -> Result<i32, EvalError> {
89 let count = a.iter().count();
90 count
91 .try_into()
92 .map_err(|_| EvalError::Int32OutOfRange(count.to_string().into()))
93}
94
95#[derive(
96 Ord,
97 PartialOrd,
98 Clone,
99 Debug,
100 Eq,
101 PartialEq,
102 Serialize,
103 Deserialize,
104 Hash
105)]
106pub struct MapBuildFromRecordList {
107 pub value_type: SqlScalarType,
108}
109
110impl LazyUnaryFunc for MapBuildFromRecordList {
111 fn eval<'a>(
112 &'a self,
113 datums: &[Datum<'a>],
114 temp_storage: &'a RowArena,
115 a: &'a impl Eval,
116 ) -> Result<Datum<'a>, EvalError> {
117 let a = a.eval(datums, temp_storage)?;
118 if a.is_null() {
119 return Ok(Datum::Null);
120 }
121 let list = a.unwrap_list();
122 let mut map = std::collections::BTreeMap::new();
123
124 for i in list.iter() {
125 if i.is_null() {
126 continue;
127 }
128
129 for (k, v) in i.unwrap_list().iter().tuples() {
130 if k.is_null() {
131 continue;
132 }
133 map.insert(k.unwrap_str(), v);
134 }
135 }
136
137 let map = temp_storage.make_datum(|packer| packer.push_dict(map));
138 Ok(map)
139 }
140
141 fn output_sql_type(&self, _input_type: SqlColumnType) -> SqlColumnType {
142 SqlScalarType::Map {
143 value_type: Box::new(self.value_type.clone()),
144 custom_id: None,
145 }
146 .nullable(true)
147 }
148
149 fn propagates_nulls(&self) -> bool {
150 true
151 }
152
153 fn introduces_nulls(&self) -> bool {
154 true
155 }
156
157 fn preserves_uniqueness(&self) -> bool {
158 false
159 }
160
161 fn inverse(&self) -> Option<crate::UnaryFunc> {
162 None
163 }
164
165 fn is_monotone(&self) -> bool {
166 false
167 }
168
169 fn is_eliminable_cast(&self) -> bool {
170 false
171 }
172}
173
174impl fmt::Display for MapBuildFromRecordList {
175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176 f.write_str("map_build")
177 }
178}