generic_relation_helpers 0.2.0

Traits et helpers génériques pour jointures parent/enfant
Documentation
use std::collections::HashMap;

use serde::Serialize;

use crate::enumerations::enum_field_value::NameFilter;
use crate::traits::trait_communs::{BuildFromParent, BuildFromSon, GetValueFieldForSourceParent, GetValueFieldForSourceSecondary, GetValuePKFieldForSourceSecondary, GetValuePropertyOfKeyParent, HasMatchKey};


fn build_filtre_callback(
    type_filter:    Option<NameFilter>,
    filter_by_name: Option<String>,
) -> Box<dyn Fn(&str) -> bool> {
 
    let valeur = filter_by_name.unwrap_or_default();
 
    match type_filter {
 
        // Correspondance exacte (insensible à la casse)
        Some(NameFilter::Equal) => Box::new(move |nom: &str| {
            nom.to_uppercase().eq(valeur.to_uppercase().as_str())
        }),
 
        // Le nom doit commencer par la valeur (insensible à la casse)
        Some(NameFilter::Begin) => Box::new(move |nom: &str| {
            nom.to_uppercase().starts_with(valeur.to_uppercase().as_str())
        }),
 
        // Le nom doit se terminer par la valeur (insensible à la casse)
        Some(NameFilter::Finished) => Box::new(move |nom: &str| {
            nom.to_uppercase().ends_with(valeur.to_uppercase().as_str())
        }),
 
        // Le nom doit contenir la valeur n'importe où (insensible à la casse)
        Some(NameFilter::Contains) => Box::new(move |nom: &str| {
            nom.to_uppercase().contains(valeur.to_uppercase().as_str())
        }),
 
        // None → aucun filtre, tout passe
        _ => Box::new(|_: &str| true),
    }
}


pub fn get_parents_with_their_childrens<ParentSource,SourceSon,TEnfant,SourceDestination>(
    source_parent:Vec<ParentSource>,
    source_son:&Vec<SourceSon>,
    source_enfants:&Vec<TEnfant>,
    type_filter:Option<NameFilter> ,
    filter_by_name:Option<String>
)-> Vec<SourceDestination>
where 
    ParentSource: GetValuePropertyOfKeyParent + GetValueFieldForSourceParent<TEnfant>,
    SourceSon:  GetValuePKFieldForSourceSecondary + GetValueFieldForSourceSecondary,
    TEnfant: BuildFromSon + Serialize + HasMatchKey + Clone + GetValueFieldForSourceSecondary,
    SourceDestination: BuildFromParent
{    
    let is_filtre_passed=build_filtre_callback(type_filter, filter_by_name);
    
    let mut hasmap_indexed__enfants:HashMap<&str,&TEnfant> =HashMap::new();
    source_enfants.iter().for_each(|enfant|{
        hasmap_indexed__enfants.insert(enfant.get_match_key(), enfant);
    });

    let mut hasmap_indexed_liaisons:HashMap<&str,Vec<&SourceSon>>=HashMap::new();
    source_son.iter().for_each(|liaison|{
        hasmap_indexed_liaisons.entry(liaison.get_FK_field_of_source_secondary())
        .or_default().push(liaison);
    });

    source_parent.iter()
    .filter(|parent|is_filtre_passed(&parent.get_value()))
    .map(|parent| {
        
        let enfants = get_childrens_of_parent(
                hasmap_indexed_liaisons.get(parent.get_value()).map(|v| v.as_slice()).unwrap_or(&[]),
                &hasmap_indexed__enfants,
        );
        
        SourceDestination::build(parent.get_values_of_property(enfants))
    })
    .collect()

}

pub fn get_childrens_of_parent<TEnfant,TJointure>(
    liaison_of_parent:&[&TJointure],
    enfants_source:&HashMap<&str,&TEnfant>
) -> Vec<TEnfant>
where 
    TJointure: GetValuePKFieldForSourceSecondary + GetValueFieldForSourceSecondary,
    TEnfant: Clone + HasMatchKey + BuildFromSon + GetValueFieldForSourceSecondary
{
    liaison_of_parent.iter()
    .filter_map(|row| {
        let key_enfant=row.get_field_of_source_secondary();

        enfants_source.get(key_enfant).map(|enfant| {
            let mut fields_of_enfant_join_liaison=enfant.get_values_of_property();
            
            row.get_values_of_property().iter().for_each(|(key,val)| {
                fields_of_enfant_join_liaison.entry(key.to_string()).or_insert(val.clone());
            });

            TEnfant::build(fields_of_enfant_join_liaison)
        })
    }).collect() 
}