diff --git a/fiberplane-pdk-macros/src/schema_field.rs b/fiberplane-pdk-macros/src/schema_field.rs index 66a4ab1..167e59a 100644 --- a/fiberplane-pdk-macros/src/schema_field.rs +++ b/fiberplane-pdk-macros/src/schema_field.rs @@ -10,13 +10,14 @@ use crate::casing::Casing; /// All the possible field types we can generate. pub enum SchemaField { + Array(ArrayField), Checkbox(CheckboxField), DateTimeRange(DateTimeRangeField), Integer(IntegerField), Label(LabelField), Select(SelectField), Text(TextField), - Array(ArraySchema), + Timestamp(TimestampField), } /// A compile-time representation of an ArrayField schema, @@ -28,7 +29,7 @@ pub enum SchemaField { /// /// This is why all fields are only exposed to the crate, /// and no public method is available either. -pub struct ArraySchema { +pub struct ArrayField { pub(crate) name: String, pub(crate) label: String, pub(crate) element_struct_type_name: String, @@ -40,16 +41,17 @@ impl SchemaField { pub fn required(self) -> Self { use SchemaField::*; match self { + Array(schema) => Array(ArrayField { + minimum_length: 1, + ..schema + }), Checkbox(field) => Checkbox(field.required()), DateTimeRange(field) => DateTimeRange(field.required()), Integer(field) => Integer(field.required()), Label(field) => Label(field.required()), Select(field) => Select(field.required()), Text(field) => Text(field.required()), - Array(schema) => Array(ArraySchema { - minimum_length: 1, - ..schema - }), + Timestamp(field) => Timestamp(field.required()), } } @@ -66,26 +68,28 @@ impl SchemaField { use SchemaField::*; let field_variant = match &self { + Array(_) => quote! { Array }, Checkbox(_) => quote! { Checkbox }, DateTimeRange(_) => quote! { DateTimeRange }, Integer(_) => quote! { Integer }, Label(_) => quote! { Label }, Select(_) => quote! { Select }, Text(_) => quote! { Text }, - Array(_) => quote! { Array }, + Timestamp(_) => quote! { Timestamp }, }; let enum_ident = Ident::new(field_enum, Span::call_site()); let field_ident = Ident::new(&format!("{field_variant}Field"), Span::call_site()); let name = serde_field_attrs.rename.unwrap_or_else(|| { let name = match &self { + Array(field) => &field.name, Checkbox(field) => &field.name, DateTimeRange(field) => &field.name, Integer(field) => &field.name, Label(field) => &field.name, Select(field) => &field.name, Text(field) => &field.name, - Array(field) => &field.name, + Timestamp(field) => &field.name, }; serde_struct_attrs.rename_all.format_string(name) }); @@ -97,13 +101,14 @@ impl SchemaField { }; let label = match &self { + Array(field) => &field.label, Checkbox(field) => &field.label, DateTimeRange(field) => &field.label, Integer(field) => &field.label, Label(field) => &field.label, Select(field) => &field.label, Text(field) => &field.label, - Array(field) => &field.label, + Timestamp(field) => &field.label, }; let label = match label.is_empty() { true => quote! {}, @@ -112,7 +117,7 @@ impl SchemaField { let max = match &self { Integer(IntegerField { max: Some(max), .. }) => quote! { .with_max(#max) }, - Array(ArraySchema { + Array(ArrayField { maximum_length: Some(maximum_length), .. }) => quote! { .with_maximum_length(#maximum_length) }, @@ -121,7 +126,7 @@ impl SchemaField { let min = match &self { Integer(IntegerField { min: Some(min), .. }) => quote! { .with_min(#min) }, - Array(ArraySchema { minimum_length, .. }) if *minimum_length != 0 => { + Array(ArrayField { minimum_length, .. }) if *minimum_length != 0 => { quote! { .with_minimum_length(#minimum_length) } } _ => quote! {}, @@ -170,13 +175,14 @@ impl SchemaField { }; let required = match &self { + Array(_) => false, Checkbox(field) => field.required, DateTimeRange(field) => field.required, Integer(field) => field.required, Label(field) => field.required, Select(field) => field.required, Text(field) => field.required, - Array(_) => false, + Timestamp(field) => field.required, }; let required = match required { true => quote! { .required() }, @@ -212,7 +218,7 @@ impl SchemaField { }; let element_schema = match &self { - Array(ArraySchema { + Array(ArrayField { element_struct_type_name, .. }) => { @@ -247,45 +253,46 @@ impl SchemaField { pub fn with_label(self, label: &str) -> Self { use SchemaField::*; match self { + Array(field) => Array(ArrayField { + label: label.to_string(), + ..field + }), Checkbox(field) => Checkbox(field.with_label(label)), DateTimeRange(field) => DateTimeRange(field.with_label(label)), Integer(field) => Integer(field.with_label(label)), Label(field) => Label(field.with_label(label)), Select(field) => Select(field.with_label(label)), Text(field) => Text(field.with_label(label)), - Array(field) => Array(ArraySchema { - label: label.to_string(), - ..field - }), + Timestamp(field) => Timestamp(field.with_label(label)), } } pub fn with_name(self, name: &str) -> Self { use SchemaField::*; match self { + Array(field) => Array(ArrayField { + name: name.to_string(), + ..field + }), Checkbox(field) => Checkbox(field.with_name(name)), DateTimeRange(field) => DateTimeRange(field.with_name(name)), Integer(field) => Integer(field.with_name(name)), Label(field) => Label(field.with_name(name)), Select(field) => Select(field.with_name(name)), Text(field) => Text(field.with_name(name)), - Array(field) => Array(ArraySchema { - name: name.to_string(), - ..field - }), + Timestamp(field) => Timestamp(field.with_name(name)), } } pub fn with_placeholder(self, name: &str) -> Self { use SchemaField::*; match self { - Checkbox(_) => self, + Array(_) | Checkbox(_) | Timestamp(_) => self, DateTimeRange(field) => DateTimeRange(field.with_placeholder(name)), Integer(_) => self, Label(field) => Label(field.with_placeholder(name)), Select(field) => Select(field.with_placeholder(name)), Text(field) => Text(field.with_placeholder(name)), - Array(_) => self, } } } diff --git a/fiberplane-pdk-macros/src/schema_generator.rs b/fiberplane-pdk-macros/src/schema_generator.rs index 670f0f0..8f7315b 100644 --- a/fiberplane-pdk-macros/src/schema_generator.rs +++ b/fiberplane-pdk-macros/src/schema_generator.rs @@ -1,5 +1,5 @@ use crate::schema_field::SchemaField; -use crate::{field_attrs::FieldAttrs, schema_field::ArraySchema}; +use crate::{field_attrs::FieldAttrs, schema_field::ArrayField}; use fiberplane_models::providers::*; use proc_macro::TokenStream; use proc_macro_error::abort; @@ -99,7 +99,8 @@ fn determine_field_type(field: &Field) -> SchemaField { SchemaField::Text(field) } } - (struct_name, true) => SchemaField::Array(ArraySchema { + ("Timestamp", false) => SchemaField::Timestamp(TimestampField::new()), + (struct_name, true) => SchemaField::Array(ArrayField { element_struct_type_name: struct_name.to_string(), name: name.clone(), label: String::new(), diff --git a/providers/prometheus/src/instants.rs b/providers/prometheus/src/instants.rs index 791230a..250e04e 100644 --- a/providers/prometheus/src/instants.rs +++ b/providers/prometheus/src/instants.rs @@ -7,6 +7,15 @@ use grafana_common::{query_direct_and_proxied, Config}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; +#[derive(Deserialize, QuerySchema)] +pub(crate) struct InstantsQuery { + #[pdk(label = "Enter your Prometheus query", supports_suggestions)] + query: String, + + #[pdk(label = "Specify a time")] + time: Option, +} + #[derive(Clone, Debug, Deserialize, ProviderData, Serialize)] #[pdk(mime_type = INSTANTS_MIME_TYPE)] pub struct Instants(pub Vec); @@ -20,14 +29,19 @@ pub struct Instant { pub metric: Metric, } -pub async fn query_instants(request: ProviderRequest) -> Result { - let response: PrometheusResponse> = query_direct_and_proxied( - &Config::parse(request.config)?, - "prometheus", - "api/v1/query", - Some(request.query_data), - ) - .await?; +pub async fn query_instants(query: InstantsQuery, config: Config) -> Result { + let body = Blob::from({ + let mut form_data = form_urlencoded::Serializer::new(String::new()); + form_data.append_pair("query", &query.query); + form_data.append_pair( + "time", + &query.time.unwrap_or_else(Timestamp::now_utc).to_string(), + ); + form_data + }); + + let response: PrometheusResponse> = + query_direct_and_proxied(&config, "prometheus", "api/v1/query", Some(body)).await?; let instants = response .data diff --git a/providers/prometheus/src/lib.rs b/providers/prometheus/src/lib.rs index c18725a..decfe23 100644 --- a/providers/prometheus/src/lib.rs +++ b/providers/prometheus/src/lib.rs @@ -12,7 +12,7 @@ use config::*; use constants::{INSTANTS_MIME_TYPE, INSTANTS_QUERY_TYPE}; use fiberplane_pdk::prelude::*; use grafana_common::{query_direct_and_proxied, Config}; -use instants::query_instants; +use instants::{query_instants, InstantsQuery}; use serde_json::Value; use std::env; use timeseries::{create_graph_cell, query_series, TimeseriesQuery}; @@ -31,7 +31,7 @@ pdk_query_types! { supported_mime_types: [YAML_MIME_TYPE] }, INSTANTS_QUERY_TYPE => { - handler: query_instants(ProviderRequest).await, + handler: query_instants(InstantsQuery, Config).await, supported_mime_types: [INSTANTS_MIME_TYPE] }, TIMESERIES_QUERY_TYPE => {