edgedb / edgedb-rust

The official Rust binding for EdgeDB
https://edgedb.com
Apache License 2.0
208 stars 26 forks source link

Simplify manual implementations of `QueryArg`/`Queryable` #269

Open XAMPPRocky opened 1 year ago

XAMPPRocky commented 1 year ago

Currently QueryArg's definition is pretty opaque and how an implementor is supposed to implement encode_slot and check_descriptor is undocumented, and a user is mostly expected to use this trait through the derive macros. However using derive macros is not possible when the types are defined in another crate. This requires you to duplicate the type definition in your own crate and write a From conversion. This approach is not scalable and hinders the ability to use EdgeDB with types in the Rust ecosystem.

I don't have all the context on why these traits are defined like this, but looking at the source it seems like it's leaking some encoder specific details that aren't relevant for users. It would be great if the implementations of these traits could be simplified into a codec model like serde so that users could easily write their own manual implementations.

// External crate…
struct A<T: std::fmt::Display> {
    foo: String,
    bar: T,
    baz: HashMap<String, serde_json::Value>,
}

// My crate…
struct B<T: std::fmt::Display>(A<T>);

impl<T: std::fmt::Display> edgedb_protocol::QueryArg for B<T> {
    fn encode(&self, enc: &mut edgedb_protocol::Encoder) -> Result<(), Error> {
        self.0.foo.encode(enc)?;
        enc.encode_str(&self.0.bar.to_string())?;
        enc.encode_json(&serde_json::encode_to_value(&self.0.baz).map_err(Error::custom)?)?;
        Ok(())
    }
}