edgedb / edgedb-rust

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

Add Rust client tutorial #236

Closed Dhghomon closed 1 year ago

Dhghomon commented 1 year ago

The largest part of this PR is the tutorial.md file containing a tutorial for the Rust client. Also includes:

@raddevon I'll ping you too in case you want to give the tutorial.md a look.

Dhghomon commented 1 year ago

I think the general flow should be:

  1. Basic queries
  2. derive Queryable
  3. Arguments
  4. Query methods explained (where to use single, required single, why json are special methods)
  5. Transactions
  6. Configuring pool (different methods of with_* pattern, although, not sure what are good examples of that, maybe query/transaction timeout)
  7. How to organize things? Do we have to pass the pool everywhere? What's the downsides of putting it into a static var (that is the configuration)?

Other things can be moved around to a different documentation pages.

On general flow there's a bit of a dilemma here because Queryable is the slickest way to use the client but new users are probably more likely to flock to because doing a .to_string() and then serde_json::from_str() is the most comfortable pattern. (My own experience was the same here, started out with json-ing everything before moving on to Queryable). So introducing that ahead of time makes the experience a bit more comfortable IMO but at the same time it does feel a bit weird to make it look like Queryable is an afterthought when it's the better way to do it.

Maybe this could work:

Start with derive Queryable, followed by edgedb(json), then add the same example if it were to be done with to get EdgeDB to return a json result, then .to_string() and serde_json::from_str()". The reader can then see that the familiar serde_json::from_str pattern works too, but edgedb(json) simplifies it.

That dips into the 4. you mentioned here a bit earlier on but could be worth it since it avoids giving the impression that there's only one way to unpack into a Rust struct.

tailhook commented 1 year ago

slickest way to use the client but new users are probably more likely to flock to because doing a .to_string() and then serde_json::from_str() is the most comfortable pattern. (My own experience was the same here, started out with json-ing everything before moving on to Queryable). That means we're doing something wrong. Either APIs are wrong or documentation is missing.

The edgedb(json) attribute was made just to support migrations, which is an internal EdgeDB thing.

The attribute should be documented, but I don't see good use cases for that. Returning partially JSON values and partially not JSON makes little sense. Especially in our rich data model, where we discourage JSON columns.

On the othe hand, JSON output of EdgeDB is thing that should be used to directly send result to the client. So it's also not a use case for the attribute.

Dhghomon commented 1 year ago

slickest way to use the client but new users are probably more likely to flock to because doing a .to_string() and then serde_json::from_str() is the most comfortable pattern. (My own experience was the same here, started out with json-ing everything before moving on to Queryable). That means we're doing something wrong. Either APIs are wrong or documentation is missing.

Okay, let me think...personally, I think what might have gotten me to use it before serde_json would have been a simplified (i.e. easily readable) example of the generated code. Usually when I see a macro in a crate I haven't used before I avoid it until I have an idea of exactly what it does, and to get an idea of what it does means checking out cargo expand and wading through a bit of that code, and in the meantime I tend to come across other ways of getting things done and forget to use the crate's macros. But if that were front and centre then I probably would have given it a try earlier. So maybe that's an option? ("The Queryable macro generates code that looks roughly like this: (insert example with lots of macro bits removed)")

The edgedb(json) attribute was made just to support migrations, which is an internal EdgeDB thing.

The attribute should be documented, but I don't see good use cases for that. Returning partially JSON values and partially not JSON makes little sense. Especially in our rich data model, where we discourage JSON columns.

On the othe hand, JSON output of EdgeDB is thing that should be used to directly send result to the client. So it's also not a use case for the attribute.

That's good to know as I haven't been able to find a use case for the partial JSON attribute. Can strip it down to more minimal documentation then.

tailhook commented 1 year ago

"The Queryable macro generates code that looks roughly like this: (insert example with lots of macro bits removed)"

The actual code is quite weird :( Although, you may come to a rough estimation that looks sensible to users. Generally you can compare it to serde::Serialize.

Dhghomon commented 1 year ago

"The Queryable macro generates code that looks roughly like this: (insert example with lots of macro bits removed)"

The actual code is quite weird :( Although, you may come to a rough estimation that looks sensible to users. Generally you can compare it to serde::Serialize.

I think I've come up with a nice way to demonstrate this to my past self that I want to convince to use the macro earlier rather than later without cluttering up the tutorial. First a quick struct and cargo expand to grab the output, cleaned up the macro-y bits and stuck it in here:

https://github.com/Dhghomon/edgedb_rust_client_examples/blob/master/src/lib.rs#L12

Only 70 lines and looks close to human written. Then the tutorial will have a link to that for anyone who is curious (like my past self) and anyone who clones it will be able to quickly click around the methods to satisfy their curiosity.

Currently working on a lot of your other suggestions like changing order and tidying up by removing a lot of implementation details. (Also changing the order in the minimal example repo to emphasize using Queryable before showing other ways to unpack into a struct)

Dhghomon commented 1 year ago

Okay @tailhook and @raddevon, once more from the top! The tutorial is now a lot shorter and mostly in the order tailhook suggested so maybe just read the whole tutorial.md afresh and see what you think.

Lacks tailhook's suggested part 7 though:

How to organize things? Do we have to pass the pool everywhere? What's the downsides of putting it into a static var (that is the configuration)?

It keeps feeling like getting into other people's implementation details and preferences whenever I try to put this one together - do you think we need it?

Dhghomon commented 1 year ago

Getting back to this now that the 3.0 rush is over: @tailhook any thoughts on the changes made after your last feedback? Feels like it's getting closer to mergeable by now.

1st1 commented 1 year ago

@tailhook is on extended leave now. @fantix can you take a look at this PR?

fantix commented 1 year ago

Yeah sure, will do!