<commit_before>// Note that it appears that loopback uses the connector's destroyAll,
// updateAll, and all to operate even on singular documents.  I'm not
// sure whether it uses destroy, update, and find at all or whether
// these are intended to be private methods for the connector.

/*!
 * Module dependencies
 */
var riak       = require('riak-js');
var util       = require('util');
var deepExtend = require('deep-extend');
var async      = require('async');
var Connector  = require('loopback-connector').Connector;

/**
 * The constructor for Riak connector
 * @param {Object} settings The settings object
 * @param {DataSource} dataSource The data source instance
 * @constructor
 */
function Riak(settings, dataSource){
  this.name       = 'riak';
  this.settings   = settings;
  this.debug      = !!settings.debug;
  this.dataSource = dataSource;
}

/**
 * Initialize the Riak connector for the given data source
 * @param {DataSource} dataSource The data source instance
 * @param {Function} [apiCallback] The callback function
 */
exports.initialize = function initializeDataSource(dataSource, callback){
  dataSource.connector            = new Riak(dataSource.settings, dataSource);
  dataSource.connector.dataSource = dataSource;

  if (callback) dataSource.connector.connect(callback);
};

util.inherits(Riak, Connector);

//
// "public" methods (Loopback connector API implementation)
//

/**
 * Connect to Riak
 * RiakJS doesn't connect per se but we'll ping the db to make sure it
 * works.
 *
 * @param {Function} [apiCallback] The callback function
 *
 * @callback callback
 * @param {Error} err The error object
 * @param {Db} db The riak client object
 */
Riak.prototype.connect = function(apiCallback){
  var self = this;

  this.db = riak({host: self.settings.host, port: self.settings.port});
  this._models = {};

  self.ping(function(error, response){
    if (error)         self._onConnectionFailure(error);
    else if (response) self._onConnectionSuccess();
    else               self._onUnexpectedError("connecting to Riak");

    apiCallback && apiCallback(error, self.db);
  });
};

Riak.prototype.getTypes = function(){
  return ['db', 'nosql', 'riak'];
};

/**
 * Create a new model instance for the given data
 * @param {String} modelName The model name
 * @param {Object} data The model data
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.create = function(modelName, data, apiCallback){
  var self = this;

  var key = data.key;
  if (!key) throw new Error('Riak create called for a document with no key');

  async.waterfall([
    checkExistance,
    store
  ], apiCallback);

  function checkExistance(callback){
    self.db.exists(modelName, key, function(error, exists){
      if (exists) return callback(self._consoleLog("key conflict during create for key", key));

      callback(error, exists);
    });
  }

  function store(exists, callback){
    self.db.save(modelName, key, data, { returnbody: true }, callback);
  }
};

/**
 * Save the model instance for the given data
 * @param {String} modelName The model name
 * @param {Object} data The model data
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.save = function(modelName, data, apiCallback){
  var key = data.key;
  if (!key) throw new Error('Riak save called for a document with no key');

  this.db.save(modelName, key, data, { returnbody: true }, apiCallback);
};

/**
 * Check if a model instance exists by key
 * @param {String} modelName The model name
 * @param {*} key The key value
 * @param {Function} [apiCallback] The callback function
 *
 */
Riak.prototype.exists = function(modelName, key, apiCallback){
  this.db.exists(modelName, key, {}, apiCallback);
};

/**
 * Find a model instance by key
 * @param {String} modelName The model name
 * @param {*} key The key value
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.find = function(modelName, key, apiCallback){
  this.db.get(modelName, key, apiCallback);
};

/**
 * Update if the model instance exists with the same key or create a new instance
 *
 * @param {String} modelName The model name
 * @param {Object} data The model instance data
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.updateOrCreate = function(modelName, data, apiCallback){
  throw new Error('updateOrCreate is not currently supported in Riak');
};

/**
 * Delete a model instance by key
 * @param {String} modelName The model name
 * @param {*} key The key value
 * @param [apiCallback] The callback function
 */
Riak.prototype.destroy = function(modelName, key, apiCallback){
  this.db.remove(modelName, { id: key }, apiCallback);
};

/**
 * Find matching model instances by the filter
 * WARNING: at the moment this just returns all the things ever
 *
 * @param {String} model The model name
 * @param {Object} filter The filter
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.all = function(modelName, conditions, apiCallback){
  // what's up with "ACL" being sent in here?
  if (modelName === "ACL") return apiCallback(null);

  this._searchAndMapResults(modelName, where, this.find, apiCallback);
};

/**
 * Delete all instances for the given model
 * @param {String} model The model name
 * @param {Object} [where] The filter for where
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.destroyAll = function(model, where, apiCallback){
  this._searchAndMapResults(modelName, where, this.destroy, apiCallback);
};

/**
 * Count the number of records for the given model
 *
 * @param {String} modelName The model name
 * @param {Function} [apiCallback] The callback function
 * @param {Object} filter The filter for where
 *
 */
Riak.prototype.count = function(modelName, apiCallback, where){
  // TODO: probably mapReduce
  this._notImplemented("count");
};

/**
 * Update properties for the model instance data
 * @param {String} model The model name
 * @param {Object} data The model data
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.updateAttributes = function(modelName, key, data, apiCallback){
  var self = this;

  if (!key) throw new Error('Riak updateAttributes called for a document with no key');

  async.waterfall([
    find,
    merge,
    save<commit_msg>sort of looks like you can send javascript to Solr to do map reduce. This is pseudocode for doing that to count results. Will test with an actual index.<commit_after>// Note that it appears that loopback uses the connector's destroyAll,
// updateAll, and all to operate even on singular documents.  I'm not
// sure whether it uses destroy, update, and find at all or whether
// these are intended to be private methods for the connector.

/*!
 * Module dependencies
 */
var riak       = require('riak-js');
var util       = require('util');
var deepExtend = require('deep-extend');
var async      = require('async');
var Connector  = require('loopback-connector').Connector;

/**
 * The constructor for Riak connector
 * @param {Object} settings The settings object
 * @param {DataSource} dataSource The data source instance
 * @constructor
 */
function Riak(settings, dataSource){
  this.name       = 'riak';
  this.settings   = settings;
  this.debug      = !!settings.debug;
  this.dataSource = dataSource;
}

/**
 * Initialize the Riak connector for the given data source
 * @param {DataSource} dataSource The data source instance
 * @param {Function} [apiCallback] The callback function
 */
exports.initialize = function initializeDataSource(dataSource, callback){
  dataSource.connector            = new Riak(dataSource.settings, dataSource);
  dataSource.connector.dataSource = dataSource;

  if (callback) dataSource.connector.connect(callback);
};

util.inherits(Riak, Connector);

//
// "public" methods (Loopback connector API implementation)
//

/**
 * Connect to Riak
 * RiakJS doesn't connect per se but we'll ping the db to make sure it
 * works.
 *
 * @param {Function} [apiCallback] The callback function
 *
 * @callback callback
 * @param {Error} err The error object
 * @param {Db} db The riak client object
 */
Riak.prototype.connect = function(apiCallback){
  var self = this;

  this.db = riak({host: self.settings.host, port: self.settings.port});
  this._models = {};

  self.ping(function(error, response){
    if (error)         self._onConnectionFailure(error);
    else if (response) self._onConnectionSuccess();
    else               self._onUnexpectedError("connecting to Riak");

    apiCallback && apiCallback(error, self.db);
  });
};

Riak.prototype.getTypes = function(){
  return ['db', 'nosql', 'riak'];
};

/**
 * Create a new model instance for the given data
 * @param {String} modelName The model name
 * @param {Object} data The model data
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.create = function(modelName, data, apiCallback){
  var self = this;

  var key = data.key;
  if (!key) throw new Error('Riak create called for a document with no key');

  async.waterfall([
    checkExistance,
    store
  ], apiCallback);

  function checkExistance(callback){
    self.db.exists(modelName, key, function(error, exists){
      if (exists) return callback(self._consoleLog("key conflict during create for key", key));

      callback(error, exists);
    });
  }

  function store(exists, callback){
    self.db.save(modelName, key, data, { returnbody: true }, callback);
  }
};

/**
 * Save the model instance for the given data
 * @param {String} modelName The model name
 * @param {Object} data The model data
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.save = function(modelName, data, apiCallback){
  var key = data.key;
  if (!key) throw new Error('Riak save called for a document with no key');

  this.db.save(modelName, key, data, { returnbody: true }, apiCallback);
};

/**
 * Check if a model instance exists by key
 * @param {String} modelName The model name
 * @param {*} key The key value
 * @param {Function} [apiCallback] The callback function
 *
 */
Riak.prototype.exists = function(modelName, key, apiCallback){
  this.db.exists(modelName, key, {}, apiCallback);
};

/**
 * Find a model instance by key
 * @param {String} modelName The model name
 * @param {*} key The key value
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.find = function(modelName, key, apiCallback){
  this.db.get(modelName, key, apiCallback);
};

/**
 * Update if the model instance exists with the same key or create a new instance
 *
 * @param {String} modelName The model name
 * @param {Object} data The model instance data
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.updateOrCreate = function(modelName, data, apiCallback){
  throw new Error('updateOrCreate is not currently supported in Riak');
};

/**
 * Delete a model instance by key
 * @param {String} modelName The model name
 * @param {*} key The key value
 * @param [apiCallback] The callback function
 */
Riak.prototype.destroy = function(modelName, key, apiCallback){
  this.db.remove(modelName, { id: key }, apiCallback);
};

/**
 * Find matching model instances by the filter
 * WARNING: at the moment this just returns all the things ever
 *
 * @param {String} model The model name
 * @param {Object} filter The filter
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.all = function(modelName, conditions, apiCallback){
  // what's up with "ACL" being sent in here?
  if (modelName === "ACL") return apiCallback(null);

  this._searchAndMapResults(modelName, where, this.find, apiCallback);
};

/**
 * Delete all instances for the given model
 * @param {String} model The model name
 * @param {Object} [where] The filter for where
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.destroyAll = function(model, where, apiCallback){
  this._searchAndMapResults(modelName, where, this.destroy, apiCallback);
};

/**
 * Count the number of records for the given model
 *
 * @param {String} modelName The model name
 * @param {Function} [apiCallback] The callback function
 * @param {Object} filter The filter for where
 *
 */
Riak.prototype.count = function(modelName, apiCallback, where){
  this.db.yokozuna.find(
    modelName,
    this._conditionsToQueryString(modelName, where),
    [
      {
        "map": {
          "language": "javascript",
          "keep": false,
          "source": "function(v) { return [1]; }"
        }
      },
      {
        "reduce": {
          "language": "javascript",
          "keep": true,
          "name": "Riak.reduceSum"
        }
      }
    ],
    // TODO: see what kind of a result we get back from the map reduce
    function(error, data){
      var statusCode = error && error.statusCode;

      if (statusCode === 404) return apiCallback("Not found", null);
      if (statusCode)         return apiCallback(error.message);

      apiCallback(data);
    }
  );
};

/**
 * Update properties for the model instance data
 * @param {String} model The model name
 * @param {Object} data The model data
 * @param {Function} [apiCallback] The callback function
 */
Riak.prototype.updateAttributes = function(modelName, key, data, apiCallback){
  var self = this;

  if (!key) throw new Error('Riak updateAttributes called for a document with no key');

  async.waterfall([
    find,
    merge,
    save
{'fraction_non_alphanumeric': 0.11925308733819372, 'fraction_numerical': 0.00029757476565987203, 'mean_word_length': 3.851317214002165, 'pattern_counts': {'":': 8, '<': 3, '<?xml version=': 0, '>': 3, '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': '3454775', 'n_tokens_mistral': 3884, 'n_tokens_neox': 3814, 'n_words': 1383}