• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

getdozer / dozer / 5664579549

pending completion
5664579549

push

github

web-flow
chore: Update arrow version and its ecosystem to 42 (#1793)

15 of 15 new or added lines in 9 files covered. (100.0%)

45671 of 59560 relevant lines covered (76.68%)

39051.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.85
/dozer-sql/src/pipeline/expression/execution.rs
1
use crate::pipeline::aggregation::avg::validate_avg;
2
use crate::pipeline::aggregation::count::validate_count;
3
use crate::pipeline::aggregation::max::validate_max;
4
use crate::pipeline::aggregation::min::validate_min;
5
use crate::pipeline::aggregation::sum::validate_sum;
6
use crate::pipeline::errors::PipelineError;
7
use crate::pipeline::expression::conditional::{
8
    get_conditional_expr_type, ConditionalExpressionType,
9
};
10
use crate::pipeline::expression::datetime::{get_datetime_function_type, DateTimeFunctionType};
11
use crate::pipeline::expression::geo::common::{get_geo_function_type, GeoFunctionType};
12
use crate::pipeline::expression::json_functions::JsonFunctionType;
13
use crate::pipeline::expression::operator::{BinaryOperatorType, UnaryOperatorType};
14
use crate::pipeline::expression::scalar::common::{get_scalar_function_type, ScalarFunctionType};
15
use crate::pipeline::expression::scalar::string::{evaluate_trim, validate_trim, TrimType};
16
use std::iter::zip;
17

18
use crate::pipeline::expression::case::evaluate_case;
19

20
use crate::pipeline::aggregation::max_value::validate_max_value;
21
use crate::pipeline::aggregation::min_value::validate_min_value;
22
use dozer_core::processor_record::ProcessorRecord;
23
use dozer_types::types::{Field, FieldType, Schema, SourceDefinition};
24
use uuid::Uuid;
25

26
use super::aggregate::AggregateFunctionType;
27
use super::cast::CastOperatorType;
28
use super::in_list::evaluate_in_list;
29
use super::scalar::string::{evaluate_like, get_like_operator_type};
30

31
#[derive(Clone, Debug, PartialEq)]
119,085✔
32
pub enum Expression {
33
    Column {
34
        index: usize,
35
    },
36
    Literal(Field),
37
    UnaryOperator {
38
        operator: UnaryOperatorType,
39
        arg: Box<Expression>,
40
    },
41
    BinaryOperator {
42
        left: Box<Expression>,
43
        operator: BinaryOperatorType,
44
        right: Box<Expression>,
45
    },
46
    ScalarFunction {
47
        fun: ScalarFunctionType,
48
        args: Vec<Expression>,
49
    },
50
    GeoFunction {
51
        fun: GeoFunctionType,
52
        args: Vec<Expression>,
53
    },
54
    ConditionalExpression {
55
        fun: ConditionalExpressionType,
56
        args: Vec<Expression>,
57
    },
58
    DateTimeFunction {
59
        fun: DateTimeFunctionType,
60
        arg: Box<Expression>,
61
    },
62
    AggregateFunction {
63
        fun: AggregateFunctionType,
64
        args: Vec<Expression>,
65
    },
66
    Cast {
67
        arg: Box<Expression>,
68
        typ: CastOperatorType,
69
    },
70
    Trim {
71
        arg: Box<Expression>,
72
        what: Option<Box<Expression>>,
73
        typ: Option<TrimType>,
74
    },
75
    Like {
76
        arg: Box<Expression>,
77
        pattern: Box<Expression>,
78
        escape: Option<char>,
79
    },
80
    InList {
81
        expr: Box<Expression>,
82
        list: Vec<Expression>,
83
        negated: bool,
84
    },
85
    Now {
86
        fun: DateTimeFunctionType,
87
    },
88
    Json {
89
        fun: JsonFunctionType,
90
        args: Vec<Expression>,
91
    },
92
    Case {
93
        operand: Option<Box<Expression>>,
94
        conditions: Vec<Expression>,
95
        results: Vec<Expression>,
96
        else_result: Option<Box<Expression>>,
97
    },
98
    #[cfg(feature = "python")]
99
    PythonUDF {
100
        name: String,
101
        args: Vec<Expression>,
102
        return_type: FieldType,
103
    },
104
}
105

106
impl Expression {
107
    pub fn to_string(&self, schema: &Schema) -> String {
2,461✔
108
        match &self {
2,461✔
109
            Expression::Column { index } => schema.fields[*index].name.clone(),
2,114✔
110
            Expression::Literal(value) => value
27✔
111
                .to_string()
27✔
112
                .unwrap_or_else(|| Uuid::new_v4().to_string()),
27✔
113
            Expression::UnaryOperator { operator, arg } => {
×
114
                operator.to_string() + arg.to_string(schema).as_str()
×
115
            }
116
            Expression::BinaryOperator {
117
                left,
×
118
                operator,
×
119
                right,
×
120
            } => {
×
121
                left.to_string(schema)
×
122
                    + operator.to_string().as_str()
×
123
                    + right.to_string(schema).as_str()
×
124
            }
125
            Expression::ScalarFunction { fun, args } => {
4✔
126
                fun.to_string()
4✔
127
                    + "("
4✔
128
                    + args
4✔
129
                        .iter()
4✔
130
                        .map(|e| e.to_string(schema))
9✔
131
                        .collect::<Vec<String>>()
4✔
132
                        .join(",")
4✔
133
                        .as_str()
4✔
134
                    + ")"
4✔
135
            }
136
            Expression::ConditionalExpression { fun, args } => {
×
137
                fun.to_string()
×
138
                    + "("
×
139
                    + args
×
140
                        .iter()
×
141
                        .map(|e| e.to_string(schema))
×
142
                        .collect::<Vec<String>>()
×
143
                        .join(",")
×
144
                        .as_str()
×
145
                    + ")"
×
146
            }
147
            Expression::AggregateFunction { fun, args } => {
284✔
148
                fun.to_string()
284✔
149
                    + "("
284✔
150
                    + args
284✔
151
                        .iter()
284✔
152
                        .map(|e| e.to_string(schema))
310✔
153
                        .collect::<Vec<String>>()
284✔
154
                        .join(",")
284✔
155
                        .as_str()
284✔
156
                    + ")"
284✔
157
            }
158
            #[cfg(feature = "python")]
159
            Expression::PythonUDF { name, args, .. } => {
16✔
160
                name.to_string()
16✔
161
                    + "("
16✔
162
                    + args
16✔
163
                        .iter()
16✔
164
                        .map(|expr| expr.to_string(schema))
24✔
165
                        .collect::<Vec<String>>()
16✔
166
                        .join(",")
16✔
167
                        .as_str()
16✔
168
                    + ")"
16✔
169
            }
170
            Expression::Cast { arg, typ } => {
×
171
                "CAST(".to_string()
×
172
                    + arg.to_string(schema).as_str()
×
173
                    + " AS "
×
174
                    + typ.to_string().as_str()
×
175
                    + ")"
×
176
            }
177
            Expression::Case {
178
                operand,
×
179
                conditions,
×
180
                results,
×
181
                else_result,
×
182
            } => {
×
183
                let mut op_str = String::new();
×
184
                if let Some(op) = operand {
×
185
                    op_str += " ";
×
186
                    op_str += op.to_string(schema).as_str();
×
187
                }
×
188
                let mut when_then_str = String::new();
×
189
                let iter = zip(conditions, results);
×
190
                for (cond, res) in iter {
×
191
                    when_then_str += " WHEN ";
×
192
                    when_then_str += cond.to_string(schema).as_str();
×
193
                    when_then_str += " THEN ";
×
194
                    when_then_str += res.to_string(schema).as_str();
×
195
                }
×
196
                let mut else_str = String::new();
×
197
                if let Some(else_res) = else_result {
×
198
                    else_str += " ELSE ";
×
199
                    else_str += else_res.to_string(schema).as_str();
×
200
                }
×
201

202
                "CASE".to_string()
×
203
                    + op_str.as_str()
×
204
                    + when_then_str.as_str()
×
205
                    + else_str.as_str()
×
206
                    + " END"
×
207
            }
208
            Expression::Trim { typ, what, arg } => {
16✔
209
                "TRIM(".to_string()
16✔
210
                    + if let Some(t) = typ {
16✔
211
                        t.to_string()
×
212
                    } else {
213
                        "".to_string()
16✔
214
                    }
215
                    .as_str()
16✔
216
                    + if let Some(w) = what {
16✔
217
                        w.to_string(schema) + " FROM "
×
218
                    } else {
219
                        "".to_string()
16✔
220
                    }
221
                    .as_str()
16✔
222
                    + arg.to_string(schema).as_str()
16✔
223
                    + ")"
16✔
224
            }
225

226
            Expression::Like {
227
                arg,
×
228
                pattern,
×
229
                escape: _,
×
230
            } => arg.to_string(schema) + " LIKE " + pattern.to_string(schema).as_str(),
×
231
            Expression::InList {
232
                expr,
×
233
                list,
×
234
                negated,
×
235
            } => {
×
236
                expr.to_string(schema)
×
237
                    + if *negated { " NOT" } else { "" }
×
238
                    + " IN ("
×
239
                    + list
×
240
                        .iter()
×
241
                        .map(|e| e.to_string(schema))
×
242
                        .collect::<Vec<String>>()
×
243
                        .join(",")
×
244
                        .as_str()
×
245
                    + ")"
×
246
            }
247
            Expression::GeoFunction { fun, args } => {
×
248
                fun.to_string()
×
249
                    + "("
×
250
                    + args
×
251
                        .iter()
×
252
                        .map(|e| e.to_string(schema))
×
253
                        .collect::<Vec<String>>()
×
254
                        .join(",")
×
255
                        .as_str()
×
256
                    + ")"
×
257
            }
258
            Expression::DateTimeFunction { fun, arg } => {
×
259
                fun.to_string() + "(" + arg.to_string(schema).as_str() + ")"
×
260
            }
261
            Expression::Now { fun } => fun.to_string() + "()",
×
262
            Expression::Json { fun, args } => {
×
263
                fun.to_string()
×
264
                    + "("
×
265
                    + args
×
266
                        .iter()
×
267
                        .map(|e| e.to_string(schema))
×
268
                        .collect::<Vec<String>>()
×
269
                        .join(",")
×
270
                        .as_str()
×
271
                    + ")"
×
272
            }
273
        }
274
    }
2,461✔
275
}
276

277
pub struct ExpressionType {
278
    pub return_type: FieldType,
279
    pub nullable: bool,
280
    pub source: SourceDefinition,
281
    pub is_primary_key: bool,
282
}
283

284
impl ExpressionType {
285
    pub fn new(
217,346✔
286
        return_type: FieldType,
217,346✔
287
        nullable: bool,
217,346✔
288
        source: SourceDefinition,
217,346✔
289
        is_primary_key: bool,
217,346✔
290
    ) -> Self {
217,346✔
291
        Self {
217,346✔
292
            return_type,
217,346✔
293
            nullable,
217,346✔
294
            source,
217,346✔
295
            is_primary_key,
217,346✔
296
        }
217,346✔
297
    }
217,346✔
298
}
299

300
impl Expression {
301
    pub fn evaluate(
930,951✔
302
        &self,
930,951✔
303
        record: &ProcessorRecord,
930,951✔
304
        schema: &Schema,
930,951✔
305
    ) -> Result<Field, PipelineError> {
930,951✔
306
        match self {
930,951✔
307
            Expression::Literal(field) => Ok(field.clone()),
798,867✔
308
            Expression::Column { index } => Ok(record.get_field_by_index(*index as u32).clone()),
116,785✔
309
            Expression::BinaryOperator {
×
310
                left,
13,971✔
311
                operator,
13,971✔
312
                right,
13,971✔
313
            } => operator.evaluate(schema, left, right, record),
13,971✔
314
            Expression::ScalarFunction { fun, args } => fun.evaluate(schema, args, record),
1,020✔
315

×
316
            #[cfg(feature = "python")]
×
317
            Expression::PythonUDF {
×
318
                name,
8✔
319
                args,
8✔
320
                return_type,
8✔
321
                ..
8✔
322
            } => {
8✔
323
                use crate::pipeline::expression::python_udf::evaluate_py_udf;
8✔
324
                evaluate_py_udf(schema, name, args, return_type, record)
8✔
325
            }
×
326
            Expression::UnaryOperator { operator, arg } => operator.evaluate(schema, arg, record),
1✔
327
            Expression::AggregateFunction { fun, args: _ } => {
×
328
                Err(PipelineError::InvalidExpression(format!(
×
329
                    "Aggregate Function {fun:?} should not be executed at this point"
×
330
                )))
×
331
            }
×
332
            Expression::Trim { typ, what, arg } => evaluate_trim(schema, arg, what, typ, record),
47✔
333
            Expression::Like {
×
334
                arg,
80✔
335
                pattern,
80✔
336
                escape,
80✔
337
            } => evaluate_like(schema, arg, pattern, *escape, record),
80✔
338
            Expression::InList {
×
339
                expr,
8✔
340
                list,
8✔
341
                negated,
8✔
342
            } => evaluate_in_list(schema, expr, list, *negated, record),
8✔
343
            Expression::Cast { arg, typ } => typ.evaluate(schema, arg, record),
98✔
344
            Expression::GeoFunction { fun, args } => fun.evaluate(schema, args, record),
7✔
345
            Expression::ConditionalExpression { fun, args } => fun.evaluate(schema, args, record),
5✔
346
            Expression::DateTimeFunction { fun, arg } => fun.evaluate(schema, arg, record),
35✔
347
            Expression::Now { fun } => fun.evaluate_now(),
1✔
348
            Expression::Json { fun, args } => fun.evaluate(schema, args, record),
15✔
349
            Expression::Case {
×
350
                operand,
3✔
351
                conditions,
3✔
352
                results,
3✔
353
                else_result,
3✔
354
            } => evaluate_case(schema, operand, conditions, results, else_result, record),
3✔
355
        }
×
356
    }
930,951✔
357

×
358
    pub fn get_type(&self, schema: &Schema) -> Result<ExpressionType, PipelineError> {
178,434✔
359
        match self {
178,434✔
360
            Expression::Literal(field) => {
103,055✔
361
                let field_type = get_field_type(field);
103,055✔
362
                match field_type {
103,055✔
363
                    Some(f) => Ok(ExpressionType::new(
97,055✔
364
                        f,
97,055✔
365
                        false,
97,055✔
366
                        SourceDefinition::Dynamic,
97,055✔
367
                        false,
97,055✔
368
                    )),
97,055✔
369
                    None => Err(PipelineError::InvalidExpression(
6,000✔
370
                        "literal expression cannot be null".to_string(),
6,000✔
371
                    )),
6,000✔
372
                }
×
373
            }
×
374
            Expression::Column { index } => {
73,547✔
375
                let t = schema.fields.get(*index).unwrap();
73,547✔
376

73,547✔
377
                Ok(ExpressionType::new(
73,547✔
378
                    t.typ,
73,547✔
379
                    t.nullable,
73,547✔
380
                    t.source.clone(),
73,547✔
381
                    schema.primary_index.contains(index),
73,547✔
382
                ))
73,547✔
383
            }
×
384
            Expression::UnaryOperator { operator, arg } => {
×
385
                get_unary_operator_type(operator, arg, schema)
×
386
            }
387
            Expression::BinaryOperator {
×
388
                left,
32✔
389
                operator,
32✔
390
                right,
32✔
391
            } => get_binary_operator_type(left, operator, right, schema),
32✔
392
            Expression::ScalarFunction { fun, args } => get_scalar_function_type(fun, args, schema),
1,017✔
393
            Expression::ConditionalExpression { fun, args } => {
5✔
394
                get_conditional_expr_type(fun, args, schema)
5✔
395
            }
×
396
            Expression::AggregateFunction { fun, args } => {
611✔
397
                get_aggregate_function_type(fun, args, schema)
611✔
398
            }
399
            Expression::Trim {
×
400
                what: _,
×
401
                typ: _,
402
                arg,
23✔
403
            } => validate_trim(arg, schema),
23✔
404
            Expression::Like {
405
                arg,
×
406
                pattern,
×
407
                escape: _,
×
408
            } => get_like_operator_type(arg, pattern, schema),
×
409
            Expression::InList {
×
410
                expr: _,
×
411
                list: _,
×
412
                negated: _,
413
            } => Ok(ExpressionType::new(
8✔
414
                FieldType::Boolean,
8✔
415
                false,
8✔
416
                SourceDefinition::Dynamic,
8✔
417
                false,
8✔
418
            )),
8✔
419
            Expression::Cast { arg, typ } => typ.get_return_type(schema, arg),
59✔
420
            Expression::GeoFunction { fun, args } => get_geo_function_type(fun, args, schema),
7✔
421
            Expression::DateTimeFunction { fun, arg } => {
35✔
422
                get_datetime_function_type(fun, arg, schema)
35✔
423
            }
×
424
            Expression::Now { fun: _ } => Ok(ExpressionType::new(
1✔
425
                FieldType::Timestamp,
1✔
426
                false,
1✔
427
                dozer_types::types::SourceDefinition::Dynamic,
1✔
428
                false,
1✔
429
            )),
1✔
430
            Expression::Json { fun: _, args: _ } => Ok(ExpressionType::new(
15✔
431
                FieldType::Json,
15✔
432
                false,
15✔
433
                dozer_types::types::SourceDefinition::Dynamic,
15✔
434
                false,
15✔
435
            )),
15✔
436
            Expression::Case {
×
437
                operand: _,
×
438
                conditions: _,
×
439
                results,
3✔
440
                else_result: _,
441
            } => {
442
                let typ = results.get(0).unwrap().get_type(schema)?;
3✔
443
                Ok(ExpressionType::new(
3✔
444
                    typ.return_type,
3✔
445
                    true,
3✔
446
                    dozer_types::types::SourceDefinition::Dynamic,
3✔
447
                    false,
3✔
448
                ))
3✔
449
            }
×
450
            #[cfg(feature = "python")]
×
451
            Expression::PythonUDF { return_type, .. } => Ok(ExpressionType::new(
16✔
452
                *return_type,
16✔
453
                false,
16✔
454
                SourceDefinition::Dynamic,
16✔
455
                false,
16✔
456
            )),
16✔
457
        }
×
458
    }
178,434✔
459
}
×
460

461
fn get_field_type(field: &Field) -> Option<FieldType> {
103,055✔
462
    match field {
103,055✔
463
        Field::UInt(_) => Some(FieldType::UInt),
5,000✔
464
        Field::U128(_) => Some(FieldType::U128),
×
465
        Field::Int(_) => Some(FieldType::Int),
7,010✔
466
        Field::I128(_) => Some(FieldType::I128),
×
467
        Field::Float(_) => Some(FieldType::Float),
5,000✔
468
        Field::Boolean(_) => Some(FieldType::Boolean),
×
469
        Field::String(_) => Some(FieldType::String),
38,045✔
470
        Field::Binary(_) => Some(FieldType::Binary),
×
471
        Field::Decimal(_) => Some(FieldType::Decimal),
5,000✔
472
        Field::Timestamp(_) => Some(FieldType::Timestamp),
5,000✔
473
        Field::Json(_) => Some(FieldType::Json),
×
474
        Field::Text(_) => Some(FieldType::Text),
18,000✔
475
        Field::Date(_) => Some(FieldType::Date),
5,000✔
476
        Field::Point(_) => Some(FieldType::Point),
9,000✔
477
        Field::Duration(_) => Some(FieldType::Duration),
×
478
        Field::Null => None,
6,000✔
479
    }
×
480
}
103,055✔
481

×
482
fn get_unary_operator_type(
×
483
    operator: &UnaryOperatorType,
×
484
    expression: &Expression,
×
485
    schema: &Schema,
×
486
) -> Result<ExpressionType, PipelineError> {
×
487
    let field_type = expression.get_type(schema)?;
×
488
    match operator {
×
489
        UnaryOperatorType::Not => match field_type.return_type {
×
490
            FieldType::Boolean => Ok(field_type),
×
491
            field_type => Err(PipelineError::InvalidExpression(format!(
×
492
                "cannot apply NOT to {field_type:?}"
×
493
            ))),
×
494
        },
×
495
        UnaryOperatorType::Plus => Ok(field_type),
×
496
        UnaryOperatorType::Minus => Ok(field_type),
×
497
    }
498
}
×
499

×
500
fn get_binary_operator_type(
32✔
501
    left: &Expression,
32✔
502
    operator: &BinaryOperatorType,
32✔
503
    right: &Expression,
32✔
504
    schema: &Schema,
32✔
505
) -> Result<ExpressionType, PipelineError> {
32✔
506
    let left_field_type = left.get_type(schema)?;
32✔
507
    let right_field_type = right.get_type(schema)?;
32✔
508
    match operator {
32✔
509
        BinaryOperatorType::Eq
×
510
        | BinaryOperatorType::Ne
×
511
        | BinaryOperatorType::Gt
×
512
        | BinaryOperatorType::Gte
513
        | BinaryOperatorType::Lt
514
        | BinaryOperatorType::Lte => Ok(ExpressionType::new(
10✔
515
            FieldType::Boolean,
10✔
516
            false,
10✔
517
            SourceDefinition::Dynamic,
10✔
518
            false,
10✔
519
        )),
10✔
520

×
521
        BinaryOperatorType::And | BinaryOperatorType::Or => {
×
522
            match (left_field_type.return_type, right_field_type.return_type) {
×
523
                (FieldType::Boolean, FieldType::Boolean) => Ok(ExpressionType::new(
×
524
                    FieldType::Boolean,
×
525
                    false,
×
526
                    SourceDefinition::Dynamic,
×
527
                    false,
×
528
                )),
×
529
                (
×
530
                    FieldType::Boolean,
×
531
                    FieldType::UInt
×
532
                    | FieldType::U128
533
                    | FieldType::Int
534
                    | FieldType::I128
535
                    | FieldType::String
536
                    | FieldType::Text,
537
                ) => Ok(ExpressionType::new(
×
538
                    FieldType::Boolean,
×
539
                    false,
×
540
                    SourceDefinition::Dynamic,
×
541
                    false,
×
542
                )),
×
543
                (
×
544
                    FieldType::UInt
×
545
                    | FieldType::U128
×
546
                    | FieldType::Int
547
                    | FieldType::I128
548
                    | FieldType::String
549
                    | FieldType::Text,
550
                    FieldType::Boolean,
551
                ) => Ok(ExpressionType::new(
×
552
                    FieldType::Boolean,
×
553
                    false,
×
554
                    SourceDefinition::Dynamic,
×
555
                    false,
×
556
                )),
×
557
                (left_field_type, right_field_type) => {
×
558
                    Err(PipelineError::InvalidExpression(format!(
×
559
                        "cannot apply {operator:?} to {left_field_type:?} and {right_field_type:?}"
×
560
                    )))
×
561
                }
×
562
            }
×
563
        }
×
564

565
        BinaryOperatorType::Add
566
        | BinaryOperatorType::Sub
567
        | BinaryOperatorType::Mul
568
        | BinaryOperatorType::Mod => {
569
            match (left_field_type.return_type, right_field_type.return_type) {
14✔
570
                (FieldType::UInt, FieldType::UInt) => Ok(ExpressionType::new(
×
571
                    FieldType::UInt,
×
572
                    false,
×
573
                    SourceDefinition::Dynamic,
×
574
                    false,
×
575
                )),
×
576
                (FieldType::U128, FieldType::U128)
×
577
                | (FieldType::U128, FieldType::UInt)
×
578
                | (FieldType::UInt, FieldType::U128) => Ok(ExpressionType::new(
×
579
                    FieldType::U128,
×
580
                    false,
×
581
                    SourceDefinition::Dynamic,
×
582
                    false,
×
583
                )),
×
584
                (FieldType::Timestamp, FieldType::Timestamp) => Ok(ExpressionType::new(
1✔
585
                    FieldType::Duration,
1✔
586
                    false,
1✔
587
                    SourceDefinition::Dynamic,
1✔
588
                    false,
1✔
589
                )),
1✔
590
                (FieldType::Timestamp, FieldType::Duration) => Ok(ExpressionType::new(
2✔
591
                    FieldType::Timestamp,
2✔
592
                    false,
2✔
593
                    SourceDefinition::Dynamic,
2✔
594
                    false,
2✔
595
                )),
2✔
596
                (FieldType::Duration, FieldType::Timestamp) => Ok(ExpressionType::new(
1✔
597
                    FieldType::Timestamp,
1✔
598
                    false,
1✔
599
                    SourceDefinition::Dynamic,
1✔
600
                    false,
1✔
601
                )),
1✔
602
                (FieldType::Duration, FieldType::Duration) => Ok(ExpressionType::new(
×
603
                    FieldType::Duration,
×
604
                    false,
×
605
                    SourceDefinition::Dynamic,
×
606
                    false,
×
607
                )),
×
608
                (FieldType::Int, FieldType::Int)
×
609
                | (FieldType::Int, FieldType::UInt)
×
610
                | (FieldType::UInt, FieldType::Int) => Ok(ExpressionType::new(
2✔
611
                    FieldType::Int,
2✔
612
                    false,
2✔
613
                    SourceDefinition::Dynamic,
2✔
614
                    false,
2✔
615
                )),
2✔
616
                (FieldType::I128, FieldType::I128)
×
617
                | (FieldType::I128, FieldType::UInt)
×
618
                | (FieldType::I128, FieldType::U128)
×
619
                | (FieldType::I128, FieldType::Int)
620
                | (FieldType::UInt, FieldType::I128)
621
                | (FieldType::U128, FieldType::I128)
622
                | (FieldType::Int, FieldType::I128) => Ok(ExpressionType::new(
×
623
                    FieldType::I128,
×
624
                    false,
×
625
                    SourceDefinition::Dynamic,
×
626
                    false,
×
627
                )),
×
628
                (FieldType::Float, FieldType::Float)
×
629
                | (FieldType::Float, FieldType::UInt)
×
630
                | (FieldType::Float, FieldType::U128)
×
631
                | (FieldType::Float, FieldType::Int)
632
                | (FieldType::Float, FieldType::I128)
633
                | (FieldType::UInt, FieldType::Float)
634
                | (FieldType::U128, FieldType::Float)
635
                | (FieldType::Int, FieldType::Float)
636
                | (FieldType::I128, FieldType::Float) => Ok(ExpressionType::new(
×
637
                    FieldType::Float,
×
638
                    false,
×
639
                    SourceDefinition::Dynamic,
×
640
                    false,
×
641
                )),
×
642
                (FieldType::Decimal, FieldType::Decimal)
×
643
                | (FieldType::UInt, FieldType::Decimal)
×
644
                | (FieldType::U128, FieldType::Decimal)
×
645
                | (FieldType::Int, FieldType::Decimal)
646
                | (FieldType::I128, FieldType::Decimal)
647
                | (FieldType::Float, FieldType::Decimal)
648
                | (FieldType::Decimal, FieldType::UInt)
649
                | (FieldType::Decimal, FieldType::U128)
650
                | (FieldType::Decimal, FieldType::Int)
651
                | (FieldType::Decimal, FieldType::I128)
652
                | (FieldType::Decimal, FieldType::Float) => Ok(ExpressionType::new(
8✔
653
                    FieldType::Decimal,
8✔
654
                    false,
8✔
655
                    SourceDefinition::Dynamic,
8✔
656
                    false,
8✔
657
                )),
8✔
658
                (left_field_type, right_field_type) => {
×
659
                    Err(PipelineError::InvalidExpression(format!(
×
660
                        "cannot apply {operator:?} to {left_field_type:?} and {right_field_type:?}"
×
661
                    )))
×
662
                }
×
663
            }
×
664
        }
×
665

666
        BinaryOperatorType::Div => {
667
            match (left_field_type.return_type, right_field_type.return_type) {
8✔
668
                (FieldType::Int, FieldType::UInt)
669
                | (FieldType::Int, FieldType::Int)
670
                | (FieldType::Int, FieldType::U128)
×
671
                | (FieldType::Int, FieldType::I128)
672
                | (FieldType::Int, FieldType::Float)
673
                | (FieldType::I128, FieldType::UInt)
674
                | (FieldType::I128, FieldType::Int)
675
                | (FieldType::I128, FieldType::U128)
676
                | (FieldType::I128, FieldType::I128)
677
                | (FieldType::I128, FieldType::Float)
678
                | (FieldType::UInt, FieldType::UInt)
679
                | (FieldType::UInt, FieldType::U128)
680
                | (FieldType::UInt, FieldType::Int)
681
                | (FieldType::UInt, FieldType::I128)
682
                | (FieldType::UInt, FieldType::Float)
683
                | (FieldType::U128, FieldType::UInt)
684
                | (FieldType::U128, FieldType::U128)
685
                | (FieldType::U128, FieldType::Int)
686
                | (FieldType::U128, FieldType::I128)
687
                | (FieldType::U128, FieldType::Float)
688
                | (FieldType::Float, FieldType::UInt)
689
                | (FieldType::Float, FieldType::U128)
690
                | (FieldType::Float, FieldType::Int)
691
                | (FieldType::Float, FieldType::I128)
692
                | (FieldType::Float, FieldType::Float) => Ok(ExpressionType::new(
×
693
                    FieldType::Float,
×
694
                    false,
×
695
                    SourceDefinition::Dynamic,
×
696
                    false,
×
697
                )),
×
698
                (FieldType::Decimal, FieldType::Decimal)
×
699
                | (FieldType::Decimal, FieldType::UInt)
×
700
                | (FieldType::Decimal, FieldType::U128)
×
701
                | (FieldType::Decimal, FieldType::Int)
702
                | (FieldType::Decimal, FieldType::I128)
703
                | (FieldType::Decimal, FieldType::Float)
704
                | (FieldType::UInt, FieldType::Decimal)
705
                | (FieldType::U128, FieldType::Decimal)
706
                | (FieldType::Int, FieldType::Decimal)
707
                | (FieldType::I128, FieldType::Decimal)
708
                | (FieldType::Float, FieldType::Decimal) => Ok(ExpressionType::new(
8✔
709
                    FieldType::Decimal,
8✔
710
                    false,
8✔
711
                    SourceDefinition::Dynamic,
8✔
712
                    false,
8✔
713
                )),
8✔
714
                (left_field_type, right_field_type) => {
×
715
                    Err(PipelineError::InvalidExpression(format!(
×
716
                        "cannot apply {operator:?} to {left_field_type:?} and {right_field_type:?}"
×
717
                    )))
×
718
                }
×
719
            }
×
720
        }
×
721
    }
722
}
32✔
723

724
fn get_aggregate_function_type(
611✔
725
    function: &AggregateFunctionType,
611✔
726
    args: &[Expression],
611✔
727
    schema: &Schema,
611✔
728
) -> Result<ExpressionType, PipelineError> {
611✔
729
    match function {
611✔
730
        AggregateFunctionType::Avg => validate_avg(args, schema),
54✔
731
        AggregateFunctionType::Count => validate_count(args, schema),
297✔
732
        AggregateFunctionType::Max => validate_max(args, schema),
50✔
733
        AggregateFunctionType::MaxValue => validate_max_value(args, schema),
26✔
734
        AggregateFunctionType::Min => validate_min(args, schema),
50✔
735
        AggregateFunctionType::MinValue => validate_min_value(args, schema),
26✔
736
        AggregateFunctionType::Sum => validate_sum(args, schema),
108✔
737
    }
×
738
}
611✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc