<commit_before>//
// DynamoDB wrapper
//
var _ = require('lodash');
var async = require('async');
var aws = require('aws-sdk');
var errors = require('./errors');

function keyName(obj) {
  return Object.getOwnPropertyNames(obj)[0];
}

function keyValue(obj) {
  return obj[keyName(obj)];
}

var Table = function(name) {
  this.name = name;
  this.dynamo = new aws.DynamoDB.DocumentClient();
};

/**
 * Lists items with a given hash key and optional range of range keys.
 *
 * Params:
 *   Key: the hash key for items to list (required)
 *   MinRangeKey: the minimum range key to return, inclusive
 *   MaxRangeKey: the maximum range key to return, inclusive
 *   Limit: maximum items to return
 */
Table.prototype.list = function(params, callback) {
  var expression = '#hashKey=:hashKey';
  var attributeNames = { '#hashKey': keyName(params.Key) };
  var attributeValues = { ':hashKey': keyValue(params.Key) };
  if (params.MinRangeKey && params.MaxRangeKey) {
    expression += ' AND #rangeKey BETWEEN :minRangeKey AND :maxRangeKey';
    attributeNames['#rangeKey'] = keyName(params.MinRangeKey);
    attributeValues[':minRangeKey'] = keyValue(params.MinRangeKey);
    attributeValues[':maxRangeKey'] = keyValue(params.MaxRangeKey);
  } else if (params.minRangeKey) {
    expression += ' AND #rangeKey>=:minRangeKey';
    attributeNames['#rangeKey'] = keyName(params.MinRangeKey);
    attributeValues[':minRangeKey'] = keyValue(params.MinRangeKey);
  } else if (params.maxRangeKey) {
    expression += ' AND #rangeKey<=:maxRangeKey';
    attributeNames['#rangeKey'] = keyName(params.MaxRangeKey);
    attributeValues[':maxRangeKey'] = keyValue(params.MaxRangeKey);
  }

  this.dynamo.query({
    TableName: this.name,
    KeyConditionExpression: expression,
    ExpressionAttributeNames: attributeNames,
    ExpressionAttributeValues: attributeValues,
    ConsistentRead: true,
    ScanIndexForward: true,
    Limit: params.Limit || 100,
  }, function(err, result) {
    callback(err, err ? undefined : result.Items || []);
  });
};

/**
 * Returns the item for a single key from the table.
 *
 * Params:
 *   Key: the key to use for the lookup (can contain both a hash key and range key)
 *   AllowMissing: if true, succeeds with null if the item is not found; if false (default),
 *     fails with a not found error.
 */
Table.prototype.get = function(params, callback) {
  this.dynamo.get({
    TableName: this.name,
    Key: params.Key
  }, function(err, result) {
    if (err) {
      callback(err);
    } else if (!result.Item && !params.AllowMissing) {
      callback(errors.notFound());
    } else {
      callback(null, result.Item ? result.Item : null);
    }
  });
};

/**
 * Returns items for multiple keys. This is limited to 100 keys at a time due to DynamoDB limits.
 *
 * Params:<commit_msg>added ability to pass in IndexName to list. Also made ConsistentRead and ScanIndexForward configurable<commit_after>//
// DynamoDB wrapper
//
var _ = require('lodash');
var async = require('async');
var aws = require('aws-sdk');
var errors = require('./errors');

function keyName(obj) {
  return Object.getOwnPropertyNames(obj)[0];
}

function keyValue(obj) {
  return obj[keyName(obj)];
}

var Table = function(name) {
  this.name = name;
  this.dynamo = new aws.DynamoDB.DocumentClient();
};

/**
 * Lists items with a given hash key and optional range of range keys.
 *
 * Params:
 *   Key: the hash key for items to list (required)
 *   MinRangeKey: the minimum range key to return, inclusive
 *   MaxRangeKey: the maximum range key to return, inclusive
 *   Limit: maximum items to return
 *   ScanIndexForward: if false, will return results in descending order. If true (default),
 *     it will return results in ascending order
 *   ConsistentRead: if false, the operation will use eventually consistent reads. If true (default),
 *     the operation will use strongly consistent reads
 *   IndexName: The name of an index to query. This index can be any local secondary index or 
 *     global secondary index on the table.
 */
Table.prototype.list = function(params, callback) {
  var expression = '#hashKey=:hashKey';
  var attributeNames = { '#hashKey': keyName(params.Key) };
  var attributeValues = { ':hashKey': keyValue(params.Key) };
  var scanIndexForward = true;
  var consistentRead = true;
  if (params.MinRangeKey && params.MaxRangeKey) {
    expression += ' AND #rangeKey BETWEEN :minRangeKey AND :maxRangeKey';
    attributeNames['#rangeKey'] = keyName(params.MinRangeKey);
    attributeValues[':minRangeKey'] = keyValue(params.MinRangeKey);
    attributeValues[':maxRangeKey'] = keyValue(params.MaxRangeKey);
  } else if (params.MinRangeKey) {
    expression += ' AND #rangeKey>=:minRangeKey';
    attributeNames['#rangeKey'] = keyName(params.MinRangeKey);
    attributeValues[':minRangeKey'] = keyValue(params.MinRangeKey);
  } else if (params.MaxRangeKey) {
    expression += ' AND #rangeKey<=:maxRangeKey';
    attributeNames['#rangeKey'] = keyName(params.MaxRangeKey);
    attributeValues[':maxRangeKey'] = keyValue(params.MaxRangeKey);
  }
  if (params.ScanIndexForward !== undefined) {
    scanIndexForward = params.ScanIndexForward;
  };
  if (params.ConsistentRead !== undefined) {
    consistentRead = params.ConsistentRead;
  };
  var queryParams = {
    TableName: this.name,
    KeyConditionExpression: expression,
    ExpressionAttributeNames: attributeNames,
    ExpressionAttributeValues: attributeValues,
    ConsistentRead: consistentRead,
    ScanIndexForward: scanIndexForward,
    Limit: params.Limit || 100,
  };
  if (params.IndexName) {
    queryParams.IndexName = params.IndexName;
    delete queryParams.ConsistentRead;
  };
  this.dynamo.query(queryParams, function(err, result) {
    callback(err, err ? undefined : result.Items || []);
  });
};

/**
 * Returns the item for a single key from the table.
 *
 * Params:
 *   Key: the key to use for the lookup (can contain both a hash key and range key)
 *   AllowMissing: if true, succeeds with null if the item is not found; if false (default),
 *     fails with a not found error.
 */
Table.prototype.get = function(params, callback) {
  this.dynamo.get({
    TableName: this.name,
    Key: params.Key
  }, function(err, result) {
    if (err) {
      callback(err);
    } else if (!result.Item && !params.AllowMissing) {
      callback(errors.notFound());
    } else {
      callback(null, result.Item ? result.Item : null);
    }
  });
};

/**
 * Returns items for multiple keys. This is limited to 100 keys at a time due to DynamoDB limits.
 *
 * Params:
{'fraction_non_alphanumeric': 0.12511415525114156, 'fraction_numerical': 0.00213089802130898, 'mean_word_length': 3.9331831831831834, 'pattern_counts': {'":': 0, '<': 5, '<?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': '6771942', 'n_tokens_mistral': 1988, 'n_tokens_neox': 1956, 'n_words': 572}