Correlating Fields to Columns
You'll need to provide a bit of information about each column and its relationship to the table, if any. For fields with a one-to-one correspondence, use the sqlColumn
property.
const User = new GraphQLObjectType({
//...
fields: () => ({
id: {
// the column name is assumed to be the same as the field name
type: GraphQLInt
},
email: {
type: GraphQLString,
extensions: {
joinMonster: {
// if the column name is different, it must be specified
sqlColumn: 'email_address'
}
}
},
idEncoded: {
description: 'The ID base-64 encoded',
type: GraphQLString,
extensions: {
joinMonster: {
sqlColumn: 'id'
}
},
// this field uses a sqlColumn and applies a resolver function on the value
// if a resolver is present, the `sqlColumn` MUST be specified even if it is the same name as the field
resolve: user => toBase64(user.id)
}
})
})
function toBase64(clear) {
return Buffer.from(String(clear)).toString('base64')
}
In the case of the id
field, the sqlColumn
was omitted. Since it has no resolver, it is assumed to have to come from the table and the column name is assumed to be the same as the field name. The same inference is not made if a resolver is present.
Note
Some external libraries add resolvers to your schema, such as Optics, or the logger
option in graphql-tools.
If using one of these, sqlColumn
cannot be omitted.
Computed Columns
You can manipulate the data in your query without losing the benefit of batched requests.
Maybe your field(s) needs a SQL column to compute a value. If there isn't a simple one-to-one correspondence of columns to field, you can use sqlDeps
. sqlDeps
is an array of columns that will get retrieved if the GraphQL field is requested. These are exposed to your resolver, so you can write a resolve
function to compute a value in JavaScript. For example, a first_name
and last_name
column can be depended on for a fullName
field in your API.
const User = new GraphQLObjectType({
//...
fields: () => ({
fullName: {
description: "A user's first and last name",
type: GraphQLString,
extensions: {
joinMonster: {
// perhaps there is no 1-to-1 mapping of field to column
// this field depends on multiple columns
sqlDeps: ['first_name', 'last_name']
}
},
resolve: user => `${user.first_name} ${user.last_name}`
}
})
})
You can also do computed columns in the SQL itself with a raw expression using sqlExpr
. This is a function that generated the expression. Its parameters are the table alias (generated automatically by joinMonster), the GraphQL arguments on that field, and a context object.
const User = new GraphQLObjectType({
//...
fields: () => ({
capitalizedLastName: {
type: GraphQLString,
extensions: {
joinMonster: {
// do a computed column in SQL with raw expression
sqlExpr: (table, args) => `UPPER(${table}.last_name)`
}
}
},
fullNameAnotherWay: {
description: 'Another way we can get the full name.',
type: GraphQLString,
extensions: {
joinMonster: {
sqlExpr: table => `${table}.first_name || ' ' || ${table}.last_name`
}
}
}
})
})