edgedb / edgedb-rust

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

Support named arguments #304

Closed MrFoxPro closed 2 months ago

MrFoxPro commented 3 months ago

Basic usage:

use edgedb_protocol::eargs;

let mut args = eargs! { "a" => "a".to_string() };
args.extend(eargs! { "b" => Some(5_i64) });

edb.query_required_single_json("select { a := <str>$a, b := <optional int64>$b }", &args)
.await?;
MrFoxPro commented 3 months ago

I realised it probably doesn't need indexmap crate, it's possible to use simple std::collections::HashMap instead.

MrFoxPro commented 3 months ago

Also I'm not sure about Cardinality::Many. Is it relevant for query arguments?

msullivan commented 3 months ago

Also I'm not sure about Cardinality::Many. Is it relevant for query arguments?

I don't think so, no.

msullivan commented 3 months ago

Thanks for the contribution!

I think this will suffer from the same problem that started all of this: it doesn't understand how to put the arguments in the correct order. It will need to consult the expected order from the server and put them in that order. It should also be able to get all of the cardinalities that way.

msullivan commented 3 months ago

Sure, but I think I would rather not merge #299 and instead do the logic while handling named arguments themselves.

It seems weird to me to do the ordering at the object encoding layer, since the object is ordered in the protocol.

On Wed, Mar 27, 2024, 14:09 MrFoxPro @.***> wrote:

Thanks for the contribution!

I think this will suffer from the same problem that started all of this: it doesn't understand how to put the arguments in the correct order. It will need to consult the expected order from the server and put them in that order. It should also be able to get all of the cardinalities that way.

For me it works fine when merged with #299 https://github.com/edgedb/edgedb-rust/pull/299

— Reply to this email directly, view it on GitHub https://github.com/edgedb/edgedb-rust/pull/304#issuecomment-2023994861, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACTC7PUS5IQRUPVAMRYR4LY2MYRNAVCNFSM6AAAAABFK26ZLOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRTHE4TIOBWGE . You are receiving this because your review was requested.Message ID: @.***>

MrFoxPro commented 3 months ago

As I understand the problem is that now driver only checks https://github.com/edgedb/edgedb-rust/blob/0bf094963ed2f29d825d3cdae37a136a72999ee5/edgedb-protocol/src/query_arg.rs#L195-L246 that shape is correct, but it doesn't use this information to align shape in correct way. I guess it will require a lot of effort to change this behaviour, or users will have to enforce correct order and provide cardinality themselves explicitly.

MrFoxPro commented 3 months ago

Ok, maybe I exaggerated about level of effort required.

MrFoxPro commented 3 months ago

@msullivan would it be sufficient to align input shape to required one here: https://github.com/edgedb/edgedb-rust/blob/0bf094963ed2f29d825d3cdae37a136a72999ee5/edgedb-protocol/src/codec.rs#L657-L691 I mean just walk over input shape elements, match corresponding element by name, place it in correct order and try to adjust correct cardinality?

If so, is it worth to modify this PR and preserve only HashMap -> Value transformation?

msullivan commented 3 months ago

What I think that I would recommend (and this might be what you were saying), is to make an implementation of encode for HashMap (or maybe for an iterator of str, value pairs?) that constructs an object Value with the correct order and cardinality, and then encodes that. It would consult the encoder's ctx in order to do that.

MrFoxPro commented 3 months ago

I was struggling with making something more generic than hashmap, ended up with simple solution.

msullivan commented 3 months ago

Actually running the tests requires the tests being able to find an edgedb-server binary to run. This can be accomplished with something like

PATH=$PATH:$(dirname $(edgedb server info --latest --bin-path)) cargo test --workspace --all-features
MrFoxPro commented 3 months ago

The encoder looks good and matches what I had in mind.

Could you please add some tests for this? The rust bindings seem substantially under-tested, unfortunately, but we need to start improving that, and seeing examples as tests will make it easier to review the design of the interface.

I think the easiest way to add tests would be by adding them to edgedb-tokio/tests/func/client.rs

Also, I can read and write rust but I wouldn't call myself idiomatic; @aljazerzen could you please review the proposed interface here?

For sure, but I probably will wait for another review so I don't need to rewrite tests later too. Also, I'm not familiar with writing Rust tests, so my tests could be not so good.

MrFoxPro commented 3 months ago

Examples for providing None values:

eargs! {
   "me" => 1 as i64,
   "e" => None::<Vec<f32>>,
   "q" => None::<String>,
   "sphere" => None::<String>,
   "lower" => None::<i64>,
   "upper" => None::<i64>,
   "geoarea" => None::<String>
}
MrFoxPro commented 3 months ago

This looks like a sound API design to me.

Before merging, take a look at the few low-priority comments I've left about naming and definitely add a few tests.

For an example, you can see the tests I've added in #308. If you want, I can get this PR over the line.

I will be happy if you add tests

aljazerzen commented 2 months ago

@MrFoxPro I've moved a few things around and added a bit of docs. Thank you for contributing!