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

getdozer / dozer / 5996155062

28 Aug 2023 05:54AM UTC coverage: 76.026% (+0.5%) from 75.575%
5996155062

push

github

web-flow
chore: setup MySQL and MariaDB services in the CI (#1920)

The MySQL connector should be tested against MariaDB as well, because it has been failing recently on MariaDB.

The switch to `docker run` to start the services from the nicer declarative service specification is because the latter doesn't have an option to specify the container command line arguments, which are needed to enable CDC on MariaDB.

47318 of 62239 relevant lines covered (76.03%)

49704.23 hits per line

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

42.76
/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> {
950,954✔
302
        match self {
950,954✔
303
            Expression::Literal(field) => Ok(field.clone()),
802,811✔
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
    }
950,954✔
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

© 2025 Coveralls, Inc