From 9212a1970e08f994e7487b237be8c5a0c6efbf3a Mon Sep 17 00:00:00 2001 From: Justin Reynolds Date: Sun, 28 Jan 2018 22:24:33 -0600 Subject: [PATCH] Add upsert mutation --- .../lib/modules/containers/withUpsert.js | 59 +++++++++++++++++++ .../lib/modules/default_mutations.js | 27 ++++++++- packages/vulcan-core/lib/modules/index.js | 1 + .../vulcan-lib/lib/modules/collections.js | 13 ++++ 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 packages/vulcan-core/lib/modules/containers/withUpsert.js diff --git a/packages/vulcan-core/lib/modules/containers/withUpsert.js b/packages/vulcan-core/lib/modules/containers/withUpsert.js new file mode 100644 index 000000000..063d869ca --- /dev/null +++ b/packages/vulcan-core/lib/modules/containers/withUpsert.js @@ -0,0 +1,59 @@ +/* + + Generic mutation wrapper to upsert a document in a collection. + + Sample mutation: + + mutation moviesUpsert($search: MoviesInput, $set: MoviesInput, $unset: MoviesUnset) { + moviesUpsert(search: $search, set: $set, unset: $unset) { + ...MoviesUpsertFormFragment + } + } + + Arguments: + + - search: the search fields to match on in the database + - set: an object containing all the fields to modify and their new values + - unset: an object containing the fields to unset + + Child Props: + + - upsertMutation(search, set, unset) + + */ + +import React, { Component } from 'react'; +import { graphql } from 'react-apollo'; +import gql from 'graphql-tag'; +import { getFragment, getFragmentName, getCollection } from 'meteor/vulcan:core'; + +export default function withUpsert(options) { + + let { collection, collectionName } = options; + if (!collection) { + collection = getCollection(collectionName); + } + const fragment = options.fragment || getFragment(options.fragmentName); + const fragmentName = getFragmentName(fragment); + collectionName = collection.options.collectionName; + const mutationName = collection.options.mutations.upsert.name; + + return graphql(gql` + mutation ${mutationName}($search: ${collectionName}Input, $set: ${collectionName}Input, $unset: ${collectionName}Unset) { + ${mutationName}(search: $search, set: $set, unset: $unset) { + ...${fragmentName} + } + } + ${fragment} + `, { + alias: 'withUpsert', + props: ({ ownProps, mutate }) => ({ + upsertMutation: ({ search, set, unset }) => { + return mutate({ + variables: { search, set, unset } + }); + } + }), + }); + +} diff --git a/packages/vulcan-core/lib/modules/default_mutations.js b/packages/vulcan-core/lib/modules/default_mutations.js index ad162fdb4..d9b71f5dc 100644 --- a/packages/vulcan-core/lib/modules/default_mutations.js +++ b/packages/vulcan-core/lib/modules/default_mutations.js @@ -96,7 +96,32 @@ export const getDefaultMutations = (collectionName, options = {}) => { }, }, - + + // mutation for upserting a specific document + upsert: { + name: `${collectionName}Upsert`, + + description: `Mutation for upserting a ${collectionName} document`, + + async mutation(root, { search, set, unset }, context) { + const collection = context[collectionName]; + + // check if document exists already + const existingDocument = collection.findOne(search, { fields: { _id: 1 } }); + + if (existingDocument) { + const editArgs = { + documentId: existingDocument._id, + set, + unset, + }; + return await collection.options.mutations.edit.mutation(root, editArgs, context); + } else { + return await collection.options.mutations.new.mutation(root, { document: set }, context); + } + }, + }, + // mutation for removing a specific document (same checks as edit mutation) remove: { diff --git a/packages/vulcan-core/lib/modules/index.js b/packages/vulcan-core/lib/modules/index.js index 683811564..74d9c5008 100644 --- a/packages/vulcan-core/lib/modules/index.js +++ b/packages/vulcan-core/lib/modules/index.js @@ -34,3 +34,4 @@ export { default as withEdit } from './containers/withEdit.js'; export { default as withRemove } from './containers/withRemove.js'; export { default as withCurrentUser } from './containers/withCurrentUser.js'; export { default as withMutation } from './containers/withMutation.js'; +export { default as withUpsert } from './containers/withMutation.js'; diff --git a/packages/vulcan-lib/lib/modules/collections.js b/packages/vulcan-lib/lib/modules/collections.js index 1c09d0a0e..fc2c9a281 100644 --- a/packages/vulcan-lib/lib/modules/collections.js +++ b/packages/vulcan-lib/lib/modules/collections.js @@ -202,6 +202,19 @@ export const createCollection = options => { ) : ${typeName}`, mutations.edit.description); mutationResolvers[mutations.edit.name] = mutations.edit.mutation.bind(mutations.edit); } + // upsert + if (mutations.upsert) { // e.g. "moviesUpsert(search: moviesInput, set: moviesInput, unset: moviesUnset) : Movie" + addGraphQLMutation( + `${mutations.upsert.name}( + # The document to search for (or partial document) + search: ${collectionName}Input, + # An array of fields to insert + set: ${collectionName}Input, + # An array of fields to delete + unset: ${collectionName}Unset + ) : ${typeName}`, mutations.upsert.description); + mutationResolvers[mutations.upsert.name] = mutations.upsert.mutation.bind(mutations.upsert); + } // remove if (mutations.remove) { // e.g. "moviesRemove(documentId: String) : Movie" addGraphQLMutation(