mod builder;
mod erased;
mod meta;
mod resolver_input;
mod resolver_output;
pub use builder::ProcedureBuilder;
pub use erased::ErasedProcedure;
pub use meta::ProcedureMeta;
pub use resolver_input::ResolverInput;
pub use resolver_output::ResolverOutput;
use std::{borrow::Cow, marker::PhantomData, panic::Location, sync::Arc};
use futures_util::{FutureExt, TryStreamExt};
use specta::datatype::DataType;
use crate::{Error, Extension, ProcedureKind, State};
#[derive(Clone)]
pub(crate) struct ProcedureType {
pub(crate) kind: ProcedureKind,
pub(crate) input: DataType,
pub(crate) output: DataType,
pub(crate) error: DataType,
pub(crate) location: Location<'static>,
}
pub struct Procedure<TCtx, TInput, TResult> {
pub(crate) build:
Box<dyn FnOnce(Vec<Box<dyn FnOnce(&mut State, ProcedureMeta)>>) -> ErasedProcedure<TCtx>>,
pub(crate) phantom: PhantomData<(TInput, TResult)>,
}
impl<TCtx, TInput, TOutput> Procedure<TCtx, TInput, TOutput> {
#[track_caller]
pub fn builder<TError>(
) -> ProcedureBuilder<TError, TCtx, TCtx, TInput, TInput, TOutput, TOutput>
where
TCtx: Send + 'static,
TError: Error,
TInput: ResolverInput,
TOutput: ResolverOutput<TError>,
{
let location = Location::caller().clone();
ProcedureBuilder {
build: Box::new(move |kind, setup, handler| {
ErasedProcedure {
kind,
setup: setup
.into_iter()
.map(|setup| {
let v: Box<dyn FnOnce(&mut State)> =
Box::new(move |state: &mut State| {
let key: Cow<'static, str> = "todo".to_string().into(); let meta = ProcedureMeta::new(
key.into(),
kind,
Arc::new(State::default()), );
setup(state, meta);
});
v
})
.collect::<Vec<_>>(),
location,
inner: Box::new(move |state, types| {
let key: Cow<'static, str> = "todo".to_string().into(); let meta = ProcedureMeta::new(key.clone(), kind, state);
(
rspc_procedure::Procedure::new(move |ctx, input| {
TOutput::into_procedure_stream(
handler(
ctx,
TInput::from_input(input).unwrap(), meta.clone(),
)
.into_stream()
.map_ok(|v| v.into_stream())
.map_err(|err| err.into_procedure_error())
.try_flatten()
.into_stream(),
)
}),
ProcedureType {
kind,
location,
input: TInput::data_type(types),
output: TOutput::data_type(types),
error: DataType::Unknown, },
)
}),
}
}),
phantom: PhantomData,
}
}
pub fn with(self, mw: Extension<TCtx, TInput, TOutput>) -> Self
where
TCtx: 'static,
{
Procedure {
build: Box::new(move |mut setups| {
if let Some(setup) = mw.setup {
setups.push(setup);
}
(self.build)(setups)
}),
phantom: PhantomData,
}
}
}
impl<TCtx, TInput, TResult> Into<ErasedProcedure<TCtx>> for Procedure<TCtx, TInput, TResult> {
fn into(self) -> ErasedProcedure<TCtx> {
(self.build)(Default::default())
}
}