rspc/procedure/
resolver_input.rs

1// /// The input to a procedure which is derived from an [`ProcedureInput`](crate::procedure::Argument).
2// ///
3// /// This trait has a built in implementation for any type which implements [`DeserializeOwned`](serde::de::DeserializeOwned).
4// ///
5// /// ## How this works?
6// ///
7// /// [`Self::from_value`] will be provided with a [`ProcedureInput`] which wraps the [`Argument::Value`](super::Argument::Value) from the argument provided to the [`Procedure::exec`](super::Procedure) call.
8// ///
9// /// Input is responsible for converting this value into the type the user specified for the procedure.
10// ///
11// /// If the type implements [`DeserializeOwned`](serde::de::DeserializeOwned) we will use Serde, otherwise we will attempt to downcast the value.
12// ///
13// /// ## Implementation for custom types
14// ///
15// /// Say you have a type `MyCoolThing` which you want to use as an argument to an rspc procedure:
16// ///
17// /// ```
18// /// pub struct MyCoolThing(pub String);
19// ///
20// /// impl ResolverInput for MyCoolThing {
21// ///     fn from_value(value: ProcedureInput<Self>) -> Result<Self, InternalError> {
22// ///        Ok(todo!()) // Refer to ProcedureInput's docs
23// ///     }
24// /// }
25// ///
26// /// // You should also implement `ProcedureInput`.
27// ///
28// /// fn usage_within_rspc() {
29// ///     <Procedure>::builder().query(|_, _: MyCoolThing| async move { () });
30// /// }
31// /// ```
32
33// TODO: Should this be in `rspc_procedure`???
34// TODO: Maybe rename?
35
36use serde::de::DeserializeOwned;
37use specta::{datatype::DataType, Type, TypeCollection};
38
39/// TODO: Restore the above docs but check they are correct
40pub trait ResolverInput: Sized + Send + 'static {
41    fn data_type(types: &mut TypeCollection) -> DataType;
42
43    /// Convert the [`DynInput`] into the type the user specified for the procedure.
44    fn from_input(input: rspc_procedure::DynInput) -> Result<Self, rspc_procedure::ProcedureError>;
45}
46
47impl<T: DeserializeOwned + Type + Send + 'static> ResolverInput for T {
48    fn data_type(types: &mut TypeCollection) -> DataType {
49        T::inline(types, specta::Generics::Definition)
50    }
51
52    fn from_input(input: rspc_procedure::DynInput) -> Result<Self, rspc_procedure::ProcedureError> {
53        Ok(input.deserialize()?)
54    }
55}