<commit_before>var Kuery = require('kuery');
var Observe = require('./observe');
var reconcile = require('./reconcile');
var _ = require('lodash');

/**
 *
 * @param {*} query Mongodb query, for example: { 'identifiers.identifier': 'abc' }
 * @param {*} local Local cursor
 * @param {*} remote Remote cursor
 * @param {*} findOptions Not in use?
 * @param {*} options Options supplied from collection.
 */
var HybridCursor = function (query, local, remote, findOptions, options) {
  this._query = query;
  this._sort = null;
  this._limit = null;
  this._local = local;
  this._remote = remote;
  this._findOptions = findOptions;
  this._options = options;
  this._onCacheUpdateCallback = options.onCacheUpdateCallback;
  this._getCachedData = options.getCachedData;
};

HybridCursor.prototype._toArray = function (callback) {
  //reconcile strategy
  var self = this;
  var localData = null;
  var remoteData = null;
  var localErr = null;
  var remoteErr = null;
  var kuery = new Kuery(this._query);
  var sort = this._sort;
  var limit = this._limit;
  var skip = this._skip;
  var project = this._project;

  if (sort) {
    kuery.sort(sort);
  }
  if (limit) {
    kuery.limit(limit);
  }

  function serverResult(err, result) {
    if (err) {
      remoteErr = err;
      result = result || [];
      if (self._options.throwRemoteErr) {
        return callback(err);
      }
    }
    remoteData = result;
    if (localData) {
      var combinedResult = kuery.find(reconcile(localData, remoteData));
      callback(null, combinedResult);
      if (_.isFunction(self._onCacheUpdateCallback)) {
        self._onCacheUpdateCallback(self._query, skip, limit, sort, project, combinedResult);
      }
    }
  }

  function localResult(err, result) {
    if (err) {
      localErr = err;
      return callback(err, result);
    }

    localData = result;
    if (remoteData || remoteErr) {
      if (!(remoteErr && self._options.throwRemoteErr)) {
        var combinedResult = kuery.find(reconcile(localData, remoteData || []));
        callback(null, combinedResult);
        if (_.isFunction(self._onCacheUpdateCallback)) {
          self._onCacheUpdateCallback(self._query, skip, limit, sort, project, combinedResult);
        }
      }
    } else {
      if (self._options.localFirst) {
        callback(err, localData);
      }
    }
  }

  if (sort) {
    this._local.sort(sort);
    this._remote.sort(sort);
  }
  if (limit) {
    this._local.limit(limit);
    this._remote.limit(limit);
  }
  if (project && _.isFunction(this._remote.project)) {
    this._remote.project(project);
  }

  this._local.toArray(localResult);
  this._remote.toArray(serverResult);
};

HybridCursor.prototype.toArray = function (callback) {
  var self = this;

  if (this._getCachedData) {
    this._getCachedData(this._query, this._skip, this._limit, this._sort, this._project, function (err, data) {
      if (data && data.length > 0) {
        callback(null, data);
        return;
      }

      self._toArray(callback);
    });
  } else {
    this._toArray(callback);
  }
};

HybridCursor.prototype._refresh = function () {
  this._remote._refresh();
  this._local._refresh();
};

HybridCursor.prototype.sort = function (sort) {
  this._sort = sort;
  return this;
};

HybridCursor.prototype.limit = function (limit) {
  this._limit = limit;
  return this;
};

HybridCursor.prototype.skip = function (skip) {
  console.warn('skip not supported on hybrid');
  return this;
};

HybridCursor.prototype.updateQuery = function (query) {
  this._local._query.query = query;
  this._remote._query.query = query;
  this._query = query;
  this._refresh();
};

HybridCursor.prototype._onObserverCacheUpdate = function (result) {
  if (_.isFunction(this._onCacheUpdateCallback)) {
    this._onCacheUpdateCallback(this._query, this._skip, this._limit, this._sort, this._project, result);
  }
};

HybridCursor.prototype._getObserverData = function (callback) {
  this._getCachedData(this._query, this._skip, this._limit, this._sort, callback);
};

HybridCursor.prototype.observe = function (options) {
  if (this._project) {
    this._remote.project(this._project);
  }

  return new Observe(this._local, this._remote, this._options, options, this._onObserverCacheUpdate.bind(this), this._getObserverData.bind(this));
};

HybridCursor.prototype.project = function (project) {
  this._project = project;
  return this;
};

module.exports = HybridCursor;
<commit_msg>Fixed crash if project is not supported<commit_after>var Kuery = require('kuery');
var Observe = require('./observe');
var reconcile = require('./reconcile');
var _ = require('lodash');

/**
 *
 * @param {*} query Mongodb query, for example: { 'identifiers.identifier': 'abc' }
 * @param {*} local Local cursor
 * @param {*} remote Remote cursor
 * @param {*} findOptions Not in use?
 * @param {*} options Options supplied from collection.
 */
var HybridCursor = function (query, local, remote, findOptions, options) {
  this._query = query;
  this._sort = null;
  this._limit = null;
  this._local = local;
  this._remote = remote;
  this._findOptions = findOptions;
  this._options = options;
  this._onCacheUpdateCallback = options.onCacheUpdateCallback;
  this._getCachedData = options.getCachedData;
};

HybridCursor.prototype._toArray = function (callback) {
  //reconcile strategy
  var self = this;
  var localData = null;
  var remoteData = null;
  var localErr = null;
  var remoteErr = null;
  var kuery = new Kuery(this._query);
  var sort = this._sort;
  var limit = this._limit;
  var skip = this._skip;
  var project = this._project;

  if (sort) {
    kuery.sort(sort);
  }
  if (limit) {
    kuery.limit(limit);
  }

  function serverResult(err, result) {
    if (err) {
      remoteErr = err;
      result = result || [];
      if (self._options.throwRemoteErr) {
        return callback(err);
      }
    }
    remoteData = result;
    if (localData) {
      var combinedResult = kuery.find(reconcile(localData, remoteData));
      callback(null, combinedResult);
      if (_.isFunction(self._onCacheUpdateCallback)) {
        self._onCacheUpdateCallback(self._query, skip, limit, sort, project, combinedResult);
      }
    }
  }

  function localResult(err, result) {
    if (err) {
      localErr = err;
      return callback(err, result);
    }

    localData = result;
    if (remoteData || remoteErr) {
      if (!(remoteErr && self._options.throwRemoteErr)) {
        var combinedResult = kuery.find(reconcile(localData, remoteData || []));
        callback(null, combinedResult);
        if (_.isFunction(self._onCacheUpdateCallback)) {
          self._onCacheUpdateCallback(self._query, skip, limit, sort, project, combinedResult);
        }
      }
    } else {
      if (self._options.localFirst) {
        callback(err, localData);
      }
    }
  }

  if (sort) {
    this._local.sort(sort);
    this._remote.sort(sort);
  }
  if (limit) {
    this._local.limit(limit);
    this._remote.limit(limit);
  }
  if (project && _.isFunction(this._remote.project)) {
    this._remote.project(project);
  }

  this._local.toArray(localResult);
  this._remote.toArray(serverResult);
};

HybridCursor.prototype.toArray = function (callback) {
  var self = this;

  if (this._getCachedData) {
    this._getCachedData(this._query, this._skip, this._limit, this._sort, this._project, function (err, data) {
      if (data && data.length > 0) {
        callback(null, data);
        return;
      }

      self._toArray(callback);
    });
  } else {
    this._toArray(callback);
  }
};

HybridCursor.prototype._refresh = function () {
  this._remote._refresh();
  this._local._refresh();
};

HybridCursor.prototype.sort = function (sort) {
  this._sort = sort;
  return this;
};

HybridCursor.prototype.limit = function (limit) {
  this._limit = limit;
  return this;
};

HybridCursor.prototype.skip = function (skip) {
  console.warn('skip not supported on hybrid');
  return this;
};

HybridCursor.prototype.updateQuery = function (query) {
  this._local._query.query = query;
  this._remote._query.query = query;
  this._query = query;
  this._refresh();
};

HybridCursor.prototype._onObserverCacheUpdate = function (result) {
  if (_.isFunction(this._onCacheUpdateCallback)) {
    this._onCacheUpdateCallback(this._query, this._skip, this._limit, this._sort, this._project, result);
  }
};

HybridCursor.prototype._getObserverData = function (callback) {
  this._getCachedData(this._query, this._skip, this._limit, this._sort, callback);
};

HybridCursor.prototype.observe = function (options) {
  if (this._project && _.isFunction(this._remote.project)) {
    this._remote.project(this._project);
  }

  return new Observe(this._local, this._remote, this._options, options, this._onObserverCacheUpdate.bind(this), this._getObserverData.bind(this));
};

HybridCursor.prototype.project = function (project) {
  this._project = project;
  return this;
};

module.exports = HybridCursor;

{'fraction_non_alphanumeric': 0.13575418994413407, 'fraction_numerical': 0.000223463687150838, 'mean_word_length': 3.4532338308457713, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '1161902', 'n_tokens_mistral': 2815, 'n_tokens_neox': 2780, 'n_words': 595}