use std::collections::HashMap;
use std::str::FromStr;
use chrono::{DateTime, Utc};
use graphql_client::{GraphQLQuery, Response};
use reqwest::Client;
use specifications::common::{Function, Type};
use specifications::data::{DataIndex, DataInfo};
use specifications::package::{PackageIndex, PackageInfo, PackageKind};
use specifications::version::Version;
use uuid::Uuid;
pub use crate::errors::ApiError as Error;
pub type DateTimeUtc = DateTime<Utc>;
pub async fn get_package_index(endpoint: impl AsRef<str>) -> Result<PackageIndex, Error> {
#[derive(GraphQLQuery)]
#[graphql(schema_path = "graphql/api_schema.json", query_path = "graphql/get_packages.graphql", response_derives = "Debug")]
pub struct GetPackages;
let endpoint: &str = endpoint.as_ref();
let client = Client::new();
let variables = get_packages::Variables {};
let graphql_query = GetPackages::build_query(variables);
let graphql_response: reqwest::Response = match client.post(endpoint).json(&graphql_query).send().await {
Ok(response) => response,
Err(err) => {
return Err(Error::RequestError { address: endpoint.into(), err });
},
};
let body: String = match graphql_response.text().await {
Ok(body) => body,
Err(err) => {
return Err(Error::ResponseBodyError { address: endpoint.into(), err });
},
};
let graphql_response: Response<get_packages::ResponseData> = match serde_json::from_str(&body) {
Ok(datasets) => datasets,
Err(err) => {
return Err(Error::ResponseJsonParseError { address: endpoint.into(), raw: body, err });
},
};
let packages: Vec<get_packages::GetPackagesPackages> = match graphql_response.data {
Some(packages) => packages.packages,
None => {
return Err(Error::NoResponse { address: endpoint.into() });
},
};
let mut infos: Vec<PackageInfo> = Vec::with_capacity(packages.len());
for (i, p) in packages.into_iter().enumerate() {
let functions: HashMap<String, Function> = p.functions_as_json.map(|f| serde_json::from_str(&f).unwrap()).unwrap_or_default();
let types: HashMap<String, Type> = p.types_as_json.map(|t| serde_json::from_str(&t).unwrap()).unwrap_or_default();
let kind: PackageKind = match PackageKind::from_str(&p.kind) {
Ok(kind) => kind,
Err(err) => {
return Err(Error::PackageKindParseError { address: endpoint.into(), index: i, raw: p.kind, err });
},
};
let version: Version = match Version::from_str(&p.version) {
Ok(version) => version,
Err(err) => {
return Err(Error::VersionParseError { address: endpoint.into(), index: i, raw: p.version, err });
},
};
infos.push(PackageInfo {
created: p.created,
id: p.id,
digest: p.digest,
name: p.name,
version,
kind,
owners: p.owners,
description: p.description.unwrap_or_default(),
detached: p.detached,
functions,
types,
});
}
match PackageIndex::from_packages(infos) {
Ok(index) => Ok(index),
Err(err) => Err(Error::PackageIndexError { address: endpoint.into(), err }),
}
}
pub async fn get_data_index(endpoint: impl AsRef<str>) -> Result<DataIndex, Error> {
let endpoint: &str = endpoint.as_ref();
let res: reqwest::Response = match reqwest::get(endpoint).await {
Ok(res) => res,
Err(err) => {
return Err(Error::RequestError { address: endpoint.into(), err });
},
};
let body: String = match res.text().await {
Ok(body) => body,
Err(err) => {
return Err(Error::ResponseBodyError { address: endpoint.into(), err });
},
};
let datasets: HashMap<String, DataInfo> = match serde_json::from_str(&body) {
Ok(datasets) => datasets,
Err(err) => {
return Err(Error::ResponseJsonParseError { address: endpoint.into(), raw: body, err });
},
};
let datasets: Vec<DataInfo> = datasets.into_values().collect();
match DataIndex::from_infos(datasets) {
Ok(index) => Ok(index),
Err(err) => Err(Error::DataIndexError { address: endpoint.into(), err }),
}
}