Skip to content

Commit

Permalink
fix(graphql): remove ID type conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
calebmer committed May 5, 2016
1 parent b9ff37a commit 58e05ec
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 36 deletions.
11 changes: 4 additions & 7 deletions src/graphql/createTableType.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { memoize, fromPairs, camelCase } from 'lodash'
import { GraphQLObjectType } from 'graphql'
import { IDType, NodeType } from './types.js'
import { GraphQLObjectType, GraphQLID } from 'graphql'
import { NodeType, toID } from './types.js'
import getColumnType from './getColumnType.js'
import resolveTableSingle from './resolveTableSingle.js'
import createConnectionType from './createConnectionType.js'
Expand Down Expand Up @@ -51,12 +51,9 @@ const createTableType = memoize(table => {
// anything.
...(isNode ? {
id: {
type: IDType,
type: GraphQLID,
description: `The globally unique identifier for this ${table.getMarkdownTypeName()}.`,
resolve: source => ({
tableName: table.name,
values: primaryKeyColumns.map(column => source[column.name]),
}),
resolve: source => toID(table.name, primaryKeyColumns.map(column => source[column.name])),
},
} : {}),
...fromPairs(
Expand Down
15 changes: 8 additions & 7 deletions src/graphql/query/createNodeQueryField.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { memoize } from 'lodash'
import { GraphQLNonNull } from 'graphql'
import { NodeType, IDType } from '../types.js'
import { GraphQLNonNull, GraphQLID } from 'graphql'
import { NodeType, fromID } from '../types.js'
import resolveTableSingle from '../resolveTableSingle.js'

const createNodeQueryField = schema => ({
Expand All @@ -9,19 +9,20 @@ const createNodeQueryField = schema => ({

args: {
id: {
type: new GraphQLNonNull(IDType),
type: new GraphQLNonNull(GraphQLID),
description: 'The `ID` of the node.',
},
},

resolve: (source, args, context) => {
const { id } = args
const table = schema.getTable(id.tableName)
const { tableName, values } = fromID(id)
const table = schema.getTable(tableName)

if (!table)
throw new Error(`No table '${id.tableName}' in schema '${schema.name}'.`)
throw new Error(`No table '${tableName}' in schema '${schema.name}'.`)

return getResolver(table)(source, args, context)
return getResolver(table)({ values }, {}, context)
},
})

Expand All @@ -32,5 +33,5 @@ export default createNodeQueryField
const getResolver = memoize(table => resolveTableSingle(
table,
table.getPrimaryKeyColumns(),
(source, args) => args.id.values,
({ values }) => values,
))
9 changes: 5 additions & 4 deletions src/graphql/query/createSingleQueryField.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GraphQLNonNull } from 'graphql'
import { IDType } from '../types.js'
import { GraphQLNonNull, GraphQLID } from 'graphql'
import { fromID } from '../types.js'
import createTableType from '../createTableType.js'
import resolveTableSingle from '../resolveTableSingle.js'

Expand All @@ -22,15 +22,16 @@ const createSingleQueryField = table => {

args: {
id: {
type: new GraphQLNonNull(IDType),
type: new GraphQLNonNull(GraphQLID),
description: `The \`ID\` of the ${table.getMarkdownTypeName()} node.`,
},
},

resolve: resolveTableSingle(
table,
primaryKeyColumns,
(source, { id: { tableName, values } }) => {
(source, { id }) => {
const { tableName, values } = fromID(id)
if (tableName !== table.name) return null
return values
}
Expand Down
18 changes: 4 additions & 14 deletions src/graphql/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
GraphQLBoolean,
GraphQLInt,
GraphQLFloat,
GraphQLID,
GraphQLNonNull,
GraphQLScalarType,
GraphQLObjectType,
Expand All @@ -29,9 +30,9 @@ const createStringScalarType = ({ name, description }) =>
* Node Types
* ========================================================================= */

const toID = id => toBase64(`${id.tableName}:${id.values.join(',')}`)
export const toID = (tableName, values) => toBase64(`${tableName}:${values.join(',')}`)

const fromID = encodedString => {
export const fromID = encodedString => {
const string = fromBase64(encodedString)
if (!string) throw new Error(`Invalid ID '${encodedString}'.`)
const [tableName, valueString] = string.split(':', 2)
Expand All @@ -40,24 +41,13 @@ const fromID = encodedString => {
return { tableName, values }
}

export const IDType =
new GraphQLScalarType({
name: 'ID',
description:
'A globally unique identifier used to refetch an object or as a key for a ' +
'cache. It is not intended to be human readable.',
serialize: toID,
parseValue: fromID,
parseLiteral: ast => (ast.kind === Kind.STRING ? fromID(ast.value) : null),
})

export const NodeType =
new GraphQLInterfaceType({
name: 'Node',
description: 'A single node object in the graph with a globally unique identifier.',
fields: {
id: {
type: IDType,
type: GraphQLID,
description: 'The `Node`’s globally unique identifier used to refetch the node.',
},
},
Expand Down
3 changes: 2 additions & 1 deletion tests/graphql/createTableType.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import expect from 'expect'
import { GraphQLObjectType } from 'graphql'
import { GraphQLObjectType, GraphQLID } from 'graphql'
import { TestTable, TestColumn } from '../helpers.js'
import createTableType from '#/graphql/createTableType.js'

Expand Down Expand Up @@ -48,6 +48,7 @@ describe('createTableType', () => {
const type = createTableType(new TestTable())
expect(type.getInterfaces()[0].name).toEqual('Node')
expect(type.getFields()).toIncludeKey('id')
expect(type.getFields().id.type).toBe(GraphQLID)
})

it('will not implement the `Node` type for tables without primary keys', () => {
Expand Down
6 changes: 3 additions & 3 deletions tests/graphql/query/createSingleQueryField.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import expect from 'expect'
import { keys } from 'lodash'
import { GraphQLObjectType, GraphQLNonNull } from 'graphql'
import { GraphQLObjectType, GraphQLNonNull, GraphQLID } from 'graphql'
import { TestTable, TestColumn } from '../../helpers.js'
import createSingleQueryField from '#/graphql/query/createSingleQueryField.js'

Expand Down Expand Up @@ -38,10 +38,10 @@ describe('createSingleQueryField', () => {

expect(keys(person.args)).toEqual(['id'])
expect(person.args.id.type).toBeA(GraphQLNonNull)
expect(person.args.id.type.ofType.name).toEqual('ID')
expect(person.args.id.type.ofType).toBe(GraphQLID)
expect(keys(compoundKey.args)).toEqual(['id'])
expect(compoundKey.args.id.type).toBeA(GraphQLNonNull)
expect(compoundKey.args.id.type.ofType.name).toEqual('ID')
expect(compoundKey.args.id.type.ofType).toBe(GraphQLID)
})

it('it will return null for tables without primary keys', () => {
Expand Down

0 comments on commit 58e05ec

Please sign in to comment.