<commit_before>#!/usr/bin/env node

var transactions = module.exports = {};

/**
 * transactions.createTransaction:
 * @client: a postgres client to use
 * @transactionCallback: a callback to invoked for the transaction
 * @finalCallback: the callback to indicate the result state of the transaction
 *
 * Create a transaction and get ready to execute it.
 */
transactions.queueTransaction = function queueTransaction (client, transactionCallback, finalCallback) {
    var queries = [];
    var transaction = {};

    transaction.executeSql = function executeSql () {
        switch (arguments.length) {
        case 1: // executeSql(statement)
            return queries.push({
                statement: arguments[0],
                parameters: [],
                callback: null
            });
        case 2:
            switch (typeof arguments[1]) {
            case 'function': // executeSql(statement, callback)
                return queries.push({
                    statement: arguments[0],
                    parameters: [],
                    callback: arguments[1]
                });
            case 'object': // executeSql(statement, parameters)
                return queries.push({
                    statement: arguments[0],
                    parameters: arguments[1],
                    callback: null
                });
                break;
            default:
                throw new Error('executeSql() does not accept a second argument of type ' + typeof arguments[1]);
            }
        case 3: // executeSql(statement, parameters, callback)
            return queries.push({
                statement: arguments[0],
                parameters: arguments[1],
                callback: arguments[2]
            });
        default:
            throw new Error('executeSql() cannot be invoked with ' + arguments.length + ' argument(s).');
        }
    };

    var checkEndOfTransaction = function () {
        if (queries.length < 1) {
            return client.query("COMMIT TRANSACTION", function (error, result) {
                if (error) {
                    console.log('FIXME: document internError: ' + require('util').inspect(error));
                    throw error;
                }

                if (finalCallback) {
                    finalCallback(null);
                }
            });
        }

        var query = queries.shift();

        client.query(query.statement, query.parameters, function (error, resultSet) {
            if (error) {
                return client.query("ROLLBACK TRANSACTION", function (internError, resultSet) {
                    if (internError) {
                        console.log('FIXME: document internError: ' + require('util').inspect(internError));
                    }

                    try {
                        if (query.callback) {
                            query.callback(error, null);
                        }
                        return finalCallback(error);
                    } catch (exception) {
                        return finalCallback(exception);
                    }
                });
            }

            if (typeof query.callback === 'function') {
                query.callback(null, resultSet);
            }

            checkEndOfTransaction();
        });
    };

    client.query("BEGIN TRANSACTION", function (error, result) {
        if (error) {
            return finalCallback(error);
        }

        try {
            transactionCallback(transaction);
        } catch (exception) {
            transaction = null;
            queries = null;
            return finalCallback(exception);
        }

        checkEndOfTransaction();
    });
};

// FIXME: add unit tests here

/* vim:set sw=4 et: */<commit_msg>make sure we roll back on more exceptions<commit_after>#!/usr/bin/env node

var transactions = module.exports = {};

/**
 * transactions.createTransaction:
 * @client: a postgres client to use
 * @transactionCallback: a callback to invoked for the transaction
 * @finalCallback: the callback to indicate the result state of the transaction
 *
 * Create a transaction and get ready to execute it.
 */
transactions.queueTransaction = function queueTransaction (client, transactionCallback, finalCallback) {
    var queries = [];
    var transaction = {};

    transaction.executeSql = function executeSql () {
        switch (arguments.length) {
        case 1: // executeSql(statement)
            return queries.push({
                statement: arguments[0],
                parameters: [],
                callback: null
            });
        case 2:
            switch (typeof arguments[1]) {
            case 'function': // executeSql(statement, callback)
                return queries.push({
                    statement: arguments[0],
                    parameters: [],
                    callback: arguments[1]
                });
            case 'object': // executeSql(statement, parameters)
                return queries.push({
                    statement: arguments[0],
                    parameters: arguments[1],
                    callback: null
                });
                break;
            default:
                throw new Error('executeSql() does not accept a second argument of type ' + typeof arguments[1]);
            }
        case 3: // executeSql(statement, parameters, callback)
            return queries.push({
                statement: arguments[0],
                parameters: arguments[1],
                callback: arguments[2]
            });
        default:
            throw new Error('executeSql() cannot be invoked with ' + arguments.length + ' argument(s).');
        }
    };

    var checkEndOfTransaction = function () {
        if (queries.length < 1) {
            return client.query("COMMIT TRANSACTION", function (error, result) {
                if (error) {
                    console.log('FIXME: document internError: ' + require('util').inspect(error));
                    throw error;
                }

                if (finalCallback) {
                    finalCallback(null);
                }
            });
        }

        var query = queries.shift();

        client.query(query.statement, query.parameters, function (error, resultSet) {
            var rollback = function (callback) {
                client.query("ROLLBACK TRANSACTION", function (internError, resultSet) {
                    if (internError) {
                        console.log('FIXME: document internError: ' + require('util').inspect(internError));
                    }

                    callback();
                });
            };

            if (error) {
                return rollback(function () {
                    try {
                        if (query.callback) {
                            query.callback(error, null);
                        }
                        finalCallback(error);
                    } catch (exception) {
                        finalCallback(exception);
                    }
                });
            }

            if (typeof query.callback === 'function') {
                try {
                    query.callback(null, resultSet);
                } catch (exception) {
                    return rollback(function () {
                        finalCallback(exception);
                    });
                }
            }

            checkEndOfTransaction();
        });
    };

    client.query("BEGIN TRANSACTION", function (error, result) {
        if (error) {
            return finalCallback(error);
        }

        try {
            transactionCallback(transaction);
        } catch (exception) {
            transaction = null;
            queries = null;
            return finalCallback(exception);
        }

        checkEndOfTransaction();
    });
};

// FIXME: add unit tests here

/* FIXME: make sure this test works
 * var exception = new Error("this is a test exception " + Math.random());
 * tx.queueTransaction(client, function (transaction) {
 *     throw exception;
 * }, function (error) {
 *     if (error !== exception) {
 *         throw new Error('The test failed.');
 *     }
 * });
 */

/* FIXME: make sure this test works
 * var exception = new Error("this is a test exception " + Math.random());
 * tx.queueTransaction(client, function (transaction) {
 *     transaction.executeSql('SELECT now() as "date"', function (error, resultSet) {
 *         throw exception;
 *     });
 * }, function (error) {
 *     if (error !== exception) {
 *         throw new Error('The test failed.');
 *     }
 * });
 */

/* FIXME: make sure this test throws an exception
 * tx.queueTransaction(client, function (transaction) {
 *     process.nextTick(function () {
 *         transaction.executeSql('SELECT now() AS "date"');
 *     });
 * }, function (error) {
 *     if (error) throw error;
 * });
 */

/* vim:set sw=4 et: */
{'fraction_non_alphanumeric': 0.10805676611911945, 'fraction_numerical': 0.003352329869259135, 'mean_word_length': 1.5027964205816555, 'pattern_counts': {'":': 0, '<': 5, '<?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': '6280323', 'n_tokens_mistral': 2123, 'n_tokens_neox': 2005, 'n_words': 552}