use fathom_function::tracing; use pipeline_application::{ application::{ Application, IliComparisonOutput, MatchingCriteria, SurfaceLocationCriteria as SLC, }, serialization::{ serialize_meter, serialize_millimeter, serialize_orientation_min, serialize_percent, }, }; use uom::si::f64::{Angle, Length, Ratio}; use uuid::Uuid; #[fathom_function::function] async fn ili_compare_all(input: Input) -> Result { let mut output = Output::new(input.org_id, &input.project_id); let app = Application::new_from_compile_env(input.org_id, &input.project_id).unwrap(); for pipeline_id in input.pipeline_id { let result = app .ili_compare_all(pipeline_id, &input.criteria) .await .map_err(|err| { tracing::error!(%pipeline_id, ?err, "Error running comparison algorithm"); format!("{err:?}") })?; output.push_result(pipeline_id, result); } Ok(output) } #[derive(Debug, serde::Serialize, Default)] struct Output { org_id: Uuid, project_id: String, /// TODO: remove when proper mapping can happen between function nodes #[serde(rename = "pipeline_id")] pipeline_ids: Vec, /// TODO: remove when proper mapping can happen between function nodes #[serde(rename = "ili_comparison_id")] matched_ids: Vec, unmatched_ids: Vec, summary_ids: Vec, } impl Output { fn new(org_id: Uuid, project_id: impl ToString) -> Self { Self { org_id, project_id: project_id.to_string(), ..Default::default() } } fn push_result(&mut self, pipeline_id: Uuid, ili_comparison_result: Vec) { ili_comparison_result.into_iter().for_each(|res| { self.pipeline_ids.push(pipeline_id); self.matched_ids.push(res.matched_id); self.unmatched_ids.push(res.unmatched_id); self.summary_ids.push(res.summary_id); }); } } #[derive(Debug, serde::Deserialize)] struct Input { org_id: Uuid, project_id: String, pipeline_id: Vec, #[serde(flatten)] criteria: Criteria, } #[derive(Debug, serde::Deserialize)] struct Criteria { #[serde(with = "serialize_meter")] weld_location_threshold: Length, #[serde(with = "serialize_meter")] feature_location_threshold: Length, #[serde(with = "serialize_meter")] upstream_girth_threshold: Length, #[serde(with = "serialize_orientation_min")] orientation_threshold: Angle, #[serde(with = "serialize_percent")] minimum_depth_growth_threshold: Ratio, #[serde(with = "serialize_millimeter")] minimum_length_growth_threshold: Length, surface_location_criteria: SurfaceLocationCriteria, #[serde(with = "serialize_percent")] target_minimum_match_rate: Ratio, } #[derive(Debug, Clone, Copy, serde::Deserialize)] #[serde(rename_all = "snake_case")] enum SurfaceLocationCriteria { Matching, Any, } impl From for SLC { fn from(value: SurfaceLocationCriteria) -> Self { match value { SurfaceLocationCriteria::Matching => Self::Matching, SurfaceLocationCriteria::Any => Self::Any, } } } impl From<&Criteria> for MatchingCriteria { fn from(value: &Criteria) -> Self { MatchingCriteria::default() .with_weld_location_threshold(value.weld_location_threshold) .with_feature_location_threshold(value.feature_location_threshold) .with_upstream_girth_threshold(value.upstream_girth_threshold) .with_orientation_threshold(value.orientation_threshold) .with_minimum_depth_growth_threshold(value.minimum_depth_growth_threshold) .with_minimum_length_growth_threshold(value.minimum_length_growth_threshold) .with_surface_location_criteria(value.surface_location_criteria) .with_target_minimum_match_rate(value.target_minimum_match_rate) } }