<commit_before>var async = require('async');
var assert = require('assert');
var Promise = require('bluebird');
var knex = require('knex');
var ripple = require('ripple-lib');
var validator = require('./schema-validator');
var config = require('./config-loader.js');
var logger = require('./logger.js').logger;

/**
 * @constructor DatabaseInterface
 * @param {String} filePath
 */

function DatabaseInterface(filePath) {
  assert.strictEqual(typeof filePath, 'string', 'Invalid database path');

  this.initialized = false;
  this.filePath = filePath;

  this.db = knex({
    dialect: 'sqlite3',
    connection: {
      filename: filePath
    },
    pool: {
      refreshIdle: false
    }
  });

  /**
   * Dirty hack to make in-memory sqlite work
   * 10/07/2014
   * @geertweening
   *
   * problem: knex would lose its sqlite3 database connection after 30 secs
   * which would cause sqlite3 to remove the in-memory database and create
   * a new fresh one once a new connection was established
   *
   * reason: knex uses generic-pool-redux package as its pool manager
   * which has a default timeout of 30secs. It can keep a pool of 1 connection
   * and not refresh idles, but there's a bug in the option logic that won't
   * allow a pool with min and max set to 1
   *
   * solution: have generic-pool-redux fix this logic
   * for now we'll keep this dirty hack and pin the knex version
   *
   * knex: 0.7.3
   * generic-pool-redux: 0.1.0
   */
  this.db.client.pool.genericPool.min = 1;

  this.init();
};

const DI = DatabaseInterface.prototype;

DI.__proto__ = process.EventEmitter.prototype;

/**
 * Initialize database tables
 *
 * @param [Function] callback
 * @return {Promise}
 */

DI.init = function(callback) {
  var self = this;

  if (this.initialized) {
    logger.info('[DB] Warning: Re-initializing');
  }

  // Create transaction_history table if it does not already exist
  var promise = self.db.schema
  .hasTable('transaction_history')
  .then(function(exists) {
    if (!exists) {
      return self.db.schema
      .createTable('transaction_history', function(table) {
        table.text('source_account').notNullable();
        table.text('type').notNullable();
        table.text('client_resource_id').primary().notNullable();
        table.text('hash').unique().notNullable();
        table.text('submitted_hashes').notNullable();
        table.integer('ledger').notNullable();
        table.text('state').notNullable();
        table.boolean('finalized').notNullable();
        table.text('rippled_result').nullable();
      });
    }
  })
  .then(function(res) {
    self.initialized = true;
    self.emit('ready');

    logger.info('[DB] Initialized: ' + self.filePath);

    (callback || new Function)(null, res);

    return res;
  })
  .caught(function(err) {
    logger.info('[DB] Error. Failed to initialize database:' + err);

    (callback || new Function)(err);
  });

  return promise;
};

/**
 * Clear the database. For testing
 *
 * @param [Function] callback
 * @return {Promise}
 */

DI.clear = function(callback) {
  var self = this;

  var promise = self.db.schema
  .dropTableIfExists('transaction_history')
  .then(function(res) {
    (callback || new Function)(null, res);

    return res;
  })
  .caught(function(err) {
    (callback || new Function)(err);
  });

  return promise;
};

/**
 * Save transaction to temporary table. If new validated transactions
 * are detected, move them to permanent table
 *
 * @param {Object} transaction
 * @param [Function] callback
 * @return {Promise}
 */

DI.saveTransaction = function(transaction, callback) {
  assert.strictEqual(typeof transaction, 'object');
  assert(transaction.state, 'Transaction missing property: state');
  assert(transaction.tx_json, 'Transaction missing property: tx_json');
  assert(transaction.tx_json.TransactionType,
         'Transaction missing property: tx_json.TransactionType');
  assert(transaction.tx_json.Account,
         'Transaction missing property: tx_json.Account');
  //assert(transaction.clientID, 'Transaction missing property: clientID');
  assert(transaction.submitIndex,
         'Transaction missing property: submitIndex');
  assert(transaction.submittedIDs,
         'Transaction missing property: submittedIDs');

  var self = this;

  if (!transaction.result) {<commit_msg>[FIX] prevent crash on failed asserts<commit_after>var async = require('async');
var assert = require('assert');
var Promise = require('bluebird');
var knex = require('knex');
var ripple = require('ripple-lib');
var validator = require('./schema-validator');
var config = require('./config-loader.js');
var logger = require('./logger.js').logger;

/**
 * @constructor DatabaseInterface
 * @param {String} filePath
 */

function DatabaseInterface(filePath) {
  assert.strictEqual(typeof filePath, 'string', 'Invalid database path');

  this.initialized = false;
  this.filePath = filePath;

  this.db = knex({
    dialect: 'sqlite3',
    connection: {
      filename: filePath
    },
    pool: {
      refreshIdle: false
    }
  });

  /**
   * Dirty hack to make in-memory sqlite work
   * 10/07/2014
   * @geertweening
   *
   * problem: knex would lose its sqlite3 database connection after 30 secs
   * which would cause sqlite3 to remove the in-memory database and create
   * a new fresh one once a new connection was established
   *
   * reason: knex uses generic-pool-redux package as its pool manager
   * which has a default timeout of 30secs. It can keep a pool of 1 connection
   * and not refresh idles, but there's a bug in the option logic that won't
   * allow a pool with min and max set to 1
   *
   * solution: have generic-pool-redux fix this logic
   * for now we'll keep this dirty hack and pin the knex version
   *
   * knex: 0.7.3
   * generic-pool-redux: 0.1.0
   */
  this.db.client.pool.genericPool.min = 1;

  this.init();
};

const DI = DatabaseInterface.prototype;

DI.__proto__ = process.EventEmitter.prototype;

/**
 * Initialize database tables
 *
 * @param [Function] callback
 * @return {Promise}
 */

DI.init = function(callback) {
  var self = this;

  if (this.initialized) {
    logger.info('[DB] Warning: Re-initializing');
  }

  // Create transaction_history table if it does not already exist
  var promise = self.db.schema
  .hasTable('transaction_history')
  .then(function(exists) {
    if (!exists) {
      return self.db.schema
      .createTable('transaction_history', function(table) {
        table.text('source_account').notNullable();
        table.text('type').notNullable();
        table.text('client_resource_id').primary().notNullable();
        table.text('hash').unique().notNullable();
        table.text('submitted_hashes').notNullable();
        table.integer('ledger').notNullable();
        table.text('state').notNullable();
        table.boolean('finalized').notNullable();
        table.text('rippled_result').nullable();
      });
    }
  })
  .then(function(res) {
    self.initialized = true;
    self.emit('ready');

    logger.info('[DB] Initialized: ' + self.filePath);

    (callback || new Function)(null, res);

    return res;
  })
  .caught(function(err) {
    logger.info('[DB] Error. Failed to initialize database:' + err);

    (callback || new Function)(err);
  });

  return promise;
};

/**
 * Clear the database. For testing
 *
 * @param [Function] callback
 * @return {Promise}
 */

DI.clear = function(callback) {
  var self = this;

  var promise = self.db.schema
  .dropTableIfExists('transaction_history')
  .then(function(res) {
    (callback || new Function)(null, res);

    return res;
  })
  .caught(function(err) {
    (callback || new Function)(err);
  });

  return promise;
};

/**
 * Save transaction to temporary table. If new validated transactions
 * are detected, move them to permanent table
 *
 * @param {Object} transaction
 * @param [Function] callback
 * @return {Promise}
 */

DI.saveTransaction = function(transaction, callback) {

  try {
    assert.strictEqual(typeof transaction, 'object');
    assert(transaction.state, 'Transaction missing property: state');
    assert(transaction.tx_json, 'Transaction missing property: tx_json');
    assert(transaction.tx_json.TransactionType,
      'Transaction missing property: tx_json.TransactionType');
    assert(transaction.tx_json.Account,
      'Transaction missing property: tx_json.Account');
    //assert(transaction.clientID, 'Transaction missing property: clientID');
    assert(transaction.submitIndex,
      'Transaction missing property: submitIndex');
    assert(transaction.submittedIDs,
      'Transaction missing property: submittedIDs');
  } catch(err) {
    return console.log('[DB] Save transaction error. ' + err);
  }

  var self = this;

  if (!transaction.result) {
{'fraction_non_alphanumeric': 0.1331054131054131, 'fraction_numerical': 0.00547008547008547, 'mean_word_length': 3.507447354904982, 'pattern_counts': {'":': 0, '<': 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': '7206066', 'n_tokens_mistral': 2603, 'n_tokens_neox': 2531, 'n_words': 703}