<commit_before>
var mysql  = require('mysql');
var when   = require('when');
var Class  = require('cakes').Class;

var _      = require('../utils');
var errors = require('../errors');

/**
 * Mysql driver.
 * @type {Function}
 */
var Mysql = Class(function() {

    /**
     * instances of mysql conncetion
     * @type {Object}
     */
    var _instances = {};

    return {

        __construct: function(config) {
            config = config || {};
            this.config = {
                host:     config.host     || '127.0.0.1',
                port:     config.port     || 3306,
                database: config.database || 'test',
                user    : config.username || 'root',
                password: config.password || '',
                charset : config.charset  || 'utf8'
            }
        },

        connect: function() {
            if (!_.isset(this.identifier)) {
                this.identifier = _.serialize(this.config);
            }

            if (_instances[this.identifier]) {
                this.instance = _instances[this.identifier];

                if (!this.instance) {
                    delete this.identifier;
                    return this.connect();
                }

                return this.deferred.promise;
            }

            if (this.deferred) {
                this.deferred.reject(new errors.MysqlError('Connection had been close.'));
                this.deferred = null;
            }
            this.deferred = when.defer();

            var self = this;
            var conncetion = mysql.createConnection(this.config);

            this.instance = conncetion;

            // connect to mysql
            conncetion.connect(function(err) {
                if (err) {
                    self.close();
                    self.deferred.reject(err);
                }

                // connect success
                self.deferred.resolve();
            });

            conncetion.on('end', function() {
                self.close();
            });

            conncetion.on('error', function(err) {
                self.close();
            });

            return this.deferred.promise;
        },

        close: function() {
            function free(instance) {
                instance.destroy();
            }

            if (this.instance) {
                free(this.instance);
                this.instance = null;
            } else if (_instances[this.identifier]) {
                free(_instances[this.identifier]);
                _instances[this.identifier] = null;
                delete this.identifier;
            } else {<commit_msg>Add `query` method to /lib/drivers/mysql.js.<commit_after>
var mysql  = require('mysql');
var when   = require('when');
var Class  = require('cakes').Class;

var _      = require('../utils');
var errors = require('../errors');

/**
 * Mysql driver.
 * @type {Function}
 */
var Mysql = Class(function() {

    /**
     * instances of mysql conncetion
     * @type {Object}
     */
    var _instances = {};
    var MAX_RECONNECT_TIMES = 3;

    return {

        __construct: function(config) {
            this.reconnectTimes = 0;

            config = config || {};
            this.config = {
                host:     config.host     || '127.0.0.1',
                port:     config.port     || 3306,
                database: config.database || 'test',
                user    : config.username || 'root',
                password: config.password || '',
                charset : config.charset  || 'utf8'
            };
        },

        connect: function() {
            if (!_.isset(this.identifier)) {
                this.identifier = _.serialize(this.config);
            }

            if (_instances[this.identifier]) {
                this.instance = _instances[this.identifier];

                if (!this.instance) {
                    delete this.identifier;
                    return this.connect();
                }

                return this.deferred.promise;
            }

            if (this.deferred) {
                this.deferred.reject(new errors.MysqlError('Connection had been close.'));
                this.deferred = null;
            }
            this.deferred = when.defer();

            var self = this;
            var conncetion = mysql.createConnection(this.config);

            this.instance = conncetion;

            // connect to mysql
            conncetion.connect(function(err) {
                if (err) {
                    self.close();
                    self.deferred.reject(err);
                }

                // connect success
                self.deferred.resolve();
            });

            conncetion.on('end', function() {
                self.close();
            });

            conncetion.on('error', function(err) {
                self.close();
            });

            return this.deferred.promise;
        },

        query: function(sql) {
            var self = this;

            return this.connect().then(function() {
                var deferred = when.defer();

                self.instance.query(sql, function(err, result) {
                    if (err) {
                        // when query a large amount of data, it may be cause connection timeout, so we should do reconnect to database
                        if (err.code === 'PROTOCOL_CONNECTION_LOST' && self.reconnectTimes < MAX_RECONNECT_TIMES) {
                            self.close();
                            return self.query(sql);
                        }

                        deferred.reject(err);
                    }

                    self.reconnectTimes = 0;
                    deferred.resolve(result);
                });

                return deferred.promise;
            });
        },

        close: function() {
            function free(instance) {
                instance.destroy();
            }

            if (this.instance) {
                free(this.instance);
                this.instance = null;
            } else if (_instances[this.identifier]) {
                free(_instances[this.identifier]);
                _instances[this.identifier] = null;
                delete this.identifier;
            } else {
{'fraction_non_alphanumeric': 0.11771282542724805, 'fraction_numerical': 0.003992972368631209, 'mean_word_length': 1.212720848056537, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, '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': '5069944', 'n_tokens_mistral': 1654, 'n_tokens_neox': 1521, 'n_words': 314}