use connectrpc::client::{ClientConfig, HttpClient};
use headwaters_proto::connect_gen::headwaters::read::v1::ReadServiceClient;
use crate::types::*;
use crate::{Error, HeadwatersConfig};
#[derive(Clone)]
pub struct HeadwatersClient {
inner: ReadServiceClient<HttpClient>,
}
impl HeadwatersClient {
pub fn connect(base_url: impl Into<String>) -> Result<Self, Error> {
Self::new(HeadwatersConfig::new(base_url))
}
pub fn new(config: HeadwatersConfig) -> Result<Self, Error> {
let uri: http::Uri = config
.base_url
.parse()
.map_err(|_| Error::InvalidBaseUrl(config.base_url.clone()))?;
if uri.scheme_str() == Some("https") {
return Err(Error::InvalidBaseUrl(format!(
"{}: https is not supported yet (TLS is a planned follow-up)",
config.base_url
)));
}
let mut client_config = ClientConfig::new(uri).with_default_timeout(config.timeout);
if let Some(token) = &config.token {
client_config =
client_config.with_default_header("authorization", format!("Bearer {token}"));
}
Ok(Self {
inner: ReadServiceClient::new(HttpClient::plaintext(), client_config),
})
}
pub fn from_env() -> Result<Self, Error> {
Self::new(HeadwatersConfig::from_env()?)
}
pub async fn list_namespaces(&self) -> Result<ListNamespacesResponse, Error> {
Ok(self
.inner
.list_namespaces(ListNamespacesRequest::default())
.await?
.into_owned())
}
pub async fn list_jobs(
&self,
namespace: &str,
limit: i32,
offset: i32,
) -> Result<ListJobsResponse, Error> {
Ok(self
.inner
.list_jobs(ListJobsRequest {
namespace: namespace.to_string(),
limit,
offset,
..Default::default()
})
.await?
.into_owned())
}
pub async fn get_job(&self, namespace: &str, name: &str) -> Result<JobDetail, Error> {
Ok(self
.inner
.get_job(GetJobRequest {
namespace: namespace.to_string(),
name: name.to_string(),
..Default::default()
})
.await?
.into_owned())
}
pub async fn get_job_runs(
&self,
namespace: &str,
name: &str,
) -> Result<ListRunsResponse, Error> {
Ok(self
.inner
.get_job_runs(GetJobRunsRequest {
namespace: namespace.to_string(),
name: name.to_string(),
..Default::default()
})
.await?
.into_owned())
}
pub async fn list_datasets(
&self,
namespace: &str,
limit: i32,
offset: i32,
) -> Result<ListDatasetsResponse, Error> {
Ok(self
.inner
.list_datasets(ListDatasetsRequest {
namespace: namespace.to_string(),
limit,
offset,
..Default::default()
})
.await?
.into_owned())
}
pub async fn get_dataset(&self, namespace: &str, name: &str) -> Result<Dataset, Error> {
Ok(self
.inner
.get_dataset(GetDatasetRequest {
namespace: namespace.to_string(),
name: name.to_string(),
..Default::default()
})
.await?
.into_owned())
}
pub async fn list_dataset_versions(
&self,
namespace: &str,
name: &str,
limit: i32,
offset: i32,
) -> Result<ListDatasetVersionsResponse, Error> {
Ok(self
.inner
.list_dataset_versions(ListDatasetVersionsRequest {
namespace: namespace.to_string(),
name: name.to_string(),
limit,
offset,
..Default::default()
})
.await?
.into_owned())
}
pub async fn search(
&self,
q: &str,
limit: i32,
kind: EntityKind,
namespace: &str,
) -> Result<SearchResponse, Error> {
Ok(self
.inner
.search(SearchRequest {
q: q.to_string(),
limit,
r#type: kind.into(),
namespace: namespace.to_string(),
..Default::default()
})
.await?
.into_owned())
}
pub async fn get_lineage(&self, node_id: &str, depth: i32) -> Result<LineageGraph, Error> {
Ok(self
.inner
.get_lineage(GetLineageRequest {
node_id: node_id.to_string(),
depth,
..Default::default()
})
.await?
.into_owned())
}
pub async fn get_column_lineage(&self, node_id: &str) -> Result<LineageGraph, Error> {
Ok(self
.inner
.get_column_lineage(GetColumnLineageRequest {
node_id: node_id.to_string(),
..Default::default()
})
.await?
.into_owned())
}
pub async fn list_events(&self, limit: i32, offset: i32) -> Result<ListEventsResponse, Error> {
Ok(self
.inner
.list_events(ListEventsRequest {
limit,
offset,
..Default::default()
})
.await?
.into_owned())
}
pub async fn get_run_facets(&self, run_id: &str) -> Result<RunFacetsResponse, Error> {
Ok(self
.inner
.get_run_facets(GetRunFacetsRequest {
run_id: run_id.to_string(),
..Default::default()
})
.await?
.into_owned())
}
pub async fn list_tags(&self) -> Result<ListTagsResponse, Error> {
Ok(self
.inner
.list_tags(ListTagsRequest::default())
.await?
.into_owned())
}
pub async fn get_tag_downstream(&self, tag: &str) -> Result<TagPropagation, Error> {
Ok(self
.inner
.get_tag_downstream(GetTagDownstreamRequest {
tag: tag.to_string(),
..Default::default()
})
.await?
.into_owned())
}
pub async fn get_lineage_event_stats(
&self,
period: &str,
limit: i32,
) -> Result<StatsResponse, Error> {
Ok(self
.inner
.get_lineage_event_stats(GetLineageEventStatsRequest {
period: period.to_string(),
limit,
..Default::default()
})
.await?
.into_owned())
}
pub async fn get_asset_stats(
&self,
asset: &str,
period: &str,
limit: i32,
) -> Result<StatsResponse, Error> {
Ok(self
.inner
.get_asset_stats(GetAssetStatsRequest {
asset: asset.to_string(),
period: period.to_string(),
limit,
..Default::default()
})
.await?
.into_owned())
}
}