use crate::{CommandExt, Executor, ExecutorError, GraphInput, GraphOutput, JsonlStream};
use alloc::boxed::Box;
use async_trait::async_trait;
use derive_more::Debug;
use std::{ffi::OsStr, process::Stdio};
pub use asimov_patterns::MatcherOptions;
pub type MatcherResult = Result<JsonlStream, ExecutorError>;
#[allow(unused)]
#[derive(Debug)]
pub struct Matcher {
executor: Executor,
options: MatcherOptions,
input: GraphInput,
output: GraphOutput,
}
impl Matcher {
pub fn new(
program: impl AsRef<OsStr>,
input: GraphInput,
output: GraphOutput,
options: MatcherOptions,
) -> Self {
let mut executor = Executor::new(program);
executor
.command()
.option("input", options.input.as_ref())
.option("output", options.output.as_ref())
.args(&options.other)
.stdin(input.as_stdio())
.stdout(output.as_stdio())
.stderr(Stdio::piped());
Self {
executor,
options,
input: input.into_jsonl(),
output,
}
}
pub async fn execute(&mut self) -> MatcherResult {
self.executor
.execute_jsonl_with_io(&mut self.input, &mut self.output)
.await
}
}
impl asimov_patterns::Matcher<JsonlStream> for Matcher {}
crate::batch::with_batching!(Matcher);
crate::pipeline::stage!(
Matcher,
value,
value.input,
value.output,
value.options.input.as_deref(),
value.options.output.as_deref()
);
#[async_trait]
impl asimov_patterns::Execute<JsonlStream> for Matcher {
type Error = ExecutorError;
async fn execute(&mut self) -> MatcherResult {
self.execute().await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::StreamExt;
use alloc::vec::Vec;
use std::io::Cursor;
#[test]
fn test_options() {
let options = MatcherOptions::builder()
.input("jsonl")
.output("nquads")
.other("--exact")
.maybe_other(Some("--custom"))
.maybe_other(None::<&str>)
.build();
let mut matcher = Matcher::new(
"asimov-test-matcher",
GraphInput::Ignored,
GraphOutput::Captured,
options,
);
let args: Vec<_> = matcher.executor.command().as_std().get_args().collect();
assert_eq!(
args,
["--input=jsonl", "--output=nquads", "--exact", "--custom"]
);
}
#[test]
fn test_default_options() {
let mut matcher = Matcher::new(
"asimov-test-matcher",
GraphInput::Ignored,
GraphOutput::Captured,
MatcherOptions::default(),
);
assert_eq!(matcher.executor.command().as_std().get_args().count(), 0);
}
#[cfg(unix)]
#[tokio::test]
async fn test_execute() {
let graph = b"{\"subject\":\"https://example.com/\"}\n";
let mut matcher = Matcher::new(
"cat",
GraphInput::AsyncRead(Box::new(Cursor::new(graph.to_vec()))),
GraphOutput::Captured,
MatcherOptions::default(),
);
let mut output = asimov_patterns::Execute::execute(&mut matcher)
.await
.unwrap();
let batch = output.next().await.unwrap().unwrap();
assert_eq!(batch.len(), 1);
assert_eq!(batch.lines().next().unwrap(), graph);
assert!(output.next().await.is_none());
}
}