vortex_layout/layouts/row_idx/
expr.rs1use std::fmt::Formatter;
5
6use vortex_array::{ArrayRef, DeserializeMetadata, EmptyMetadata};
7use vortex_dtype::{DType, Nullability, PType};
8use vortex_error::{VortexResult, vortex_bail};
9use vortex_expr::display::{DisplayAs, DisplayFormat};
10use vortex_expr::{
11 AnalysisExpr, ExprEncodingRef, ExprId, ExprRef, IntoExpr, Scope, VTable, vtable,
12};
13
14vtable!(RowIdx);
15
16#[derive(Clone, Debug, PartialEq, Eq, Hash)]
17pub struct RowIdxExpr;
18
19impl AnalysisExpr for RowIdxExpr {}
20
21impl DisplayAs for RowIdxExpr {
22 fn fmt_as(&self, df: DisplayFormat, f: &mut Formatter) -> std::fmt::Result {
23 match df {
24 DisplayFormat::Compact => write!(f, "#row_idx"),
25 DisplayFormat::Tree => write!(f, "RowIdx"),
26 }
27 }
28}
29
30#[derive(Clone)]
31pub struct RowIdxExprEncoding;
32
33impl VTable for RowIdxVTable {
34 type Expr = RowIdxExpr;
35 type Encoding = RowIdxExprEncoding;
36 type Metadata = EmptyMetadata;
37
38 fn id(_encoding: &Self::Encoding) -> ExprId {
39 ExprId::new_ref("vortex.row_idx")
40 }
41
42 fn encoding(_expr: &Self::Expr) -> ExprEncodingRef {
43 ExprEncodingRef::new_ref(RowIdxExprEncoding.as_ref())
44 }
45
46 fn metadata(_expr: &Self::Expr) -> Option<Self::Metadata> {
47 Some(EmptyMetadata)
49 }
50
51 fn children(_expr: &Self::Expr) -> Vec<&ExprRef> {
52 vec![]
53 }
54
55 fn with_children(expr: &Self::Expr, _children: Vec<ExprRef>) -> VortexResult<Self::Expr> {
56 Ok(expr.clone())
57 }
58
59 fn build(
60 _encoding: &Self::Encoding,
61 _metadata: &<Self::Metadata as DeserializeMetadata>::Output,
62 children: Vec<ExprRef>,
63 ) -> VortexResult<Self::Expr> {
64 if !children.is_empty() {
65 vortex_bail!(
66 "RowIdxExpr does not expect any children, got {}",
67 children.len()
68 );
69 }
70 Ok(RowIdxExpr)
71 }
72
73 fn evaluate(_expr: &Self::Expr, _scope: &Scope) -> VortexResult<ArrayRef> {
74 vortex_bail!(
75 "RowIdxExpr should not be evaluated directly, use it in the context of a Vortex scan and it will be substituted for a row index array"
76 );
77 }
78
79 fn return_dtype(_expr: &Self::Expr, _scope: &DType) -> VortexResult<DType> {
80 Ok(DType::Primitive(PType::U64, Nullability::NonNullable))
81 }
82}
83
84pub fn row_idx() -> ExprRef {
85 RowIdxExpr.into_expr()
86}
87
88#[cfg(test)]
89mod tests {
90 use rstest::rstest;
91 use vortex_array::EmptyMetadata;
92 use vortex_dtype::{DType, Nullability, PType};
93 use vortex_expr::{ExprRef, IntoExpr, VTable};
94
95 use crate::layouts::row_idx::{RowIdxExpr, RowIdxExprEncoding, RowIdxVTable, row_idx};
96
97 #[test]
98 fn test_row_idx_expr_creation() {
99 let expr = row_idx();
100 assert!(expr.is::<RowIdxVTable>());
101 }
102
103 #[test]
104 fn test_vtable_id() {
105 let encoding = RowIdxExprEncoding;
106 let id = RowIdxVTable::id(&encoding);
107 assert_eq!(id.as_ref(), "vortex.row_idx");
108 }
109
110 #[test]
111 fn test_vtable_encoding() {
112 let expr = RowIdxExpr;
113 let encoding_ref = RowIdxVTable::encoding(&expr);
114
115 let encoding_ref2 = RowIdxVTable::encoding(&expr);
117 assert!(std::ptr::eq(
118 encoding_ref.as_ref() as *const _,
119 encoding_ref2.as_ref() as *const _
120 ));
121 }
122
123 #[test]
124 fn test_vtable_metadata() {
125 let expr = RowIdxExpr;
126 let metadata = RowIdxVTable::metadata(&expr);
127 assert!(metadata.is_some());
128 let _empty = metadata.unwrap();
130 }
131
132 #[test]
133 fn test_vtable_children() {
134 let expr = RowIdxExpr;
135 let children = RowIdxVTable::children(&expr);
136 assert!(children.is_empty());
137 }
138
139 #[test]
140 fn test_vtable_with_children() {
141 let expr = RowIdxExpr;
142
143 let result = RowIdxVTable::with_children(&expr, vec![]);
145 assert!(result.is_ok());
146 assert_eq!(result.unwrap(), expr);
147
148 let dummy_expr = row_idx();
150 let result = RowIdxVTable::with_children(&expr, vec![dummy_expr]);
151 assert!(result.is_ok());
152 assert_eq!(result.unwrap(), expr);
153 }
154
155 #[test]
156 fn test_vtable_build_success() {
157 let encoding = RowIdxExprEncoding;
158 let metadata = EmptyMetadata;
159 let result = RowIdxVTable::build(&encoding, &metadata, vec![]);
160 assert!(result.is_ok());
161 assert_eq!(result.unwrap(), RowIdxExpr);
162 }
163
164 #[test]
165 fn test_vtable_build_with_children_fails() {
166 let encoding = RowIdxExprEncoding;
167 let metadata = EmptyMetadata;
168 let dummy_expr = row_idx();
169 let result = RowIdxVTable::build(&encoding, &metadata, vec![dummy_expr]);
170 assert!(result.is_err());
171 let err_msg = format!("{}", result.unwrap_err());
172 assert!(err_msg.contains("does not expect any children"));
173 assert!(err_msg.contains("got 1"));
174 }
175
176 #[test]
177 fn test_vtable_build_with_multiple_children_fails() {
178 let encoding = RowIdxExprEncoding;
179 let metadata = EmptyMetadata;
180 let dummy_expr1 = row_idx();
181 let dummy_expr2 = row_idx();
182 let result = RowIdxVTable::build(&encoding, &metadata, vec![dummy_expr1, dummy_expr2]);
183 assert!(result.is_err());
184 let err_msg = format!("{}", result.unwrap_err());
185 assert!(err_msg.contains("does not expect any children"));
186 assert!(err_msg.contains("got 2"));
187 }
188
189 #[test]
190 fn test_vtable_evaluate_fails() {
191 use vortex_array::IntoArray;
192 use vortex_array::arrays::PrimitiveArray;
193 use vortex_expr::Scope;
194
195 let expr = RowIdxExpr;
196 let array = PrimitiveArray::from_iter([0u64, 1, 2]).into_array();
198 let scope = Scope::new(array);
199 let result = RowIdxVTable::evaluate(&expr, &scope);
200 assert!(result.is_err());
201 let err_msg = format!("{}", result.unwrap_err());
202 assert!(err_msg.contains("should not be evaluated directly"));
203 assert!(err_msg.contains("context of a Vortex scan"));
204 }
205
206 #[test]
207 fn test_vtable_return_dtype() {
208 let expr = RowIdxExpr;
209 let scope = DType::Primitive(PType::U32, Nullability::Nullable);
210 let result = RowIdxVTable::return_dtype(&expr, &scope);
211 assert!(result.is_ok());
212 let dtype = result.unwrap();
213 assert_eq!(
214 dtype,
215 DType::Primitive(PType::U64, Nullability::NonNullable)
216 );
217 }
218
219 #[rstest]
220 #[case(DType::Primitive(PType::U8, Nullability::Nullable))]
221 #[case(DType::Primitive(PType::I64, Nullability::NonNullable))]
222 #[case(DType::Primitive(PType::F32, Nullability::Nullable))]
223 #[case(DType::Utf8(Nullability::NonNullable))]
224 #[case(DType::Binary(Nullability::Nullable))]
225 fn test_vtable_return_dtype_with_various_scopes(#[case] scope_dtype: DType) {
226 let expr = RowIdxExpr;
227 let result = RowIdxVTable::return_dtype(&expr, &scope_dtype);
228 assert!(result.is_ok());
229 assert_eq!(
231 result.unwrap(),
232 DType::Primitive(PType::U64, Nullability::NonNullable)
233 );
234 }
235
236 #[test]
237 fn test_row_idx_function_creates_correct_expr() {
238 let expr = row_idx();
239
240 assert!(expr.is::<RowIdxVTable>());
242
243 let children = RowIdxVTable::children(&RowIdxExpr);
245 assert_eq!(children.len(), 0);
246
247 let metadata = RowIdxVTable::metadata(&RowIdxExpr);
249 assert!(metadata.is_some());
250 }
251
252 #[test]
253 fn test_expr_into_expr_conversion() {
254 let expr = RowIdxExpr;
255 let expr_ref: ExprRef = expr.into_expr();
256 assert!(expr_ref.is::<RowIdxVTable>());
257 }
258}