use std::{
collections::BTreeMap, error::Error, ffi::OsStr, fs, path::Path, sync::Arc,
};
use serde::Deserialize;
use trustfall::TransparentValue;
use crate::errors::FileParseError;
type QueryArgs = BTreeMap<Arc<str>, TransparentValue>;
#[derive(Debug, Clone, Deserialize)]
pub struct FullQuery {
pub query: String,
pub args: QueryArgs,
}
impl FullQuery {
pub fn from_path(path: &Path) -> Result<FullQuery, Box<dyn Error>> {
if !path.exists() {
Err(Box::new(FileParseError::NotFound(
path.to_string_lossy().to_string(),
)))
} else {
let raw_query = fs::read_to_string(path)?;
match path.extension().and_then(OsStr::to_str) {
Some("json") => {
let q: FullQuery =
serde_json::from_str::<FullQuery>(&raw_query)?;
Ok(q)
}
Some("ron") => {
let q = ron::from_str::<FullQuery>(&raw_query)?;
Ok(q)
}
Some(ext) => {
Err(Box::new(FileParseError::UnsupportedFileExtension {
ext: String::from(ext),
path: path.to_string_lossy().to_string(),
}))
}
None => Err(Box::new(FileParseError::UnknownFileExtension(
path.to_string_lossy().to_string(),
))),
}
}
}
}
pub struct FullQueryBuilder {
query: String,
args: Option<QueryArgs>,
}
impl FullQueryBuilder {
#[must_use]
pub fn new(query: String) -> Self {
Self { query, args: None }
}
#[must_use]
pub fn query(mut self, query: String) -> Self {
self.query = query;
self
}
#[must_use]
pub fn args(mut self, args: QueryArgs) -> Self {
self.args = Some(args);
self
}
#[must_use]
pub fn build(self) -> FullQuery {
FullQuery {
query: self.query,
args: self.args.unwrap_or(BTreeMap::new()),
}
}
}
#[cfg(test)]
mod test {
use std::{fs, path::Path};
use test_case::test_case;
use super::FullQuery;
#[test_case("test_data/queries/count_dependencies.in.ron" ; "parse count_dependencies ron")]
#[test_case("test_data/queries/dependency_package_info.in.ron" ; "parse dependency package info ron")]
fn deserialize_ron(query_path: &str) {
let s = fs::read_to_string(Path::new(query_path))
.unwrap_or_else(|_| panic!("could not read file {query_path}"));
ron::from_str::<FullQuery>(&s)
.unwrap_or_else(|_| panic!("could not deserialize {query_path}"));
}
#[test_case("test_data/queries/count_dependencies.in.json" ; "parse count_dependencies json")]
fn deserialize_json(query_path: &str) {
let s = fs::read_to_string(Path::new(query_path))
.unwrap_or_else(|_| panic!("could not read file {query_path}"));
serde_json::from_str::<FullQuery>(&s)
.unwrap_or_else(|_| panic!("could not deserialize {query_path}"));
}
}