Skip to content

Documentation on how to use LookAhead* features. #234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jearbear opened this issue Aug 26, 2018 · 19 comments · Fixed by #1230
Closed

Documentation on how to use LookAhead* features. #234

jearbear opened this issue Aug 26, 2018 · 19 comments · Fixed by #1230
Assignees
Labels
enhancement Improvement of existing features or bugfix k::documentation Related to project documentation
Milestone

Comments

@jearbear
Copy link

I saw that support for look ahead functionality was added in #136, but I'm a bit confused as to how to use it since it's not at all documented. I see they are exported here, but attempting to use them throws a compiler error:

error[E0432]: unresolved import `juniper::LookAheadArgument`
 --> src/schema.rs:4:5
  |
4 | use juniper::LookAheadArgument;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ no `LookAheadArgument` in the root
warning: unused import: `juniper::LookAheadArgument`
 --> src/schema.rs:4:5
  |
4 | use juniper::LookAheadArgument;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(unused_imports)] on by default

Any help here would be greatly appreciated, thanks!

@LegNeato
Copy link
Member

/cc @weiznich

@weiznich
Copy link
Contributor

I think the released version on crates.io does not contain that feature yet. So to make this work you need to dependent directly on the git version.

@LegNeato
Copy link
Member

LegNeato commented Aug 26, 2018

Oh, yes, sorry...I should have read closer. You need to use master/git until a new release (#210). Sadly I can't do a release because I don't have permissions and @theduke and @mhallin haven't been around lately.

It would still be good to get some docs on how to actually use it in the book so keeping this open.

@LegNeato LegNeato reopened this Aug 26, 2018
@jearbear
Copy link
Author

Ah I see, I suspected as much, thanks!

Out of curiosity are these the main way people are recommended to tackle the N+1 query problem? I find that even in the most simple case it gets pretty chatty and haven't been able to find much guidance on that in particular. (Well other than using dataloader-rs, which I believe requires async support to work?)

@weiznich
Copy link
Contributor

There are basically 2 ways to solve the N+1 query problem:

  • Using something like dataloader
  • Using a lookahead mechanism to inspect the whole query

The first solution won't work with juniper as implemented currently, because it needs async support, so this leaves currently only the lookahead solution.

(Btw: If you are trying to integrate juniper with a relational database checkout wundergraph)

@LegNeato
Copy link
Member

This discussion may also be of use:

#124

@jearbear
Copy link
Author

Yup that's what alerted me to wundergraph's existence 😄. During my first pass through I found it a bit hard to grok, but I haven't set some time aside to really dig into it so I'll do that and report back.

@LegNeato LegNeato added the k::documentation Related to project documentation label Aug 28, 2018
@weiznich
Copy link
Contributor

weiznich commented Aug 28, 2018

I guess if we define these types in juniper consumers of the lib aren't forced to use them. They could just use the default Int and Float types and it would be as if they were never added.

Writing documentation is a big point of what's left before wundergraph will be released officially. For now the two examples are the only documentation that exists beside the code.

@kestred
Copy link
Contributor

kestred commented Oct 25, 2018

@weiznich: While it isn't as complete as facebook's GraphQL dataloader, at work we've got a pretty decent to solution to handle batching of nested objects.


Our solution to handle nested objects is to wrap our RealObject in a new struct:

struct BatchedObject { id: Id, batch: Rc<MultipleObjectDataWithLazyRefCells> }

and then load the data out of the Rc in the field blah() -> { self.batch.get_blah(&self.id) }.

Here is a gist with part of the bits you might use https://gist.github.com/kestred/6cac1149b072228bd398e2c60e3c7871.

The gist example is fairly unusual, because all of our typical batching has been replaced a graphql_batch! macro which hides most of the noise.

@Darkeye9
Copy link

Would anyone, please, mind to show a basic example of how this works? I am not a Rust begginer, but neither a pro... And I could not get any cue from the wundergraph project :(

@weiznich
Copy link
Contributor

The basic idea is quite simple:
You call Executor::look_ahead() to get a LookAheadSelection. That's basically just a structure that represents the whole request. After that you can use the methods provided by LookAheadMethods to traverse the request tree. How you do that and what you do with the result depends quite a lot on your exact use case. For wundergraph this is used to construct sql queries.

@LegNeato I think this could be closed because the documentation was released.

@Darkeye9
Copy link

@weiznich Thanks, but should this Executor::look_ahead() call be made inside an object field code?
What happens if I return e.g. Books with Authors from the books field? Will Juniper execute the code for Book.Author for each book anyway?

@weiznich
Copy link
Contributor

A simple pseudo code implementation would look like this:

struct Query;

#[derive(GraphQLObject)]
struct User { 
    id: String,
    posts: Vec<Post>,
}

impl User {
    fn from_lookahead(selection: LookAheadSelection) -> Self {
        // do something with the selection here
    }
}

#[derive(GraphQLObject)]
struct Post {
    id: String,
    content: String,
}

graphql_object!(Query: () |&self| {
    field user(&executor) -> User {
        let lookahead = executor.look_ahead();
        User::from_lookahead(lookahead)
    }
});

@Darkeye9
Copy link

@weiznich Thank you very much for the effort. But could you please clarify on this?
If I make the following query:

{
   users   {
      id,
      name,
      posts      {
         id,
         name
      }
   }
}

So, if I return the users, along with the posts, in the field users, will Juniper continue traversing the graph? Or I must remove the rest of the graph in the lookahead?

Thank you very much for your time!

@weiznich
Copy link
Contributor

That depends on the exact implementation. In the example above juniper will continue to traverse the graph. In detail because of the derives it will just select the right fields from the response. If GrapQLType is manually implemented (or by using graphql_object!) for Users a other behaviour is possible.
In wundergraph I let do juniper the exact field resolution, but look for nested fields (in this case posts) and load them only if they are requested.

@Darkeye9
Copy link

Thanks @weiznich I'll try to use your wishdom to implement it when I got home. BTW, you said that the documentation was released. Where has this been done?

Thank you very much!

@weiznich
Copy link
Contributor

Basically the api documentation here and for all other lookahead related types.
At the time this issue was opened those documentation did not exist.

@jimsynz
Copy link
Contributor

jimsynz commented Sep 26, 2019

Circling back around on this; the example in #234 (comment) no longer compiles because LookAheadSelection and LookAheadMethods are generic, but I don't quite understand what they are generic over and how I am supposed to use them. I'd happily send a PR adding docs if I could figure out how to work it.

@theduke
Copy link
Member

theduke commented Sep 26, 2019

It's generic over the lifetime and the scalar type, which will be juniper::DefaultScalarValue, unless you customize it.

@tyranron tyranron added this to the 0.16.0 milestone Nov 24, 2023
@tyranron tyranron added the enhancement Improvement of existing features or bugfix label Nov 24, 2023
@tyranron tyranron self-assigned this Nov 24, 2023
@tyranron tyranron mentioned this issue Dec 1, 2023
31 tasks
tyranron added a commit that referenced this issue Mar 20, 2024
- rework and update existing chapters
- mention correct case transformation for GraphQL enums (#1029)
- document N+1 mitigation techniques and look-ahead features (#234, #444)
- mention all integration crates (#867)
- fix Book links (#679, #974, #1056)
- remove old version of Book (#1168)

Additionally:
- disable `bson`, `url`, `uuid` and `schema-language` Cargo features by default in `juniper` crate

Co-authored-by: Christian Legnitto <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improvement of existing features or bugfix k::documentation Related to project documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants