Last active
July 29, 2017 00:18
-
-
Save bw/4444c7866742ebfb499294c5da5b1ee9 to your computer and use it in GitHub Desktop.
junction.include shim to get edge fields back onto the edge
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* CONNECTION EDGE FIELDS SHIM | |
* (c) 2017 Conduit Analytics Inc. All rights reserved. https://conduithq.com | |
* | |
* Temporary fix for https://github.com/stems/join-monster/issues/155 | |
* By Brandon Wang (https://github.com/bw) | |
* | |
* ## Why | |
* | |
* This shim hacks in the ability to request fields from a junction table to Relay-compliant edge fields directly. | |
* The current limitation requires us to resolve on the node, so a "shim field" is used. The shim field must be | |
* requested any time that edge fields are also requested. We serialize any columns we want to use from the junction | |
* table into a JSON payload on the shim field itself. | |
* | |
* ## Usage | |
* | |
* Let's assume there are two tables, 'actors' and 'movies', and a junction table 'actor_movie_links' which has the | |
* 'movie_role' that we want. | |
* ```js | |
* export const ActorMovieEdgeShim = new JunctionShim({ | |
* columns: ['movie_role'], | |
* }); | |
* ``` | |
* | |
* Where the field is defined for usage, set junction.include equal to ActorMovieEdgeShim.junctionInclude(). | |
* Now you can request them on the Relay-compliant edge: | |
* ```js | |
* edgeFields: { | |
* movieRole: { | |
* type: GraphQLString, | |
* resolve: ActorMovieEdgeShim.resolve(({ movie_role }) => movie_role), | |
* } | |
* } | |
* ``` | |
*/ | |
import assert from 'assert'; | |
import { GraphQLError } from 'graphql'; | |
class JunctionShim { | |
constructor(config = {}) { | |
this.columns = config.columns || []; | |
this.shimField = config.shimField || '_edgeFix'; | |
} | |
/** | |
* Constructs a pseudo-field with junction table columns. Set junction.include equal to this. | |
* @returns {Object} | |
*/ | |
junctionInclude() { | |
return { | |
[this.shimField]: { | |
sqlExpr: (junctionTable) => `json_build_object(${this.columns.map( | |
(column) => `'${column}',${junctionTable}."${column}"`, | |
).join(',')})`, | |
}, | |
}; | |
} | |
/** | |
* Runs the resolver passed into the parameter with the relevant fields as an argument. | |
* | |
* @param {Function} resolve: Resolver that accepts edge fields. | |
* @returns {function({ edgeFields })} | |
*/ | |
resolve(resolve) { | |
assert.ok(resolve, 'Missing resolving function as parameter.'); | |
return ({ node }) => { | |
if (!node[this.shimField]) { | |
throw new GraphQLError( | |
`Temporary hack: In order to resolve edge fields, include the '${this.shimField}' field on the node itself.`); | |
} | |
return resolve(node[this.shimField]); | |
}; | |
} | |
} | |
export default JunctionShim; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment