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

getdozer / dozer / 4102355041

pending completion
4102355041

Pull #811

github

GitHub
Merge 37b55f3df into 7c772e92a
Pull Request #811: chore: integrating sql planner

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

24596 of 37831 relevant lines covered (65.02%)

37254.69 hits per line

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

34.84
/dozer-sql/src/pipeline/expression/builder.rs
1
use dozer_types::{
2
    ordered_float::OrderedFloat,
3
    types::{Field, FieldDefinition, Schema, SourceDefinition},
4
};
5

6
use sqlparser::ast::{
7
    BinaryOperator as SqlBinaryOperator, DataType, Expr as SqlExpr, Expr, Function, FunctionArg,
8
    FunctionArgExpr, Ident, TrimWhereField, UnaryOperator as SqlUnaryOperator, Value as SqlValue,
9
};
10

11
use crate::pipeline::errors::PipelineError;
12
use crate::pipeline::errors::PipelineError::{
13
    AmbiguousFieldIdentifier, IllegalFieldIdentifier, UnknownFieldIdentifier,
14
};
15
use crate::pipeline::expression::aggregate::AggregateFunctionType;
16
use crate::pipeline::expression::builder::PipelineError::InvalidArgument;
17
use crate::pipeline::expression::builder::PipelineError::InvalidExpression;
18
use crate::pipeline::expression::builder::PipelineError::InvalidOperator;
19
use crate::pipeline::expression::builder::PipelineError::InvalidValue;
20
use crate::pipeline::expression::execution::Expression;
21
use crate::pipeline::expression::execution::Expression::ScalarFunction;
22
use crate::pipeline::expression::operator::{BinaryOperatorType, UnaryOperatorType};
23
use crate::pipeline::expression::scalar::common::ScalarFunctionType;
24
use crate::pipeline::expression::scalar::string::TrimType;
25

26
use super::cast::CastOperatorType;
27

28
pub type Bypass = bool;
29

30
#[allow(dead_code)]
31
pub enum BuilderExpressionType {
32
    PreAggregation,
33
    Aggregation,
34
    // PostAggregation,
35
    FullExpression,
36
}
×
37
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1,337✔
38
pub struct NameOrAlias(pub String, pub Option<String>);
39

40
pub struct ExpressionBuilder;
41

42
impl ExpressionBuilder {
×
43
    pub fn build(
43✔
44
        &self,
43✔
45
        expression_type: &BuilderExpressionType,
43✔
46
        sql_expression: &SqlExpr,
43✔
47
        schema: &Schema,
43✔
48
    ) -> Result<Box<Expression>, PipelineError> {
43✔
49
        let (expression, _bypass) =
43✔
50
            self.parse_sql_expression(expression_type, sql_expression, schema)?;
43✔
51
        Ok(expression)
43✔
52
    }
43✔
53

54
    pub fn parse_sql_expression(
55
        &self,
56
        expression_type: &BuilderExpressionType,
57
        expression: &SqlExpr,
58
        schema: &Schema,
59
    ) -> Result<(Box<Expression>, bool), PipelineError> {
×
60
        match expression {
69✔
61
            SqlExpr::Trim {
×
62
                expr,
14✔
63
                trim_where,
14✔
64
                trim_what,
14✔
65
            } => self.parse_sql_trim_function(expression_type, expr, trim_where, trim_what, schema),
14✔
66
            SqlExpr::Identifier(ident) => Ok((parse_sql_column(&[ident.clone()], schema)?, false)),
171✔
67
            SqlExpr::CompoundIdentifier(ident) => Ok((parse_sql_column(ident, schema)?, false)),
×
68
            SqlExpr::Value(SqlValue::Number(n, _)) => self.parse_sql_number(n),
43✔
69
            SqlExpr::Value(SqlValue::Null) => {
×
70
                Ok((Box::new(Expression::Literal(Field::Null)), false))
×
71
            }
×
72
            SqlExpr::Value(SqlValue::SingleQuotedString(s) | SqlValue::DoubleQuotedString(s)) => {
26✔
73
                parse_sql_string(s)
26✔
74
            }
×
75
            SqlExpr::UnaryOp { expr, op } => {
×
76
                self.parse_sql_unary_op(expression_type, op, expr, schema)
×
77
            }
×
78
            SqlExpr::BinaryOp { left, op, right } => {
79✔
79
                self.parse_sql_binary_op(expression_type, left, op, right, schema)
79✔
80
            }
×
81
            SqlExpr::Nested(expr) => self.parse_sql_expression(expression_type, expr, schema),
12✔
82
            SqlExpr::Function(sql_function) => match expression_type {
16✔
83
                BuilderExpressionType::PreAggregation => self.parse_sql_function_pre_aggregation(
×
84
                    expression_type,
×
85
                    sql_function,
×
86
                    schema,
×
87
                    expression,
×
88
                ),
×
89
                BuilderExpressionType::Aggregation => self.parse_sql_function_aggregation(
×
90
                    expression_type,
×
91
                    sql_function,
×
92
                    schema,
×
93
                    expression,
×
94
                ),
×
95
                // ExpressionType::PostAggregation => todo!(),
96
                BuilderExpressionType::FullExpression => {
×
97
                    self.parse_sql_function(expression_type, sql_function, schema, expression)
16✔
98
                }
99
            },
100
            SqlExpr::Like {
×
101
                negated,
×
102
                expr,
×
103
                pattern,
×
104
                escape_char,
×
105
            } => self.parse_sql_like_operator(
×
106
                expression_type,
×
107
                negated,
×
108
                expr,
×
109
                pattern,
×
110
                escape_char,
×
111
                schema,
×
112
            ),
×
113
            SqlExpr::Cast { expr, data_type } => {
64✔
114
                self.parse_sql_cast_operator(expression_type, expr, data_type, schema)
64✔
115
            }
×
116
            _ => Err(InvalidExpression(format!("{expression:?}"))),
×
117
        }
×
118
    }
425✔
119

×
120
    fn parse_sql_trim_function(
14✔
121
        &self,
14✔
122
        expression_type: &BuilderExpressionType,
14✔
123
        expr: &Expr,
14✔
124
        trim_where: &Option<TrimWhereField>,
14✔
125
        trim_what: &Option<Box<Expr>>,
14✔
126
        schema: &Schema,
14✔
127
    ) -> Result<(Box<Expression>, bool), PipelineError> {
14✔
128
        let arg = self.parse_sql_expression(expression_type, expr, schema)?.0;
14✔
129
        let what = match trim_what {
14✔
130
            Some(e) => Some(self.parse_sql_expression(expression_type, e, schema)?.0),
8✔
131
            _ => None,
6✔
132
        };
×
133
        let typ = trim_where.as_ref().map(|e| match e {
14✔
134
            TrimWhereField::Both => TrimType::Both,
2✔
135
            TrimWhereField::Leading => TrimType::Leading,
2✔
136
            TrimWhereField::Trailing => TrimType::Trailing,
2✔
137
        });
14✔
138
        Ok((Box::new(Expression::Trim { arg, what, typ }), false))
14✔
139
    }
14✔
140

×
141
    fn parse_sql_function(
16✔
142
        &self,
16✔
143
        expression_type: &BuilderExpressionType,
16✔
144
        sql_function: &Function,
16✔
145
        schema: &Schema,
16✔
146
        expression: &SqlExpr,
16✔
147
    ) -> Result<(Box<Expression>, bool), PipelineError> {
16✔
148
        let name = sql_function.name.to_string().to_lowercase();
16✔
149
        if let Ok(function) = ScalarFunctionType::new(&name) {
16✔
150
            let mut arg_exprs = vec![];
15✔
151
            for arg in &sql_function.args {
37✔
152
                let r = self.parse_sql_function_arg(expression_type, arg, schema);
22✔
153
                match r {
22✔
154
                    Ok(result) => {
22✔
155
                        if result.1 {
22✔
156
                            return Ok(result);
×
157
                        } else {
22✔
158
                            arg_exprs.push(*result.0);
22✔
159
                        }
22✔
160
                    }
×
161
                    Err(error) => {
×
162
                        return Err(error);
×
163
                    }
164
                }
165
            }
166

×
167
            return Ok((
15✔
168
                Box::new(ScalarFunction {
15✔
169
                    fun: function,
15✔
170
                    args: arg_exprs,
15✔
171
                }),
15✔
172
                false,
15✔
173
            ));
15✔
174
        };
1✔
175
        if AggregateFunctionType::new(&name).is_ok() {
1✔
176
            let arg = sql_function.args.first().unwrap();
1✔
177
            let r = self.parse_sql_function_arg(expression_type, arg, schema)?;
1✔
178
            return Ok((r.0, false)); // switch bypass to true, since the argument of this Aggregation must be the final result
1✔
179
        };
×
180
        Err(InvalidExpression(format!("{expression:?}")))
×
181
    }
16✔
182

×
183
    fn parse_sql_function_pre_aggregation(
×
184
        &self,
×
185
        expression_type: &BuilderExpressionType,
×
186
        sql_function: &Function,
×
187
        schema: &Schema,
×
188
        expression: &SqlExpr,
×
189
    ) -> Result<(Box<Expression>, bool), PipelineError> {
×
190
        let name = sql_function.name.to_string().to_lowercase();
×
191

×
192
        if let Ok(function) = ScalarFunctionType::new(&name) {
×
193
            let mut arg_exprs = vec![];
×
194
            for arg in &sql_function.args {
×
195
                let r = self.parse_sql_function_arg(expression_type, arg, schema);
×
196
                match r {
×
197
                    Ok(result) => {
×
198
                        if result.1 {
×
199
                            return Ok(result);
×
200
                        } else {
×
201
                            arg_exprs.push(*result.0);
×
202
                        }
×
203
                    }
×
204
                    Err(error) => {
×
205
                        return Err(error);
×
206
                    }
207
                }
208
            }
209

×
210
            return Ok((
×
211
                Box::new(ScalarFunction {
×
212
                    fun: function,
×
213
                    args: arg_exprs,
×
214
                }),
×
215
                false,
×
216
            ));
×
217
        };
×
218
        if AggregateFunctionType::new(&name).is_ok() {
×
219
            let arg = sql_function.args.first().unwrap();
×
220
            let r = self.parse_sql_function_arg(expression_type, arg, schema)?;
×
221
            return Ok((r.0, true)); // switch bypass to true, since the argument of this Aggregation must be the final result
×
222
        };
×
223
        Err(InvalidExpression(format!("{expression:?}")))
×
224
    }
×
225

×
226
    fn parse_sql_function_aggregation(
×
227
        &self,
×
228
        expression_type: &BuilderExpressionType,
×
229
        sql_function: &Function,
×
230
        schema: &Schema,
×
231
        expression: &SqlExpr,
×
232
    ) -> Result<(Box<Expression>, bool), PipelineError> {
×
233
        let name = sql_function.name.to_string().to_lowercase();
×
234

×
235
        if let Ok(function) = ScalarFunctionType::new(&name) {
×
236
            let mut arg_exprs = vec![];
×
237
            for arg in &sql_function.args {
×
238
                let r = self.parse_sql_function_arg(expression_type, arg, schema);
×
239
                match r {
×
240
                    Ok(result) => {
×
241
                        if result.1 {
×
242
                            return Ok(result);
×
243
                        } else {
×
244
                            arg_exprs.push(*result.0);
×
245
                        }
×
246
                    }
×
247
                    Err(error) => {
×
248
                        return Err(error);
×
249
                    }
250
                }
251
            }
252

×
253
            return Ok((
×
254
                Box::new(ScalarFunction {
×
255
                    fun: function,
×
256
                    args: arg_exprs,
×
257
                }),
×
258
                false,
×
259
            ));
×
260
        };
×
261

×
262
        if let Ok(function) = AggregateFunctionType::new(&name) {
×
263
            let mut arg_exprs = vec![];
×
264
            for arg in &sql_function.args {
×
265
                let r = self.parse_sql_function_arg(expression_type, arg, schema);
×
266
                match r {
×
267
                    Ok(result) => {
×
268
                        if result.1 {
×
269
                            return Ok(result);
×
270
                        } else {
×
271
                            arg_exprs.push(*result.0);
×
272
                        }
×
273
                    }
×
274
                    Err(error) => {
×
275
                        return Err(error);
×
276
                    }
277
                }
278
            }
279

×
280
            return Ok((
×
281
                Box::new(Expression::AggregateFunction {
×
282
                    fun: function,
×
283
                    args: arg_exprs,
×
284
                }),
×
285
                true, // switch bypass to true, since this Aggregation must be the final result
×
286
            ));
×
287
        };
×
288

×
289
        Err(InvalidExpression(format!(
×
290
            "Unsupported Expression: {expression:?}"
×
291
        )))
×
292
    }
×
293

294
    fn parse_sql_function_arg(
295
        &self,
296
        expression_type: &BuilderExpressionType,
297
        argument: &FunctionArg,
298
        schema: &Schema,
299
    ) -> Result<(Box<Expression>, bool), PipelineError> {
×
300
        match argument {
23✔
301
            FunctionArg::Named {
302
                name: _,
×
303
                arg: FunctionArgExpr::Expr(arg),
×
304
            } => self.parse_sql_expression(expression_type, arg, schema),
×
305
            FunctionArg::Named {
306
                name: _,
307
                arg: FunctionArgExpr::Wildcard,
×
308
            } => Err(InvalidArgument(format!("{argument:?}"))),
×
309
            FunctionArg::Unnamed(FunctionArgExpr::Expr(arg)) => {
23✔
310
                self.parse_sql_expression(expression_type, arg, schema)
23✔
311
            }
312
            FunctionArg::Unnamed(FunctionArgExpr::Wildcard) => {
×
313
                Err(InvalidArgument(format!("{argument:?}")))
×
314
            }
×
315
            _ => Err(InvalidArgument(format!("{argument:?}"))),
×
316
        }
×
317
    }
23✔
318

×
319
    fn parse_sql_unary_op(
×
320
        &self,
×
321
        expression_type: &BuilderExpressionType,
×
322
        op: &SqlUnaryOperator,
×
323
        expr: &SqlExpr,
×
324
        schema: &Schema,
×
325
    ) -> Result<(Box<Expression>, Bypass), PipelineError> {
×
326
        let (arg, bypass) = self.parse_sql_expression(expression_type, expr, schema)?;
×
327
        if bypass {
×
328
            return Ok((arg, bypass));
×
329
        }
×
330

×
331
        let operator = match op {
×
332
            SqlUnaryOperator::Not => UnaryOperatorType::Not,
×
333
            SqlUnaryOperator::Plus => UnaryOperatorType::Plus,
×
334
            SqlUnaryOperator::Minus => UnaryOperatorType::Minus,
×
335
            _ => return Err(InvalidOperator(format!("{op:?}"))),
×
336
        };
337

×
338
        Ok((Box::new(Expression::UnaryOperator { operator, arg }), false))
×
339
    }
×
340

×
341
    fn parse_sql_binary_op(
79✔
342
        &self,
79✔
343
        expression_type: &BuilderExpressionType,
79✔
344
        left: &SqlExpr,
79✔
345
        op: &SqlBinaryOperator,
79✔
346
        right: &SqlExpr,
79✔
347
        schema: &Schema,
79✔
348
    ) -> Result<(Box<Expression>, bool), PipelineError> {
79✔
349
        let (left_op, bypass_left) = self.parse_sql_expression(expression_type, left, schema)?;
79✔
350
        if bypass_left {
79✔
351
            return Ok((left_op, bypass_left));
×
352
        }
79✔
353
        let (right_op, bypass_right) = self.parse_sql_expression(expression_type, right, schema)?;
79✔
354
        if bypass_right {
79✔
355
            return Ok((right_op, bypass_right));
×
356
        }
79✔
357

×
358
        let operator = match op {
79✔
359
            SqlBinaryOperator::Gt => BinaryOperatorType::Gt,
18✔
360
            SqlBinaryOperator::GtEq => BinaryOperatorType::Gte,
1✔
361
            SqlBinaryOperator::Lt => BinaryOperatorType::Lt,
12✔
362
            SqlBinaryOperator::LtEq => BinaryOperatorType::Lte,
12✔
363
            SqlBinaryOperator::Eq => BinaryOperatorType::Eq,
18✔
364
            SqlBinaryOperator::NotEq => BinaryOperatorType::Ne,
×
365

×
366
            SqlBinaryOperator::Plus => BinaryOperatorType::Add,
×
367
            SqlBinaryOperator::Minus => BinaryOperatorType::Sub,
×
368
            SqlBinaryOperator::Multiply => BinaryOperatorType::Mul,
×
369
            SqlBinaryOperator::Divide => BinaryOperatorType::Div,
×
370
            SqlBinaryOperator::Modulo => BinaryOperatorType::Mod,
×
371

×
372
            SqlBinaryOperator::And => BinaryOperatorType::And,
12✔
373
            SqlBinaryOperator::Or => BinaryOperatorType::Or,
6✔
374

375
            // BinaryOperator::BitwiseAnd => ...
376
            // BinaryOperator::BitwiseOr => ...
377
            // BinaryOperator::StringConcat => ...
×
378
            _ => return Err(InvalidOperator(format!("{op:?}"))),
×
379
        };
380

×
381
        Ok((
79✔
382
            Box::new(Expression::BinaryOperator {
79✔
383
                left: left_op,
79✔
384
                operator,
79✔
385
                right: right_op,
79✔
386
            }),
79✔
387
            false,
79✔
388
        ))
79✔
389
    }
79✔
390

×
391
    fn parse_sql_number(&self, n: &str) -> Result<(Box<Expression>, Bypass), PipelineError> {
43✔
392
        match n.parse::<i64>() {
43✔
393
            Ok(n) => Ok((Box::new(Expression::Literal(Field::Int(n))), false)),
43✔
394
            Err(_) => match n.parse::<f64>() {
×
395
                Ok(f) => Ok((
×
396
                    Box::new(Expression::Literal(Field::Float(OrderedFloat(f)))),
×
397
                    false,
×
398
                )),
×
399
                Err(_) => Err(InvalidValue(n.to_string())),
×
400
            },
401
        }
×
402
    }
43✔
403

×
404
    fn parse_sql_like_operator(
×
405
        &self,
×
406
        expression_type: &BuilderExpressionType,
×
407
        negated: &bool,
×
408
        expr: &Expr,
×
409
        pattern: &Expr,
×
410
        escape_char: &Option<char>,
×
411
        schema: &Schema,
×
412
    ) -> Result<(Box<Expression>, bool), PipelineError> {
×
413
        let arg = self.parse_sql_expression(expression_type, expr, schema)?;
×
414
        let pattern = self.parse_sql_expression(expression_type, pattern, schema)?;
×
415
        let like_expression = Box::new(Expression::Like {
×
416
            arg: arg.0,
×
417
            pattern: pattern.0,
×
418
            escape: *escape_char,
×
419
        });
×
420
        if *negated {
×
421
            Ok((
×
422
                Box::new(Expression::UnaryOperator {
×
423
                    operator: UnaryOperatorType::Not,
×
424
                    arg: like_expression,
×
425
                }),
×
426
                arg.1,
×
427
            ))
×
428
        } else {
×
429
            Ok((like_expression, arg.1))
×
430
        }
×
431
    }
×
432

×
433
    fn parse_sql_cast_operator(
64✔
434
        &self,
64✔
435
        expression_type: &BuilderExpressionType,
64✔
436
        expr: &Expr,
64✔
437
        data_type: &DataType,
64✔
438
        schema: &Schema,
64✔
439
    ) -> Result<(Box<Expression>, bool), PipelineError> {
64✔
440
        let expression = self.parse_sql_expression(expression_type, expr, schema)?;
64✔
441
        let cast_to = match data_type {
64✔
442
            DataType::Decimal(_) => CastOperatorType::Decimal,
×
443
            DataType::Binary(_) => CastOperatorType::Binary,
×
444
            DataType::Float(_) => CastOperatorType::Float,
10✔
445
            DataType::Int(_) => CastOperatorType::Int,
6✔
446
            DataType::Integer(_) => CastOperatorType::Int,
×
447
            DataType::UnsignedInt(_) => CastOperatorType::UInt,
×
448
            DataType::UnsignedInteger(_) => CastOperatorType::UInt,
×
449
            DataType::Boolean => CastOperatorType::Boolean,
12✔
450
            DataType::Date => CastOperatorType::Date,
×
451
            DataType::Timestamp(..) => CastOperatorType::Timestamp,
×
452
            DataType::Text => CastOperatorType::Text,
18✔
453
            DataType::String => CastOperatorType::String,
18✔
454
            DataType::Custom(name, ..) => {
×
455
                if name.to_string().to_lowercase() == "bson" {
×
456
                    CastOperatorType::Bson
×
457
                } else {
×
458
                    Err(PipelineError::InvalidFunction(format!(
×
459
                        "Unsupported Cast type {name}"
×
460
                    )))?
×
461
                }
462
            }
×
463
            _ => Err(PipelineError::InvalidFunction(format!(
×
464
                "Unsupported Cast type {data_type}"
×
465
            )))?,
×
466
        };
×
467
        Ok((
64✔
468
            Box::new(Expression::Cast {
64✔
469
                arg: expression.0,
64✔
470
                typ: cast_to,
64✔
471
            }),
64✔
472
            expression.1,
64✔
473
        ))
64✔
474
    }
64✔
475
}
476

×
477
pub fn fullname_from_ident(ident: &[Ident]) -> String {
52✔
478
    let mut ident_tokens = vec![];
52✔
479
    for token in ident.iter() {
52✔
480
        ident_tokens.push(token.value.clone());
52✔
481
    }
52✔
482
    ident_tokens.join(".")
52✔
483
}
52✔
484

×
485
fn parse_sql_string(s: &str) -> Result<(Box<Expression>, bool), PipelineError> {
26✔
486
    Ok((
26✔
487
        Box::new(Expression::Literal(Field::String(s.to_owned()))),
26✔
488
        false,
26✔
489
    ))
26✔
490
}
26✔
491

×
492
pub(crate) fn normalize_ident(id: &Ident) -> String {
152✔
493
    match id.quote_style {
152✔
494
        Some(_) => id.value.clone(),
×
495
        None => id.value.clone(),
152✔
496
    }
×
497
}
152✔
498

×
499
pub fn extend_schema_source_def(schema: &Schema, name: &NameOrAlias) -> Schema {
398✔
500
    let mut output_schema = schema.clone();
398✔
501
    let mut fields = vec![];
398✔
502
    for mut field in schema.clone().fields.into_iter() {
1,761✔
503
        if let Some(alias) = &name.1 {
1,761✔
504
            field.source = SourceDefinition::Alias {
612✔
505
                name: alias.to_string(),
612✔
506
            };
612✔
507
        }
1,149✔
508

×
509
        fields.push(field);
1,761✔
510
    }
×
511
    output_schema.fields = fields;
398✔
512

398✔
513
    output_schema
398✔
514
}
398✔
515

×
516
fn parse_sql_column(ident: &[Ident], schema: &Schema) -> Result<Box<Expression>, PipelineError> {
171✔
517
    let (src_field, src_table_or_alias, src_connection) = match ident.len() {
171✔
518
        1 => (&ident[0].value, None, None),
171✔
519
        2 => (&ident[1].value, Some(&ident[0].value), None),
×
520
        3 => (
×
521
            &ident[2].value,
×
522
            Some(&ident[1].value),
×
523
            Some(&ident[0].value),
×
524
        ),
×
525
        _ => {
×
526
            return Err(IllegalFieldIdentifier(
×
527
                ident
×
528
                    .iter()
×
529
                    .fold(String::new(), |a, b| a + "." + b.value.as_str()),
×
530
            ))
×
531
        }
532
    };
533

×
534
    let matching_by_field: Vec<(usize, &FieldDefinition)> = schema
171✔
535
        .fields
171✔
536
        .iter()
171✔
537
        .enumerate()
171✔
538
        .filter(|(_idx, f)| &f.name == src_field)
371✔
539
        .collect();
171✔
540

171✔
541
    match matching_by_field.len() {
171✔
542
        0 => Err(UnknownFieldIdentifier(
×
543
            ident
×
544
                .iter()
×
545
                .fold(String::new(), |a, b| a + "." + b.value.as_str()),
×
546
        )),
×
547
        1 => Ok(Box::new(Expression::Column {
171✔
548
            index: matching_by_field[0].0,
171✔
549
        })),
171✔
550
        _ => match src_table_or_alias {
×
551
            None => Err(AmbiguousFieldIdentifier(
×
552
                ident
×
553
                    .iter()
×
554
                    .fold(String::new(), |a, b| a + "." + b.value.as_str()),
×
555
            )),
×
556
            Some(src_table_or_alias) => {
×
557
                let matching_by_table_or_alias: Vec<(usize, &FieldDefinition)> = matching_by_field
×
558
                    .into_iter()
×
559
                    .filter(|(_idx, field)| match &field.source {
×
560
                        SourceDefinition::Alias { name } => name == src_table_or_alias,
×
561
                        SourceDefinition::Table {
×
562
                            name,
×
563
                            connection: _,
×
564
                        } => name == src_table_or_alias,
×
565
                        _ => false,
×
566
                    })
×
567
                    .collect();
×
568

×
569
                match matching_by_table_or_alias.len() {
×
570
                    0 => Err(UnknownFieldIdentifier(
×
571
                        ident
×
572
                            .iter()
×
573
                            .fold(String::new(), |a, b| a + "." + b.value.as_str()),
×
574
                    )),
×
575
                    1 => Ok(Box::new(Expression::Column {
×
576
                        index: matching_by_table_or_alias[0].0,
×
577
                    })),
×
578
                    _ => match src_connection {
×
579
                        None => Err(InvalidExpression(
×
580
                            ident
×
581
                                .iter()
×
582
                                .fold(String::new(), |a, b| a + "." + b.value.as_str()),
×
583
                        )),
×
584
                        Some(src_connection) => {
×
585
                            let matching_by_connection: Vec<(usize, &FieldDefinition)> =
×
586
                                matching_by_table_or_alias
×
587
                                    .into_iter()
×
588
                                    .filter(|(_idx, field)| match &field.source {
×
589
                                        SourceDefinition::Table {
590
                                            name: _,
×
591
                                            connection,
×
592
                                        } => connection == src_connection,
×
593
                                        _ => false,
×
594
                                    })
×
595
                                    .collect();
×
596

×
597
                            match matching_by_connection.len() {
×
598
                                0 => Err(UnknownFieldIdentifier(
×
599
                                    ident
×
600
                                        .iter()
×
601
                                        .fold(String::new(), |a, b| a + "." + b.value.as_str()),
×
602
                                )),
×
603
                                1 => Ok(Box::new(Expression::Column {
×
604
                                    index: matching_by_connection[0].0,
×
605
                                })),
×
606
                                _ => Err(InvalidExpression(
×
607
                                    ident
×
608
                                        .iter()
×
609
                                        .fold(String::new(), |a, b| a + "." + b.value.as_str()),
×
610
                                )),
×
611
                            }
612
                        }
613
                    },
614
                }
615
            }
616
        },
617
    }
×
618
}
171✔
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