Skip to content

Commit 7bd9e58

Browse files
committed
Experimental: add compatibility with GATs in backend::DataService
This means we don't need to clone so many things or connect to the database more than once, and we can organise things in a clearer way. Hooray for GATs!
1 parent 6704c72 commit 7bd9e58

File tree

3 files changed

+52
-64
lines changed

3 files changed

+52
-64
lines changed

Cargo.lock

+2-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ authors = [
1111
bytes = "1.1.0"
1212
chrono = "0.4.19"
1313
futures-util = "0.3.21"
14-
grafana-plugin-sdk = "0.4.2"
14+
# grafana-plugin-sdk = "0.4.2"
15+
grafana-plugin-sdk = { git = "https://github.com/grafana/grafana-plugin-sdk-rust", branch = "query-data-gat" }
1516
http = "0.2.6"
1617
md5 = "0.7.0"
1718
rust_decimal = { version = "1.22.0", features = ["db-tokio-postgres"] }

backend/src/data.rs

+48-59
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
1-
use std::{collections::HashMap, sync::Arc};
1+
use futures_util::stream::FuturesOrdered;
22

3-
use futures_util::{
4-
stream::{FuturesOrdered, FuturesUnordered},
5-
StreamExt,
6-
};
7-
8-
use grafana_plugin_sdk::backend;
9-
use tokio::sync::RwLock;
10-
use tokio_postgres::Client;
3+
use grafana_plugin_sdk::backend::{self, DataSourceInstanceSettings};
114

125
use crate::{
13-
path::{self, PathDisplay, QueryId},
14-
queries::{Query, SelectStatement, TailTarget},
6+
path::{PathDisplay, QueryId},
7+
queries::{Query, TailTarget},
158
rows_to_frame, Error, MaterializePlugin,
169
};
1710

@@ -34,73 +27,69 @@ impl backend::DataQueryError for QueryError {
3427
// Unfortunately this has to take all of its arguments by value until we have
3528
// GATs, since the `DataService::Stream` associated type can't contain references.
3629
// Ideally we'd just borrow the query/uid etc but it's really not a big deal.
37-
async fn query_data_single(
38-
client: Client,
39-
uid: String,
40-
query: backend::DataQuery<Query>,
41-
queries: Arc<RwLock<HashMap<path::QueryId, SelectStatement>>>,
42-
) -> Result<backend::DataResponse, Error> {
43-
let q = query.query;
44-
let target = q.as_tail()?;
45-
let rows = target.select_all(&client).await?;
46-
let mut frame = rows_to_frame(&rows);
30+
impl MaterializePlugin {
31+
async fn query_data_single(
32+
&self,
33+
datasource_instance_settings: &DataSourceInstanceSettings,
34+
query: &backend::DataQuery<Query>,
35+
) -> Result<backend::DataResponse, Error> {
36+
let q = &query.query;
37+
let client = self.get_client(datasource_instance_settings).await?;
38+
let target = q.as_tail()?;
39+
let rows = target.select_all(&client).await?;
40+
let mut frame = rows_to_frame(&rows);
4741

48-
if let TailTarget::Select { statement } = target {
49-
let query_id = QueryId::from_statement(statement);
50-
queries.write().await.insert(query_id, statement.clone());
51-
}
42+
if let TailTarget::Select { statement } = target {
43+
let query_id = QueryId::from_statement(statement);
44+
self.sql_queries
45+
.write()
46+
.await
47+
.insert(query_id, statement.clone());
48+
}
5249

53-
let path = q.to_path();
54-
// Set the channel of the frame, indicating to Grafana that it should switch to
55-
// streaming.
56-
let channel = format!("ds/{}/{}", uid, path)
57-
.parse()
58-
.map_err(Error::CreatingChannel)?;
59-
frame.set_channel(channel);
60-
let frame = frame.check()?;
50+
let path = q.to_path();
51+
// Set the channel of the frame, indicating to Grafana that it should switch to
52+
// streaming.
53+
let channel = format!("ds/{}/{}", datasource_instance_settings.uid, path)
54+
.parse()
55+
.map_err(Error::CreatingChannel)?;
56+
frame.set_channel(channel);
57+
let frame = frame.check()?;
6158

62-
Ok(backend::DataResponse::new(query.ref_id, vec![frame]))
59+
Ok(backend::DataResponse::new(
60+
query.ref_id.clone(),
61+
vec![frame],
62+
))
63+
}
6364
}
6465

6566
#[backend::async_trait]
6667
impl backend::DataService for MaterializePlugin {
6768
type Query = Query;
6869
type QueryError = QueryError;
69-
type Stream = backend::BoxDataResponseStream<Self::QueryError>;
70+
type Stream<'a> = backend::BoxDataResponseStream<'a, Self::QueryError>;
7071

71-
async fn query_data(&self, request: backend::QueryDataRequest<Self::Query>) -> Self::Stream {
72+
async fn query_data<'stream, 'req: 'stream, 'slf: 'req>(
73+
&'slf self,
74+
request: &'req backend::QueryDataRequest<Self::Query>,
75+
) -> Self::Stream<'stream> {
7276
let datasource_settings = request
7377
.plugin_context
7478
.datasource_instance_settings
75-
.clone()
79+
.as_ref()
7680
.ok_or(Error::MissingDatasource)
7781
.unwrap();
78-
let clients: Vec<_> = request
79-
.queries
80-
.iter()
81-
.map(|_| self.get_client(&datasource_settings))
82-
.collect::<FuturesUnordered<_>>()
83-
.collect()
84-
.await;
85-
let queries = self.sql_queries.clone();
8682
Box::pin(
8783
request
8884
.queries
89-
.into_iter()
90-
.zip(clients)
91-
.map(move |(x, client)| {
92-
let queries = queries.clone();
93-
let ref_id = x.ref_id.clone();
94-
let uid = datasource_settings.uid.clone();
95-
async {
96-
let client = client.map_err(|source| QueryError {
97-
ref_id: ref_id.clone(),
85+
.iter()
86+
.map(|x| async move {
87+
self.query_data_single(datasource_settings, x)
88+
.await
89+
.map_err(|source| QueryError {
90+
ref_id: x.ref_id.clone(),
9891
source,
99-
})?;
100-
query_data_single(client, uid, x, queries)
101-
.await
102-
.map_err(|source| QueryError { ref_id, source })
103-
}
92+
})
10493
})
10594
.collect::<FuturesOrdered<_>>(),
10695
)

0 commit comments

Comments
 (0)