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

getdozer / dozer / 6015696039

29 Aug 2023 05:40PM UTC coverage: 75.532% (-0.8%) from 76.332%
6015696039

push

github

web-flow
Bump clap from 4.3.11 to 4.4.1 (#1941)

Bumps [clap](https://github.com/clap-rs/clap) from 4.3.11 to 4.4.1.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.3.11...v4.4.1)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

49076 of 64974 relevant lines covered (75.53%)

65447.31 hits per line

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

41.9
/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_types::types::Record;
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)]
123,590✔
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 {
3,958✔
108
        match &self {
3,958✔
109
            Expression::Column { index } => schema.fields[*index].name.clone(),
3,443✔
110
            Expression::Literal(value) => value
33✔
111
                .to_string()
33✔
112
                .unwrap_or_else(|| Uuid::new_v4().to_string()),
33✔
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 } => {
422✔
148
                fun.to_string()
422✔
149
                    + "("
422✔
150
                    + args
422✔
151
                        .iter()
422✔
152
                        .map(|e| e.to_string(schema))
448✔
153
                        .collect::<Vec<String>>()
422✔
154
                        .join(",")
422✔
155
                        .as_str()
422✔
156
                    + ")"
422✔
157
            }
×
158
            #[cfg(feature = "python")]
×
159
            Expression::PythonUDF { name, args, .. } => {
28✔
160
                name.to_string()
28✔
161
                    + "("
28✔
162
                    + args
28✔
163
                        .iter()
28✔
164
                        .map(|expr| expr.to_string(schema))
42✔
165
                        .collect::<Vec<String>>()
28✔
166
                        .join(",")
28✔
167
                        .as_str()
28✔
168
                    + ")"
28✔
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 } => {
28✔
209
                "TRIM(".to_string()
28✔
210
                    + if let Some(t) = typ {
28✔
211
                        t.to_string()
×
212
                    } else {
×
213
                        "".to_string()
28✔
214
                    }
×
215
                    .as_str()
28✔
216
                    + if let Some(w) = what {
28✔
217
                        w.to_string(schema) + " FROM "
×
218
                    } else {
×
219
                        "".to_string()
28✔
220
                    }
×
221
                    .as_str()
28✔
222
                    + arg.to_string(schema).as_str()
28✔
223
                    + ")"
28✔
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
    }
3,958✔
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(
219,118✔
286
        return_type: FieldType,
219,118✔
287
        nullable: bool,
219,118✔
288
        source: SourceDefinition,
219,118✔
289
        is_primary_key: bool,
219,118✔
290
    ) -> Self {
219,118✔
291
        Self {
219,118✔
292
            return_type,
219,118✔
293
            nullable,
219,118✔
294
            source,
219,118✔
295
            is_primary_key,
219,118✔
296
        }
219,118✔
297
    }
219,118✔
298
}
299

300
impl Expression {
301
    pub fn evaluate(&self, record: &Record, schema: &Schema) -> Result<Field, PipelineError> {
951,830✔
302
        match self {
951,830✔
303
            Expression::Literal(field) => Ok(field.clone()),
803,687✔
304
            Expression::Column { index } => Ok(record.values[*index].clone()),
129,865✔
305
            Expression::BinaryOperator {
×
306
                left,
16,824✔
307
                operator,
16,824✔
308
                right,
16,824✔
309
            } => operator.evaluate(schema, left, right, record),
16,824✔
310
            Expression::ScalarFunction { fun, args } => fun.evaluate(schema, args, record),
1,020✔
311

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

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

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

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

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

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

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

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

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

720
fn get_aggregate_function_type(
926✔
721
    function: &AggregateFunctionType,
926✔
722
    args: &[Expression],
926✔
723
    schema: &Schema,
926✔
724
) -> Result<ExpressionType, PipelineError> {
926✔
725
    match function {
926✔
726
        AggregateFunctionType::Avg => validate_avg(args, schema),
81✔
727
        AggregateFunctionType::Count => validate_count(args, schema),
498✔
728
        AggregateFunctionType::Max => validate_max(args, schema),
68✔
729
        AggregateFunctionType::MaxValue => validate_max_value(args, schema),
26✔
730
        AggregateFunctionType::Min => validate_min(args, schema),
68✔
731
        AggregateFunctionType::MinValue => validate_min_value(args, schema),
26✔
732
        AggregateFunctionType::Sum => validate_sum(args, schema),
159✔
733
    }
734
}
926✔
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