Skip to content
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

Use new version of async-graphql for dynamic schema generation #287

Merged
merged 74 commits into from
Mar 16, 2023

Conversation

sandreae
Copy link
Member

@sandreae sandreae commented Mar 10, 2023

Use https://github.com/async-graphql/async-graphql and https://github.com/smmoosavi/dynamic-graphql to implement dynamic schema handling in our graphql api.

This took a little bit of time as I had to get to grips with the new async-graphql dynamic schema creation patterns, but I'm very happy with the result, it will be much more enjoyable (and quite quick) to expand our query api now with new features.

Design decisions

  • we use async-graphql to build all queries dynamically. It doesn't seem possible to combine "statically" defined queries with dynamic ones, so even nextArgs is defined using the dynamic API
  • all scalar and known types are defined using dynamic-graphql which offers macro wrappers for async-graphql, these are then registered on the root schema and can be referenced by name in dynamic queries where object types can be defined
  • the resolver pattern i adopted (i believe it's the recommended way) is to have each field perform a single db query to retrieve it's own value. The query bubbles up from it's root to tips, only resolving actual values in it's final step. For this to be efficient, we may want to make two changes:
    1. implement a data loader which helps cache results for duplicate queries which occur in the same query tree (avoids N+1).
    2. write a new SQL query for the field resolver which only targets the requested field.

Tasks

  • remove old graphql module
  • remove replication end points (we might want these back later, but for now they're gone)
  • re-implement all functionality using above crates
    • scalar types
    • types
      • document meta
      • next args
    • build document fields schema
    • build document schema
    • build document query one
    • relations (single and lists)
    • build document query all
    • build next args
    • mutations: publish
  • bring back all tests
    • make them pass....
  • add some more tests let's do this in next steps 😶‍🌫️ we at least shouldn't have fewer tests than we did before!
  • get dynamic-schema published or remove it from this PR it already was

Next steps

  • implement a data loader for efficient query caching
  • write field only SQL queries for field resolver (optional)

📋 Checklist

  • Add tests that cover your changes
  • Add this PR to the Unreleased section in CHANGELOG.md
  • Link this PR to any issues it closes
  • New files contain a SPDX license header

@adzialocha adzialocha changed the title Use async-graphql for dynamic schema Use new version of async-graphql for dynamic schema Mar 14, 2023
@adzialocha adzialocha changed the title Use new version of async-graphql for dynamic schema Use new version of async-graphql for dynamic schema generation Mar 14, 2023
Copy link
Member

@adzialocha adzialocha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't believe how easy it is to understand this and at the same time it is super powerful. It's really nicely done!

I've added some smaller comments in my review, some general remarks:

  • You have a whole bunch of "TODO" markers in the code which partly need to be extended or discussed. My suggestion would be to remove them and rather create GitHub issues instead? Then we can continue discussion there.
  • There is a lot of underscores 😆 Don't think we make use of that naming pattern so far, what was the intention here? Is this a sign of too much dead code which needs to be removed? In general I think its good to not keep dead code around at any point.

aquadoggo/Cargo.toml Outdated Show resolved Hide resolved
aquadoggo/src/db/stores/entry.rs Show resolved Hide resolved
aquadoggo/src/graphql/mutations/mod.rs Show resolved Hide resolved
aquadoggo/src/graphql/mutations/publish.rs Outdated Show resolved Hide resolved
aquadoggo/src/graphql/scalars/encoded_entry_scalar.rs Outdated Show resolved Hide resolved
aquadoggo/src/graphql/schema_builders/document.rs Outdated Show resolved Hide resolved
aquadoggo/src/graphql/schema_builders/next_args.rs Outdated Show resolved Hide resolved
aquadoggo/src/graphql/utils.rs Outdated Show resolved Hide resolved
aquadoggo/src/replication/service.rs Show resolved Hide resolved
aquadoggo/src/tests.rs Outdated Show resolved Hide resolved
@adzialocha adzialocha linked an issue Mar 14, 2023 that may be closed by this pull request
@adzialocha
Copy link
Member

Clippy fails because of #295, will merge now anyhow. The replication service refactoring / removal I'll do in a separate PR 👍 Thank you for this amazing work @sandreae!

@adzialocha adzialocha merged commit cb411c0 into main Mar 16, 2023
@adzialocha adzialocha deleted the async-graphql-dynamic-schema branch March 16, 2023 11:54
Comment on lines +27 to +33
move |ctx| {
FieldFuture::new(async move {
// Here we just pass up the root query parameters to be used in the fields resolver
let params = downcast_id_params(&ctx);
Ok(Some(FieldValue::owned_any(params)))
})
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This 😭😭😭 So much better

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use new dynamic schema API of async-graphql
3 participants