Created
May 10, 2019 20:11
-
-
Save bhoriuchi/6de5a4fa8d7eadbbd602b4392888a537 to your computer and use it in GitHub Desktop.
Merge multiple GraphQL typeDefs into a single typeDef
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
import { parse, print } from 'graphql' | |
/** | |
* Merges multiple graphql definitions into a single one | |
* with the ability to merge fields and perform conflict | |
* resolution on types and fields with custom functions | |
*/ | |
export function mergeDefinitions(documents, options) { | |
const types = {}; | |
const opts = Object.assign({ | |
mergeFields: ['Query', 'Mutation', 'Subscription'], | |
onTypeConflict(original) { | |
return original | |
}, | |
onFieldConflict(original) { | |
return original | |
}, | |
parsed: true, | |
}, options) | |
// expand documents and parse any strings | |
const docs = documents | |
.reduce((accum, def) => accum.concat(def), []) | |
.map(def => typeof def === 'string' ? parse(def) : def) | |
.filter(def => Object.assign({}, def).kind === 'Document') | |
// validate there is at least 2 documents | |
if (docs.length < 2) { | |
throw new Error('merge requires at least two documents') | |
} | |
// attempt to merge defs | |
for (let doc of docs) { | |
for (let def of doc.definitions) { | |
const typeName = def.name.value | |
const oType = types[typeName] | |
// if the type doesnt exist in the type hash add it | |
if (!oType) { | |
types[typeName] = def | |
continue; | |
} | |
// if the type has fields and is in the field merge list | |
if (Array.isArray(def.fields) && opts.mergeFields.indexOf(typeName) !== -1) { | |
const fields = oType.fields.reduce((accum, field) => { | |
accum[field.name.value] = field | |
return accum; | |
}, {}) | |
for (let field of def.fields) { | |
const fieldName = field.name.value | |
const oField = fields[fieldName] | |
// if the field doesnt exist add it | |
if (!oField) { | |
fields[fieldName] = field | |
continue; | |
} | |
// otherwise perform a conflict resolution | |
fields[fieldName] = opts.onFieldConflict(oField, field) | |
} | |
// convert the keys back into a field array | |
oType.fields = Object.keys(fields).map(fieldName => fields[fieldName]) | |
continue; | |
} | |
// otherwise perform the type conflict | |
types[typeName] = opts.onTypeConflict(oType, def) | |
} | |
} | |
const mergedDefinitions = print({ | |
kind: 'Document', | |
definitions: Object.keys(types).map(typeName => types[typeName]) | |
}) | |
return opts.parsed ? parse(mergedDefinitions) : mergedDefinitions | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment