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

Issue with GlobalIDs not transforming back to "native" uuid4 IDs #475

Closed
moltco opened this issue Mar 30, 2022 · 1 comment
Closed

Issue with GlobalIDs not transforming back to "native" uuid4 IDs #475

moltco opened this issue Mar 30, 2022 · 1 comment
Assignees
Labels

Comments

@moltco
Copy link

moltco commented Mar 30, 2022

I guess this is between "help need" and "feature request" category :) All help much appreciated!

I am using node & graphqljs + Join Monster to serve as GraphQL server for the PostgreSQL DB. GraphiQL on the client side for the test query. I use uuid4 for IDs in the Postgres DB.

When posting queries to GraphQL Server, the Relay specification requires Global IDs re used for each entity (node). Relay implements this Global ID as combination of node Type and my own ID, something like "User:dsft-23s3-fg14-ds2g" just base64 encoded (node type User, ID: the rest). This is fine and Relay provides a helper fromGlobalID that returns {type, id}.

My problem is that when react-relay posts a query to the GraphQL server it will use Global ID but I can't find an appropriate point where to unpack 'id' argument and convert it from GlobalID to uuid4 that my database understands.

So, the flow is:

  • GraphiQL manual query (see sample below): "query {project(id: globalID){id name}}"
  • graphql Server takes query
  • join monster 'where' thunk kicks in and takes argument id (args.id) as global ID (without transforming it into uuid4)
  • query fails as database expect id to be in uuid4 form, not global ID.

I have tried in my query resolver to unpack global ID but joinMonster where clause kicks in before the resolver so this does not work for me. I wonder if there was an entry point where I could unpack ID before it gets processed by join monster and resolver?

I know I could manually transform the ID in the join Monster's where function but... then I would need to do the same transformation anywhere where id is used (I could have multiple where clauses or joins + the resolver) so I am looking to process/transform args.id before it reaches joinMonster or the final query resolver.

Simplified code to illustrate problem:

import { globalIdField } from 'graphql-relay'

const Project = new GraphQLObjectType({
  name: 'Project',
  interfaces: [ nodeInterface ],
  extensions: {
    joinMonster: {
      sqlTable: 'public.project',
      uniqueKey: 'id'
    }
  },
  fields: () => {
    return {
      id: {...globalIdField(),}, 
      name: { type: graphql.GraphQLString },
    }
  }
});
const QueryRoot = new GraphQLObjectType(
  {
    name: 'Query', 
    fields: () => ({
      node: nodeField,
      project: { 
        type: new GraphQLList(Project),
        args: { 
          id: { ...globalIdField() }
        },
        extensions:
        {
          joinMonster:
          {
            where: (projectsTable, args, context, ast) => { 
              // this kicks in before resolve: or anything else and args.id is still base64
              // global Id so the where clause fails when executed at the database
              return `${projectsTable}.id = ${escape("%L", args.id)}`
            },
          }
        },
        
        resolve: async (parent, args, context, resolveInfo) => 
             // this kicks in after the joinMonster where clause so the sql has been
             // prepared already and args.id is not unpacked into uuid4 and dbCall reports
             // error as id could not be found.
             joinMonster(resolveInfo, context, async sql=>dbCall(sql),
    })
  });

Sample Query (returns error as Global ID is not unpacked by the Where join monster clause):

query
{
  project(id:"UHJvamVjdDozZDkzYWE2NS01MDE1LTRmNGEtYTIyYy04MDY3YjRmYmYwOGI=") {
    name
    id
  }
}
@nicoabie
Copy link
Contributor

Explained here with a demo and link to the code https://join-monster.readthedocs.io/en/latest/relay/

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

No branches or pull requests

2 participants