fully-api
Version:
API framework for Fully Stacked, LLC REST-ful APIs
1,058 lines • 45.4 kB
JavaScript
;
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