import { isObject } from '@gravityforms/utils';
import { buildQueryString } from './query';
/**
* @function buildInsertObject
* @description Build an insert object for use in Hermes mutation.
*
* @since 4.1.0
*
* @param {object} obj The object to convert to an insert object.
*
* @return {object} The insert object.
*/
export const buildInsertObject = ( obj ) => {
const { objects = [], returning = {} } = obj;
return {
_args: { objects },
returning,
};
};
/**
* @function buildUpdateObject
* @description Build an update object for use in Hermes mutation.
*
* @since 4.1.0
*
* @param {object} obj The object to convert to an update object.
*
* @return {object} The update object.
*/
export const buildUpdateObject = ( obj ) => {
const { id, _args = {}, returning = {} } = obj;
if ( ! id ) {
throw new Error( 'An id is required for update mutations.' );
}
return {
_args: {
id,
..._args,
},
returning,
};
};
/**
* @function buildDeleteObject
* @description Build a delete object for use in Hermes mutation.
*
* @since 4.1.0
*
* @param {object} obj The object to convert to a delete object.
*
* @return {object} The delete object.
*/
export const buildDeleteObject = ( obj ) => {
const { id } = obj;
if ( ! id ) {
throw new Error( 'An id is required for delete mutations.' );
}
return {
_args: { id },
};
};
/**
* @function buildConnectObject
* @description Build a connect or disconnect object for use in Hermes mutation.
*
* @since 4.1.0
*
* @param {object|Array} obj The object or array of objects to convert to a connect or disconnect object.
*
* @return {object} The connect or disconnect object.
*/
export const buildConnectObject = ( obj ) => {
let objects = [];
if ( Array.isArray( obj ) ) {
// Check that each item has a from and to key and are not empty, otherwise throw error.
for ( const item of obj ) {
if ( ! isObject( item ) ) {
throw new Error( 'An object or array of objects is required for connect mutations.' );
}
const { from, to } = item;
if ( ! from || ! to ) {
throw new Error( 'Both from id and to id are required for connect mutations.' );
}
}
objects = obj;
} else if ( isObject( obj ) ) {
// Check that the object has a from and to key and are not empty, otherwise throw error.
const { from, to } = obj;
if ( ! from || ! to ) {
throw new Error( 'Both from id and to id are required for connect mutations.' );
}
objects = [ obj ];
} else {
// Throw error if the object is not an object or array.
throw new Error( 'An object or array of objects is required for connect mutations.' );
}
return {
_args: {
objects,
},
};
};
const INSERT = 'insert';
const UPDATE = 'update';
const DELETE = 'delete';
const CONNECT = 'connect';
const DISCONNECT = 'disconnect';
export const mutationTypes = [ INSERT, UPDATE, DELETE, CONNECT, DISCONNECT ];
const mutationTypesToBuildObjectMap = {
[ INSERT ]: buildInsertObject,
[ UPDATE ]: buildUpdateObject,
[ DELETE ]: buildDeleteObject,
[ CONNECT ]: buildConnectObject,
[ DISCONNECT ]: buildConnectObject,
};
/**
* @function buildMutationString
* @description Build a mutation string from a mutation object and mutation type for use in Hermes mutation.
*
* @since 4.1.0
*
* @param {object} mutationObj The mutation object to convert to a string.
* @param {string} mutationType The type of mutation to build. Must be one of 'insert', 'update', 'delete', 'connect', or 'disconnect'.
*
* @return {string} The mutation string.
*
* @example
* // Example inserting single company object.
* const insertMutationObj = {
* company: {
* objects: [ { name: 'My Business', address: '123 Main St' } ],
* returning: {
* id: true,
* name: true,
* address: true,
* },
* },
* };
*
* const insertMutationString = buildMutationString( insertMutationObj, 'insert' );
* // insertMutationString = '{insert_company(objects: [{name: "My Business", address: "123 Main St"}]) {returning {id, name, address}}}';
*
*
* // Example with single company updates.
* const updateMutationObj = {
* company: {
* id: 1,
* _args: {
* name: 'My Business',
* address: '123 Main St',
* },
* returning: {
* id: true,
* name: true,
* address: true,
* },
* },
* };
*
* const updateMutationString = buildMutationString( updateMutationObj, 'update' );
* // updateMutationString = '{update_company(id: 1, name: "My Business", address: "123 Main St") {returning {id, name, address}}}';
*
*
* // Example deleting single company object.
* const deleteMutationObj = {
* company: {
* id: 1,
* },
* };
*
* const deleteMutationString = buildMutationString( deleteMutationObj, 'delete' );
* // deleteMutationString = '{delete_company(id: 1) {}}';
*
*
* // Example connecting single company and department objects.
* const singleConnectMutationObj = {
* company_department: {
* from: 1,
* to: 2,
* },
* };
*
* const singleConnectMutationString = buildMutationString( singleConnectMutationObj, 'connect' );
* // connectMutationString = '{connect_company_department(objects: [{from: 1, to: 2}]) {}}';
*
*
* // Example connecting multiple company and department objects.
* const multipleConnectMutationObj = {
* company_department: [
* {
* from: 1,
* to: 2,
* },
* {
* from: 3,
* to: 4,
* },
* ],
* };
*
* const multipleConnectMutationString = buildMutationString( multipleConnectMutationObj, 'connect' );
* // multipleConnectMutationString = '{connect_company_department(objects: [{from: 1, to: 2}, {from: 3, to: 4}]) {}}';
*
*
* // Example disconnecting single company and department objects.
* const singleDisconnectMutationObj = {
* company_department: {
* from: 1,
* to: 2,
* },
* };
*
* const disconnectMutationString = buildMutationString( singleDisconnectMutationObj, 'disconnect' );
* // disconnectMutationString = '{disconnect_company_department(objects: [{from: 1, to: 2}]) {}}';
*
*
* // Example disconnecting multiple company and department objects.
* const multipleDisconnectMutationObj = {
* company_department: [
* {
* from: 1,
* to: 2,
* },
* {
* from: 3,
* to: 4,
* },
* ],
* };
*
* const multipleDisconnectMutationString = buildMutationString( multipleDisconnectMutationObj, 'disconnect' );
* // multipleDisconnectMutationString = '{disconnect_company_department(objects: [{from: 1, to: 2}, {from: 3, to: 4}]) {}}';
*
*/
export const buildMutationString = ( mutationObj, mutationType ) => {
// If mutation type is not one of 'insert', 'update', 'delete', 'connect', or 'disconnect', throw an error.
if ( ! mutationTypes.includes( mutationType ) ) {
throw new Error( 'Invalid mutation type. Must be one of "insert", "update", "delete", "connect", or "disconnect".' );
}
// We only handle single key mutation objects for now.
const keys = Object.keys( mutationObj );
if ( keys.length !== 1 ) {
throw new Error( 'Only a single key mutation object is allowed.' );
}
const key = keys[ 0 ];
const buildObject = mutationTypesToBuildObjectMap[ mutationType ];
const queryObj = {
[ `${ mutationType }_${ key }` ]: buildObject( mutationObj[ key ] ),
};
return buildQueryString( queryObj );
};