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

getdozer / dozer / 4423198119

pending completion
4423198119

push

github

GitHub
Bump geo from 0.23.1 to 0.24.0 (#1207)

28601 of 39109 relevant lines covered (73.13%)

51246.35 hits per line

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

70.7
/dozer-sql/src/pipeline/expression/builder.rs
1
use dozer_types::{
2
    ordered_float::OrderedFloat,
3
    types::{Field, FieldDefinition, Schema, SourceDefinition},
4
};
5
use sqlparser::ast::{
6
    BinaryOperator as SqlBinaryOperator, DataType, Expr as SqlExpr, Expr, Function, FunctionArg,
7
    FunctionArgExpr, Ident, TrimWhereField, UnaryOperator as SqlUnaryOperator, Value as SqlValue,
8
};
9

10
use crate::pipeline::errors::PipelineError::{
11
    InvalidArgument, InvalidExpression, InvalidNestedAggregationFunction, InvalidOperator,
12
    InvalidValue,
13
};
14
use crate::pipeline::errors::{PipelineError, SqlError};
15
use crate::pipeline::expression::aggregate::AggregateFunctionType;
16
use crate::pipeline::expression::datetime::DateTimeFunctionType;
17

18
use crate::pipeline::expression::execution::Expression;
19
use crate::pipeline::expression::execution::Expression::{GeoFunction, ScalarFunction};
20
use crate::pipeline::expression::geo::common::GeoFunctionType;
21
use crate::pipeline::expression::operator::{BinaryOperatorType, UnaryOperatorType};
22
use crate::pipeline::expression::scalar::common::ScalarFunctionType;
23
use crate::pipeline::expression::scalar::string::TrimType;
24

25
use super::cast::CastOperatorType;
26

27
#[derive(Clone, PartialEq, Debug)]
9✔
28
pub struct ExpressionBuilder {
29
    // Must be an aggregation function
30
    pub aggregations: Vec<Expression>,
31
    pub offset: usize,
32
}
33

34
impl ExpressionBuilder {
35
    pub fn new(offset: usize) -> Self {
3,161✔
36
        Self {
3,161✔
37
            aggregations: Vec::new(),
3,161✔
38
            offset,
3,161✔
39
        }
3,161✔
40
    }
3,161✔
41

42
    pub fn from(offset: usize, aggregations: Vec<Expression>) -> Self {
6✔
43
        Self {
6✔
44
            aggregations,
6✔
45
            offset,
6✔
46
        }
6✔
47
    }
6✔
48

49
    pub fn build(
2,984✔
50
        &mut self,
2,984✔
51
        parse_aggregations: bool,
2,984✔
52
        sql_expression: &SqlExpr,
2,984✔
53
        schema: &Schema,
2,984✔
54
    ) -> Result<Expression, PipelineError> {
2,984✔
55
        self.parse_sql_expression(parse_aggregations, sql_expression, schema)
2,984✔
56
    }
2,984✔
57

58
    pub(crate) fn parse_sql_expression(
59
        &mut self,
60
        parse_aggregations: bool,
61
        expression: &SqlExpr,
62
        schema: &Schema,
63
    ) -> Result<Expression, PipelineError> {
64
        match expression {
165✔
65
            SqlExpr::Trim {
66
                expr,
44✔
67
                trim_where,
44✔
68
                trim_what,
44✔
69
            } => self.parse_sql_trim_function(
44✔
70
                parse_aggregations,
44✔
71
                expr,
44✔
72
                trim_where,
44✔
73
                trim_what,
44✔
74
                schema,
44✔
75
            ),
44✔
76
            SqlExpr::Identifier(ident) => Self::parse_sql_column(&[ident.clone()], schema),
2,862✔
77
            SqlExpr::CompoundIdentifier(ident) => Self::parse_sql_column(ident, schema),
385✔
78
            SqlExpr::Value(SqlValue::Number(n, _)) => Self::parse_sql_number(n),
87✔
79
            SqlExpr::Value(SqlValue::Null) => Ok(Expression::Literal(Field::Null)),
×
80
            SqlExpr::Value(SqlValue::SingleQuotedString(s) | SqlValue::DoubleQuotedString(s)) => {
78✔
81
                Self::parse_sql_string(s)
78✔
82
            }
83
            SqlExpr::UnaryOp { expr, op } => {
×
84
                self.parse_sql_unary_op(parse_aggregations, op, expr, schema)
×
85
            }
86
            SqlExpr::BinaryOp { left, op, right } => {
147✔
87
                self.parse_sql_binary_op(parse_aggregations, left, op, right, schema)
147✔
88
            }
89
            SqlExpr::Nested(expr) => self.parse_sql_expression(parse_aggregations, expr, schema),
21✔
90
            SqlExpr::Function(sql_function) => {
346✔
91
                self.parse_sql_function(parse_aggregations, sql_function, schema)
346✔
92
            }
93
            SqlExpr::Like {
94
                negated,
×
95
                expr,
×
96
                pattern,
×
97
                escape_char,
×
98
            } => self.parse_sql_like_operator(
×
99
                parse_aggregations,
×
100
                negated,
×
101
                expr,
×
102
                pattern,
×
103
                escape_char,
×
104
                schema,
×
105
            ),
×
106
            SqlExpr::Cast { expr, data_type } => {
65✔
107
                self.parse_sql_cast_operator(parse_aggregations, expr, data_type, schema)
65✔
108
            }
109
            SqlExpr::Extract { field, expr } => {
64✔
110
                self.parse_sql_extract_operator(parse_aggregations, field, expr, schema)
64✔
111
            }
112
            _ => Err(InvalidExpression(format!("{expression:?}"))),
×
113
        }
114
    }
4,099✔
115

116
    fn parse_sql_column(ident: &[Ident], schema: &Schema) -> Result<Expression, PipelineError> {
3,249✔
117
        let (src_field, src_table_or_alias, src_connection) = match ident.len() {
3,249✔
118
            1 => (&ident[0].value, None, None),
2,864✔
119
            2 => (&ident[1].value, Some(&ident[0].value), None),
384✔
120
            3 => (
1✔
121
                &ident[2].value,
1✔
122
                Some(&ident[1].value),
1✔
123
                Some(&ident[0].value),
1✔
124
            ),
1✔
125
            _ => {
126
                return Err(PipelineError::SqlError(SqlError::InvalidColumn(
×
127
                    ident
×
128
                        .iter()
×
129
                        .map(|e| e.value.as_str())
×
130
                        .collect::<Vec<&str>>()
×
131
                        .join("."),
×
132
                )));
×
133
            }
134
        };
135

136
        let matching_by_field: Vec<(usize, &FieldDefinition)> = schema
3,249✔
137
            .fields
3,249✔
138
            .iter()
3,249✔
139
            .enumerate()
3,249✔
140
            .filter(|(_idx, f)| &f.name == src_field)
16,369✔
141
            .collect();
3,249✔
142

3,249✔
143
        match matching_by_field.len() {
3,249✔
144
            1 => Ok(Expression::Column {
3,044✔
145
                index: matching_by_field[0].0,
3,044✔
146
            }),
3,044✔
147
            _ => match src_table_or_alias {
205✔
148
                None => Err(PipelineError::SqlError(SqlError::InvalidColumn(
×
149
                    ident
×
150
                        .iter()
×
151
                        .map(|e| e.value.as_str())
×
152
                        .collect::<Vec<&str>>()
×
153
                        .join("."),
×
154
                ))),
×
155
                Some(src_table_or_alias) => {
205✔
156
                    let matching_by_table_or_alias: Vec<(usize, &FieldDefinition)> =
205✔
157
                        matching_by_field
205✔
158
                            .into_iter()
205✔
159
                            .filter(|(_idx, field)| match &field.source {
400✔
160
                                SourceDefinition::Alias { name } => name == src_table_or_alias,
340✔
161
                                SourceDefinition::Table {
162
                                    name,
60✔
163
                                    connection: _,
60✔
164
                                } => name == src_table_or_alias,
60✔
165
                                _ => false,
×
166
                            })
400✔
167
                            .collect();
205✔
168

205✔
169
                    match matching_by_table_or_alias.len() {
205✔
170
                        1 => Ok(Expression::Column {
200✔
171
                            index: matching_by_table_or_alias[0].0,
200✔
172
                        }),
200✔
173
                        _ => match src_connection {
5✔
174
                            None => Err(PipelineError::SqlError(SqlError::InvalidColumn(
×
175
                                ident
×
176
                                    .iter()
×
177
                                    .fold(String::new(), |a, b| a + "." + b.value.as_str()),
×
178
                            ))),
×
179
                            Some(src_connection) => {
5✔
180
                                let matching_by_connection: Vec<(usize, &FieldDefinition)> =
5✔
181
                                    matching_by_table_or_alias
5✔
182
                                        .into_iter()
5✔
183
                                        .filter(|(_idx, field)| match &field.source {
5✔
184
                                            SourceDefinition::Table {
185
                                                name: _,
186
                                                connection,
×
187
                                            } => connection == src_connection,
×
188
                                            _ => false,
×
189
                                        })
5✔
190
                                        .collect();
5✔
191

5✔
192
                                match matching_by_connection.len() {
5✔
193
                                    1 => Ok(Expression::Column {
×
194
                                        index: matching_by_connection[0].0,
×
195
                                    }),
×
196
                                    _ => Err(PipelineError::SqlError(SqlError::InvalidColumn(
×
197
                                        ident
×
198
                                            .iter()
×
199
                                            .map(|e| e.value.as_str())
×
200
                                            .collect::<Vec<&str>>()
×
201
                                            .join("."),
×
202
                                    ))),
×
203
                                }
204
                            }
205
                        },
206
                    }
207
                }
208
            },
209
        }
210
    }
3,244✔
211

212
    fn parse_sql_trim_function(
44✔
213
        &mut self,
44✔
214
        parse_aggregations: bool,
44✔
215
        expr: &Expr,
44✔
216
        trim_where: &Option<TrimWhereField>,
44✔
217
        trim_what: &Option<Box<Expr>>,
44✔
218
        schema: &Schema,
44✔
219
    ) -> Result<Expression, PipelineError> {
44✔
220
        let arg = Box::new(self.parse_sql_expression(parse_aggregations, expr, schema)?);
44✔
221
        let what = match trim_what {
44✔
222
            Some(e) => Some(Box::new(self.parse_sql_expression(
8✔
223
                parse_aggregations,
8✔
224
                e,
8✔
225
                schema,
8✔
226
            )?)),
8✔
227
            _ => None,
36✔
228
        };
229
        let typ = trim_where.as_ref().map(|e| match e {
44✔
230
            TrimWhereField::Both => TrimType::Both,
2✔
231
            TrimWhereField::Leading => TrimType::Leading,
2✔
232
            TrimWhereField::Trailing => TrimType::Trailing,
2✔
233
        });
44✔
234
        Ok(Expression::Trim { arg, what, typ })
44✔
235
    }
44✔
236

237
    fn parse_sql_function(
345✔
238
        &mut self,
345✔
239
        parse_aggregations: bool,
345✔
240
        sql_function: &Function,
345✔
241
        schema: &Schema,
345✔
242
    ) -> Result<Expression, PipelineError> {
345✔
243
        let function_name = sql_function.name.to_string().to_lowercase();
345✔
244

345✔
245
        #[cfg(feature = "python")]
345✔
246
        if function_name.starts_with("py_") {
345✔
247
            // The function is from python udf.
248
            let udf_name = function_name.strip_prefix("py_").unwrap();
30✔
249
            return self.parse_python_udf(udf_name, sql_function, schema);
30✔
250
        }
315✔
251

315✔
252
        match (
315✔
253
            AggregateFunctionType::new(function_name.as_str()),
315✔
254
            parse_aggregations,
315✔
255
        ) {
315✔
256
            (Ok(aggr), true) => {
267✔
257
                let mut arg_expr: Vec<Expression> = Vec::new();
267✔
258
                for arg in &sql_function.args {
537✔
259
                    let aggregation = self.parse_sql_function_arg(true, arg, schema)?;
270✔
260
                    arg_expr.push(aggregation);
270✔
261
                }
262
                let measure = Expression::AggregateFunction {
270✔
263
                    fun: aggr,
270✔
264
                    args: arg_expr,
270✔
265
                };
270✔
266
                let index = match self
270✔
267
                    .aggregations
270✔
268
                    .iter()
270✔
269
                    .enumerate()
270✔
270
                    .find(|e| e.1 == &measure)
270✔
271
                {
272
                    Some((index, _existing)) => index,
9✔
273
                    _ => {
274
                        self.aggregations.push(measure);
257✔
275
                        self.aggregations.len() - 1
257✔
276
                    }
277
                };
278
                Ok(Expression::Column {
266✔
279
                    index: self.offset + index,
266✔
280
                })
266✔
281
            }
282
            (Ok(_agg), false) => Err(InvalidNestedAggregationFunction(function_name)),
×
283
            (Err(_), _) => {
284
                let mut function_args: Vec<Expression> = Vec::new();
48✔
285
                for arg in &sql_function.args {
142✔
286
                    function_args.push(self.parse_sql_function_arg(
94✔
287
                        parse_aggregations,
94✔
288
                        arg,
94✔
289
                        schema,
94✔
290
                    )?);
94✔
291
                }
292

293
                match ScalarFunctionType::new(function_name.as_str()) {
48✔
294
                    Ok(sft) => Ok(ScalarFunction {
34✔
295
                        fun: sft,
34✔
296
                        args: function_args.clone(),
34✔
297
                    }),
34✔
298
                    Err(_d) => match GeoFunctionType::new(function_name.as_str()) {
14✔
299
                        Ok(gft) => Ok(GeoFunction {
14✔
300
                            fun: gft,
14✔
301
                            args: function_args.clone(),
14✔
302
                        }),
14✔
303
                        Err(_err) => Err(InvalidNestedAggregationFunction(function_name)),
×
304
                    },
305
                }
306
            }
307
        }
308
    }
344✔
309

310
    fn parse_sql_function_arg(
311
        &mut self,
312
        parse_aggregations: bool,
313
        argument: &FunctionArg,
314
        schema: &Schema,
315
    ) -> Result<Expression, PipelineError> {
316
        match argument {
435✔
317
            FunctionArg::Named {
318
                name: _,
319
                arg: FunctionArgExpr::Expr(arg),
×
320
            } => self.parse_sql_expression(parse_aggregations, arg, schema),
×
321
            FunctionArg::Named {
322
                name: _,
323
                arg: FunctionArgExpr::Wildcard,
324
            } => Err(InvalidArgument(format!("{argument:?}"))),
×
325
            FunctionArg::Unnamed(FunctionArgExpr::Expr(arg)) => {
436✔
326
                self.parse_sql_expression(parse_aggregations, arg, schema)
436✔
327
            }
328
            FunctionArg::Unnamed(FunctionArgExpr::Wildcard) => {
329
                Err(InvalidArgument(format!("{argument:?}")))
×
330
            }
331
            FunctionArg::Named {
332
                name: _,
333
                arg: FunctionArgExpr::QualifiedWildcard(_),
334
            } => Err(InvalidArgument(format!("{argument:?}"))),
×
335
            FunctionArg::Unnamed(FunctionArgExpr::QualifiedWildcard(_)) => {
336
                Err(InvalidArgument(format!("{argument:?}")))
×
337
            }
338
        }
339
    }
436✔
340

341
    fn parse_sql_unary_op(
×
342
        &mut self,
×
343
        parse_aggregations: bool,
×
344
        op: &SqlUnaryOperator,
×
345
        expr: &SqlExpr,
×
346
        schema: &Schema,
×
347
    ) -> Result<Expression, PipelineError> {
×
348
        let arg = Box::new(self.parse_sql_expression(parse_aggregations, expr, schema)?);
×
349
        let operator = match op {
×
350
            SqlUnaryOperator::Not => UnaryOperatorType::Not,
×
351
            SqlUnaryOperator::Plus => UnaryOperatorType::Plus,
×
352
            SqlUnaryOperator::Minus => UnaryOperatorType::Minus,
×
353
            _ => return Err(InvalidOperator(format!("{op:?}"))),
×
354
        };
355

356
        Ok(Expression::UnaryOperator { operator, arg })
×
357
    }
×
358

359
    fn parse_sql_binary_op(
147✔
360
        &mut self,
147✔
361
        parse_aggregations: bool,
147✔
362
        left: &SqlExpr,
147✔
363
        op: &SqlBinaryOperator,
147✔
364
        right: &SqlExpr,
147✔
365
        schema: &Schema,
147✔
366
    ) -> Result<Expression, PipelineError> {
147✔
367
        let left_op = self.parse_sql_expression(parse_aggregations, left, schema)?;
147✔
368
        let right_op = self.parse_sql_expression(parse_aggregations, right, schema)?;
147✔
369

370
        let operator = match op {
147✔
371
            SqlBinaryOperator::Gt => BinaryOperatorType::Gt,
36✔
372
            SqlBinaryOperator::GtEq => BinaryOperatorType::Gte,
1✔
373
            SqlBinaryOperator::Lt => BinaryOperatorType::Lt,
22✔
374
            SqlBinaryOperator::LtEq => BinaryOperatorType::Lte,
20✔
375
            SqlBinaryOperator::Eq => BinaryOperatorType::Eq,
30✔
376
            SqlBinaryOperator::NotEq => BinaryOperatorType::Ne,
×
377
            SqlBinaryOperator::Plus => BinaryOperatorType::Add,
4✔
378
            SqlBinaryOperator::Minus => BinaryOperatorType::Sub,
2✔
379
            SqlBinaryOperator::Multiply => BinaryOperatorType::Mul,
×
380
            SqlBinaryOperator::Divide => BinaryOperatorType::Div,
×
381
            SqlBinaryOperator::Modulo => BinaryOperatorType::Mod,
×
382
            SqlBinaryOperator::And => BinaryOperatorType::And,
22✔
383
            SqlBinaryOperator::Or => BinaryOperatorType::Or,
10✔
384
            _ => return Err(InvalidOperator(format!("{op:?}"))),
×
385
        };
386

387
        Ok(Expression::BinaryOperator {
147✔
388
            left: Box::new(left_op),
147✔
389
            operator,
147✔
390
            right: Box::new(right_op),
147✔
391
        })
147✔
392
    }
147✔
393

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

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

430
    fn parse_sql_extract_operator(
64✔
431
        &mut self,
64✔
432
        parse_aggregations: bool,
64✔
433
        field: &sqlparser::ast::DateTimeField,
64✔
434
        expr: &Expr,
64✔
435
        schema: &Schema,
64✔
436
    ) -> Result<Expression, PipelineError> {
64✔
437
        let right = self.parse_sql_expression(parse_aggregations, expr, schema)?;
64✔
438
        Ok(Expression::DateTimeFunction {
64✔
439
            fun: DateTimeFunctionType::Extract { field: *field },
64✔
440
            arg: Box::new(right),
64✔
441
        })
64✔
442
    }
64✔
443

444
    fn parse_sql_cast_operator(
65✔
445
        &mut self,
65✔
446
        parse_aggregations: bool,
65✔
447
        expr: &Expr,
65✔
448
        data_type: &DataType,
65✔
449
        schema: &Schema,
65✔
450
    ) -> Result<Expression, PipelineError> {
65✔
451
        let expression = self.parse_sql_expression(parse_aggregations, expr, schema)?;
65✔
452
        let cast_to = match data_type {
65✔
453
            DataType::Decimal(_) => CastOperatorType::Decimal,
×
454
            DataType::Binary(_) => CastOperatorType::Binary,
×
455
            DataType::Float(_) => CastOperatorType::Float,
10✔
456
            DataType::Int(_) => CastOperatorType::Int,
6✔
457
            DataType::Integer(_) => CastOperatorType::Int,
×
458
            DataType::UnsignedInt(_) => CastOperatorType::UInt,
×
459
            DataType::UnsignedInteger(_) => CastOperatorType::UInt,
×
460
            DataType::Boolean => CastOperatorType::Boolean,
12✔
461
            DataType::Date => CastOperatorType::Date,
×
462
            DataType::Timestamp(..) => CastOperatorType::Timestamp,
×
463
            DataType::Text => CastOperatorType::Text,
18✔
464
            DataType::String => CastOperatorType::String,
19✔
465
            DataType::Custom(name, ..) => {
×
466
                if name.to_string().to_lowercase() == "bson" {
×
467
                    CastOperatorType::Bson
×
468
                } else {
469
                    Err(PipelineError::InvalidFunction(format!(
×
470
                        "Unsupported Cast type {name}"
×
471
                    )))?
×
472
                }
473
            }
474
            _ => Err(PipelineError::InvalidFunction(format!(
×
475
                "Unsupported Cast type {data_type}"
×
476
            )))?,
×
477
        };
478
        Ok(Expression::Cast {
65✔
479
            arg: Box::new(expression),
65✔
480
            typ: cast_to,
65✔
481
        })
65✔
482
    }
65✔
483

484
    fn parse_sql_string(s: &str) -> Result<Expression, PipelineError> {
78✔
485
        Ok(Expression::Literal(Field::String(s.to_owned())))
78✔
486
    }
78✔
487

488
    pub fn fullname_from_ident(ident: &[Ident]) -> String {
130✔
489
        let mut ident_tokens = vec![];
130✔
490
        for token in ident.iter() {
130✔
491
            ident_tokens.push(token.value.clone());
130✔
492
        }
130✔
493
        ident_tokens.join(".")
130✔
494
    }
130✔
495

496
    pub(crate) fn normalize_ident(id: &Ident) -> String {
842✔
497
        match id.quote_style {
842✔
498
            Some(_) => id.value.clone(),
×
499
            None => id.value.clone(),
842✔
500
        }
501
    }
842✔
502

503
    #[cfg(feature = "python")]
504
    fn parse_python_udf(
30✔
505
        &mut self,
30✔
506
        name: &str,
30✔
507
        function: &Function,
30✔
508
        schema: &Schema,
30✔
509
    ) -> Result<Expression, PipelineError> {
30✔
510
        // First, get python function define by name.
511
        // Then, transfer python function to Expression::PythonUDF
512

513
        use dozer_types::types::FieldType;
514
        use PipelineError::InvalidQuery;
515

516
        let args = function
30✔
517
            .args
30✔
518
            .iter()
30✔
519
            .map(|argument| self.parse_sql_function_arg(false, argument, schema))
75✔
520
            .collect::<Result<Vec<_>, PipelineError>>()?;
30✔
521

522
        let last_arg = args
30✔
523
            .last()
30✔
524
            .ok_or_else(|| InvalidQuery("Can't get python udf return type".to_string()))?;
30✔
525

526
        let return_type = match last_arg {
30✔
527
            Expression::Literal(Field::String(s)) => {
30✔
528
                FieldType::try_from(s.as_str()).map_err(|e| InvalidQuery(format!("Failed to parse Python UDF return type: {e}")))?
30✔
529
            }
530
            _ => return Err(InvalidArgument("The last arg for python udf should be a string literal, which represents return type".to_string())),
×
531
        };
532

533
        Ok(Expression::PythonUDF {
30✔
534
            name: name.to_string(),
30✔
535
            args,
30✔
536
            return_type,
30✔
537
        })
30✔
538
    }
30✔
539
}
540

541
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
5,346✔
542
pub struct NameOrAlias(pub String, pub Option<String>);
543

544
pub fn extend_schema_source_def(schema: &Schema, name: &NameOrAlias) -> Schema {
1,244✔
545
    let mut output_schema = schema.clone();
1,244✔
546
    let mut fields = vec![];
1,244✔
547
    for mut field in schema.clone().fields.into_iter() {
5,300✔
548
        if let Some(alias) = &name.1 {
5,300✔
549
            field.source = SourceDefinition::Alias {
1,490✔
550
                name: alias.to_string(),
1,490✔
551
            };
1,490✔
552
        }
3,810✔
553

554
        fields.push(field);
5,300✔
555
    }
556
    output_schema.fields = fields;
1,244✔
557

1,244✔
558
    output_schema
1,244✔
559
}
1,244✔
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