<commit_before>var logger = require('../../logger');
var Step = require('step');
var Storage = require('../../storage').Storage;
var util = require('util');

var mongo = require('mongodb');

var Db = mongo.Db;
var Server = mongo.Server;
var Collection = mongo.Collection;

var url = require('url');

var PlainBlock = require('../../schema/block').Block;
var PlainTransaction = require('../../schema/transaction').Transaction;

var MongoStorage = exports.MongoStorage = exports.Storage =
function MongoStorage(uri)
{
  var connInfo = url.parse(uri);
  var host = connInfo.host || 'localhost';
  var port = connInfo.port || 27017;
  var dbname = (connInfo.pathname || '/bitcoin').slice(1);

  var db = new Db(dbname, new Server(host, port, {}), {});
  var Binary = db.bson_serializer.Binary;

  var cBlock;
  var cTransaction;

  function serializeBlock(block) {
    var data = {
      _id: new Binary(block.getHash()),
      prev_hash: new Binary(block.prev_hash),
      merkle_root: new Binary(block.merkle_root),
      timestamp: block.timestamp,
      bits: block.bits,
      nonce: block.nonce,
      version: block.version,
      height: block.height,
      size: block.size,
      active: block.active,
      chainWork: new Binary(block.chainWork),
      txs: block.txs.map(function (hash) {
        return new Binary(hash);
      })
    };

    return data;
  };

  function deserializeBlock(data) {
    data.hash = data._id.buffer;
    data.prev_hash = data.prev_hash.buffer;
    data.merkle_root = data.merkle_root.buffer;
    data.chainWork = data.chainWork.buffer;
    data.txs = data.txs.forEach(function (tx) {
      return tx.buffer;
    });
    return new PlainBlock(data);
  };

  function serializeTransaction(tx) {
    var data = {
      _id: new Binary(tx.getHash()),
      version: tx.version,
      ins: tx.ins.map(function (txin) {
        return {
          s: new Binary(txin.s),
          q: txin.q,
          o: new Binary(txin.o)
        };
      }),
      outs: tx.outs.map(function (txout) {
        return {
          v: new Binary(txout.v),
          s: new Binary(txout.s)
        };
      }),
      lock_time: tx.lock_time
    };

    if (tx.affects) {
      data.affects = tx.affects.map(function (hash) {
        return new Binary(hash);
      });
    }

    return data;
  };

  function deserializeTransaction(data) {
    data.hash = data._id.buffer;
    data.ins = data.ins ? data.ins.map(function (txin) {
      txin.s = txin.s.buffer;
      txin.o = txin.o.buffer;
      return txin;
    }) : [];
    data.outs = data.outs ? data.outs.map(function (txout) {
      txout.v = txout.v.buffer;
      txout.s = txout.s.buffer;
      return txout;
    }) : [];

    if (data.affects) {
      data.affects = data.affects.map(function (hash) {
        return hash.buffer;
      });
    }

    return new PlainTransaction(data);
  };

  var connected = false;
  this.connect = function (callback) {
    // Only run if not yet connected
    if (connected) {
      callback(null);
      return;
    }
    connected = true;

    Step(
      function openDatabaseStep() {
        db.open(this);
      },
      function createCollectionsStep(err) {
        if (err) throw err;
        cBlock = new Collection(db, 'blocks');
        cTransaction = new Collection(db, 'transactions');
        this(null);
      },
      callback
    );
  };

  this.emptyDatabase = function (callback) {
    logger.info('Resetting database');
    Step(
      function dropBlocks() {
        cBlock.drop(this);
      },
      function dropTransactions(err) {
        if (err && err.message !== "ns not found") throw err;

        cTransaction.drop(this);
      },
      function finish(err) {
        if ("function" === typeof callback) {
          if (err && err.message !== "ns not found") {
            callback(err);
          } else {
            callback(null);
          }
        }
      }
    );
  };

  this.dropDatabase = function (callback) {
    logger.info('Deleting database');<commit_msg>Re-add MongoDB indexes.<commit_after>var logger = require('../../logger');
var Step = require('step');
var Storage = require('../../storage').Storage;
var util = require('util');

var mongo = require('mongodb');

var Db = mongo.Db;
var Server = mongo.Server;
var Collection = mongo.Collection;

var url = require('url');

var PlainBlock = require('../../schema/block').Block;
var PlainTransaction = require('../../schema/transaction').Transaction;

var MongoStorage = exports.MongoStorage = exports.Storage =
function MongoStorage(uri)
{
  var connInfo = url.parse(uri);
  var host = connInfo.host || 'localhost';
  var port = connInfo.port || 27017;
  var dbname = (connInfo.pathname || '/bitcoin').slice(1);

  var db = new Db(dbname, new Server(host, port, {}), {});
  var Binary = db.bson_serializer.Binary;

  var cBlock;
  var cTransaction;

  function serializeBlock(block) {
    var data = {
      _id: new Binary(block.getHash()),
      prev_hash: new Binary(block.prev_hash),
      merkle_root: new Binary(block.merkle_root),
      timestamp: block.timestamp,
      bits: block.bits,
      nonce: block.nonce,
      version: block.version,
      height: block.height,
      size: block.size,
      active: block.active,
      chainWork: new Binary(block.chainWork),
      txs: block.txs.map(function (hash) {
        return new Binary(hash);
      })
    };

    return data;
  };

  function deserializeBlock(data) {
    data.hash = data._id.buffer;
    data.prev_hash = data.prev_hash.buffer;
    data.merkle_root = data.merkle_root.buffer;
    data.chainWork = data.chainWork.buffer;
    data.txs = data.txs.forEach(function (tx) {
      return tx.buffer;
    });
    return new PlainBlock(data);
  };

  function serializeTransaction(tx) {
    var data = {
      _id: new Binary(tx.getHash()),
      version: tx.version,
      ins: tx.ins.map(function (txin) {
        return {
          s: new Binary(txin.s),
          q: txin.q,
          o: new Binary(txin.o)
        };
      }),
      outs: tx.outs.map(function (txout) {
        return {
          v: new Binary(txout.v),
          s: new Binary(txout.s)
        };
      }),
      lock_time: tx.lock_time
    };

    if (tx.affects) {
      data.affects = tx.affects.map(function (hash) {
        return new Binary(hash);
      });
    }

    return data;
  };

  function deserializeTransaction(data) {
    data.hash = data._id.buffer;
    data.ins = data.ins ? data.ins.map(function (txin) {
      txin.s = txin.s.buffer;
      txin.o = txin.o.buffer;
      return txin;
    }) : [];
    data.outs = data.outs ? data.outs.map(function (txout) {
      txout.v = txout.v.buffer;
      txout.s = txout.s.buffer;
      return txout;
    }) : [];

    if (data.affects) {
      data.affects = data.affects.map(function (hash) {
        return hash.buffer;
      });
    }

    return new PlainTransaction(data);
  };

  var connected = false;
  this.connect = function (callback) {
    // Only run if not yet connected
    if (connected) {
      callback(null);
      return;
    }
    connected = true;

    Step(
      function openDatabaseStep() {
        db.open(this);
      },
      function createCollectionsStep(err) {
        if (err) throw err;
        cBlock = new Collection(db, 'blocks');
        cTransaction = new Collection(db, 'transactions');

        this(null);
      },
      function createPrevIndexStep(err) {
        if (err) throw err;
        cBlock.ensureIndex('prev_hash', this);
      },
      function createHeightIndexStep(err) {
        if (err) throw err;
        cBlock.ensureIndex('height', this);
      },
      function createTxsIndexStep(err) {
        if (err) throw err;
        cBlock.ensureIndex('txs', this);
      },
      function createAffectsIndexStep(err) {
        if (err) throw err;
        cTransaction.ensureIndex('affects', this);
      },
      function createOutpointIndexStep(err) {
        if (err) throw err;
        cTransaction.ensureIndex({"ins.o": 1}, this);
      },
      callback
    );
  };

  this.emptyDatabase = function (callback) {
    logger.info('Resetting database');
    Step(
      function dropBlocks() {
        cBlock.remove({}, this);
      },
      function dropTransactions(err) {
        if (err && err.message !== "ns not found") throw err;

        cTransaction.remove({}, this);
      },
      function finish(err) {
        if ("function" === typeof callback) {
          if (err && err.message !== "ns not found") {
            callback(err);
          } else {
            callback(null);
          }
        }
      }
    );
  };

  this.dropDatabase = function (callback) {
    logger.info('Deleting database');
{'fraction_non_alphanumeric': 0.14203432784241446, 'fraction_numerical': 0.0014975233268056676, 'mean_word_length': 2.262683201803833, 'pattern_counts': {'":': 1, '<': 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': '4502041', 'n_tokens_mistral': 2813, 'n_tokens_neox': 2734, 'n_words': 602}