Skip to content

Instantly share code, notes, and snippets.

@bw
Last active July 29, 2017 00:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bw/4444c7866742ebfb499294c5da5b1ee9 to your computer and use it in GitHub Desktop.
Save bw/4444c7866742ebfb499294c5da5b1ee9 to your computer and use it in GitHub Desktop.
junction.include shim to get edge fields back onto the edge
/*
* 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