text: "use strict";
  
  var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
  
  var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
  
  var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
  
  var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
  
  var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
  
  var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
  
  var _Object$keys2 = require("@babel/runtime-corejs2/core-js/object/keys");
  
  _Object$defineProperty(exports, "__esModule", {
    value: true
  });
  
  exports.translateMutation = void 0;
  
  var _entries = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/entries"));
  
  var _isArray = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/array/is-array"));
  
  var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/typeof"));
  
  var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
  
  var _values = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/values"));
  
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
  
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
  
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/toConsumableArray"));
  
  var _utils = require("../utils");
  
  var _selection = require("../augment/types/node/selection");
  
  var _graphql = require("graphql");
  
  var _selections = require("../selections");
  
  var _lodash = _interopRequireDefault(require("lodash"));
  
  var _types = require("../augment/types/types");
  
  var _fields = require("../augment/fields");
  
  var _directives = require("../augment/directives");
  
  var _inputValues2 = require("../augment/input-values");
  
  var _translate = require("./translate");
  
  var _apolloServerErrors = require("apollo-server-errors");
  
  function ownKeys(object, enumerableOnly) { var keys = _Object$keys2(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
  
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors) { _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } } return target; }
  
  // Mutation API root operation branch
  var translateMutation = function translateMutation(_ref) {
    var resolveInfo = _ref.resolveInfo,
        context = _ref.context,
        first = _ref.first,
        offset = _ref.offset,
        otherParams = _ref.otherParams;
    var typeMap = resolveInfo.schema.getTypeMap();
  
    var _typeIdentifiers = (0, _utils.typeIdentifiers)(resolveInfo.returnType),
        typeName = _typeIdentifiers.typeName,
        variableName = _typeIdentifiers.variableName;
  
    var schemaType = resolveInfo.schema.getType(typeName);
    var selections = (0, _utils.getPayloadSelections)(resolveInfo);
    var outerSkipLimit = (0, _utils.getOuterSkipLimit)(first, offset);
    var orderByValue = (0, _utils.computeOrderBy)(resolveInfo, schemaType);
    var additionalNodeLabels = (0, _utils.getAdditionalLabels)(schemaType, (0, _translate.getCypherParams)(context));
    var mutationTypeCypherDirective = (0, _utils.getMutationCypherDirective)(resolveInfo);
    var mutationMeta = resolveInfo.schema.getMutationType().getFields()[resolveInfo.fieldName].astNode.directives.find(function (x) {
      return x.name.value === 'MutationMeta';
    });
    var fieldArguments = (0, _utils.getMutationArguments)(resolveInfo);
    var serializedParams = (0, _inputValues2.analyzeMutationArguments)({
      fieldArguments: fieldArguments,
      values: otherParams,
      resolveInfo: resolveInfo
    });
    var params = (0, _utils.initializeMutationParams)({
      mutationMeta: mutationMeta,
      resolveInfo: resolveInfo,
      mutationTypeCypherDirective: mutationTypeCypherDirective,
      first: first,
      otherParams: serializedParams,
      offset: offset
    });
    var isInterfaceType = (0, _utils.isGraphqlInterfaceType)(schemaType);
    var isObjectType = (0, _utils.isGraphqlObjectType)(schemaType);
    var isUnionType = (0, _utils.isGraphqlUnionType)(schemaType);
    var usesFragments = (0, _selections.isFragmentedSelection)({
      selections: selections
    });
    var isFragmentedObjectType = usesFragments && isObjectType;
    var isFragmentedInterfaceType = usesFragments && isInterfaceType;
    var interfaceLabels = typeof schemaType.getInterfaces === 'function' ? schemaType.getInterfaces().map(function (i) {
      return i.name;
    }) : [];
    var unionLabels = getUnionLabels({
      typeName: typeName,
      typeMap: typeMap
    });
    var additionalLabels = [].concat((0, _toConsumableArray2["default"])(additionalNodeLabels), (0, _toConsumableArray2["default"])(interfaceLabels), (0, _toConsumableArray2["default"])(unionLabels));
  
    var _mergeSelectionFragme = (0, _selections.mergeSelectionFragments)({
      schemaType: schemaType,
      selections: selections,
      isFragmentedObjectType: isFragmentedObjectType,
      isFragmentedInterfaceType: isFragmentedInterfaceType,
      isUnionType: isUnionType,
      typeMap: typeMap,
      resolveInfo: resolveInfo
    }),
        _mergeSelectionFragme2 = (0, _slicedToArray2["default"])(_mergeSelectionFragme, 2),
        schemaTypeFields = _mergeSelectionFragme2[0],
        derivedTypeMap = _mergeSelectionFragme2[1];
  
    var translation = "";
    var translationParams = {};
  
    if (mutationTypeCypherDirective) {
      var _customMutation = customMutation({
        resolveInfo: resolveInfo,
        schemaType: schemaType,
        schemaTypeFields: schemaTypeFields,
        derivedTypeMap: derivedTypeMap,
        isObjectType: isObjectType,
        isInterfaceType: isInterfaceType,
        isUnionType: isUnionType,
        usesFragments: usesFragments,
        selections: selections,
        params: params,
        context: context,
        mutationTypeCypherDirective: mutationTypeCypherDirective,
        variableName: variableName,
        orderByValue: orderByValue,
        outerSkipLimit: outerSkipLimit,
        typeMap: typeMap
      });
  
      var _customMutation2 = (0, _slicedToArray2["default"])(_customMutation, 2);
  
      translation = _customMutation2[0];
      translationParams = _customMutation2[1];
    } else if ((0, _utils.isCreateMutation)(resolveInfo)) {
      var _nodeCreate = nodeCreate({
        resolveInfo: resolveInfo,
        schemaType: schemaType,
        selections: selections,
        params: params,
        context: context,
        variableName: variableName,
        typeName: typeName,
        additionalLabels: additionalLabels,
        typeMap: typeMap
      });
  
      var _nodeCreate2 = (0, _slicedToArray2["default"])(_nodeCreate, 2);
  
      translation = _nodeCreate2[0];
      translationParams = _nodeCreate2[1];
    } else if ((0, _utils.isDeleteMutation)(resolveInfo)) {
      var _nodeDelete = nodeDelete({
        resolveInfo: resolveInfo,
        schemaType: schemaType,
        selections: selections,
        params: params,
        variableName: variableName,
        typeName: typeName,
        typeMap: typeMap
      });
  
      var _nodeDelete2 = (0, _slicedToArray2["default"])(_nodeDelete, 2);
  
      translation = _nodeDelete2[0];
      translationParams = _nodeDelete2[1];
    } else if ((0, _utils.isAddMutation)(resolveInfo)) {
      var _relationshipCreate = relationshipCreate({
        resolveInfo: resolveInfo,
        schemaType: schemaType,
        selections: selections,
        params: params,
        context: context
      });
  
      var _relationshipCreate2 = (0, _slicedToArray2["default"])(_relationshipCreate, 2);
  
      translation = _relationshipCreate2[0];
      translationParams = _relationshipCreate2[1];
    } else if ((0, _utils.isUpdateMutation)(resolveInfo) || (0, _utils.isMergeMutation)(resolveInfo)) {
      /**
       * TODO: Once we are no longer using the @MutationMeta directive
       * on relationship mutations, we will need to more directly identify
       * whether this Merge mutation if for a node or relationship
       */
      if (mutationMeta) {
        var _relationshipMergeOrU = relationshipMergeOrUpdate({
          mutationMeta: mutationMeta,
          resolveInfo: resolveInfo,
          selections: selections,
          schemaType: schemaType,
          params: params,
          context: context
        });
  
        var _relationshipMergeOrU2 = (0, _slicedToArray2["default"])(_relationshipMergeOrU, 2);
  
        translation = _relationshipMergeOrU2[0];
        translationParams = _relationshipMergeOrU2[1];
      } else {
        var _nodeMergeOrUpdate = nodeMergeOrUpdate({
          resolveInfo: resolveInfo,
          variableName: variableName,
          typeName: typeName,
          selections: selections,
          schemaType: schemaType,
          additionalLabels: additionalLabels,
          params: params,
          context: context,
          typeMap: typeMap
        });
  
        var _nodeMergeOrUpdate2 = (0, _slicedToArray2["default"])(_nodeMergeOrUpdate, 2);
  
        translation = _nodeMergeOrUpdate2[0];
        translationParams = _nodeMergeOrUpdate2[1];
      }
    } else if ((0, _utils.isRemoveMutation)(resolveInfo)) {
      var _relationshipDelete = relationshipDelete({
        resolveInfo: resolveInfo,
        schemaType: schemaType,
        selections: selections,
        params: params,
        context: context
      });
  
      var _relationshipDelete2 = (0, _slicedToArray2["default"])(_relationshipDelete, 2);
  
      translation = _relationshipDelete2[0];
      translationParams = _relationshipDelete2[1];
    } else {
      // throw error - don't know how to handle this type of mutation
      throw new _apolloServerErrors.ApolloError('Do not know how to handle this type of mutation. Mutation does not follow naming convention.');
    }
  
    return [translation, translationParams];
  }; // Custom write operation
  
  
  exports.translateMutation = translateMutation;
  
  var customMutation = function customMutation(_ref2) {
    var params = _ref2.params,
        context = _ref2.context,
        mutationTypeCypherDirective = _ref2.mutationTypeCypherDirective,
        selections = _ref2.selections,
        variableName = _ref2.variableName,
        schemaType = _ref2.schemaType,
        schemaTypeFields = _ref2.schemaTypeFields,
        derivedTypeMap = _ref2.derivedTypeMap,
        isObjectType = _ref2.isObjectType,
        isInterfaceType = _ref2.isInterfaceType,
        isUnionType = _ref2.isUnionType,
        usesFragments = _ref2.usesFragments,
        resolveInfo = _ref2.resolveInfo,
        orderByValue = _ref2.orderByValue,
        outerSkipLimit = _ref2.outerSkipLimit,
        typeMap = _ref2.typeMap;
    var cypherParams = (0, _translate.getCypherParams)(context);
    var safeVariableName = (0, _utils.safeVar)(variableName); // FIXME: support IN for multiple values -> WHERE
  
    var argString = (0, _utils.paramsToString)((0, _utils.innerFilterParams)((0, _utils.getFilterParams)(params.params || params), null, null, true), cypherParams);
    var args = (0, _utils.getMutationArguments)(resolveInfo);
    var cypherQueryArg = mutationTypeCypherDirective.arguments.find(function (x) {
      return x.name.value === 'statement';
    });
    var rootStatement = cypherQueryArg.value.value;
    var nestedStatements = translateNestedMutations({
      args: args,
      mutationStatement: rootStatement,
      dataParams: params,
      typeMap: typeMap,
      isRoot: true,
      isCustom: true
    });
    var cypherStatement = augmentCustomMutation({
      rootStatement: rootStatement,
      nestedStatements: nestedStatements
    });
  
    var _buildCypherSelection = (0, _selections.buildCypherSelection)({
      selections: selections,
      variableName: variableName,
      schemaType: schemaType,
      resolveInfo: resolveInfo,
      cypherParams: cypherParams
    }),
        _buildCypherSelection2 = (0, _slicedToArray2["default"])(_buildCypherSelection, 2),
        subQuery = _buildCypherSelection2[0],
        subParams = _buildCypherSelection2[1];
  
    var isScalarType = (0, _utils.isGraphqlScalarType)(schemaType);
    var isNeo4jTypeOutput = (0, _utils.isNeo4jType)(schemaType.name);
    var isScalarField = isNeo4jTypeOutput || isScalarType;
    var orderByClause = orderByValue.cypherPart;
    var listVariable = "apoc.map.values(value, [keys(value)[0]])[0] ";
  
    var _buildMapProjection = (0, _translate.buildMapProjection)({
      isComputedMutation: true,
      listVariable: listVariable,
      schemaType: schemaType,
      schemaTypeFields: schemaTypeFields,
      derivedTypeMap: derivedTypeMap,
      isObjectType: isObjectType,
      isInterfaceType: isInterfaceType,
      isUnionType: isUnionType,
      usesFragments: usesFragments,
      safeVariableName: safeVariableName,
      subQuery: subQuery,
      resolveInfo: resolveInfo
    }),
        _buildMapProjection2 = (0, _slicedToArray2["default"])(_buildMapProjection, 2),
        mapProjection = _buildMapProjection2[0],
        labelPredicate = _buildMapProjection2[1];
  
    var query = '';
  
    if (labelPredicate) {
      query = "CALL apoc.cypher.doIt(\"".concat(cypherStatement, "\", ").concat(argString, ") YIELD value\n    ").concat(!isScalarField ? labelPredicate : '', "AS ").concat(safeVariableName, "\n    RETURN ").concat(!isScalarField ? "".concat(mapProjection, " AS ").concat(safeVariableName).concat(orderByClause).concat(outerSkipLimit) : '');
    } else {
      query = "CALL apoc.cypher.doIt(\"".concat(cypherStatement, "\", ").concat(argString, ") YIELD value\n    WITH ").concat(listVariable, "AS ").concat(safeVariableName, "\n    RETURN ").concat(safeVariableName, " ").concat(!isScalarField ? "{".concat(isInterfaceType ? "".concat((0, _translate.fragmentType)(safeVariableName, schemaType.name), ",") : '').concat(subQuery, "} AS ").concat(safeVariableName).concat(orderByClause).concat(outerSkipLimit) : '');
    }
  
    var fragmentTypeParams = (0, _translate.derivedTypesParams)({
      isInterfaceType: isInterfaceType,
      isUnionType: isUnionType,
      schema: resolveInfo.schema,
      schemaTypeName: schemaType.name,
      usesFragments: usesFragments
    });
    params = _objectSpread(_objectSpread(_objectSpread({}, params), subParams), fragmentTypeParams);
  
    if (cypherParams) {
      params['cypherParams'] = cypherParams;
    }
  
    return [query, _objectSpread({}, params)];
  };
  
  var augmentCustomMutation = function augmentCustomMutation(_ref3) {
    var _ref3$rootStatement = _ref3.rootStatement,
        rootStatement = _ref3$rootStatement === void 0 ? '' : _ref3$rootStatement,
        _ref3$nestedStatement = _ref3.nestedStatements,
        nestedStatements = _ref3$nestedStatement === void 0 ? '' : _ref3$nestedStatement;
    var augmented = rootStatement;
  
    if (nestedStatements) {
      var statement = rootStatement.replace(/\r?\n|\r/g, ' ');
      var newlinedWithClauses = statement.replace(/\r?RETURN|\r/gi, "\nRETURN");
      var splitOnClause = newlinedWithClauses.split('\n');
      var returnClauseIndex = splitOnClause.length - 1;
      var returnClause = splitOnClause[returnClauseIndex];
      var endsWithReturnClause = returnClause.startsWith('RETURN'); // require that the root @cypher statement have a RETURN clause
  
      if (endsWithReturnClause) {
        var rootWithClause = "WITH *";
  
        var _returnClause = splitOnClause.splice(returnClauseIndex, 1, rootWithClause); // add the existent nested mutations
  
  
        splitOnClause.push(nestedStatements);
        splitOnClause.push(_returnClause[0]);
      }
  
      augmented = splitOnClause.join('\n');
    }
  
    return augmented;
  };
  
  var nodeCreate = function nodeCreate(_ref4) {
    var resolveInfo = _ref4.resolveInfo,
        schemaType = _ref4.schemaType,
        selections = _ref4.selections,
        params = _ref4.params,
        context = _ref4.context,
        variableName = _ref4.variableName,
        typeName = _ref4.typeName,
        additionalLabels = _ref4.additionalLabels,
        typeMap = _ref4.typeMap;
    var args = (0, _utils.getMutationArguments)(resolveInfo);
    var dataArgument = args.find(function (arg) {
      return arg.name.value === 'data';
    });
    var paramKey = 'params';
    var dataParams = params[paramKey];
    var nestedStatements = ''; // handle differences with experimental input object argument format
  
    if (dataArgument) {
      // config.experimental
      var unwrappedType = (0, _fields.unwrapNamedType)({
        type: dataArgument.type
      });
      var name = unwrappedType.name;
      var inputType = typeMap[name];
      var inputValues = inputType.getFields(); // get the input value AST definitions of the .data input object
      // use the .data key instead of the existing .params format
  
      paramKey = 'data';
      dataParams = dataParams[paramKey]; // elevate .data to top level so it matches "data" argument
  
      params = _objectSpread(_objectSpread(_objectSpread({}, params), params.params), {}, {
        data: dataParams
      }); // remove .params entry
  
      delete params.params; // translate nested mutations discovered in input object arguments
  
      nestedStatements = translateNestedMutations({
        args: args,
        dataParams: params,
        typeMap: typeMap,
        isRoot: true
      });
      args = (0, _values["default"])(inputValues).map(function (arg) {
        return arg.astNode;
      });
    } else {
      // translate nested mutations discovered in input object arguments
      nestedStatements = translateNestedMutations({
        args: args,
        dataParams: dataParams,
        typeMap: typeMap,
        paramVariable: paramKey,
        isRoot: true
      });
    } // use apoc.create.uuid() to set a default value for @id field,
    // if no value for it is provided in dataParams
  
  
    var fieldMap = schemaType.getFields();
    var fields = (0, _values["default"])(fieldMap).map(function (field) {
      return field.astNode;
    });
    var primaryKey = (0, _selection.getPrimaryKey)({
      fields: fields
    });
    var primaryKeyStatement = (0, _utils.setPrimaryKeyValue)({
      args: args,
      params: dataParams,
      primaryKey: primaryKey
    }); // build Cypher for root CREATE statement
  
    var safeVariableName = (0, _utils.safeVar)(variableName);
    var safeLabelName = (0, _utils.safeLabel)([typeName].concat((0, _toConsumableArray2["default"])(additionalLabels)));
    var paramStatements = (0, _utils.buildCypherParameters)({
      args: args,
      statements: primaryKeyStatement,
      params: params,
      paramKey: paramKey,
      resolveInfo: resolveInfo,
      typeMap: typeMap
    });
    var createStatement = "CREATE (".concat(safeVariableName, ":").concat(safeLabelName, " {").concat(paramStatements.join(','), "})"); // translate selection set
  
    var _buildCypherSelection3 = (0, _selections.buildCypherSelection)({
      selections: selections,
      variableName: variableName,
      schemaType: schemaType,
      resolveInfo: resolveInfo,
      cypherParams: (0, _translate.getCypherParams)(context)
    }),
        _buildCypherSelection4 = (0, _slicedToArray2["default"])(_buildCypherSelection3, 2),
        subQuery = _buildCypherSelection4[0],
        subParams = _buildCypherSelection4[1];
  
    params = _objectSpread(_objectSpread({}, params), subParams);
    var translation = "".concat(createStatement).concat(nestedStatements ? "\n  WITH *\n  ".concat(nestedStatements) : '');
    var query = "\n    ".concat(translation, "\n    RETURN ").concat(safeVariableName, " {").concat(subQuery, "} AS ").concat(safeVariableName, "\n  ");
    return [query, params];
  };
  
  var nodeMergeOrUpdate = function nodeMergeOrUpdate(_ref5) {
    var resolveInfo = _ref5.resolveInfo,
        variableName = _ref5.variableName,
        typeName = _ref5.typeName,
        selections = _ref5.selections,
        schemaType = _ref5.schemaType,
        additionalLabels = _ref5.additionalLabels,
        params = _ref5.params,
        context = _ref5.context,
        typeMap = _ref5.typeMap;
    var safeVariableName = (0, _utils.safeVar)(variableName);
    var args = (0, _utils.getMutationArguments)(resolveInfo);
    var paramKey = 'params';
    var dataParams = params[paramKey];
    var nestedStatements = '';
    var selectionArgument = args.find(function (arg) {
      return arg.name.value === 'where';
    });
    var dataArgument = args.find(function (arg) {
      return arg.name.value === 'data';
    });
    var fieldMap = schemaType.getFields();
    var fields = (0, _values["default"])(fieldMap).map(function (field) {
      return field.astNode;
    });
    var primaryKey = (0, _selection.getPrimaryKey)({
      fields: fields
    });
    var primaryKeyArgName = primaryKey.name.value;
    var cypherOperation = '';
    var safeLabelName = (0, _utils.safeLabel)(typeName);
  
    if ((0, _utils.isMergeMutation)(resolveInfo)) {
      safeLabelName = (0, _utils.safeLabel)([typeName].concat((0, _toConsumableArray2["default"])(additionalLabels)));
      cypherOperation = 'MERGE';
    } else if ((0, _utils.isUpdateMutation)(resolveInfo)) {
      cypherOperation = 'MATCH';
    }
  
    var query = "";
    var paramUpdateStatements = [];
  
    if (selectionArgument && dataArgument) {
      // config.experimental
      // no need to use .params key in this argument design
      params = dataParams;
  
      var _translateNodeInputAr = translateNodeInputArgument({
        selectionArgument: selectionArgument,
        dataArgument: dataArgument,
        params: params,
        primaryKey: primaryKey,
        typeMap: typeMap,
        fieldMap: fieldMap,
        resolveInfo: resolveInfo,
        context: context
      }),
          _translateNodeInputAr2 = (0, _slicedToArray2["default"])(_translateNodeInputAr, 2),
          propertyStatements = _translateNodeInputAr2[0],
          generatePrimaryKey = _translateNodeInputAr2[1];
  
      var onMatchStatements = "";
  
      if (propertyStatements.length > 0) {
        onMatchStatements = "SET ".concat((0, _utils.safeVar)(variableName), " += {").concat(propertyStatements.join(','), "} ");
      }
  
      if ((0, _utils.isMergeMutation)(resolveInfo)) {
        var unwrappedType = (0, _fields.unwrapNamedType)({
          type: selectionArgument.type
        });
        var name = unwrappedType.name;
        var inputType = typeMap[name];
        var inputValues = inputType.getFields();
        var selectionArgs = (0, _values["default"])(inputValues).map(function (arg) {
          return arg.astNode;
        });
        var selectionExpression = (0, _utils.buildCypherParameters)({
          args: selectionArgs,
          params: params,
          paramKey: 'where',
          resolveInfo: resolveInfo,
          cypherParams: (0, _translate.getCypherParams)(context),
          typeMap: typeMap
        });
        var onCreateProps = [].concat((0, _toConsumableArray2["default"])(propertyStatements), (0, _toConsumableArray2["default"])(generatePrimaryKey));
        var onCreateStatements = "";
  
        if (onCreateProps.length > 0) {
          onCreateStatements = "SET ".concat((0, _utils.safeVar)(variableName), " += {").concat(onCreateProps.join(','), "}");
        }
  
        var keySelectionStatement = selectionExpression.join(',');
        query = "".concat(cypherOperation, " (").concat(safeVariableName, ":").concat(safeLabelName, "{").concat(keySelectionStatement, "})\nON CREATE\n  ").concat(onCreateStatements, "\nON MATCH\n  ").concat(onMatchStatements);
      } else {
        var _translateNodeSelecti = translateNodeSelectionArgument({
          variableName: variableName,
          args: args,
          params: params,
          schemaType: schemaType,
          resolveInfo: resolveInfo
        }),
            _translateNodeSelecti2 = (0, _slicedToArray2["default"])(_translateNodeSelecti, 2),
            predicate = _translateNodeSelecti2[0],
            serializedFilter = _translateNodeSelecti2[1];
  
        query = "".concat(cypherOperation, " (").concat(safeVariableName, ":").concat(safeLabelName, ")").concat(predicate, "\n").concat(onMatchStatements, "\n");
        params = _objectSpread(_objectSpread({}, params), serializedFilter);
      }
  
      nestedStatements = translateNestedMutations({
        args: args,
        dataParams: dataParams,
        typeMap: typeMap,
        isRoot: true
      });
    } else {
      nestedStatements = translateNestedMutations({
        args: args,
        dataParams: dataParams,
        paramVariable: paramKey,
        typeMap: typeMap,
        isRoot: true
      });
  
      var _splitSelectionParame = (0, _utils.splitSelectionParameters)(params, primaryKeyArgName, paramKey),
          _splitSelectionParame2 = (0, _slicedToArray2["default"])(_splitSelectionParame, 2),
          primaryKeyParam = _splitSelectionParame2[0],
          updateParams = _splitSelectionParame2[1];
  
      paramUpdateStatements = (0, _utils.buildCypherParameters)({
        args: args,
        params: updateParams,
        paramKey: paramKey,
        resolveInfo: resolveInfo,
        cypherParams: (0, _translate.getCypherParams)(context),
        typeMap: typeMap
      });
      query = "".concat(cypherOperation, " (").concat(safeVariableName, ":").concat(safeLabelName, "{").concat(primaryKeyArgName, ": $params.").concat(primaryKeyArgName, "})\n  ");
  
      if (paramUpdateStatements.length > 0) {
        query += "SET ".concat(safeVariableName, " += {").concat(paramUpdateStatements.join(','), "} ");
      }
  
      if (!params.params) params.params = {};
      params.params[primaryKeyArgName] = primaryKeyParam[primaryKeyArgName];
    }
  
    var _buildCypherSelection5 = (0, _selections.buildCypherSelection)({
      selections: selections,
      variableName: variableName,
      schemaType: schemaType,
      resolveInfo: resolveInfo,
      cypherParams: (0, _translate.getCypherParams)(context)
    }),
        _buildCypherSelection6 = (0, _slicedToArray2["default"])(_buildCypherSelection5, 2),
        subQuery = _buildCypherSelection6[0],
        subParams = _buildCypherSelection6[1];
  
    params = _objectSpread(_objectSpread({}, params), subParams);
    query = "".concat(query).concat(nestedStatements ? "\n  WITH *\n  ".concat(nestedStatements) : '', "RETURN ").concat(safeVariableName, " {").concat(subQuery, "} AS ").concat(safeVariableName);
    return [query, params];
  };
  
  var nodeDelete = function nodeDelete(_ref6) {
    var resolveInfo = _ref6.resolveInfo,
        selections = _ref6.selections,
        variableName = _ref6.variableName,
        typeName = _ref6.typeName,
        schemaType = _ref6.schemaType,
        typeMap = _ref6.typeMap,
        params = _ref6.params;
    var safeVariableName = (0, _utils.safeVar)(variableName);
    var safeLabelName = (0, _utils.safeLabel)(typeName);
    var args = (0, _utils.getMutationArguments)(resolveInfo);
    var fieldMap = schemaType.getFields();
    var fields = (0, _values["default"])(fieldMap).map(function (field) {
      return field.astNode;
    });
    var primaryKey = (0, _selection.getPrimaryKey)({
      fields: fields
    });
    var primaryKeyArgName = primaryKey.name.value;
    var matchStatement = "";
    var selectionArgument = args.find(function (arg) {
      return arg.name.value === 'where';
    });
  
    if (selectionArgument) {
      var _translateNodeSelecti3 = translateNodeSelectionArgument({
        variableName: variableName,
        args: args,
        params: params,
        schemaType: schemaType,
        resolveInfo: resolveInfo
      }),
          _translateNodeSelecti4 = (0, _slicedToArray2["default"])(_translateNodeSelecti3, 2),
          predicate = _translateNodeSelecti4[0],
          serializedFilter = _translateNodeSelecti4[1];
  
      matchStatement = "MATCH (".concat(safeVariableName, ":").concat(safeLabelName, ")").concat(predicate);
      params = _objectSpread(_objectSpread({}, params), serializedFilter);
    } else {
      matchStatement = "MATCH (".concat(safeVariableName, ":").concat(safeLabelName, " {").concat(primaryKeyArgName, ": $").concat(primaryKeyArgName, "})");
    }
  
    var nestedStatements = translateNestedMutations({
      args: args,
      dataParams: params,
      typeMap: typeMap,
      isRoot: true
    });
  
    var _buildCypherSelection7 = (0, _selections.buildCypherSelection)({
      selections: selections,
      variableName: variableName,
      schemaType: schemaType,
      resolveInfo: resolveInfo
    }),
        _buildCypherSelection8 = (0, _slicedToArray2["default"])(_buildCypherSelection7, 2),
        subQuery = _buildCypherSelection8[0],
        subParams = _buildCypherSelection8[1];
  
    params = _objectSpread(_objectSpread({}, params), subParams);
    var deletionVariableName = (0, _utils.safeVar)("".concat(variableName, "_toDelete"));
    var query = '';
  
    if (nestedStatements) {
      // Cannot execute a map projection on a deleted node in Neo4j
      // so the projection is executed and aliased before the delete
      query = "".concat(matchStatement, "\n").concat(nestedStatements, "\nWITH ").concat(safeVariableName, " AS ").concat(deletionVariableName, ", ").concat(safeVariableName, " {").concat(subQuery, "} AS ").concat(safeVariableName, "\nDETACH DELETE ").concat(deletionVariableName, "\nRETURN ").concat(safeVariableName);
    } else {
      // Cannot execute a map projection on a deleted node in Neo4j
      // so the projection is executed and aliased before the delete
      query = "".concat(matchStatement, "\nWITH ").concat(safeVariableName, " AS ").concat(deletionVariableName, ", ").concat(safeVariableName, " {").concat(subQuery, "} AS ").concat(safeVariableName, "\nDETACH DELETE ").concat(deletionVariableName, "\nRETURN ").concat(safeVariableName);
    }
  
    return [query, params];
  };
  
  var translateNodeInputArgument = function translateNodeInputArgument(_ref7) {
    var _ref7$selectionArgume = _ref7.selectionArgument,
        selectionArgument = _ref7$selectionArgume === void 0 ? {} : _ref7$selectionArgume,
        _ref7$dataArgument = _ref7.dataArgument,
        dataArgument = _ref7$dataArgument === void 0 ? {} : _ref7$dataArgument,
        params = _ref7.params,
        primaryKey = _ref7.primaryKey,
        typeMap = _ref7.typeMap,
        resolveInfo = _ref7.resolveInfo,
        context = _ref7.context;
    var unwrappedType = (0, _fields.unwrapNamedType)({
      type: dataArgument.type
    });
    var name = unwrappedType.name;
    var inputType = typeMap[name];
    var inputValues = inputType.getFields();
    var updateArgs = (0, _values["default"])(inputValues).map(function (arg) {
      return arg.astNode;
    });
    var propertyStatements = (0, _utils.buildCypherParameters)({
      args: updateArgs,
      params: params,
      paramKey: 'data',
      resolveInfo: resolveInfo,
      cypherParams: (0, _translate.getCypherParams)(context),
      typeMap: typeMap
    });
    var primaryKeyStatement = [];
  
    if ((0, _utils.isMergeMutation)(resolveInfo)) {
      var _unwrappedType = (0, _fields.unwrapNamedType)({
        type: selectionArgument.type
      });
  
      var _name = _unwrappedType.name;
      var _inputType = typeMap[_name];
  
      var _inputValues = _inputType.getFields();
  
      var selectionArgs = (0, _values["default"])(_inputValues).map(function (arg) {
        return arg.astNode;
      }); // check key selection values for @id key argument
  
      var primaryKeySelectionValue = (0, _utils.setPrimaryKeyValue)({
        args: selectionArgs,
        params: params['where'],
        primaryKey: primaryKey
      });
      var primaryKeyValue = (0, _utils.setPrimaryKeyValue)({
        args: updateArgs,
        params: params['data'],
        primaryKey: primaryKey
      });
  
      if (primaryKeySelectionValue.length && primaryKeyValue.length) {
        // apoc.create.uuid() statement returned for both, so a value exists in neither
        primaryKeyStatement = primaryKeySelectionValue;
      }
    }
  
    return [propertyStatements, primaryKeyStatement];
  };
  
  var translateNodeSelectionArgument = function translateNodeSelectionArgument(_ref8) {
    var variableName = _ref8.variableName,
        args = _ref8.args,
        params = _ref8.params,
        schemaType = _ref8.schemaType,
        resolveInfo = _ref8.resolveInfo;
  
    var _processFilterArgumen = (0, _translate.processFilterArgument)({
      argumentName: 'where',
      fieldArgs: args,
      schemaType: schemaType,
      variableName: variableName,
      resolveInfo: resolveInfo,
      params: params
    }),
        _processFilterArgumen2 = (0, _slicedToArray2["default"])(_processFilterArgumen, 2),
        filterPredicates = _processFilterArgumen2[0],
        serializedFilter = _processFilterArgumen2[1];
  
    var predicateClauses = (0, _toConsumableArray2["default"])(filterPredicates).filter(function (predicate) {
      return !!predicate;
    }).join(' AND ');
    var predicate = "";
  
    if ((0, _utils.isMergeMutation)(resolveInfo)) {
      predicate = predicateClauses;
    } else {
      predicate = predicateClauses ? " WHERE ".concat(predicateClauses, " ") : '';
    }
  
    return [predicate, serializedFilter];
  }; // Relation Add / Remove
  
  
  var relationshipCreate = function relationshipCreate(_ref9) {
    var _parentSelectionInfo;
  
    var resolveInfo = _ref9.resolveInfo,
        selections = _ref9.selections,
        schemaType = _ref9.schemaType,
        params = _ref9.params,
        context = _ref9.context;
    var mutationMeta, relationshipNameArg, fromTypeArg, toTypeArg;
  
    try {
      mutationMeta = resolveInfo.schema.getMutationType().getFields()[resolveInfo.fieldName].astNode.directives.find(function (x) {
        return x.name.value === 'MutationMeta';
      });
    } catch (e) {
      throw new Error('Missing required MutationMeta directive on add relationship directive');
    }
  
    try {
      relationshipNameArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'relationship';
      });
      fromTypeArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'from';
      });
      toTypeArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'to';
      });
    } catch (e) {
      throw new Error('Missing required argument in MutationMeta directive (relationship, from, or to)');
    }
  
    var schemaTypeName = (0, _utils.safeVar)(schemaType);
    var cypherParams = (0, _translate.getCypherParams)(context);
    var args = (0, _utils.getMutationArguments)(resolveInfo);
    var typeMap = resolveInfo.schema.getTypeMap();
    var fromType = fromTypeArg.value.value;
    var fromSchemaType = resolveInfo.schema.getType(fromType);
    var fromAdditionalLabels = (0, _utils.getAdditionalLabels)(fromSchemaType, cypherParams);
    var fromLabel = (0, _utils.safeLabel)([fromType].concat((0, _toConsumableArray2["default"])(fromAdditionalLabels)));
    var firstArg = args[0];
    var fromArgName = firstArg.name.value;
    var fromVar = "".concat((0, _utils.lowFirstLetter)(fromType), "_").concat(fromArgName);
    var fromVariable = (0, _utils.safeVar)(fromVar);
    var fromInputArg = firstArg.type;
    var fromInputArgType = (0, _graphql.getNamedType)(fromInputArg).type.name.value;
    var fromInputAst = typeMap[fromInputArgType].astNode;
    var fromFields = fromInputAst.fields;
    var fromCypherParam = fromFields[0].name.value;
    var toType = toTypeArg.value.value;
    var toSchemaType = resolveInfo.schema.getType(toType);
    var toAdditionalLabels = (0, _utils.getAdditionalLabels)(toSchemaType, cypherParams);
    var toLabel = (0, _utils.safeLabel)([toType].concat((0, _toConsumableArray2["default"])(toAdditionalLabels)));
    var secondArg = args[1];
    var toArgName = secondArg.name.value;
    var toVar = "".concat((0, _utils.lowFirstLetter)(toType), "_").concat(toArgName);
    var toVariable = (0, _utils.safeVar)(toVar);
    var toInputArg = secondArg.type;
    var toInputArgType = (0, _graphql.getNamedType)(toInputArg).type.name.value;
    var toInputAst = typeMap[toInputArgType].astNode;
    var toFields = toInputAst.fields;
    var toCypherParam = toFields[0].name.value;
    var relationshipName = relationshipNameArg.value.value;
    var lowercased = relationshipName.toLowerCase();
    var relationshipLabel = (0, _utils.safeLabel)(relationshipName);
    var relationshipVariable = (0, _utils.safeVar)(lowercased + '_relation');
    var dataInputArg = args.find(function (e) {
      return e.name.value === 'data';
    });
    var dataInputAst = dataInputArg ? typeMap[(0, _graphql.getNamedType)(dataInputArg.type).type.name.value].astNode : undefined;
    var dataFields = dataInputAst ? dataInputAst.fields : [];
  
    var _buildCypherSelection9 = (0, _selections.buildCypherSelection)({
      selections: selections,
      schemaType: schemaType,
      resolveInfo: resolveInfo,
      parentSelectionInfo: (_parentSelectionInfo = {
        fromArgName: fromArgName,
        toArgName: toArgName
      }, (0, _defineProperty2["default"])(_parentSelectionInfo, fromArgName, fromVar), (0, _defineProperty2["default"])(_parentSelectionInfo, toArgName, toVar), (0, _defineProperty2["default"])(_parentSelectionInfo, "variableName", lowercased), _parentSelectionInfo),
      cypherParams: (0, _translate.getCypherParams)(context)
    }),
        _buildCypherSelection10 = (0, _slicedToArray2["default"])(_buildCypherSelection9, 2),
        subQuery = _buildCypherSelection10[0],
        subParams = _buildCypherSelection10[1];
  
    var nodeSelectionStatements = "";
    var fromUsesWhereInput = fromInputArgType.startsWith('_') && fromInputArgType.endsWith('Where');
    var toUsesWhereInput = toInputArgType.startsWith('_') && toInputArgType.endsWith('Where');
  
    if (fromUsesWhereInput && toUsesWhereInput) {
      var _processFilterArgumen3 = (0, _translate.processFilterArgument)({
        argumentName: fromArgName,
        variableName: fromVar,
        schemaType: fromSchemaType,
        fieldArgs: args,
        resolveInfo: resolveInfo,
        params: params
      }),
          _processFilterArgumen4 = (0, _slicedToArray2["default"])(_processFilterArgumen3, 2),
          fromPredicate = _processFilterArgumen4[0],
          serializedFromFilter = _processFilterArgumen4[1];
  
      var fromClauses = (0, _toConsumableArray2["default"])(fromPredicate).filter(function (predicate) {
        return !!predicate;
      }).join(' AND ');
  
      var _processFilterArgumen5 = (0, _translate.processFilterArgument)({
        argumentName: toArgName,
        variableName: toVar,
        schemaType: toSchemaType,
        fieldArgs: args,
        resolveInfo: resolveInfo,
        params: params
      }),
          _processFilterArgumen6 = (0, _slicedToArray2["default"])(_processFilterArgumen5, 2),
          toPredicate = _processFilterArgumen6[0],
          serializedToFilter = _processFilterArgumen6[1];
  
      var toClauses = (0, _toConsumableArray2["default"])(toPredicate).filter(function (predicate) {
        return !!predicate;
      }).join(' AND ');
      var sourceNodeSelectionPredicate = fromClauses ? " WHERE ".concat(fromClauses, " ") : '';
      var targetNodeSelectionPredicate = toClauses ? " WHERE ".concat(toClauses, " ") : '';
      params = _objectSpread(_objectSpread({}, params), serializedFromFilter);
      params = _objectSpread(_objectSpread({}, params), serializedToFilter);
      nodeSelectionStatements = "MATCH (".concat(fromVariable, ":").concat(fromLabel, ")").concat(sourceNodeSelectionPredicate, "\n      MATCH (").concat(toVariable, ":").concat(toLabel, ")").concat(targetNodeSelectionPredicate);
    } else {
      nodeSelectionStatements = "MATCH (".concat(fromVariable, ":").concat(fromLabel, " {").concat(fromCypherParam, ": $").concat(fromArgName, ".").concat(fromCypherParam, "})\n      MATCH (").concat(toVariable, ":").concat(toLabel, " {").concat(toCypherParam, ": $").concat(toArgName, ".").concat(toCypherParam, "})");
    }
  
    var paramStatements = (0, _utils.buildCypherParameters)({
      args: dataFields,
      params: params,
      paramKey: 'data',
      resolveInfo: resolveInfo,
      typeMap: typeMap
    });
    params = _objectSpread(_objectSpread({}, params), subParams);
    var query = "\n      ".concat(nodeSelectionStatements, "\n      CREATE (").concat(fromVariable, ")-[").concat(relationshipVariable, ":").concat(relationshipLabel).concat(paramStatements.length > 0 ? " {".concat(paramStatements.join(','), "}") : '', "]->(").concat(toVariable, ")\n      RETURN ").concat(relationshipVariable, " { ").concat(subQuery, " } AS ").concat(schemaTypeName, ";\n    ");
    return [query, params];
  };
  
  var relationshipDelete = function relationshipDelete(_ref10) {
    var _parentSelectionInfo2;
  
    var resolveInfo = _ref10.resolveInfo,
        selections = _ref10.selections,
        schemaType = _ref10.schemaType,
        params = _ref10.params,
        context = _ref10.context;
    var mutationMeta, relationshipNameArg, fromTypeArg, toTypeArg;
  
    try {
      mutationMeta = resolveInfo.schema.getMutationType().getFields()[resolveInfo.fieldName].astNode.directives.find(function (x) {
        return x.name.value === 'MutationMeta';
      });
    } catch (e) {
      throw new Error('Missing required MutationMeta directive on add relationship directive');
    }
  
    try {
      relationshipNameArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'relationship';
      });
      fromTypeArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'from';
      });
      toTypeArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'to';
      });
    } catch (e) {
      throw new Error('Missing required argument in MutationMeta directive (relationship, from, or to)');
    }
  
    var schemaTypeName = (0, _utils.safeVar)(schemaType);
    var cypherParams = (0, _translate.getCypherParams)(context);
    var args = (0, _utils.getMutationArguments)(resolveInfo);
    var typeMap = resolveInfo.schema.getTypeMap();
    var fromType = fromTypeArg.value.value;
    var fromSchemaType = resolveInfo.schema.getType(fromType);
    var fromAdditionalLabels = (0, _utils.getAdditionalLabels)(resolveInfo.schema.getType(fromType), cypherParams);
    var fromLabel = (0, _utils.safeLabel)([fromType].concat((0, _toConsumableArray2["default"])(fromAdditionalLabels)));
    var firstArg = args[0];
    var fromArgName = firstArg.name.value;
    var fromVar = "".concat((0, _utils.lowFirstLetter)(fromType), "_").concat(fromArgName);
    var fromVariable = (0, _utils.safeVar)(fromVar);
    var fromInputArg = firstArg.type;
    var fromInputArgType = (0, _graphql.getNamedType)(fromInputArg).type.name.value;
    var fromInputAst = typeMap[fromInputArgType].astNode;
    var fromFields = fromInputAst.fields;
    var fromCypherParam = fromFields[0].name.value;
    var toType = toTypeArg.value.value;
    var toSchemaType = resolveInfo.schema.getType(toType);
    var toAdditionalLabels = (0, _utils.getAdditionalLabels)(resolveInfo.schema.getType(toType), cypherParams);
    var toLabel = (0, _utils.safeLabel)([toType].concat((0, _toConsumableArray2["default"])(toAdditionalLabels)));
    var secondArg = args[1];
    var toArgName = secondArg.name.value;
    var toVar = "".concat((0, _utils.lowFirstLetter)(toType), "_").concat(toArgName);
    var toVariable = (0, _utils.safeVar)(toVar);
    var toInputArg = secondArg.type;
    var toInputArgType = (0, _graphql.getNamedType)(toInputArg).type.name.value;
    var toInputAst = typeMap[toInputArgType].astNode;
    var toFields = toInputAst.fields;
    var toCypherParam = toFields[0].name.value;
    var relationshipName = relationshipNameArg.value.value;
    var relationshipVariable = (0, _utils.safeVar)(fromVar + toVar);
    var relationshipLabel = (0, _utils.safeLabel)(relationshipName);
    var nodeSelectionStatements = "";
    var fromUsesWhereInput = fromInputArgType.startsWith('_') && fromInputArgType.endsWith('Where');
    var toUsesWhereInput = toInputArgType.startsWith('_') && toInputArgType.endsWith('Where');
  
    if (fromUsesWhereInput && toUsesWhereInput) {
      var _processFilterArgumen7 = (0, _translate.processFilterArgument)({
        argumentName: fromArgName,
        variableName: fromVar,
        schemaType: fromSchemaType,
        fieldArgs: args,
        resolveInfo: resolveInfo,
        params: params
      }),
          _processFilterArgumen8 = (0, _slicedToArray2["default"])(_processFilterArgumen7, 2),
          fromPredicate = _processFilterArgumen8[0],
          serializedFromFilter = _processFilterArgumen8[1];
  
      var fromClauses = (0, _toConsumableArray2["default"])(fromPredicate).filter(function (predicate) {
        return !!predicate;
      }).join(' AND ');
  
      var _processFilterArgumen9 = (0, _translate.processFilterArgument)({
        argumentName: toArgName,
        variableName: toVar,
        schemaType: toSchemaType,
        fieldArgs: args,
        resolveInfo: resolveInfo,
        params: params
      }),
          _processFilterArgumen10 = (0, _slicedToArray2["default"])(_processFilterArgumen9, 2),
          toPredicate = _processFilterArgumen10[0],
          serializedToFilter = _processFilterArgumen10[1];
  
      var toClauses = (0, _toConsumableArray2["default"])(toPredicate).filter(function (predicate) {
        return !!predicate;
      }).join(' AND ');
      var sourceNodeSelectionPredicate = fromClauses ? " WHERE ".concat(fromClauses, " ") : '';
      var targetNodeSelectionPredicate = toClauses ? " WHERE ".concat(toClauses, " ") : '';
      params = _objectSpread(_objectSpread({}, params), serializedFromFilter);
      params = _objectSpread(_objectSpread({}, params), serializedToFilter);
      nodeSelectionStatements = "MATCH (".concat(fromVariable, ":").concat(fromLabel, ")").concat(sourceNodeSelectionPredicate, "\n      MATCH (").concat(toVariable, ":").concat(toLabel, ")").concat(targetNodeSelectionPredicate);
    } else {
      nodeSelectionStatements = "MATCH (".concat(fromVariable, ":").concat(fromLabel, " {").concat(fromCypherParam, ": $").concat(fromArgName, ".").concat(fromCypherParam, "})\n      MATCH (").concat(toVariable, ":").concat(toLabel, " {").concat(toCypherParam, ": $").concat(toArgName, ".").concat(toCypherParam, "})");
    }
  
    var _buildCypherSelection11 = (0, _selections.buildCypherSelection)({
      selections: selections,
      schemaType: schemaType,
      resolveInfo: resolveInfo,
      parentSelectionInfo: (_parentSelectionInfo2 = {
        fromArgName: fromArgName,
        toArgName: toArgName
      }, (0, _defineProperty2["default"])(_parentSelectionInfo2, fromArgName, '_' + fromVar), (0, _defineProperty2["default"])(_parentSelectionInfo2, toArgName, '_' + toVar), _parentSelectionInfo2),
      cypherParams: (0, _translate.getCypherParams)(context)
    }),
        _buildCypherSelection12 = (0, _slicedToArray2["default"])(_buildCypherSelection11, 2),
        subQuery = _buildCypherSelection12[0],
        subParams = _buildCypherSelection12[1];
  
    var query = "\n      ".concat(nodeSelectionStatements, "\n      OPTIONAL MATCH (").concat(fromVariable, ")-[").concat(relationshipVariable, ":").concat(relationshipLabel, "]->(").concat(toVariable, ")\n      DELETE ").concat(relationshipVariable, "\n      WITH COUNT(*) AS scope, ").concat(fromVariable, " AS ").concat((0, _utils.safeVar)("_".concat(fromVar)), ", ").concat(toVariable, " AS ").concat((0, _utils.safeVar)("_".concat(toVar)), "\n      RETURN {").concat(subQuery, "} AS ").concat(schemaTypeName, ";\n    ");
    params = _objectSpread(_objectSpread({}, params), subParams);
    return [query, params];
  };
  
  var relationshipMergeOrUpdate = function relationshipMergeOrUpdate(_ref11) {
    var mutationMeta = _ref11.mutationMeta,
        resolveInfo = _ref11.resolveInfo,
        selections = _ref11.selections,
        schemaType = _ref11.schemaType,
        params = _ref11.params,
        context = _ref11.context;
    var query = '';
    var relationshipNameArg = undefined;
    var fromTypeArg = undefined;
    var toTypeArg = undefined;
  
    try {
      relationshipNameArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'relationship';
      });
      fromTypeArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'from';
      });
      toTypeArg = mutationMeta.arguments.find(function (x) {
        return x.name.value === 'to';
      });
    } catch (e) {
      throw new Error('Missing required argument in MutationMeta directive (relationship, from, or to)');
    }
  
    if (relationshipNameArg && fromTypeArg && toTypeArg) {
      var _parentSelectionInfo3;
  
      var schemaTypeName = (0, _utils.safeVar)(schemaType);
      var cypherParams = (0, _translate.getCypherParams)(context);
      var args = (0, _utils.getMutationArguments)(resolveInfo);
      var typeMap = resolveInfo.schema.getTypeMap();
      var fromType = fromTypeArg.value.value;
      var fromSchemaType = resolveInfo.schema.getType(fromType);
      var fromAdditionalLabels = (0, _utils.getAdditionalLabels)(resolveInfo.schema.getType(fromType), cypherParams);
      var fromLabel = (0, _utils.safeLabel)([fromType].concat((0, _toConsumableArray2["default"])(fromAdditionalLabels)));
      var firstArg = args[0];
      var fromArgName = firstArg.name.value;
      var fromVar = "".concat((0, _utils.lowFirstLetter)(fromType), "_").concat(fromArgName);
      var fromVariable = (0, _utils.safeVar)(fromVar);
      var fromInputArg = firstArg.type;
      var fromInputArgType = (0, _graphql.getNamedType)(fromInputArg).type.name.value;
      var fromInputAst = typeMap[fromInputArgType].astNode;
      var fromFields = fromInputAst.fields;
      var fromCypherParam = fromFields[0].name.value;
      var toType = toTypeArg.value.value;
      var toSchemaType = resolveInfo.schema.getType(toType);
      var toAdditionalLabels = (0, _utils.getAdditionalLabels)(resolveInfo.schema.getType(toType), cypherParams);
      var toLabel = (0, _utils.safeLabel)([toType].concat((0, _toConsumableArray2["default"])(toAdditionalLabels)));
      var secondArg = args[1];
      var toArgName = secondArg.name.value;
      var toVar = "".concat((0, _utils.lowFirstLetter)(toType), "_").concat(toArgName);
      var toVariable = (0, _utils.safeVar)(toVar);
      var toInputArg = secondArg.type;
      var toInputArgType = (0, _graphql.getNamedType)(toInputArg).type.name.value;
      var toInputAst = typeMap[toInputArgType].astNode;
      var toFields = toInputAst.fields;
      var toCypherParam = toFields[0].name.value;
      var relationshipName = relationshipNameArg.value.value;
      var lowercased = relationshipName.toLowerCase();
      var relationshipLabel = (0, _utils.safeLabel)(relationshipName);
      var relationshipVariable = (0, _utils.safeVar)(lowercased + '_relation');
      var dataInputArg = args.find(function (e) {
        return e.name.value === 'data';
      });
      var dataInputAst = dataInputArg ? typeMap[(0, _graphql.getNamedType)(dataInputArg.type).type.name.value].astNode : undefined;
      var dataFields = dataInputAst ? dataInputAst.fields : [];
      var nodeSelectionStatements = "";
      var fromUsesWhereInput = fromInputArgType.startsWith('_') && fromInputArgType.endsWith('Where');
      var toUsesWhereInput = toInputArgType.startsWith('_') && toInputArgType.endsWith('Where');
  
      if (fromUsesWhereInput && toUsesWhereInput) {
        var _processFilterArgumen11 = (0, _translate.processFilterArgument)({
          argumentName: fromArgName,
          variableName: fromVar,
          schemaType: fromSchemaType,
          fieldArgs: args,
          resolveInfo: resolveInfo,
          params: params
        }),
            _processFilterArgumen12 = (0, _slicedToArray2["default"])(_processFilterArgumen11, 2),
            fromPredicate = _processFilterArgumen12[0],
            serializedFromFilter = _processFilterArgumen12[1];
  
        var fromClauses = (0, _toConsumableArray2["default"])(fromPredicate).filter(function (predicate) {
          return !!predicate;
        }).join(' AND ');
  
        var _processFilterArgumen13 = (0, _translate.processFilterArgument)({
          argumentName: toArgName,
          variableName: toVar,
          schemaType: toSchemaType,
          fieldArgs: args,
          resolveInfo: resolveInfo,
          params: params
        }),
            _processFilterArgumen14 = (0, _slicedToArray2["default"])(_processFilterArgumen13, 2),
            toPredicate = _processFilterArgumen14[0],
            serializedToFilter = _processFilterArgumen14[1];
  
        var toClauses = (0, _toConsumableArray2["default"])(toPredicate).filter(function (predicate) {
          return !!predicate;
        }).join(' AND ');
        var sourceNodeSelectionPredicate = fromClauses ? " WHERE ".concat(fromClauses, " ") : '';
        var targetNodeSelectionPredicate = toClauses ? " WHERE ".concat(toClauses, " ") : '';
        params = _objectSpread(_objectSpread({}, params), serializedFromFilter);
        params = _objectSpread(_objectSpread({}, params), serializedToFilter);
        nodeSelectionStatements = "  MATCH (".concat(fromVariable, ":").concat(fromLabel, ")").concat(sourceNodeSelectionPredicate, "\n      MATCH (").concat(toVariable, ":").concat(toLabel, ")").concat(targetNodeSelectionPredicate);
      } else {
        nodeSelectionStatements = "  MATCH (".concat(fromVariable, ":").concat(fromLabel, " {").concat(fromCypherParam, ": $").concat(fromArgName, ".").concat(fromCypherParam, "})\n      MATCH (").concat(toVariable, ":").concat(toLabel, " {").concat(toCypherParam, ": $").concat(toArgName, ".").concat(toCypherParam, "})");
      }
  
      var _buildCypherSelection13 = (0, _selections.buildCypherSelection)({
        selections: selections,
        schemaType: schemaType,
        resolveInfo: resolveInfo,
        parentSelectionInfo: (_parentSelectionInfo3 = {
          fromArgName: fromArgName,
          toArgName: toArgName
        }, (0, _defineProperty2["default"])(_parentSelectionInfo3, fromArgName, fromVar), (0, _defineProperty2["default"])(_parentSelectionInfo3, toArgName, toVar), (0, _defineProperty2["default"])(_parentSelectionInfo3, "variableName", lowercased), _parentSelectionInfo3),
        cypherParams: (0, _translate.getCypherParams)(context)
      }),
          _buildCypherSelection14 = (0, _slicedToArray2["default"])(_buildCypherSelection13, 2),
          subQuery = _buildCypherSelection14[0],
          subParams = _buildCypherSelection14[1];
  
      var paramStatements = (0, _utils.buildCypherParameters)({
        args: dataFields,
        params: params,
        paramKey: 'data',
        resolveInfo: resolveInfo,
        typeMap: typeMap
      });
      var cypherOperation = '';
  
      if ((0, _utils.isMergeMutation)(resolveInfo)) {
        cypherOperation = 'MERGE';
      } else if ((0, _utils.isUpdateMutation)(resolveInfo)) {
        cypherOperation = 'MATCH';
      }
  
      query = "\n    ".concat(nodeSelectionStatements, "\n      ").concat(cypherOperation, " (").concat(fromVariable, ")-[").concat(relationshipVariable, ":").concat(relationshipLabel, "]->(").concat(toVariable, ")").concat(paramStatements.length > 0 ? "\n      SET ".concat(relationshipVariable, " += {").concat(paramStatements.join(','), "} ") : '', "\n      RETURN ").concat(relationshipVariable, " { ").concat(subQuery, " } AS ").concat(schemaTypeName, ";\n    ");
      params = _objectSpread(_objectSpread({}, params), subParams);
    }
  
    return [query, params];
  };
  
  var getUnionLabels = function getUnionLabels(_ref12) {
    var _ref12$typeName = _ref12.typeName,
        typeName = _ref12$typeName === void 0 ? '' : _ref12$typeName,
        _ref12$typeMap = _ref12.typeMap,
        typeMap = _ref12$typeMap === void 0 ? {} : _ref12$typeMap;
    var unionLabels = [];
    (0, _keys["default"])(typeMap).map(function (key) {
      var definition = typeMap[key];
      var astNode = definition.astNode;
  
      if ((0, _types.isUnionTypeDefinition)({
        definition: astNode
      })) {
        var types = definition.getTypes();
        var unionTypeName = definition.name;
  
        if (types.find(function (type) {
          return type.name === typeName;
        })) {
          unionLabels.push(unionTypeName);
        }
      }
    });
    return unionLabels;
  };
  
  var translateNestedMutations = function translateNestedMutations(_ref13) {
    var _ref13$args = _ref13.args,
        args = _ref13$args === void 0 ? [] : _ref13$args,
        _ref13$dataParams = _ref13.dataParams,
        dataParams = _ref13$dataParams === void 0 ? {} : _ref13$dataParams,
        paramVariable = _ref13.paramVariable,
        _ref13$mutationStatem = _ref13.mutationStatement,
        mutationStatement = _ref13$mutationStatem === void 0 ? '' : _ref13$mutationStatem,
        _ref13$typeMap = _ref13.typeMap,
        typeMap = _ref13$typeMap === void 0 ? {} : _ref13$typeMap,
        _ref13$isRoot = _ref13.isRoot,
        isRoot = _ref13$isRoot === void 0 ? false : _ref13$isRoot,
        _ref13$isCustom = _ref13.isCustom,
        isCustom = _ref13$isCustom === void 0 ? false : _ref13$isCustom;
    var mappedDataParams = mapMutationParams({
      params: dataParams
    });
    return args.reduce(function (statements, arg) {
      var argName = arg.name.value;
      var typeName = (0, _fields.unwrapNamedType)({
        type: arg.type
      }).name;
      var inputType = typeMap[typeName];
      var argValue = dataParams[argName];
      var usesInputObjectArgument = (0, _graphql.isInputObjectType)(inputType) && (0, _typeof2["default"])(argValue) === 'object';
  
      if (usesInputObjectArgument) {
        var paramName = argName;
  
        if (isRoot) {
          paramName = paramVariable;
        }
  
        var argumentIsArray = (0, _isArray["default"])(dataParams[argName]);
        var isCustomRootListArgument = isCustom && isRoot && argumentIsArray;
        var rootUsesListVariable = includesCypherUnwindClause({
          typeName: typeName,
          argName: argName,
          statement: mutationStatement
        });
        var statement = translateNestedMutation({
          paramName: paramName,
          dataParams: mappedDataParams,
          args: [arg],
          parentTypeName: typeName,
          paramVariable: paramVariable,
          typeMap: typeMap,
          isRoot: isRoot,
          isCustom: isCustom,
          argumentIsArray: argumentIsArray,
          rootUsesListVariable: rootUsesListVariable,
          isCustomRootListArgument: isCustomRootListArgument,
          mutationStatement: mutationStatement
        });
  
        if (statement.length) {
          // inputType has at least one @cypher input field
          statements.push.apply(statements, (0, _toConsumableArray2["default"])(statement));
        } else {
          var _paramName = argName; // inputType did not have a @cypher input field, so keep looking
  
          var nestedParams = mappedDataParams[argName];
          var nestedArgs = (0, _values["default"])(inputType.getFields()).map(function (arg) {
            return arg.astNode;
          });
  
          var _statement = translateNestedMutation({
            isNestedParam: true,
            isCustom: isCustom,
            paramName: _paramName,
            args: nestedArgs,
            dataParams: nestedParams,
            parentTypeName: typeName,
            paramVariable: paramVariable,
            typeMap: typeMap,
            isRoot: isRoot,
            argumentIsArray: argumentIsArray,
            rootUsesListVariable: rootUsesListVariable,
            isCustomRootListArgument: isCustomRootListArgument,
            mutationStatement: mutationStatement
          });
  
          if (_statement.length) {
            statements.push.apply(statements, (0, _toConsumableArray2["default"])(_statement));
          }
        }
      }
  
      return statements;
    }, []).join('\n');
  };
  
  var includesCypherUnwindClause = function includesCypherUnwindClause(_ref14) {
    var _ref14$typeName = _ref14.typeName,
        typeName = _ref14$typeName === void 0 ? '' : _ref14$typeName,
        _ref14$argName = _ref14.argName,
        argName = _ref14$argName === void 0 ? '' : _ref14$argName,
        _ref14$statement = _ref14.statement,
        statement = _ref14$statement === void 0 ? '' : _ref14$statement;
    var unwindRegExp = new RegExp("\\s*\\UNWIND\\s*\\$".concat(argName, "\\s*\\AS\\s*").concat(typeName), 'i');
    var matched = statement.match(unwindRegExp);
    var hasUnwindClause = false;
  
    if (matched) {
      var match = matched[0];
      var includesParameter = match.includes("$".concat(argName));
      var includesVariable = match.includes(typeName);
  
      if (includesParameter && includesVariable) {
        hasUnwindClause = true;
      }
    }
  
    return hasUnwindClause;
  };
  
  var translateNestedMutation = function translateNestedMutation(_ref15) {
    var _ref15$args = _ref15.args,
        args = _ref15$args === void 0 ? [] : _ref15$args,
        paramName = _ref15.paramName,
        isRoot = _ref15.isRoot,
        _ref15$isNestedParam = _ref15.isNestedParam,
        isNestedParam = _ref15$isNestedParam === void 0 ? false : _ref15$isNestedParam,
        _ref15$isCustom = _ref15.isCustom,
        isCustom = _ref15$isCustom === void 0 ? false : _ref15$isCustom,
        _ref15$argumentIsArra = _ref15.argumentIsArray,
        argumentIsArray = _ref15$argumentIsArra === void 0 ? false : _ref15$argumentIsArra,
        _ref15$rootUsesListVa = _ref15.rootUsesListVariable,
        rootUsesListVariable = _ref15$rootUsesListVa === void 0 ? false : _ref15$rootUsesListVa,
        _ref15$dataParams = _ref15.dataParams,
        dataParams = _ref15$dataParams === void 0 ? {} : _ref15$dataParams,
        paramVariable = _ref15.paramVariable,
        parentTypeName = _ref15.parentTypeName,
        _ref15$typeMap = _ref15.typeMap,
        typeMap = _ref15$typeMap === void 0 ? {} : _ref15$typeMap,
        isCustomRootListArgument = _ref15.isCustomRootListArgument,
        mutationStatement = _ref15.mutationStatement;
    return args.reduce(function (translations, arg) {
      var argName = arg.name.value;
      var argumentTypeName = (0, _fields.unwrapNamedType)({
        type: arg.type
      }).name;
      var argumentType = typeMap[argumentTypeName];
      var argValue = dataParams[argName];
      var usesInputObjectArgument = (0, _graphql.isInputObjectType)(argumentType) && (0, _typeof2["default"])(argValue) === 'object';
  
      if (usesInputObjectArgument) {
        (0, _keys["default"])(argValue).forEach(function (name) {
          var translation = translateNestedMutationInput({
            name: name,
            argName: argName,
            argValue: argValue,
            argumentType: argumentType,
            paramName: paramName,
            parentTypeName: parentTypeName,
            paramVariable: paramVariable,
            isRoot: isRoot,
            isNestedParam: isNestedParam,
            isCustom: isCustom,
            argumentIsArray: argumentIsArray,
            rootUsesListVariable: rootUsesListVariable,
            typeMap: typeMap,
            isCustomRootListArgument: isCustomRootListArgument,
            mutationStatement: mutationStatement
          });
          if (translation.length) translations.push.apply(translations, (0, _toConsumableArray2["default"])(translation));
        });
      }
  
      return translations;
    }, []);
  };
  
  var translateNestedMutationInput = function translateNestedMutationInput(_ref16) {
    var name = _ref16.name,
        argName = _ref16.argName,
        argValue = _ref16.argValue,
        argumentType = _ref16.argumentType,
        parentTypeName = _ref16.parentTypeName,
        paramName = _ref16.paramName,
        paramVariable = _ref16.paramVariable,
        isRoot = _ref16.isRoot,
        isNestedParam = _ref16.isNestedParam,
        isCustom = _ref16.isCustom,
        argumentIsArray = _ref16.argumentIsArray,
        rootUsesListVariable = _ref16.rootUsesListVariable,
        typeMap = _ref16.typeMap,
        isCustomRootListArgument = _ref16.isCustomRootListArgument,
        mutationStatement = _ref16.mutationStatement;
    var translations = [];
    var inputFields = argumentType.getFields();
    var inputField = inputFields[name];
  
    if (inputField) {
      var inputFieldAst = inputFields[name].astNode;
      var inputFieldTypeName = (0, _fields.unwrapNamedType)({
        type: inputFieldAst.type
      }).name;
      var inputFieldType = typeMap[inputFieldTypeName];
      var customCypher = (0, _directives.getDirective)({
        directives: inputFieldAst.directives,
        name: _directives.DirectiveDefinition.CYPHER
      });
  
      if ((0, _graphql.isInputObjectType)(inputFieldType)) {
        if (customCypher) {
          var _inputFieldTypeName = inputFieldType.name;
          var statement = (0, _directives.getDirectiveArgument)({
            directive: customCypher,
            name: 'statement'
          });
          var nestedParamVariable = paramVariable ? paramVariable : '';
  
          if (isRoot) {
            nestedParamVariable = paramName;
          } else if (isNestedParam) {
            // recursively builds nested cypher variable path
            nestedParamVariable = "".concat(paramVariable, ".").concat(paramName);
          }
  
          if (isCustomRootListArgument && rootUsesListVariable) {
            nestedParamVariable = parentTypeName;
          }
  
          var translated = buildMutationSubQuery({
            inputFieldTypeName: _inputFieldTypeName,
            inputFieldType: inputFieldType,
            statement: statement,
            name: name,
            parentTypeName: parentTypeName,
            paramVariable: nestedParamVariable,
            argName: argName,
            argValue: argValue,
            typeMap: typeMap,
            isRoot: isRoot,
            argumentIsArray: argumentIsArray,
            isNestedParam: isNestedParam,
            rootUsesListVariable: rootUsesListVariable,
            isCustomRootListArgument: isCustomRootListArgument,
            mutationStatement: mutationStatement
          });
  
          if (translated) {
            translations.push(translated);
          }
        } else if (isNestedParam) {
          // keep looking
          var nestedArgs = (0, _values["default"])(argumentType.getFields()).map(function (arg) {
            return arg.astNode;
          });
  
          var _nestedParamVariable = "".concat(paramVariable ? "".concat(paramVariable, ".") : '').concat(paramName);
  
          var nestedParamName = argName;
  
          if (isRoot) {
            // recursively builds cypher variable path
            nestedParamName = "".concat(paramName ? "".concat(paramName, ".") : '').concat(argName);
          }
  
          var _statement2 = translateNestedMutation({
            isNestedParam: true,
            isRoot: isRoot,
            paramName: nestedParamName,
            args: nestedArgs,
            dataParams: argValue,
            paramVariable: _nestedParamVariable,
            typeMap: typeMap,
            isCustom: isCustom,
            mutationStatement: mutationStatement,
            rootUsesListVariable: rootUsesListVariable,
            isCustomRootListArgument: isCustomRootListArgument
          });
  
          var nestedStatements = _statement2.join('\n');
  
          if (nestedStatements) translations.push(nestedStatements);
        }
      }
    }
  
    return translations;
  };
  
  var buildMutationSubQuery = function buildMutationSubQuery(_ref17) {
    var inputFieldTypeName = _ref17.inputFieldTypeName,
        inputFieldType = _ref17.inputFieldType,
        statement = _ref17.statement,
        name = _ref17.name,
        parentTypeName = _ref17.parentTypeName,
        paramVariable = _ref17.paramVariable,
        argName = _ref17.argName,
        argValue = _ref17.argValue,
        typeMap = _ref17.typeMap,
        isRoot = _ref17.isRoot,
        argumentIsArray = _ref17.argumentIsArray,
        isNestedParam = _ref17.isNestedParam,
        rootUsesListVariable = _ref17.rootUsesListVariable,
        isCustomRootListArgument = _ref17.isCustomRootListArgument,
        mutationStatement = _ref17.mutationStatement;
    var inputFieldTypeFields = inputFieldType.getFields();
    var nestedArgs = (0, _values["default"])(inputFieldTypeFields).map(function (arg) {
      return arg.astNode;
    });
    var nestedDataParams = argValue[name];
    var mappedDataParams = mapMutationParams({
      params: nestedDataParams
    });
    var nestedMutationStatements = translateNestedMutations({
      args: nestedArgs,
      dataParams: mappedDataParams,
      paramVariable: inputFieldTypeName,
      typeMap: typeMap,
      mutationStatement: mutationStatement
    });
    var augmentedStatement = augmentMutationWithClauses({
      inputFieldTypeName: inputFieldTypeName,
      statement: statement,
      nestedMutationStatements: nestedMutationStatements
    });
    var statements = "".concat(augmentedStatement).concat(nestedMutationStatements); // generalized solution for possible edge case where the current and
    // nested input type names are the same
  
    if (!isRoot && paramVariable) {
      paramVariable = "_".concat(paramVariable);
    }
  
    var paramPath = "".concat(paramVariable ? "".concat(paramVariable, ".") : '').concat(argName, ".").concat(name); // If we are at root, and if the argument type is not a list when
    // this is a custom @cypher mutation
  
    if (isRoot && (!isNestedParam || !argumentIsArray)) {
      paramPath = "$".concat(paramPath);
    }
  
    return cypherSubQuery({
      argName: argName,
      name: name,
      paramPath: paramPath,
      inputFieldTypeName: inputFieldTypeName,
      parentTypeName: parentTypeName,
      paramVariable: paramVariable,
      statements: statements,
      isRoot: isRoot,
      argumentIsArray: argumentIsArray,
      isNestedParam: isNestedParam,
      rootUsesListVariable: rootUsesListVariable,
      mutationStatement: mutationStatement,
      isCustomRootListArgument: isCustomRootListArgument
    });
  };
  
  var augmentMutationWithClauses = function augmentMutationWithClauses(_ref18) {
    var _ref18$inputFieldType = _ref18.inputFieldTypeName,
        inputFieldTypeName = _ref18$inputFieldType === void 0 ? '' : _ref18$inputFieldType,
        _ref18$nestedMutation = _ref18.nestedMutationStatements,
        nestedMutationStatements = _ref18$nestedMutation === void 0 ? [] : _ref18$nestedMutation,
        _ref18$statement = _ref18.statement,
        statement = _ref18$statement === void 0 ? '' : _ref18$statement;
    var openingWithClause = '';
    var endingWithClause = '';
  
    if (statement) {
      var lowercasedStatement = statement.toLowerCase();
      var isCommentedRegExp = new RegExp("with(?!/*.*)", 'i');
      var firstWithIndex = lowercasedStatement.indexOf('with');
      isCommentedRegExp.lastIndex = firstWithIndex;
      var lastWithIndex = lowercasedStatement.lastIndexOf('with'); // this makes the regex match "sticky", which begins the match from the given index
  
      isCommentedRegExp.lastIndex = lastWithIndex;
  
      if (firstWithIndex !== -1) {
        var firstWithMatch = statement.substr(firstWithIndex); // so, to determine which is at the top, see that the index is actually 0, test this
  
        if (firstWithMatch) {
          // there is only one WITH clause
          if (firstWithIndex === lastWithIndex) {
            var onlyMatch = statement.substr(firstWithIndex);
  
            if (firstWithIndex === 0) {
              // the only WITH clause also begins at index 0, so it's an opening WITH clause
              openingWithClause = onlyMatch;
            } else {
              // assume the last WITH clause is at the end of the statement
              endingWithClause = onlyMatch;
            }
          } else if (lastWithIndex !== -1) {
            // there are two or more WITH clauses
            var firstMatch = statement.substr(firstWithIndex);
            var lastMatch = statement.substr(lastWithIndex);
            if (firstWithIndex === 0) openingWithClause = firstMatch;
            endingWithClause = lastMatch;
          }
  
          if (openingWithClause && endingWithClause) {
            openingWithClause = openingWithClause.substr(0, lastWithIndex);
          }
  
          if (openingWithClause) {
            // add a Cypher variable for inputFieldTypeName - the name of the parent
            // UNWIND variable - to keep it available within the proceeding Cypher
            statement = augmentMutationWithClause({
              withClause: openingWithClause,
              inputFieldTypeName: inputFieldTypeName,
              isImportClause: true
            });
          }
  
          if (endingWithClause) {
            // add an alias for the Cypher variable from the parent UNWIND statement,
            // to allow the same input type to be used again by a nested UNWIND,
            // preventing variable name conflicts
            var augmentedWithClause = augmentMutationWithClause({
              withClause: endingWithClause,
              inputFieldTypeName: inputFieldTypeName,
              isExportClause: true
            });
  
            if (openingWithClause) {
              // if there is also a WITH clause importing variables,
              // then it has already been augmented (above) and equal to statement,
              // so the now augmented exporting WITH clause is appended
              statement = "".concat(statement).concat(augmentedWithClause);
            } else {
              // otherwise, statement is still unmodified, so get everything before
              // the exporting WITH clause, appending after it the augmented clause
              var beforeEndingWith = statement.substr(0, lastWithIndex);
              statement = "".concat(beforeEndingWith, "\n").concat(augmentedWithClause);
            }
          }
        }
      }
    }
  
    if (!endingWithClause && nestedMutationStatements.length) {
      var paramVariable = "".concat(inputFieldTypeName, " AS _").concat(inputFieldTypeName); // as a default, continue with all variables, along with the aliased input type name
      // to allow for reusing its input type in nested cases
  
      endingWithClause = "WITH *, ".concat(paramVariable);
      statement = "".concat(statement, "\n").concat(endingWithClause);
    }
  
    return statement;
  };
  
  var augmentMutationWithClause = function augmentMutationWithClause(_ref19) {
    var _ref19$withClause = _ref19.withClause,
        withClause = _ref19$withClause === void 0 ? '' : _ref19$withClause,
        _ref19$inputFieldType = _ref19.inputFieldTypeName,
        inputFieldTypeName = _ref19$inputFieldType === void 0 ? '' : _ref19$inputFieldType,
        _ref19$isImportClause = _ref19.isImportClause,
        isImportClause = _ref19$isImportClause === void 0 ? false : _ref19$isImportClause,
        _ref19$isExportClause = _ref19.isExportClause,
        isExportClause = _ref19$isExportClause === void 0 ? false : _ref19$isExportClause;
    // find the index of the first comma, for checking if this is a variable list
    var firstCommaIndex = withClause.indexOf(','); // regex to check if this clause begins with the pattern WITH *
  
    var withEverythingRegex = new RegExp("WITH\\s*\\*+", 'i');
    var continuesWithEverything = withClause.match(withEverythingRegex); // assume the clause is not a variable list, e.g., WITH *, ... or WITH x, ...
  
    var isVariableList = false; // assume the clause does not begin with WITH *
  
    var isWithAsterisk = false;
    var augmentedWithClause = withClause; // remove the WITH from the beginning of the clause
  
    var withClauseRemainder = withClause.substr(4);
  
    if (continuesWithEverything) {
      isWithAsterisk = true;
      var match = continuesWithEverything[0];
      var matchLen = match.length; // get everything proceeding WITH *
  
      var nextCypher = withClause.substr(matchLen);
  
      if (nextCypher) {
        // trim everything proceeding, so we can check the next character
        // using String.startsWith
        var trimmed = nextCypher.trim();
  
        if (trimmed.startsWith(',') && firstCommaIndex !== -1) {
          // if the clause begins with WITH * and is immediately proceeded
          // by a comma, the clause begins as: "WITH *, ..."
          isVariableList = true;
        }
      }
    }
  
    var paramVariable = '';
  
    if (isImportClause) {
      // if an importating WITH clause is provided, then we need to persist
      // the parent UNWIND clause's variable along with it to keep it available
      paramVariable = inputFieldTypeName;
    } else if (isExportClause) {
      // alias this input type name for it to be unwound by the nested UNWIND,
      // to allow for reusing the same input type in nested cases
      paramVariable = "".concat(inputFieldTypeName, " AS _").concat(inputFieldTypeName);
    }
  
    if (isWithAsterisk) {
      if (isVariableList) {
        // set withClauseRemainder forward to start at the first comma
        withClauseRemainder = withClause.substr(firstCommaIndex);
      } else {
        // set withClauseRemainder to immediately after WITH *
        withClauseRemainder = withClause.substr(6);
      } // inject paramVariable into the clause
  
  
      augmentedWithClause = "WITH *, ".concat(paramVariable).concat(withClauseRemainder);
    } else {
      // otherwise, the clause is not WITH * and not a list, as neither "WITH *", nor "WITH x, ..."
      // so it is added with a preceeding comma, assuming the clause provides at least 1 variable
      augmentedWithClause = "WITH ".concat(paramVariable).concat(withClauseRemainder ? ",".concat(withClauseRemainder) : '');
    }
  
    return augmentedWithClause;
  };
  
  var cypherSubQuery = function cypherSubQuery(_ref20) {
    var _ref20$argName = _ref20.argName,
        argName = _ref20$argName === void 0 ? '' : _ref20$argName,
        _ref20$name = _ref20.name,
        name = _ref20$name === void 0 ? '' : _ref20$name,
        _ref20$paramPath = _ref20.paramPath,
        paramPath = _ref20$paramPath === void 0 ? '' : _ref20$paramPath,
        _ref20$inputFieldType = _ref20.inputFieldTypeName,
        inputFieldTypeName = _ref20$inputFieldType === void 0 ? '' : _ref20$inputFieldType,
        _ref20$parentTypeName = _ref20.parentTypeName,
        parentTypeName = _ref20$parentTypeName === void 0 ? '' : _ref20$parentTypeName,
        _ref20$paramVariable = _ref20.paramVariable,
        paramVariable = _ref20$paramVariable === void 0 ? '' : _ref20$paramVariable,
        _ref20$statements = _ref20.statements,
        statements = _ref20$statements === void 0 ? '' : _ref20$statements,
        isRoot = _ref20.isRoot,
        argumentIsArray = _ref20.argumentIsArray,
        _ref20$isNestedParam = _ref20.isNestedParam,
        isNestedParam = _ref20$isNestedParam === void 0 ? false : _ref20$isNestedParam,
        _ref20$rootUsesListVa = _ref20.rootUsesListVariable,
        rootUsesListVariable = _ref20$rootUsesListVa === void 0 ? false : _ref20$rootUsesListVa,
        _ref20$isCustomRootLi = _ref20.isCustomRootListArgument,
        isCustomRootListArgument = _ref20$isCustomRootLi === void 0 ? false : _ref20$isCustomRootLi;
    var unwindStatement = "UNWIND ".concat(paramPath, " AS ").concat(inputFieldTypeName);
  
    if (isCustomRootListArgument) {
      if (rootUsesListVariable) {
        if (isNestedParam) {
          unwindStatement = "UNWIND ".concat(parentTypeName, ".").concat(argName, ".").concat(name, " AS ").concat(inputFieldTypeName);
        } else {
          unwindStatement = "UNWIND ".concat(paramVariable, ".").concat(name, " AS ").concat(inputFieldTypeName);
        }
      } else {
        unwindStatement = "UNWIND $".concat(argName, " AS _").concat(argName, "\n  UNWIND _").concat(argName, ".").concat(name, " as ").concat(inputFieldTypeName);
      }
    } else if (isRoot && argumentIsArray) {
      unwindStatement = "UNWIND $".concat(paramVariable, ".").concat(argName, " AS _").concat(argName, "\n  UNWIND _").concat(argName, ".").concat(name, " as ").concat(inputFieldTypeName);
    }
  
    return "\nCALL {\n  WITH *\n  ".concat(unwindStatement, "\n  ").concat(statements, "\n  RETURN COUNT(*) AS _").concat(argName, "_").concat(name, "_\n}");
  };
  
  var mapMutationParams = function mapMutationParams(_ref21) {
    var _ref21$params = _ref21.params,
        params = _ref21$params === void 0 ? {} : _ref21$params;
    return (0, _entries["default"])(params).reduce(function (mapped, _ref22) {
      var _ref23 = (0, _slicedToArray2["default"])(_ref22, 2),
          name = _ref23[0],
          param = _ref23[1];
  
      if (param === null) {
        mapped[name] = true;
      } else {
        mapped[name] = mapMutationParam({
          param: param
        });
      }
  
      return mapped;
    }, {});
  };
  
  var mapMutationParam = function mapMutationParam(_ref24) {
    var param = _ref24.param;
  
    if ((0, _isArray["default"])(param)) {
      var firstElement = param[0];
  
      if ((0, _typeof2["default"])(firstElement) === 'object' && !(0, _isArray["default"])(firstElement)) {
        // list of object values
        return param.reduce(function (subMap, listObject) {
          var subMapped = mapMutationParams({
            params: listObject
          });
          return _lodash["default"].merge(subMap, subMapped);
        }, {});
      } else {
        // list argument of non-object values
        return true;
      }
    } else if ((0, _typeof2["default"])(param) === 'object') {
      if (param === null) return true;
      return mapMutationParams({
        params: param
      });
    }
  
    return true;
  };