fn compare_fields()

in compiler/crates/schema-diff/src/lib.rs [105:225]


fn compare_fields(
    optional_current_fields: &Option<List<FieldDefinition>>,
    optional_previous_fields: Option<List<FieldDefinition>>,
) -> (Vec<TypeChange>, Vec<TypeChange>, Vec<ArgumentChange>) {
    let mut added: Vec<TypeChange> = vec![];
    let mut removed: Vec<TypeChange> = vec![];
    let mut field_changed: Vec<ArgumentChange> = vec![];

    match (optional_current_fields.as_ref(), optional_previous_fields) {
        (Some(current_fields), Some(previous_fields)) => {
            let mut previous_values = previous_fields
                .items
                .into_iter()
                .map(|input| (input.name.value, input))
                .collect::<FnvHashMap<_, _>>();

            for field in &current_fields.items {
                match previous_values.remove(&field.name.value) {
                    None => {
                        added.push(TypeChange {
                            name: field.name.value,
                            type_: Type::from(field.type_.clone()),
                        });
                    }
                    Some(previous_field) => {
                        let previous_field_type = Type::from(previous_field.type_.clone());
                        let field_type = Type::from(field.type_.clone());
                        if previous_field_type != field_type {
                            added.push(TypeChange {
                                name: field.name.value,
                                type_: field_type,
                            });
                            removed.push(TypeChange {
                                name: previous_field.name.value,
                                type_: previous_field_type,
                            });
                        } else {
                            match (field.arguments.as_ref(), previous_field.arguments) {
                                (Some(current_field_arguments), Some(previous_field_arguments)) => {
                                    let (args_added, args_removed) = compare_input_value_definition(
                                        &current_field_arguments.items,
                                        previous_field_arguments.items,
                                    );
                                    if !args_added.is_empty() || !args_removed.is_empty() {
                                        field_changed.push(ArgumentChange {
                                            name: field.name.value,
                                            added: args_added,
                                            removed: args_removed,
                                        });
                                    }
                                }
                                (Some(current_field_arguments), None) => {
                                    let current_field_arguments = current_field_arguments.clone();
                                    let args_added = current_field_arguments
                                        .items
                                        .into_iter()
                                        .map(|InputValueDefinition { name, type_, .. }| {
                                            TypeChange {
                                                name: name.value,
                                                type_: Type::from(type_),
                                            }
                                        })
                                        .collect();
                                    let args_removed = vec![];
                                    field_changed.push(ArgumentChange {
                                        name: field.name.value,
                                        added: args_added,
                                        removed: args_removed,
                                    });
                                }
                                (None, Some(previous_field_arguments)) => {
                                    let args_added = vec![];
                                    let args_removed = previous_field_arguments
                                        .items
                                        .into_iter()
                                        .map(|InputValueDefinition { name, type_, .. }| {
                                            TypeChange {
                                                name: name.value,
                                                type_: Type::from(type_),
                                            }
                                        })
                                        .collect();
                                    field_changed.push(ArgumentChange {
                                        name: field.name.value,
                                        added: args_added,
                                        removed: args_removed,
                                    });
                                }
                                (None, None) => {}
                            }
                        }
                    }
                }
            }
            removed.extend(previous_values.drain().map(|(_, field)| TypeChange {
                name: field.name.value,
                type_: Type::from(field.type_),
            }));
        }
        (None, Some(previous_fields)) => {
            removed.extend(previous_fields.items.into_iter().map(
                |FieldDefinition { name, type_, .. }| TypeChange {
                    name: name.value,
                    type_: Type::from(type_),
                },
            ));
        }
        (Some(current_fields), None) => {
            let current_field_items = current_fields.items.clone();
            added.extend(current_field_items.into_iter().map(
                |FieldDefinition { name, type_, .. }| TypeChange {
                    name: name.value,
                    type_: Type::from(type_),
                },
            ));
        }
        (None, None) => {}
    }

    (added, removed, field_changed)
}