-
Notifications
You must be signed in to change notification settings - Fork 5
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
Resolver Chains #58
Comments
This is a bit tricky to solve with resolver chains because for that you have to explicitly set / know the typename of the type. In Pylon, the schema is generated based on the signature of the queries. So in order to get the details relation, the In order to resolve over fetching, Pylon allows you to use functions, that are only executed when also queried. So take a look at the following example: export const graphql = {
Query: {
user: {
return {
"name": "John",
details: () => {
return {
"rank": 1
}
}
}
},
},
} Here, the Going back to your example, the |
So the idea would be more like this: export const graphql = {
users: {
return [
{
"name": "John",
id: 11,
},
{
"name": "Bob",
id: 12,
},
]
},
Details: {
details: (context) => {
const rank = db.getUserRank(context.id);
return {
rank,
}
}
},
} Which is dealing with nested objects in an array of users. But from what you're showing me, it sounds like this would work and not call getUserRank unless in the query. export const graphql = {
users: {
return [
{
"name": "John",
id: 11,
details: {
rank: () => db.getUserRank(11)
},
},
{
"name": "Bob",
id: 12,
details: {
rank: () => db.getUserRank(12)
},
},
]
},
} But more specifically would this code work?: export const graphql = {
users: async (type: string) => {
const users = db.getUsers(type);
return users.map(user => ({
...user,
details: {
rank: () => db.getUserRank(user.id)
},
}))
},
} This is the usecase of my problem as we're getting lots of records with nested objects I don't want to collect unless in the query. EDIT: I tested it and it does only call getUserRank if rank is in the query. |
I'm not really finding this as a solution for my needs. There is a case where we have a large record in a table in JSON I want to pick certain fields from in a sql query. Something like this (very contrived example): async getUserDetails(userId: number): Promise<Details> {
const details = { // available fields
rank: 'managed.profile',
foo: 'sub.profile',
bar: 'sub.profile',
};
let items = Object.keys(details)
.map((item) => `JSON_VALUE(detail, '$.${details[item]}.${item}') AS ${item}`)
.join(', ');
const sql = `
SELECT ${items}
FROM user_details
WHERE id ?`;
// graphQL query only selecting rank and foo outputs: "SELECT JSON_VALUE(detail, '$.managed.profile.rank') AS rank, JSON_VALUE(detail, '$.sub.profile.foo') AS foo FROM user WHERE id = ?"
return await this.query(sql, [userId]);
} export const graphql = {
Query: {
users: async (name: string) => {
const users = await db.getUsers(name); // gets fuzzy match
return users.map(async (person) => {
return {
...person,
details: async () => await db.getUserDetails(person.id), // this call would do the logic above
};
});
},
},
}; results in: It seems the only way I can generate that query is to know the graphQL query ahead of time. Is this even possible to do something like this with GraphQL let alone Pylon? |
Are multiple separate sql calls an option? If so, you could do something like that: return users.map(async (person) => {
return {
...person,
details: {
rank: async () => await db.getUserDetails(person.id, "rank"),
foo: async () => await db.getUserDetails(person.id, "foo"),
...
}
};
}); A optimal solution, but more complex, would be to use the I could add a feature to Pylon that allows you to access the |
Oh wow. That is actually exactly what I was looking for. That would be amazing if you could add that. |
@schettn do you want me to write a ticket for that? |
Sure, that would be nice. I have just started to work on this. I will expose the info via the context for now. You have to implement the helper method from the blog post yourself. At some point I think I might add this helper function to pylon. Will the following for you?: import {getContext} from "@getcronit/pylon"
...
const ctx = getContext()
const info = ctx.get("graphqlResolveInfo")
... |
@LowLifeArcade I will also create a new example that showcases this new feature and the helper methods from the blog. import { app } from '@getcronit/pylon'
import { getResolvedFields } from './get-resolved-fields'
const getUser = (): {
firstName: string,
lastName: string,
username: string
} => {
const fields = getResolvedFields()
return {
firstName: fields.nestedFields.user.flatFields.includes("firstName") ? "John" : "",
lastName: fields.nestedFields.user.flatFields.includes("lastName") ? "Doe" : "",
username: fields.nestedFields.user.flatFields.includes("username") ? "johndoe" : ""
}
}
export const graphql = {
Query: {
data: () => {
const user = getUser()
console.log("Got user", user)
return {
user,
}
}
},
Mutation: {}
}
export default app |
That looks great @schettn. And exposing through the context object looks like it will work nicely. I appreciate that. I'll create a ticket for you for the full feature you're working on 🙏 |
Wow. I didn't expect you to deploy so soon after making the change. Thank you for turning this all around so fast! This helps me so so much. I really appreciate this. |
Is your feature request related to a problem? Please describe.
The ability to create resolver chains prevents over fetching data
Describe the solution you'd like
create a resolver that is for a nested data type that we can conditionally get data for based on the query
// this won't fetch details and prevents over fetching data
Describe alternatives you've considered
This comes from resolver chains in Apollo: https://www.apollographql.com/docs/apollo-server/data/resolvers#resolver-chains
Additional context
I've started integrating Pylon in a large production echo system as I wanted to use hono and this was an obvious solution for that. I'm finding this part tricky as the problem I'm trying to solve is we have a lot of data we're pulling and the goal is to seperate it all out in chunks based on the query so we don't overfetch data.
The text was updated successfully, but these errors were encountered: