From 04a90ed3f847e15d773ac4c1faf96085e3a55cf2 Mon Sep 17 00:00:00 2001 From: Peter Holloway Date: Wed, 3 Dec 2025 17:12:47 +0000 Subject: [PATCH 1/3] Add resolvers to get details of specific runs On the instrumentSession object, run takes a scan number as these should be unique within a session. On the root, it takes a run id as these should be unique across tiled. --- src/clients.rs | 10 ++++++++++ src/model.rs | 44 +++++++++++++++++++++++++++++++++++++++++++- src/model/node.rs | 13 +++++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/clients.rs b/src/clients.rs index 61dc2c3..b659ff7 100644 --- a/src/clients.rs +++ b/src/clients.rs @@ -69,6 +69,16 @@ impl TiledClient { self.request(&format!("api/v1/search/{}", path), headers, Some(query)) .await } + + pub async fn metadata( + &self, + id: String, + headers: Option, + ) -> ClientResult { + self.request(&format!("api/v1/metadata/{id}"), headers, None) + .await + } + pub async fn table_full( &self, path: &str, diff --git a/src/model.rs b/src/model.rs index 1e0af1d..b481411 100644 --- a/src/model.rs +++ b/src/model.rs @@ -13,7 +13,7 @@ use serde_json::Value; use tracing::{info, instrument}; use crate::RootAddress; -use crate::clients::TiledClient; +use crate::clients::{ClientError, TiledClient}; use crate::handlers::AuthHeader; use crate::model::node::NodeAttributes; @@ -29,6 +29,18 @@ impl TiledQuery { async fn instrument_session(&self, name: String) -> InstrumentSession { InstrumentSession { name } } + + async fn run(&self, ctx: &Context<'_>, id: String) -> Result> { + let auth = ctx.data::>()?; + let headers = auth.as_ref().map(AuthHeader::as_header_map); + match ctx.data::()?.metadata(id, headers).await { + Ok(run) => Ok(Some(Run { + data: run.into_data(), + })), + Err(ClientError::ServerError(e)) if e.status().is_some_and(|sc| sc == 404) => Ok(None), + Err(other) => Err(other.into()), + } + } } struct InstrumentSession { @@ -40,6 +52,36 @@ impl InstrumentSession { async fn name(&self) -> &str { &self.name } + + async fn run(&self, ctx: &Context<'_>, scan_number: u32) -> Result> { + let auth = ctx.data::>()?; + let headers = auth.as_ref().map(AuthHeader::as_header_map); + let run_root = ctx + .data::()? + .search( + "", + headers, + &[ + ( + "filter[eq][condition][key]", + "start.instrument_session".into(), + ), + ( + "filter[eq][condition][value]", + format!(r#""{}""#, self.name).into(), + ), + ("filter[eq][condition][key]", "start.scan_id".into()), + ( + "filter[eq][condition][value]", + scan_number.to_string().into(), + ), + ("include_data_sources", "true".into()), + ], + ) + .await?; + Ok(run_root.into_data().next().map(|data| Run { data })) + } + async fn runs(&self, ctx: &Context<'_>) -> Result> { let auth = ctx.data::>()?; let headers = auth.as_ref().map(AuthHeader::as_header_map); diff --git a/src/model/node.rs b/src/model/node.rs index 0b5be61..6a2ce6d 100644 --- a/src/model/node.rs +++ b/src/model/node.rs @@ -6,9 +6,12 @@ use serde_json::Value; use crate::model::{array, container, table}; +pub type Root = Response>; +pub type Metadata = Response; + #[derive(Debug, PartialEq, Serialize, Deserialize)] -pub struct Root { - data: Vec, +pub struct Response { + data: D, pub error: Value, pub links: Option, pub meta: Value, @@ -23,6 +26,12 @@ impl Root { } } +impl Metadata { + pub fn into_data(self) -> Data { + self.data + } +} + #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum DataOption { From 96e64d73d282c1deed252f8bb529af8c8a95643a Mon Sep 17 00:00:00 2001 From: Peter Holloway Date: Tue, 9 Dec 2025 11:43:14 +0000 Subject: [PATCH 2/3] Remove single run resolver from instrument session --- src/model.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/model.rs b/src/model.rs index b481411..2baf55f 100644 --- a/src/model.rs +++ b/src/model.rs @@ -52,36 +52,6 @@ impl InstrumentSession { async fn name(&self) -> &str { &self.name } - - async fn run(&self, ctx: &Context<'_>, scan_number: u32) -> Result> { - let auth = ctx.data::>()?; - let headers = auth.as_ref().map(AuthHeader::as_header_map); - let run_root = ctx - .data::()? - .search( - "", - headers, - &[ - ( - "filter[eq][condition][key]", - "start.instrument_session".into(), - ), - ( - "filter[eq][condition][value]", - format!(r#""{}""#, self.name).into(), - ), - ("filter[eq][condition][key]", "start.scan_id".into()), - ( - "filter[eq][condition][value]", - scan_number.to_string().into(), - ), - ("include_data_sources", "true".into()), - ], - ) - .await?; - Ok(run_root.into_data().next().map(|data| Run { data })) - } - async fn runs(&self, ctx: &Context<'_>) -> Result> { let auth = ctx.data::>()?; let headers = auth.as_ref().map(AuthHeader::as_header_map); From 1ca99941adb0eb9e7550badb915a1fa23ea87c98 Mon Sep 17 00:00:00 2001 From: Peter Holloway Date: Tue, 9 Dec 2025 12:05:43 +0000 Subject: [PATCH 3/3] Use new error types for run resolver --- src/model.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model.rs b/src/model.rs index 2baf55f..0acabf8 100644 --- a/src/model.rs +++ b/src/model.rs @@ -37,7 +37,7 @@ impl TiledQuery { Ok(run) => Ok(Some(Run { data: run.into_data(), })), - Err(ClientError::ServerError(e)) if e.status().is_some_and(|sc| sc == 404) => Ok(None), + Err(ClientError::TiledRequest(404, _)) => Ok(None), Err(other) => Err(other.into()), } }