diff --git a/crates/grafana-plugin-sdk/examples/main.rs b/crates/grafana-plugin-sdk/examples/main.rs index 4de5d81b..7444c369 100644 --- a/crates/grafana-plugin-sdk/examples/main.rs +++ b/crates/grafana-plugin-sdk/examples/main.rs @@ -56,13 +56,16 @@ impl backend::DataQueryError for QueryError { impl backend::DataService for MyPluginService { type Query = Query; type QueryError = QueryError; - type Stream = backend::BoxDataResponseStream<Self::QueryError>; - async fn query_data(&self, request: backend::QueryDataRequest<Self::Query>) -> Self::Stream { + type Stream<'a> = backend::BoxDataResponseStream<'a, Self::QueryError>; + async fn query_data<'st, 'r: 'st, 's: 'r>( + &'s self, + request: &'r backend::QueryDataRequest<Self::Query>, + ) -> Self::Stream<'st> { Box::pin( request .queries - .into_iter() - .map(|x: DataQuery<Self::Query>| async move { + .iter() + .map(|x: &DataQuery<Self::Query>| async move { // We can see the user's query in `x.query`: debug!( expression = x.query.expression, @@ -88,7 +91,7 @@ impl backend::DataService for MyPluginService { .into_frame("foo") .check() .map_err(|source| QueryError { - ref_id: x.ref_id, + ref_id: x.ref_id.clone(), source, })?], )) diff --git a/crates/grafana-plugin-sdk/src/backend/data.rs b/crates/grafana-plugin-sdk/src/backend/data.rs index d65b7975..4d869710 100644 --- a/crates/grafana-plugin-sdk/src/backend/data.rs +++ b/crates/grafana-plugin-sdk/src/backend/data.rs @@ -191,7 +191,7 @@ pub trait DataQueryError: std::error::Error { /// /// /// /// In general the concrete type will be impossible to name in advance, /// /// so the `backend::BoxDataResponseStream` type alias will be useful. -/// type Stream = backend::BoxDataResponseStream<Self::QueryError>; +/// type Stream<'a> = backend::BoxDataResponseStream<'a, Self::QueryError>; /// /// /// Respond to a request for data from Grafana. /// /// @@ -201,7 +201,7 @@ pub trait DataQueryError: std::error::Error { /// /// /// /// Our plugin must respond to each query and return an iterator of `DataResponse`s, /// /// which themselves can contain zero or more `Frame`s. -/// async fn query_data(&self, request: backend::QueryDataRequest<Self::Query>) -> Self::Stream { +/// async fn query_data(&self, request: backend::QueryDataRequest<Self::Query>) -> Self::Stream<'_> { /// Box::pin( /// request /// .queries @@ -246,18 +246,23 @@ pub trait DataService { /// /// This will generally be impossible to name directly, so returning the /// [`BoxDataResponseStream`] type alias will probably be more convenient. - type Stream: Stream<Item = Result<DataResponse, Self::QueryError>> + Send; + type Stream<'a>: Stream<Item = Result<DataResponse, Self::QueryError>> + Send + 'a + where + Self: 'a; /// Query data for an input request. /// /// The request will contain zero or more queries, as well as information about the /// origin of the queries (such as the datasource instance) in the `plugin_context` field. - async fn query_data(&self, request: QueryDataRequest<Self::Query>) -> Self::Stream; + async fn query_data<'st, 's: 'st>( + &'s self, + request: QueryDataRequest<Self::Query>, + ) -> Self::Stream<'st>; } /// Type alias for a boxed iterator of query responses, useful for returning from [`DataService::query_data`]. -pub type BoxDataResponseStream<E> = - Pin<Box<dyn Stream<Item = Result<backend::DataResponse, E>> + Send>>; +pub type BoxDataResponseStream<'a, E> = + Pin<Box<dyn Stream<Item = Result<backend::DataResponse, E>> + Send + 'a>>; /// Serialize a slice of frames to Arrow IPC format. /// diff --git a/crates/grafana-plugin-sdk/src/backend/mod.rs b/crates/grafana-plugin-sdk/src/backend/mod.rs index d39fc0a6..3f428ec0 100644 --- a/crates/grafana-plugin-sdk/src/backend/mod.rs +++ b/crates/grafana-plugin-sdk/src/backend/mod.rs @@ -74,7 +74,7 @@ impl backend::DataService for MyPlugin { /// /// In general the concrete type will be impossible to name in advance, /// so the `backend::BoxDataResponseStream` type alias will be useful. - type Stream = backend::BoxDataResponseStream<Self::QueryError>; + type Stream<'a> = backend::BoxDataResponseStream<'a, Self::QueryError>; /// Respond to a request for data from Grafana. /// @@ -279,7 +279,7 @@ impl ShutdownHandler { /// /// /// /// In general the concrete type will be impossible to name in advance, /// /// so the `backend::BoxDataResponseStream` type alias will be useful. -/// type Stream = backend::BoxDataResponseStream<Self::QueryError>; +/// type Stream<'a> = backend::BoxDataResponseStream<'a, Self::QueryError>; /// /// /// Respond to a request for data from Grafana. /// /// diff --git a/crates/grafana-plugin-sdk/src/backend/noop.rs b/crates/grafana-plugin-sdk/src/backend/noop.rs index 8b1eb798..3aa66047 100644 --- a/crates/grafana-plugin-sdk/src/backend/noop.rs +++ b/crates/grafana-plugin-sdk/src/backend/noop.rs @@ -30,8 +30,11 @@ impl DataQueryError for Infallible { impl DataService for NoopService { type Query = (); type QueryError = Infallible; - type Stream = BoxDataResponseStream<Self::QueryError>; - async fn query_data(&self, _request: QueryDataRequest<Self::Query>) -> Self::Stream { + type Stream<'a> = BoxDataResponseStream<'static, Self::QueryError>; + async fn query_data<'st, 's: 'st>( + &'s self, + _request: QueryDataRequest<Self::Query>, + ) -> Self::Stream<'st> { unreachable!() } }