use crate::{canonical_uuid, write_execution_result};
use clap::Subcommand;
use graphforge_api::{CancellationToken, GfError, GraphForge};
use std::io::{Read, Write};
use std::path::PathBuf;
#[derive(Subcommand)]
pub(crate) enum ResearchVersionCommand {
Prepare {
#[arg(long)]
file: PathBuf,
},
Commit {
#[arg(long)]
file: PathBuf,
},
List,
Show {
#[arg(long)]
version: String,
},
Ontology {
#[arg(long)]
version: String,
},
Metadata {
#[arg(long)]
version: String,
},
Retention,
Query {
#[arg(long)]
version: String,
#[arg(long)]
query: String,
},
Artifact {
#[arg(long)]
version: String,
#[arg(long)]
artifact: String,
},
ArtifactPayload {
#[arg(long)]
version: String,
#[arg(long)]
artifact: String,
},
}
pub(crate) fn run(
graph: &mut GraphForge,
command: ResearchVersionCommand,
json: bool,
output: &mut dyn Write,
) -> Result<(), GfError> {
let value = match command {
ResearchVersionCommand::Prepare { file } => {
serde_json::to_value(graph.prepare_research_version(read_request(file)?)?)
}
ResearchVersionCommand::Commit { file } => {
serde_json::to_value(graph.commit_research_version_operation(
read_request(file)?,
&CancellationToken::new(),
)?)
}
ResearchVersionCommand::Show { version } => {
serde_json::to_value(graph.research_version(canonical_uuid(&version)?)?)
}
ResearchVersionCommand::Ontology { version } => serde_json::to_value(
graph
.open_research_version(canonical_uuid(&version)?)?
.workspace_ontology()?,
),
ResearchVersionCommand::Metadata { version } => serde_json::to_value(
graph
.open_research_version(canonical_uuid(&version)?)?
.research_project_metadata()?,
),
ResearchVersionCommand::Retention => {
serde_json::to_value(graph.research_version_retention()?)
}
ResearchVersionCommand::List => {
return write_execution_result(&graph.list_research_versions()?, json, output);
}
ResearchVersionCommand::Query { version, query } => {
return write_execution_result(
&graph
.open_research_version(canonical_uuid(&version)?)?
.execute(&query)?,
json,
output,
);
}
ResearchVersionCommand::Artifact { version, artifact } => {
return write_execution_result(
&graph
.open_research_version(canonical_uuid(&version)?)?
.artifact(canonical_uuid(&artifact)?)?,
json,
output,
);
}
ResearchVersionCommand::ArtifactPayload { version, artifact } => {
return write_execution_result(
&graph
.open_research_version(canonical_uuid(&version)?)?
.artifact_payload(canonical_uuid(&artifact)?)?,
json,
output,
);
}
}
.map_err(|error| GfError::Validation(error.to_string()))?;
serde_json::to_writer(&mut *output, &value)
.map_err(|error| GfError::Execution(error.to_string()))?;
writeln!(output).map_err(|error| GfError::Execution(error.to_string()))
}
fn read_request<T: serde::de::DeserializeOwned>(path: PathBuf) -> Result<T, GfError> {
let mut bytes = Vec::new();
std::fs::File::open(path)
.map_err(|error| GfError::Validation(error.to_string()))?
.take(1024 * 1024 + 1)
.read_to_end(&mut bytes)
.map_err(|error| GfError::Validation(error.to_string()))?;
if bytes.len() > 1024 * 1024 {
return Err(GfError::Validation("Version request exceeds 1 MiB".into()));
}
serde_json::from_slice(&bytes)
.map_err(|_| GfError::Validation("invalid research Version JSON contract".into()))
}