Skip to main content

tp_lib_core/models/
retrieval.rs

1//! Retrieval domain types for automatic ERA RINF topology download (feature 006).
2//!
3//! See `specs/006-download-rinf-topology/data-model.md` for the canonical
4//! definitions. Types here describe spatial search regions, request envelopes,
5//! typed SPARQL rows, the assembled topology bundle, its validation report,
6//! and the caller-visible outcome.
7
8use chrono::{DateTime, NaiveDate, Utc};
9use serde::{Deserialize, Serialize};
10
11use crate::models::{NetRelation, Netelement};
12
13/// Default expansion (meters) around the GNSS envelope.
14pub const DEFAULT_RETRIEVAL_BUFFER_METERS: f64 = 1000.0;
15
16/// Default RINF SPARQL endpoint.
17pub const DEFAULT_RINF_ENDPOINT: &str = "https://graph.data.era.europa.eu/repositories/rinf-plus";
18
19/// Coarse-geometry threshold (meters) above which more than two points are required.
20pub const COARSE_GEOMETRY_LENGTH_THRESHOLD_METERS: f64 = 250.0;
21
22/// Spatial search region sent to the RINF SPARQL endpoint.
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
24pub struct RetrievalArea {
25    pub min_longitude: f64,
26    pub max_longitude: f64,
27    pub min_latitude: f64,
28    pub max_latitude: f64,
29    pub expansion_meters: f64,
30    pub polygon_wkt: String,
31    pub source_crs: String,
32}
33
34/// Which workflow triggered the automatic-retrieval decision.
35#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
36#[serde(rename_all = "snake_case")]
37pub enum WorkflowKind {
38    Projection,
39    PathCalculation,
40    DetectionPreparation,
41    PathReview,
42}
43
44/// Workflow invocation that may require automatic topology retrieval.
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct AutoTopologyRequest {
47    pub workflow_kind: WorkflowKind,
48    pub supplied_topology_present: bool,
49    pub rinf_endpoint_url: String,
50    pub retrieval_area: Option<RetrievalArea>,
51    pub requested_at: DateTime<Utc>,
52}
53
54/// One parsed netelement row from the SPARQL response.
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct RinfNetelementRow {
57    pub netelement_iri: String,
58    pub netelement_id: String,
59    pub wkt: String,
60    pub geometry_point_count: usize,
61    pub length_meters: f64,
62}
63
64/// Navigability classification as encoded by ERA.
65#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
66#[serde(rename_all = "PascalCase")]
67pub enum RinfNavigability {
68    Both,
69    /// Navigable only from element A to element B.
70    AB,
71    /// Navigable only from element B to element A.
72    BA,
73    None,
74}
75
76/// One parsed netrelation row from the SPARQL response.
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct RinfNetrelationRow {
79    pub netrelation_iri: String,
80    pub element_a_id: String,
81    pub element_b_id: String,
82    pub is_on_origin_of_element_a: bool,
83    pub is_on_origin_of_element_b: bool,
84    pub navigability: RinfNavigability,
85    pub valid_on_date: NaiveDate,
86}
87
88/// Validation status for a retrieved topology bundle.
89#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
90#[serde(rename_all = "snake_case")]
91pub enum TopologyValidationStatus {
92    Valid,
93    MissingCoverage,
94    IncompleteTopology,
95    InvalidInput,
96    EndpointFailure,
97}
98
99/// Explains whether a downloaded topology is usable.
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct TopologyValidationReport {
102    pub status: TopologyValidationStatus,
103    pub netelement_count: usize,
104    pub netrelation_count: usize,
105    pub coarse_geometry_ids: Vec<String>,
106    pub uncovered_gnss_indices: Vec<usize>,
107    pub message: String,
108}
109
110/// Normalized topology bundle ready for downstream workflows.
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct RetrievedTopology {
113    pub netelements: Vec<Netelement>,
114    pub netrelations: Vec<NetRelation>,
115    pub retrieval_area: RetrievalArea,
116    pub endpoint_url: String,
117    pub retrieved_at: DateTime<Utc>,
118    pub validation_report: TopologyValidationReport,
119}
120
121/// Which source supplied the topology used by a workflow.
122#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
123#[serde(rename_all = "snake_case")]
124pub enum TopologySource {
125    SuppliedTopology,
126    EraRinf,
127}
128
129/// Outcome status surfaced to callers.
130#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
131#[serde(rename_all = "snake_case")]
132pub enum RetrievalStatus {
133    Success,
134    InvalidInput,
135    MissingCoverage,
136    IncompleteTopology,
137    EndpointFailure,
138}
139
140/// Caller-visible outcome of source selection and validation.
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct RetrievalOutcome {
143    pub source_used: TopologySource,
144    pub status: RetrievalStatus,
145    pub detail_message: String,
146    pub diagnostic_area_wkt: Option<String>,
147    pub affected_gnss_indices: Vec<usize>,
148}
149
150impl RetrievalOutcome {
151    pub fn supplied_success() -> Self {
152        Self {
153            source_used: TopologySource::SuppliedTopology,
154            status: RetrievalStatus::Success,
155            detail_message: "Using supplied topology".to_string(),
156            diagnostic_area_wkt: None,
157            affected_gnss_indices: Vec::new(),
158        }
159    }
160}