From 6ca4e8d5f66b8cfe6bbfb9bb1fc8eb9d84fc0083 Mon Sep 17 00:00:00 2001 From: Jari Maijenburg Date: Sat, 9 Mar 2024 20:20:40 +0100 Subject: [PATCH] Found a way around Rust compiler bug https://github.com/rust-lang/rust/issues/100013 --- crates/fhir-sdk/src/client/r4b/search/mod.rs | 17 +++++- crates/fhir-sdk/src/client/r5/search/mod.rs | 21 ++++++-- crates/fhir-sdk/src/client/search.rs | 52 ++++++++++--------- crates/fhir-sdk/src/client/stu3/search/mod.rs | 17 +++++- 4 files changed, 75 insertions(+), 32 deletions(-) diff --git a/crates/fhir-sdk/src/client/r4b/search/mod.rs b/crates/fhir-sdk/src/client/r4b/search/mod.rs index 141705b8..0e52a56d 100644 --- a/crates/fhir-sdk/src/client/r4b/search/mod.rs +++ b/crates/fhir-sdk/src/client/r4b/search/mod.rs @@ -1,7 +1,10 @@ //! Client search implementation. use crate::client::search::NextPageCursor; -use crate::client::{search::SearchExecutor, Client, Error, FhirR4B, SearchParameters}; +use crate::client::{ + search::PagedSearchExecutor, search::UnpagedSearchExecutor, Client, Error, FhirR4B, + SearchParameters, +}; use async_trait::async_trait; use fhir_model::r4b::resources::{Bundle, DomainResource, NamedResource, Resource}; use paging::{Page, Unpaged}; @@ -15,10 +18,12 @@ mod paging; mod params; #[async_trait] -impl SearchExecutor for Client +impl PagedSearchExecutor for Client where R: NamedResource + DomainResource + TryFrom + 'static, { + type Stream = Page; + #[allow(refining_impl_trait)] async fn search_paged( self, @@ -56,6 +61,14 @@ where Ok((page, cursor)) } +} + +#[async_trait] +impl UnpagedSearchExecutor for Client +where + R: NamedResource + DomainResource + TryFrom + 'static, +{ + type Stream = Unpaged; #[allow(refining_impl_trait)] async fn search_unpaged(self, params: SearchParameters) -> Result, Error> { diff --git a/crates/fhir-sdk/src/client/r5/search/mod.rs b/crates/fhir-sdk/src/client/r5/search/mod.rs index a36a2893..8bcad384 100644 --- a/crates/fhir-sdk/src/client/r5/search/mod.rs +++ b/crates/fhir-sdk/src/client/r5/search/mod.rs @@ -1,7 +1,10 @@ //! Client search implementation. use crate::client::search::NextPageCursor; -use crate::client::{search::SearchExecutor, Client, Error, FhirR5, SearchParameters}; +use crate::client::{ + search::PagedSearchExecutor, search::UnpagedSearchExecutor, Client, Error, FhirR5, + SearchParameters, +}; use async_trait::async_trait; use fhir_model::r5::codes::LinkRelationTypes; use fhir_model::r5::resources::{Bundle, DomainResource, NamedResource, Resource}; @@ -16,16 +19,18 @@ mod paging; mod params; #[async_trait] -impl SearchExecutor for Client +impl PagedSearchExecutor for Client where R: NamedResource + DomainResource + TryFrom + 'static, { + type Stream = Page; + #[allow(refining_impl_trait)] async fn search_paged( self, params: SearchParameters, page_size: Option, - ) -> Result<(Page, Option>), Error> { + ) -> Result<(Self::Stream, Option>), Error> { let mut url = self.url(&[R::TYPE.as_str()]); url.query_pairs_mut().extend_pairs(params.into_queries()).finish(); @@ -40,7 +45,7 @@ where async fn fetch_next_page( self, url: Url, - ) -> Result<(Page, Option>), Error> { + ) -> Result<(Self::Stream, Option>), Error> { let searchset: Bundle = self.fetch_resource(url).await?; let cursor = match find_next_page_url(&searchset) { @@ -57,6 +62,14 @@ where Ok((page, cursor)) } +} + +#[async_trait] +impl UnpagedSearchExecutor for Client +where + R: NamedResource + DomainResource + TryFrom + 'static, +{ + type Stream = Unpaged; #[allow(refining_impl_trait)] async fn search_unpaged(self, params: SearchParameters) -> Result, Error> { diff --git a/crates/fhir-sdk/src/client/search.rs b/crates/fhir-sdk/src/client/search.rs index ff6bed41..59512aaf 100644 --- a/crates/fhir-sdk/src/client/search.rs +++ b/crates/fhir-sdk/src/client/search.rs @@ -21,7 +21,7 @@ pub struct UnpagedSearch { impl UnpagedSearch where - E: SearchExecutor + 'static, + E: UnpagedSearchExecutor, { pub fn new(executor: E) -> Self { Self { executor, params: SearchParameters::empty(), resource_type: PhantomData } @@ -65,18 +65,21 @@ where self.with_raw(key, value) } - /// Make this a paged search. Next pages can be fetched using - /// [SearchResponse::next_page]. + /// Execute the search + pub async fn send(self) -> Result { + self.executor.search_unpaged(self.params).await + } +} + +impl UnpagedSearch +where + E: UnpagedSearchExecutor + PagedSearchExecutor, +{ pub fn paged(self, page_size: Option) -> PagedSearch { let Self { executor, params, resource_type } = self; PagedSearch { executor, params, resource_type, page_size } } - - /// Execute the search - pub async fn send(self) -> Result>, Error> { - self.executor.search_unpaged(self.params).await - } } #[derive(Debug)] @@ -95,12 +98,10 @@ pub struct PagedSearch { impl PagedSearch where - E: SearchExecutor + 'static, + E: PagedSearchExecutor, { /// Execute the search - pub async fn send( - self, - ) -> Result<(impl Stream>, Option>), Error> { + pub async fn send(self) -> Result<(E::Stream, Option>), Error> { self.executor.search_paged(self.params, self.page_size).await } } @@ -121,36 +122,38 @@ pub struct NextPageCursor { impl NextPageCursor where - E: SearchExecutor + 'static, + E: PagedSearchExecutor + 'static, { pub fn new(executor: E, next_page_url: Url) -> Self { Self { executor, next_page_url, resource_type: PhantomData } } - pub async fn next_page( - self, - ) -> Result<(impl Stream>, Option), Error> { + pub async fn next_page(self) -> Result<(E::Stream, Option), Error> { self.executor.fetch_next_page(self.next_page_url).await } } #[async_trait] -pub trait SearchExecutor: Sized { - async fn search_unpaged( - self, - params: SearchParameters, - ) -> Result>, Error>; +pub trait UnpagedSearchExecutor: Sized { + type Stream: Stream>; + + async fn search_unpaged(self, params: SearchParameters) -> Result; +} + +#[async_trait] +pub trait PagedSearchExecutor: Sized { + type Stream: Stream>; async fn search_paged( self, params: SearchParameters, page_size: Option, - ) -> Result<(impl Stream>, Option>), Error>; + ) -> Result<(Self::Stream, Option>), Error>; async fn fetch_next_page( self, next_page_url: Url, - ) -> Result<(impl Stream>, Option>), Error>; + ) -> Result<(Self::Stream, Option>), Error>; } impl Client { @@ -159,7 +162,8 @@ impl Client { /// matching included resources. pub fn search(&self) -> UnpagedSearch where - Self: SearchExecutor, + Self: UnpagedSearchExecutor, + R: Send, { UnpagedSearch::new(self.clone()) } diff --git a/crates/fhir-sdk/src/client/stu3/search/mod.rs b/crates/fhir-sdk/src/client/stu3/search/mod.rs index 361bea18..e0f2888c 100644 --- a/crates/fhir-sdk/src/client/stu3/search/mod.rs +++ b/crates/fhir-sdk/src/client/stu3/search/mod.rs @@ -1,7 +1,10 @@ //! Client search implementation. use crate::client::search::NextPageCursor; -use crate::client::{search::SearchExecutor, Client, Error, FhirStu3, SearchParameters}; +use crate::client::{ + search::PagedSearchExecutor, search::UnpagedSearchExecutor, Client, Error, FhirStu3, + SearchParameters, +}; use async_trait::async_trait; use fhir_model::stu3::resources::{Bundle, DomainResource, NamedResource, Resource}; use paging::{Page, Unpaged}; @@ -15,10 +18,12 @@ mod paging; mod params; #[async_trait] -impl SearchExecutor for Client +impl PagedSearchExecutor for Client where R: NamedResource + DomainResource + TryFrom + 'static, { + type Stream = Page; + #[allow(refining_impl_trait)] async fn search_paged( self, @@ -56,6 +61,14 @@ where Ok((page, cursor)) } +} + +#[async_trait] +impl UnpagedSearchExecutor for Client +where + R: NamedResource + DomainResource + TryFrom + 'static, +{ + type Stream = Unpaged; #[allow(refining_impl_trait)] async fn search_unpaged(self, params: SearchParameters) -> Result, Error> {