lib/persistence.js

/**
 * @file Persistence layer
 * @author Antonio Olmo Titos <a@olmo-titos.info>
 * @exports lib/persistence
 */

// Configuration:
const CONFIG = require('../config');

// External packages:
const PROCESS = require('process'),
    SQLITE = require('sqlite3');

// Internal packages:
const LOGGING = require('./logging'),
    UTIL = require('./util');

// Variables:
var connection;

/**
 * Terminate the DB connection (gracefully)
 */

const wrapUp = function() {
    connection.close();
    LOGGING.info(`connection to DB file closed`);
    PROCESS.exit();
};

/**
 * Run a query and retrieve a set of rows from the DB
 * @param {String} query - the SQL query
 * @param {String} params - (optional; variable length) values to interpolate in the query
 * @returns {Array} the resulting rows
 */

const retrieveRows = function(query, ...params) {
    return new Promise(function(resolve, reject) {
        connection.all(query, params, function(err, rows) {
            if (err)
                reject(err);
            else
                resolve(rows);
        });
    });
};

/**
 * Set up persistence
 */

const setUp = function() {
    if (connection)
        LOGGING.warn(`“persistence.setUp()” called more than once`);
    else {
        if (CONFIG.debug)
            SQLITE.verbose();
        // @TODO: handle issues.
        connection = new SQLITE.Database(CONFIG.db, SQLITE.OPEN_READWRITE);
        connection.exec('PRAGMA foreign_keys = ON;');
        LOGGING.info(`persistence linked to file “${CONFIG.db}”`);
        PROCESS.on('SIGINT', wrapUp);
        // Export more stuff:
        exports.TYPE_PERSON = 'people';
        exports.TYPE_MEETING = 'meetings';
        exports.TYPE_LOCATION = 'locations';
        // exports.createEntity = createEntity;
        exports.listEntities = listEntities;
        exports.findEntity = findEntity;
    }
};

// const createEntity = function(type) {
//     return new Promise(function(resolve, reject) {
//         if (exports.TYPE_PERSON === type)
//             retrieveRows(`INSERT INTO ${type} VALUES;`).then(function(rows) {
//                 resolve(rows);
//             }).catch(function(err) {
//                 LOGGING.debug(`“persistence.listEntities()” error: ${err}`);
//                 reject(err);
//             });
//         else if (exports.TYPE_MEETING === type)
//             ;
//         else if (exports.TYPE_LOCATION === type)
//             ;
//         else
//             reject();
//     });
// };

/**
 * Return all entities of a given type
 * @param {String} type - type; use constants of the form <code>persistence.TYPE_*</code>
 * @returns {Array} all entities of that type
 */

const listEntities = function(type) {
    return new Promise(function(resolve, reject) {
        if (exports.TYPE_PERSON === type || exports.TYPE_MEETING === type || exports.TYPE_LOCATION === type) {
            retrieveRows(`SELECT * FROM ${type} ORDER BY name;`).then(function(rows) {
                UTIL.processData(rows);
                resolve(rows);
            }).catch(function(err) {
                LOGGING.warn(`“persistence.listEntities()” error: ${err}`);
                reject(err);
            });
        } else
            reject();
    });
};

/**
 * Return all entities with a given ID (should be unique)
 * @param {String} id - name of the desired ID
 * @returns {Promise} found entities
 */

const findEntity = function(id) {
    LOGGING.dir(id);
    return new Promise(function(resolve, reject) {
        const normalisedID = UTIL.normaliseID(id);
        if (normalisedID) {
            const queries = [
                retrieveRows(`SELECT * FROM people WHERE name LIKE ?;`, id),
                retrieveRows(`SELECT * FROM meetings WHERE name LIKE ?;`, id),
                retrieveRows(`SELECT * FROM locations WHERE name LIKE ?;`, id)
            ];
            const result = Promise.all(queries);
            result.then(function(rows) {
                const people = rows[0],
                    meetings = rows[1],
                    locations = rows[2];
                if (1 === people.length && 0 === meetings.length && 0 === locations.length)
                    resolve({type: exports.TYPE_PERSON, data: people[0]});
                else if (0 === people.length && 1 === meetings.length && 0 === locations.length)
                    resolve({type: exports.TYPE_MEETING, data: meetings[0]});
                else if (0 === people.length && 0 === meetings.length && 1 === locations.length)
                    resolve({type: exports.TYPE_LOCATION, data: locations[0]});
                else if (people.length + meetings.length + locations.length > 1)
                    reject('more than one entity');
                else
                    reject('foo');
            });
            result.catch(function(err) {
                reject(`“persistence.findEntity()” error: ${err}`);
            });
        } else
            reject('wrong');
    });
};

// Export stuff:
exports.setUp = setUp;