4ad4257013bc48b799ece899848.../src/main.rs
2025-06-10 16:27:22 +00:00

136 lines
4.0 KiB
Rust

use fathom_function::forms::TableCellValue;
use fathom_function::tracing;
use pipeline_application::application::{
Application, CrossingConfiguration, CrossingKind, FacilityType, SegmentationConfiguration,
uom::si::f64::Length, uom::si::length::meter,
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[fathom_function::function]
async fn segment(input: Input) -> Result<Output, String> {
let app = Application::new_from_compile_env(input.org_id, input.project_id).unwrap();
for pipeline_id in input.pipeline_id {
app.segment(pipeline_id, &input.configuration)
.await
.map_err(|err| {
tracing::error!(%pipeline_id, ?err, "Error running segmentation algorithm");
format!("{err:?}")
})?;
}
Ok(Output {
status: "Success".to_owned(),
})
}
#[derive(Debug, Serialize)]
struct Output {
status: String,
}
#[derive(Debug, Deserialize)]
struct Input {
org_id: Uuid,
project_id: String,
pipeline_id: Vec<Uuid>,
#[serde(flatten)]
configuration: Configuration,
}
#[derive(Debug, Deserialize)]
struct Configuration {
facilities: Vec<FacilityType>,
local_data: Vec<String>,
crossings: Crossings,
}
#[derive(Debug, Deserialize)]
struct Crossings {
highway: CrossingRow,
road: CrossingRow,
river: CrossingRow,
railroad: CrossingRow,
overhead: CrossingRow,
pipeline: CrossingRow,
}
impl Crossings {
fn to_crossing_configurations(&self) -> impl Iterator<Item = CrossingConfiguration> {
[
self.highway
.to_crossing_configuration(CrossingKind::Highway),
self.road.to_crossing_configuration(CrossingKind::Road),
self.river.to_crossing_configuration(CrossingKind::River),
self.railroad
.to_crossing_configuration(CrossingKind::Railroad),
self.overhead
.to_crossing_configuration(CrossingKind::Overhead),
self.pipeline
.to_crossing_configuration(CrossingKind::Pipeline),
]
.into_iter()
.flatten()
}
}
#[derive(Debug, Deserialize)]
struct CrossingRow {
longer_than: TableCellValue,
selected: TableCellValue,
}
impl CrossingRow {
fn to_crossing_configuration(
&self,
crossing_kind: CrossingKind,
) -> Option<CrossingConfiguration> {
if (&self.selected).try_into().unwrap_or(false) {
Some(CrossingConfiguration {
crossing_kind,
longer_than: Length::new::<meter>(
(&self.longer_than).try_into().ok().unwrap_or(0.0),
),
})
} else {
None
}
}
}
impl From<&Configuration> for SegmentationConfiguration {
fn from(value: &Configuration) -> Self {
let mut config = Self::default_false();
config = value
.facilities
.iter()
.fold(config, |config, fac| match fac {
FacilityType::InsulationJoint => config.by_insulation_joints(true),
FacilityType::Repair => config.by_repairs(true),
FacilityType::Valve => config.by_valves(true),
_ => config,
});
config = value.crossings.to_crossing_configurations().fold(
config,
SegmentationConfiguration::with_crossing_configuration,
);
value
.local_data
.iter()
.fold(config, |config, loc| match loc.as_str() {
"material_grade" => config.by_material_grade(true),
"coating_type" => config.by_coating_type(true),
"design_factor" => config.by_design_factor(true),
"high_consequence_area" => config.by_high_consequence_area(true),
"unusual_sensitive_area" => config.by_unusual_sensitive_area(true),
"joint_type" => config.by_joint_type(true),
"soil_type" => config.by_soil_type(true),
"soil_ph" => config.by_soil_ph(true),
_ => config,
})
}
}