<commit_before>import forEach from 'lodash.foreach';
import merge from 'lodash.merge';
import union from 'lodash.union';
import warning from 'warning';

import actionTypes from '../actions/types';
import connectors from './connectors';
import processNode from './process-node';
import store from './store';

// Default state
// state will be composed of connectors data, e.g.
// {
//   connector_1: {
//     pages: [{...}, {...}]
//   },
//   connector_2: {
//     page: {...}
//   }
// }
const defaultState = {};

export default function graphqlReducer (state = defaultState, action = {}) {
  if ((action.type === actionTypes.query || action.type === actionTypes.mutation) && action.data && action.fragments) {
    const isMutation = action.type === actionTypes.mutation;
    const isRemoveMutation = isMutation && action.mutationType === 'REMOVE';
    let connectorsToUpdate = action.connectors && Object.keys(action.connectors) || [];
    let nodes = [];

    if (isRemoveMutation) {
      forEach(action.fragments, (fragment, queryName) => {
        if (fragment._id) {
          const queryData = action.data[queryName];
          if (queryData && queryData._id) {
            // Remove from store
            store.removeNode(queryData._id);

            // Remove from connectors
            connectorsToUpdate = connectors.removeNode(queryData._id);
          } else {
            warning(false, 'RELATE: Remove action failed');
            // TODO handle error in some way?
          }
        }
      });
    } else {
      forEach(action.fragments, (fragment, queryName) => {
        const nodesProcessed = processNode(action.data[queryName], fragment, queryName); // { relativeNodes: [], nodes: [], changes: {} }

        // DB changes
        store.updateNodes(nodesProcessed.changes);

        // Save nodes changed to later check which connectors to update
        nodes = union(nodes, nodesProcessed.nodes);

        // Connectors
        if (action.connectors) {
          connectors.processConnectors(action.connectors, queryName, nodesProcessed.relativeNodes, nodesProcessed.nodes);
        }

        // Mutations
        if (isMutation) {
          connectorsToUpdate = connectors.checkMutationListeners(queryName, nodesProcessed.relativeNodes, nodesProcessed.nodes);
        }
      });
    }

    // Check more connectors than need to update
    connectorsToUpdate = connectorsToUpdate.concat(connectors.getConnectorsToUpdate(nodes, connectorsToUpdate));

    // Calculate connectors data
    const changes = {};
    forEach(connectorsToUpdate, (connectorId) => {
      changes[connectorId] = connectors.generateConnectorData(connectorId);
    });

    return merge({}, state, changes);
  }

  if (action.type === actionTypes.removeConnector) {
    const newState = Object.assign({}, state);
    delete newState[action.id];
    connectors.deleteConnector(action.id);
    // TODO Delete no longer needed data from state? or maintain for future cache?
    return newState;
  }

  return state;
}<commit_msg>check for connectors listening a remove mutation<commit_after>import forEach from 'lodash.foreach';
import merge from 'lodash.merge';
import union from 'lodash.union';
import warning from 'warning';

import actionTypes from '../actions/types';
import connectors from './connectors';
import processNode from './process-node';
import store from './store';

// Default state
// state will be composed of connectors data, e.g.
// {
//   connector_1: {
//     pages: [{...}, {...}]
//   },
//   connector_2: {
//     page: {...}
//   }
// }
const defaultState = {};

export default function graphqlReducer (state = defaultState, action = {}) {
  if ((action.type === actionTypes.query || action.type === actionTypes.mutation) && action.data && action.fragments) {
    const isMutation = action.type === actionTypes.mutation;
    const isRemoveMutation = isMutation && action.mutationType === 'REMOVE';
    let connectorsToUpdate = action.connectors && Object.keys(action.connectors) || [];
    let nodes = [];

    if (isRemoveMutation) {
      forEach(action.fragments, (fragment, queryName) => {
        if (fragment._id) {
          const queryData = action.data[queryName];
          if (queryData && queryData._id) {
            // Remove from store
            store.removeNode(queryData._id);

            // Remove from connectors
            connectorsToUpdate = connectors.removeNode(queryData._id);

            // Check connectors listening to this mutation
            connectorsToUpdate = union(connectorsToUpdate, connectors.checkMutationListeners(queryName, [], []));
          } else {
            warning(false, 'RELATE: Remove action failed');
            // TODO handle error in some way?
          }
        }
      });
    } else {
      forEach(action.fragments, (fragment, queryName) => {
        const nodesProcessed = processNode(action.data[queryName], fragment, queryName); // { relativeNodes: [], nodes: [], changes: {} }

        // DB changes
        store.updateNodes(nodesProcessed.changes);

        // Save nodes changed to later check which connectors to update
        nodes = union(nodes, nodesProcessed.nodes);

        // Connectors
        if (action.connectors) {
          connectors.processConnectors(action.connectors, queryName, nodesProcessed.relativeNodes, nodesProcessed.nodes);
        }

        // Mutations
        if (isMutation) {
          connectorsToUpdate = union(connectorsToUpdate, connectors.checkMutationListeners(queryName, nodesProcessed.relativeNodes, nodesProcessed.nodes));
        }
      });
    }

    // Check more connectors than need to update
    connectorsToUpdate = connectorsToUpdate.concat(connectors.getConnectorsToUpdate(nodes, connectorsToUpdate));

    // Calculate connectors data
    const changes = {};
    forEach(connectorsToUpdate, (connectorId) => {
      changes[connectorId] = connectors.generateConnectorData(connectorId);
    });

    return merge({}, state, changes);
  }

  if (action.type === actionTypes.removeConnector) {
    const newState = Object.assign({}, state);
    delete newState[action.id];
    connectors.deleteConnector(action.id);
    // TODO Delete no longer needed data from state? or maintain for future cache?
    return newState;
  }

  return state;
}
{'fraction_non_alphanumeric': 0.12444373808010172, 'fraction_numerical': 0.0006357279084551812, 'mean_word_length': 2.8631062001227745, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3477277', 'n_tokens_mistral': 1726, 'n_tokens_neox': 1663, 'n_words': 422}