UNPKG

fully-api

Version:

API framework for Fully Stacked, LLC REST-ful APIs

1,058 lines 45.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataAccess = void 0; // ================================================================================ // dataAccess.js // // DataAccess is responsible for reading from and writing to the database. // // ================================================================================ const { Pool, Client } = require('pg'); const Q = require('q'); const async = require('async'); const pg_query_stream_1 = __importDefault(require("pg-query-stream")); const fs_1 = __importDefault(require("fs")); const stream_1 = require("stream"); const ErrorObj_1 = require("./ErrorObj"); const path_1 = __importDefault(require("path")); // Import path to control our folder structure const rootDir = path_1.default.dirname(require.main.filename); // =============================================================================== // UTILITY FUNCTIONS // =============================================================================== var utilities; var models; var extension; var settings; var config; let DataAccessExtension; var ext_path = rootDir + '/dataAccess_ext.js'; var default_path = '../dataAccess_ext.js'; if (fs_1.default.existsSync(ext_path)) { try { DataAccessExtension = require(ext_path).DataAccessExtension; } catch (e) { // tslint:disable-next-line:no-console console.log('Error loading data Access extension. Falling back to default file.', e); DataAccessExtension = require(default_path).DataAccessExtension; } } else { var ext_path = rootDir + '/services/dataAccess_ext.js'; if (fs_1.default.existsSync(ext_path)) { try { DataAccessExtension = require(ext_path).DataAccessExtension; } catch (e) { // tslint:disable-next-line:no-console console.log('Error loading data Access extension. Falling back to default file.', e); DataAccessExtension = require(default_path).DataAccessExtension; } } else { try { console.log('No custom dataAccess_ext file located. Falling back to default file.'); DataAccessExtension = require(default_path).DataAccessExtension; } catch (e) { // tslint:disable-next-line:no-console console.error('Failed to load default dataAccess extension', e); } } } // ================================================================================ // CONSTRUCTOR // ------------------------------------------------------------------ // Create the class, setup pg, initialize the extension // ------------------------------------------------------------------ let pool; class DataAccess { constructor(config, mdls, util, settings) { utilities = util; models = mdls; settings = settings; config = config; extension = new DataAccessExtension(this, config, mdls, settings); pool = new Pool({ // INSTANTIATE THE PG pool CONSTANT user: config.db.user, host: config.db.host, database: config.db.name, password: config.db.pass, port: config.db.port, max: config.db.max_connections || 1000, ssl: { rejectUnauthorized: true, ca: fs_1.default.readFileSync('aws-global-bundle.pem').toString(), }, }); this.initializePGLibraries(); this.setExtension(); } setExtension() { DataAccess.prototype.extension = new DataAccessExtension(this, config, models, settings); } // THIS FUNCTION IS USED SO ONE FUNCTION CAN RESOLVE THE CURRENT CONNECTION STATE AND RETURN A CONNECTION initializePGLibraries(connection, callback) { DataAccess.prototype .executePostgresQuery('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"', [], connection) .then((res) => { }) .fail((err) => { console.log('err', err); console.log('failed to initialize postgres extensions'); }); } // THIS FUNCTION IS USED SO ONE FUNCTION CAN RESOLVE THE CURRENT CONNECTION STATE AND RETURN A CONNECTION resolveDbConnection(connection, callback) { const deferred = Q.defer(); if (connection == null || connection == undefined) { DataAccess.prototype .getDbConnection() .then(function (db_connection) { deferred.resolve(db_connection); }) .fail(function (err) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0500', __filename, 'resolveDbConnection', 'error creating a connection to postgres', 'Database error', err); deferred.reject(errorObj); }); } else { deferred.resolve(connection); } deferred.promise.nodeify(callback); return deferred.promise; } // RELEASES A CONNECTION (IF YOU NEED TO DO THAT MANUALLY) releaseConnection(connection) { const deferred = Q.defer(); if (connection != null && !connection.isReleased) { if (connection.transactional) { DataAccess.prototype .rollbackTransaction(connection) .then(function (rollback_res) { delete connection.transactional; deferred.resolve(); }) .fail(function (rollback_err) { try { connection.release(); connection.isReleased = true; } catch (e) { console.log('Problem rolling back and releasing connection to db:'); console.log(e); } deferred.resolve(); }); } else { delete connection.transactional; try { connection.release(); connection.isReleased = true; } catch (e) { console.log('Problem releasing connection to db:'); console.log(e); } deferred.resolve(); } } else { deferred.resolve(); } return deferred.promise; } getDbConnection(callback) { const deferred = Q.defer(); pool.connect((err, client, done) => { if (!err) { deferred.resolve({ client: client, release: done, transactional: false, results: [], isReleased: false, }); } else { const errorObj = new ErrorObj_1.ErrorObj(500, 'da9004', __filename, 'getDbConnection', 'error creating connection to postgres', 'Database error', err); deferred.reject(errorObj); } }); deferred.promise.nodeify(callback); return deferred.promise; } closeDbConnection(connection, callback) { const deferred = Q.defer(); if (connection != null && !connection.isReleased) { try { connection.release(); connection.isReleased = true; deferred.resolve(true); } catch (err) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da10001', __filename, 'closeDbConnection', 'error closing postgres connection', 'Database error', err); deferred.reject(errorObj); } } else { deferred.resolve(true); } deferred.promise.nodeify(callback); return deferred.promise; } startTransaction(callback) { const deferred = Q.defer(); DataAccess.prototype .getDbConnection() .then(function (connection) { // SET TRANSACTIONAL connection.transactional = true; connection.client.query('BEGIN', (err) => { if (err) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0005', __filename, 'startTransaction', 'error querying postgres', 'Database error', err); deferred.reject(errorObj); } else { deferred.resolve(connection); } }); }) .fail(function (err) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da9005', __filename, 'startTransaction', 'error creating postgres transaction connection', 'Database error', err); deferred.reject(errorObj); }); deferred.promise.nodeify(callback); return deferred.promise; } commitTransaction(connection, callback) { const deferred = Q.defer(); connection.client.query('COMMIT', (err) => { if (err) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0006', __filename, 'commitTransaction', 'error committing transaction in postgres', 'Database error', err); DataAccess.prototype.releaseConnection(connection); deferred.reject(errorObj); } else { delete connection.transactional; try { connection.release(); } catch (e) { console.log('Problem releasing connection to db:'); console.log(e); } connection.isReleased = true; deferred.resolve(connection.results); } }); deferred.promise.nodeify(callback); return deferred.promise; } rollbackTransaction(connection, callback) { const deferred = Q.defer(); if (connection != null && !connection.isReleased) { if (connection.transactional) { connection.client.query('ROLLBACK', (err) => { if (err) { DataAccess.prototype.releaseConnection(connection).finally(function () { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0007', __filename, 'ExecutePostgresQuery', 'error rolling back transaction in postgres', 'Database error', err); console.log('***************************************************'); console.log('\t\tROLLBACK ERROR'); console.log('***************************************************'); console.log(errorObj); console.log('***************************************************'); deferred.reject(err); }); } else { DataAccess.prototype.releaseConnection(connection).finally(function () { deferred.resolve({ rollback_results: 'success' }); }); } }); } else { // not a transaction, just a connection, release and resolve either way DataAccess.prototype.releaseConnection(connection).finally(function () { deferred.resolve({ rollback_results: 'success' }); }); } } else { deferred.resolve(); } deferred.promise.nodeify(callback); return deferred.promise; } createDatabase(db_name, db_user, db_pass, db_host, db_port, callback) { const deferred = Q.defer(); const defaultConnection = 'postgres://' + db_user + ':' + db_pass + '@' + db_host + ':' + db_port + '/template1'; const qryString = 'CREATE DATABASE ' + db_name; const qryParams = []; DataAccess.prototype .executePostgresQuery(qryString, qryParams, null) .then((res) => { deferred.resolve(res); }) .fail((err) => { deferred.resolve(err); }); deferred.promise.nodeify(callback); return deferred.promise; } checkForDatabase(db_name, db_user, db_pass, db_host, db_port, callback) { const deferred = Q.defer(); const connectionString = 'postgres://' + db_user + ':' + db_pass + '@' + db_host + ':' + db_port + '/' + db_name; const qry_params = []; const qry = " IF EXISTS (SELECT 1 FROM pg_database WHERE datname = '" + db_name + "') THEN" + " SELECT 'true';" + ' ELSE' + " SELECT 'false';" + ' END IF'; DataAccess.prototype .executePostgresQuery(qry, qry_params, null) .then(function (connection) { deferred.resolve(connection.results[0]); }) .fail(function (err) { deferred.resolve(false); }); deferred.promise.nodeify(callback); return deferred.promise; } // ================================================================================ // THIS FUNCTION GLOBALIZES ALL QUERIES (SELECT) AND NON QUERIES (INSERT UPDATE DELETE ETC) // CONDITIONALLY CREATES AND DESTROYS CONNECTIONS DEPENDING IF THEY ARE TRANSACTIONAL OR NOT executePostgresQuery(query, params, connection, is_streaming = false, callback) { const deferred = Q.defer(); let pg_query = query; // THE QUERY CONFIG OBJECT DOES NOT WORK IF THERE IS AN EMPTY ARRAY OF PARAMS if (params != null && params.length > 0) { pg_query = { text: query, values: params, }; } DataAccess.prototype .resolveDbConnection(connection) .then(function (db_connection) { if (!is_streaming) { db_connection.client .query(pg_query) .then(function (res) { db_connection.results = res.rows; // IF THE ARG connection PASSED INTO THE FUNCTION IS null/undefined // THIS IS A ONE-OFF AND WE MUST SHUT DOWN THE CONNECTION WE MADE // BEFORE RETURNING THE RESULTS if (connection == null) { DataAccess.prototype.releaseConnection(db_connection).finally(function () { deferred.resolve(db_connection); }); } else { deferred.resolve(db_connection); } }) .catch(function (qry_err) { console.log('ERROR', qry_err); // IF THE ARG connection PASSED INTO THE FUNCTION IS null/undefined // THIS IS A ONE-OFF AND WE MUST SHUT DOWN THE CONNECTION WE MADE // AND FAIL OUT // EK NOTES pretty sure all of this can be replaced by single call to this.releaseConnection const errorObj = new ErrorObj_1.ErrorObj(500, 'da0501', __filename, 'ExecutePostgresQuery', 'error querying postgres', 'Database error', qry_err); DataAccess.prototype.releaseConnection(db_connection).finally(function () { deferred.reject(errorObj); }); }); } else { // STREAMING RESULTS let streamQry; if (typeof pg_query === 'object') { streamQry = new pg_query_stream_1.default(pg_query.text, pg_query.values); } else { streamQry = new pg_query_stream_1.default(pg_query); } const stream = db_connection.client.query(streamQry); const outStream = new stream_1.Stream.Readable(); outStream._read = () => { }; stream.on('data', (chunk) => { outStream.push(JSON.stringify(chunk)); }); stream.on('end', () => { outStream.push(null); try { db_connection.release(); } catch (e) { console.log('Problem releasing connection to db:'); console.log(e); } }); stream.on('error', (streamErr) => { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0501', __filename, 'ExecutePostgresQuery', 'error querying postgres', 'Database Stream error', streamErr); DataAccess.prototype.releaseConnection(db_connection).finally(function () { outStream.destroy(streamErr); deferred.reject(errorObj); }); }); db_connection.results = outStream; deferred.resolve(db_connection); } }) .fail(function (err) { console.log('CONNECTION ERROR', err); const errorObj = new ErrorObj_1.ErrorObj(500, 'da0505', __filename, 'ExecutePostgresQuery', 'error connecting to postgres', 'Database error', err); deferred.reject(errorObj); }); deferred.promise.nodeify(callback); return deferred.promise; } getUserByEmail(email, db_handle, callback) { const deferred = Q.defer(); const qry = "SELECT data FROM bsuser WHERE LOWER(bsuser.data->>'email') = LOWER($1)"; const qry_params = [email]; DataAccess.prototype .executePostgresQuery(qry, qry_params, db_handle) .then(function (connection) { if (connection.results.length === 0) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0156', __filename, 'getUserByEmailOrUsername', 'no user found', 'Cannot find user.', null); deferred.reject(errorObj); } else if (connection.results.length === 1) { deferred.resolve(connection.results[0]); } else { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0157', __filename, 'getUserByEmailOrUsername', '', 'Found multiple users with that email.', null); deferred.reject(errorObj); } }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'getUserByEmail')); }); deferred.promise.nodeify(callback); return deferred.promise; } getUserBySessionToken(tkn, connection, callback) { const deferred = Q.defer(); const qry = "SELECT bsuser.data FROM bsuser JOIN bsuser_session ON bsuser.row_id=bsuser_session.left_id JOIN session ON bsuser_session.right_id=session.row_id WHERE session.data->'token' ? '" + tkn + "'"; const qry_params = []; DataAccess.prototype .executePostgresQuery(qry, qry_params, connection) .then(function (connection) { deferred.resolve(connection.results); }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'getUserBySessionToken')); }); deferred.promise.nodeify(callback); return deferred.promise; } findOneByIDField(tableName, fieldName, id, connection, callback) { const deferred = Q.defer(); let qry; if (tableName == 'fsapi_user_auth') { qry = 'SELECT *, fsapi_user.id as id, fua.id as auth_id FROM fsapi_user_auth as fua \ INNER JOIN fsapi_user on fua.user_id = fsapi_user.id \ WHERE ' + fieldName + ' = LOWER($1)'; } else { qry = 'SELECT * FROM ' + tableName + ' WHERE ' + fieldName + ' = LOWER($1)'; } const qry_params = [id]; DataAccess.prototype .executePostgresQuery(qry, qry_params, connection) .then(function (connection) { const results = connection.results; if (results.length <= 0) { const errorObj = new ErrorObj_1.ErrorObj(404, 'da0200', __filename, 'findOneByIDField', 'no results found', 'No results found.', {}); deferred.reject(errorObj); } else if (results.length > 1) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0201', __filename, 'findOneByIDField', 'multiple results found', 'Multiple results found', {}); deferred.reject(errorObj); } else { deferred.resolve(results[0]); } }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'findUser')); }); deferred.promise.nodeify(callback); return deferred.promise; } findUser(email, username, include_auth, connection, callback) { const deferred = Q.defer(); let qry = include_auth == true ? 'SELECT *, fsapi_user.id as id, fua.id as auth_id FROM fsapi_user ' : 'SELECT *, fsapi_user.id as id FROM fsapi_user '; qry += include_auth == true ? ' INNER JOIN fsapi_user_auth as fua on fua.user_id = fsapi_user.id ' : ''; qry += ' WHERE LOWER(email) = LOWER($1) '; let qry_params = [email]; DataAccess.prototype .executePostgresQuery(qry, qry_params, connection) .then(function (connection) { const results = connection.results; if (results.length <= 0) { let qry = include_auth == true ? 'SELECT *, fsapi_user.id as id, fua.id as auth_id FROM fsapi_user ' : 'SELECT *, fsapi_user.id as id FROM fsapi_user '; qry += include_auth == true ? ' INNER JOIN fsapi_user_auth as fua on fua.user_id = fsapi_user.id ' : ''; qry += ' WHERE LOWER(username) = LOWER($1) '; qry_params = [username]; DataAccess.prototype .executePostgresQuery(qry, qry_params, connection) .then(function (connection) { const results = connection.results; if (results.length <= 0) { DataAccess.prototype.releaseConnection(connection).then(function () { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0200', __filename, 'findUser', 'no results found', 'No results found.', {}); deferred.reject(errorObj); }); } else if (results.length > 1) { DataAccess.prototype.releaseConnection(connection).then(function () { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0201', __filename, 'findUser', 'multiple results found', 'Multiple results found', {}); deferred.reject(errorObj); }); } else { deferred.resolve(results[0]); } }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'findUser')); }); } else if (results.length > 1) { DataAccess.prototype.releaseConnection(connection).then(function () { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0202', __filename, 'findUser', 'multiple results found', 'Multiple results found', {}); deferred.reject(errorObj); }); } else { deferred.resolve(results[0]); } }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'findUser')); }); deferred.promise.nodeify(callback); return deferred.promise; } getUserByUserName(userName, connection, callback) { const deferred = Q.defer(); const qry = 'SELECT * FROM fsapi_user WHERE LOWER(username) = LOWER($1)'; const qry_params = [userName]; DataAccess.prototype .executePostgresQuery(qry, qry_params, connection) .then(function (res) { if (res.results.length === 0) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da0160', __filename, 'getUserByUserName', 'no user found', 'Cannot find user.', null); deferred.reject(errorObj); } else if (res.results.length === 1) { deferred.resolve(res.results[0]); } else { console.log('found multiple users'); const errorObj = new ErrorObj_1.ErrorObj(500, 'da0161', __filename, 'getUserByUserName', '', 'Found multiple users with that user name.', null); deferred.reject(errorObj); } }) .fail(function (err) { try { deferred.reject(err.addToError(__filename, 'getUserByUserName')); } catch (e) { console.log(e); } }); deferred.promise.nodeify(callback); return deferred.promise; } createUser(userObj, db_handle, callback) { const deferred = Q.defer(); DataAccess.prototype .startTransaction() .then(function (connection) { DataAccess.prototype .insertRow('fsapi_user', userObj, connection) .then(function (created_user) { userObj.id = created_user.id; return DataAccess.prototype.updateRow('fsapi_user_auth', userObj, created_user.id, 'user_id', connection); }) .then(function (update_res) { DataAccess.prototype .commitTransaction(connection) .then(function (commit_res) { deferred.resolve(userObj); }) .fail(function (err) { deferred.reject(err); }); }) .fail(function (err) { deferred.reject(err); }); }) .fail(function (err) { deferred.reject(err); }); deferred.promise.nodeify(callback); return deferred.promise; } verifyUserAttributeUnique(field_name, field_value, db_handle, callback) { const deferred = Q.defer(); const qry = 'SELECT * FROM fsapi_user WHERE LOWER(' + field_name + ') = LOWER($1)'; const qry_params = [field_value]; DataAccess.prototype .executePostgresQuery(qry, qry_params, db_handle) .then(function (connection) { if (connection.results.length < 1) { deferred.resolve(); } else { const errorObj = new ErrorObj_1.ErrorObj(500, 'da10161', __filename, 'verifyUserAttributeUnique', 'attribute not unique', 'Attribute ' + field_name + ' with value: ' + field_value + ', is already associated with a user', {}); deferred.reject(errorObj); } }) .fail(function (err) { try { deferred.reject(err.addToError(__filename, 'verifyUserAttributeUnique')); } catch (e) { console.log(e); } }); deferred.promise.nodeify(callback); return deferred.promise; } getUserByForgotPasswordToken(tkn, db_handle, callback) { const deferred = Q.defer(); const qry_params = [tkn]; const qry = 'SELECT *, fsapi_user.id as id FROM fsapi_user \ INNER JOIN fsapi_user_auth as fua on fua.user_id = fsapi_user.id \ WHERE $1 = ANY(forgot_password_tokens)'; DataAccess.prototype .executePostgresQuery(qry, qry_params, db_handle) .then(function (connection) { deferred.resolve(connection.results); }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'getUserByForgotPasswordToken')); }); deferred.promise.nodeify(callback); return deferred.promise; } generateForgotPasswordToken(email, username) { const deferred = Q.defer(); DataAccess.prototype .findUser(email, username) .then(function (userObj) { if (userObj.is_locked) { deferred.reject(new ErrorObj_1.ErrorObj(403, 'a2006', __filename, 'forgotPassword', 'bsuser is locked', 'Unauthorized')); return deferred.promise; } else { return [userObj, utilities.getHash(null, null, 48)]; } }) .spread(function (userObj, tkn) { if (userObj.forgot_password_tokens === undefined || userObj.forgot_password_tokens === null) { userObj.forgot_password_tokens = [tkn]; } else { userObj.forgot_password_tokens.push(tkn); } // return [tkn, DataAccess.prototype.saveEntity('bsuser', userObj)]; return [tkn, null]; }) .spread(function (tkn) { deferred.resolve(tkn); }) .fail(function (err) { deferred.reject(err); }); return deferred.promise; } getUID(db_handle, callback) { const deferred = Q.defer(); DataAccess.prototype .executePostgresQuery('SELECT uuid_generate_v1() as id', [], db_handle) .then(function (res) { deferred.resolve(res.results[0].id); }) .fail(function (err) { deferred.reject(err); }); deferred.promise.nodeify(callback); return deferred.promise; } updateRow(model_name, change_fields, id, id_field = 'id', db_handle, callback) { const deferred = Q.defer(); const update_keys = []; const update_fields = {}; let model_data = null; let table_name; const system_fields = ['id', 'user_id', 'created_at', 'updated_at']; if (utilities.isNullOrUndefinedOrZeroLength(change_fields)) { deferred.resolve({}); } else { for (let i = 0; i < models.length; i++) { const element = models[i]; if (element.name == model_name) { model_data = element; break; } } if (utilities.isNullOrUndefined(model_data)) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da102001', __filename, 'updateRow', 'error updating row', 'Failed to update Entity. No data model definition found.', {}); deferred.reject(errorObj); deferred.promise.nodeify(callback); return deferred.promise; } table_name = model_data.db_table; var change_field_keys = Object.keys(change_fields); for (let i = 0; i < model_data.properties.length; i++) { const element = model_data.properties[i]; if (element.name == 'updated_at') { update_keys.push(element.name); update_fields[element.name] = new Date(); } if (change_field_keys.includes(element.name) && (!utilities.isNullOrUndefined(change_fields[element.name]) || element.nullable == true) && element.editable == true && element.system_only != true && !system_fields.includes(element.name)) { update_keys.push(element.name); update_fields[element.name] = change_fields[element.name]; } } let update_query = 'UPDATE ' + table_name + ' SET '; const update_params = [id]; for (let i = 0; i < update_keys.length; i++) { const key = update_keys[i]; update_query += update_params.length > 1 ? ' , ' : ''; update_query += ' ' + key + ' '; update_params.push(update_fields[key]); update_query += ' = $' + update_params.length + ' '; } update_query += ' WHERE ' + id_field + ' = $1 RETURNING * '; DataAccess.prototype .executePostgresQuery(update_query, update_params, db_handle) .then(function (res) { deferred.resolve(res.results[0]); }) .fail(function (err) { deferred.reject(err); }); } deferred.promise.nodeify(callback); return deferred.promise; } insertRow(model_name, insert_fields, db_handle, callback) { const deferred = Q.defer(); const insert_keys = []; let model_data; let table_name; const argKeys = Object.keys(insert_fields); if (utilities.isNullOrUndefinedOrZeroLength(argKeys)) { deferred.resolve({}); } else { for (let i = 0; i < models.length; i++) { const element = models[i]; if (element.name == model_name) { model_data = element; break; } } if (utilities.isNullOrUndefined(model_data)) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da102001', __filename, 'updateRow', 'error updating row', 'Failed to create Entity. No data model definition found in models JSON file', {}); deferred.reject(errorObj); deferred.promise.nodeify(callback); return deferred.promise; } table_name = model_data.db_table; for (let i = 0; i < model_data.properties.length; i++) { const element = model_data.properties[i]; if (!utilities.isNullOrUndefined(insert_fields[element.name]) && element.system_only != true) { insert_keys.push(element.name); } } let insert_query = 'INSERT INTO ' + table_name + ' ( '; let values_statement = 'VALUES ('; const params = []; for (let i = 0; i < insert_keys.length; i++) { const key = insert_keys[i]; insert_query += params.length > 0 ? ' , ' : ''; values_statement += params.length > 0 ? ' , ' : ''; insert_query += ' ' + key + ' '; params.push(insert_fields[key]); values_statement += ' $' + params.length + ' '; } insert_query += ' ) '; insert_query += values_statement + ' ) RETURNING * '; DataAccess.prototype .executePostgresQuery(insert_query, params, db_handle) .then(function (res) { deferred.resolve(res.results[0]); }) .fail(function (err) { deferred.reject(err); }); } deferred.promise.nodeify(callback); return deferred.promise; } deleteRow(model_name, id, db_handle, callback) { const deferred = Q.defer(); let model_data; let table_name; for (let i = 0; i < models.length; i++) { const element = models[i]; if (element.name == model_name) { model_data = element; break; } } if (utilities.isNullOrUndefined(model_data)) { const errorObj = new ErrorObj_1.ErrorObj(500, 'da102001', __filename, 'updateRow', 'error deleting row', 'Failed to delete Entity. No data model definition found.', {}); deferred.reject(errorObj); deferred.promise.nodeify(callback); return deferred.promise; } table_name = model_data.db_table; const query = 'DELETE FROM ' + table_name + ' WHERE id = $1 RETURNING * '; DataAccess.prototype .executePostgresQuery(query, [id], db_handle) .then(function (res) { deferred.resolve(res.results[0]); }) .fail(function (err) { deferred.reject(err); }); deferred.promise.nodeify(callback); return deferred.promise; } /////////////// BEGIN INVALIDATE SESSION FUNCTIONS //////////////// createSession(token, user_id, username, clientInfo, db_handle, callback) { const deferred = Q.defer(); const client_info = { 'user-agent': clientInfo }; let qry = 'INSERT INTO fsapi_session( \ user_id, token, client_info) \ VALUES ($1, $2, $3) RETURNING *'; let qry_params = [user_id, token, client_info]; DataAccess.prototype .executePostgresQuery(qry, qry_params, db_handle) .then(function (res) { const session = res.results[0]; qry = 'INSERT INTO fsapi_user_session( \ user_id, session_id) \ VALUES ($1, $2)'; qry_params = [user_id, session.id]; DataAccess.prototype .executePostgresQuery(qry, qry_params, db_handle) .then(function (connection) { deferred.resolve(session); }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'GetDeadSessions')); }); }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'GetDeadSessions')); }); deferred.promise.nodeify(callback); return deferred.promise; } touchSession(session_id, connection, callback) { const deferred = Q.defer(); var qry = 'UPDATE fsapi_session SET last_touch = current_timestamp WHERE id = $1'; const qry_params = [session_id]; DataAccess.prototype .executePostgresQuery(qry, qry_params, connection) .then(function (connection) { deferred.resolve(session_id); }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'GetDeadSessions')); }); deferred.promise.nodeify(callback); return deferred.promise; } getDeadSessions(timeOutMin, ids_only = false, db_handle, callback) { const deferred = Q.defer(); var qry; if (ids_only) { qry = "select ARRAY_AGG(id) as ids from fsapi_session where last_touch < (NOW() - INTERVAL '" + timeOutMin + " minutes')"; } else { qry = "select * from fsapi_session where last_touch < (NOW() - INTERVAL '" + timeOutMin + " minutes')"; } const qry_params = []; DataAccess.prototype .executePostgresQuery(qry, qry_params, db_handle) .then(function (connection) { if (connection.results.length < 1) { deferred.resolve([]); } else { deferred.resolve(connection.results); } }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'GetDeadSessions')); }); deferred.promise.nodeify(callback); return deferred.promise; } getAllSessions(db_handle, callback) { const deferred = Q.defer(); const qry = 'SELECT * FROM fsapi_session'; const qry_params = []; DataAccess.prototype .executePostgresQuery(qry, qry_params, db_handle) .then(function (connection) { deferred.resolve(connection.results); }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'getAllSessions')); }); deferred.promise.nodeify(callback); return deferred.promise; } deleteSessions(dsIds, callback) { const deferred = Q.defer(); let db_connection; DataAccess.prototype .startTransaction() .then((db_handle) => { db_connection = db_handle; const qry_linking = 'DELETE FROM fsapi_user_session WHERE session_id = ANY($1)'; return [ db_handle, DataAccess.prototype.executePostgresQuery(qry_linking, [dsIds], db_handle), ]; }) .spread((db_handle, qry_res) => { const qry = 'DELETE FROM fsapi_session WHERE id = ANY($1)'; return [db_handle, DataAccess.prototype.executePostgresQuery(qry, [dsIds], db_handle)]; }) .spread((db_handle, qry_res) => { return DataAccess.prototype.commitTransaction(db_handle); }) .then(() => { deferred.resolve(); }) .fail((err) => { DataAccess.prototype.rollbackTransaction(db_connection).finally(() => { deferred.reject(err); }); }); deferred.promise.nodeify(callback); return deferred.promise; } findSessionByToken(token, db_handle, callback) { const deferred = Q.defer(); DataAccess.prototype .executePostgresQuery('SELECT * from fsapi_session where token = $1', [token], db_handle) .then(function (connection) { if (connection.results.length !== 1) { const errorObj = new ErrorObj_1.ErrorObj(403, 'da30001', __filename, 'findSessionByToken', 'no unique token found', 'Unauthorized', null); deferred.reject(errorObj); } else { deferred.resolve(connection.results[0]); } }) .fail(function (err) { deferred.reject(err.addToError(__filename, 'GetDeadSessions')); }); deferred.promise.nodeify(callback); return deferred.promise; } } exports.DataAccess = DataAccess; // ================================================================================ // SCHEMA.JS FUNCTIONS // ------------------------------------------------------------------- // Schema.js performs several checks for intital db/user state and will // create the default schema depending on the current state of the db // ------------------------------------------------------------------- // ------------------------------------------------------------------- // ================================================================================ // CONNECTION LIFECYCLE FUNCTIONS // ------------------------------------------------------------------- // These functions are responsible for creating and tearing down // connections to the database as well as starting, commiting, and // rolling back transactions // ------------------------------------------------------------------- // START A CONNECTION TO THE DATABASE TO USE FUNCTIONS // ================================================================================ // ================================================================================ // FIND FUNCTIONS // ------------------------------------------------------------------ // These functions are for retrieving entities from the db by various // parameters. // ------------------------------------------------------------------ // tableName -- NAME OF THE TABLE // RETURN ALL ENTITIES IN A GIVEN TABLE // ================================================================================ // ================================================================================ // RELATIONSHIP FUNCTIONS // ------------------------------------------------------------------ // These functions are for handling relationships between entities. // You can add a relationship between entities, remove a relationship // or get the related entities. // // relType is 'default' if none is specified // ------------------------------------------------------------------ // entity1 -- ONE ENTITY IN THE RELATIONSHIP // REQUIRES AT LEAST 'object_type' AND 'id' // entity2 -- THE OTHER ENTITY IN THE RELATIONSHIP // REQUIRES AT LEAST 'object_type' AND 'id' // relType -- NAME OR TYPE FOR THIS RELATIONSHIP // THIS CREATES A NAMED RELATIONSHIP BETWEEN THE TWO SPECIFIED ENTITIES // entity1 -- ONE ENTITY IN THE RELATIONSHIP // REQUIRES AT LEAST 'object_type' AND 'id' // entity2 -- THE OTHER ENTITY IN THE RELATIONSHIP // REQUIRES AT LEAST 'object_type' AND 'id' // relType -- NAME OR TYPE FOR THIS RELATIONSHIP // THIS DESTROYS THE NAMED RELATIONSHIP BETWEEN THE TWO SPECIFIED ENTITIES //# sourceMappingURL=dataAccess.js.map