You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm interested in exploring and discussing what it'd take to implement the Node interface (and with that globally unique IDs) in Sqlmancer. This + connection based pagination would ultimately mean that Sqlmancer will be compatible with Relay, which would be a very nice thing 😀
For illustrative purposes, let's say we're implementing the Node interface as a directive @nodeInterfaceyou can use on OBJECT. This is probably a bad idea (a better idea is likely some form of global setting to enable "Relay mode"), but let's use it as a way of exploring implementing the Node interface and globally unique IDs in Sqlmancer:
Now, id defined in the model will be a database ID, which probably won't be globally unique, or contain enough information to decipher what type it's representing (which the Node interface needs). However, my thinking is that the @nodeInterface directive could do something like this;
typeWidget@model(...) @nodeInterface {
dbId: ID! # This is the old `id` field, just moved to this key so it's still accessibleid: ID! # This is changed to be a globally unique ID with the type information needed by the Node interface
...
}
The id field that's changed could then be implemented to just change the resolution of itself to something Node-interface friendly:
// Manipulating the GraphQLObjectType with the `@nodeInterface` directive defined on it
id: {type: newGraphQLNonNull(GraphQLID),resolve(obj){// obj.id below is the _old_, real database id at this point// base64.encode isn't really needed, but it's to show the clients that they shouldn't rely on the contents of the ID// This code below will allow us to take any `id`, decode it, and immediately know what type we need to fetch using what id. More on that belowreturnbase64.encode(`${typeNameFromGraphQLObject}:${obj.id}`);}}
This could then be re-used in the node field on Query:
// Extending the root Query typefields: ()=>({
...rootQueryFields,node: {type: nodeInterfaceType,args: {...}// id: ID!resolve(ctx,args){const[typename,id]=base64.decode(args.id).split(":");if(!typename||!id){thrownewError("Malformed ID");}// Here we have a typename of a GraphQL type we want to resolve, and the id we want to use// Just need to resolve it. Made up pseudo-code belowreturnctx.models[typename].findOne({ id });}}})
I believe this would accomplish what's needed for the Node interface and globally unique IDs.
Here's a few issues and things I've thought about that needs consideration:
id in input positions - if the IDs are now globally unique, they'll need decoding before being used in SQL etc.
id in relations and similar things - same as above, will need decoding.
This was a quick write up of my thoughts, I hope it's not terrible to read. What are your initial thoughts about something like this? Do you see any immediate blockers or issues?
I'm btw very willing to spend time implementing this if there's interest for it!
The text was updated successfully, but these errors were encountered:
@zth Thanks for the above input. I think your suggested approach is very reasonable and wouldn't be too difficult to implement. If we were to use a directive, I think something like the @globalId used by Lighthouse would be good
"""
Converts between IDs/types and global IDs.
When used upon a field, it encodes,
when used upon an argument, it decodes.
"""
directive @globalId(
"""
By default, an array of `[$type, $id]` is returned when decoding.
You may limit this to returning just one of both.
Allowed values: "ARRAY", "TYPE", "ID"
"""
decode: String = "ARRAY"
) on FIELD_DEFINITION | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
Customizing the id via the decode argument here is a bit overkill for me. However, I like the idea of reusing the same directive for encoding and decoding.
That said, I also kind of like your idea of having a global setting for this. That would make for better DX, and might also simplify the implementation a bit. I would imagine wanting to enable global ids for only some of the types in the schema would be quite an edge case.
Hi!
I'm interested in exploring and discussing what it'd take to implement the
Node
interface (and with that globally unique IDs) in Sqlmancer. This + connection based pagination would ultimately mean that Sqlmancer will be compatible with Relay, which would be a very nice thing 😀Below are some initial thoughts from me (https://graphql.org/learn/global-object-identification/ is recommended reading if the reader is unfamiliar with globally unique IDs and the Node interface in GraphQL):
The Node interface
For illustrative purposes, let's say we're implementing the
Node
interface as a directive@nodeInterface
you can use onOBJECT
. This is probably a bad idea (a better idea is likely some form of global setting to enable "Relay mode"), but let's use it as a way of exploring implementing theNode
interface and globally unique IDs in Sqlmancer:Now,
id
defined in the model will be a database ID, which probably won't be globally unique, or contain enough information to decipher what type it's representing (which theNode
interface needs). However, my thinking is that the@nodeInterface
directive could do something like this;The
id
field that's changed could then be implemented to just change the resolution of itself to somethingNode
-interface friendly:This could then be re-used in the
node
field onQuery
:I believe this would accomplish what's needed for the
Node
interface and globally unique IDs.Here's a few issues and things I've thought about that needs consideration:
id
in input positions - if the IDs are now globally unique, they'll need decoding before being used in SQL etc.id
in relations and similar things - same as above, will need decoding.This was a quick write up of my thoughts, I hope it's not terrible to read. What are your initial thoughts about something like this? Do you see any immediate blockers or issues?
I'm btw very willing to spend time implementing this if there's interest for it!
The text was updated successfully, but these errors were encountered: