<commit_before>import Sequelize from 'sequelize';
import {DIALECTS} from '../app/constants/constants';
import parse from './parse';
import {merge} from 'ramda';
import {ARGS} from './args';
import {APP_NOT_CONNECTED, AUTHENTICATION} from './errors';
import YAML from 'yamljs';

const PREBUILT_QUERY = {
    SHOW_DATABASES: 'SHOW_DATABASES',
    SHOW_TABLES: 'SHOW_TABLES',
    SHOW5ROWS: 'SHOW5ROWS'
};

const timestamp = () => (new Date()).toTimeString();

// http://stackoverflow.com/questions/32037385/using-sequelize-with-redshift
const REDSHIFT_OPTIONS = {
    dialect: 'postgres',
    pool: false,
    keepDefaultTimezone: true, // avoid SET TIMEZONE
    databaseVersion: '8.0.2' // avoid SHOW SERVER_VERSION
};

const setupMSSQLOptions = (connection) => {
    connection.config.dialectOptions = {encrypt: true};
};

const rememberSubdialect = (connection, subDialect) => {
    connection.config = merge(connection.config, {subDialect});
};

const EMPTY_TABLE = {
    columnnames: ['NA'],
    rows: [['empty table']],
    ncols: 1,
    nrows: 1
};

const isEmpty = (table) => {
    return table.length === 0;
};

const intoArray = (objects) => {
    return objects.map(obj => obj[Object.keys(obj)]);
};

const assembleTablesPreviewMessage = (tablePreviews) => {

    /*
        topRows is an array of one or many responses of top 5 rows queries
        [ {'table1':[top5rows]}, {'table2': [top5rows]} ...]
    */

    let parsedRows;

    return tablePreviews.map( (tablePreview) => {
        const tableName = Object.keys(tablePreview);
        const rawData = tablePreview[tableName];
        parsedRows = (isEmpty(rawData)) ? EMPTY_TABLE : parse(rawData);
        return {[tableName]: parsedRows};
    });

};

export class SequelizeManager {

    constructor(Logger) {
        this.log = Logger.log;
        this.sessionSelected = 0;
        this.sessions = {};
    }

    setSessionSelected(sessionSelected) {
        this.sessionSelected = sessionSelected;
    }

    getDialect() {
        return this.sessions[this.sessionSelected].options.dialect;
    }

    setQueryType(type) {
        /*
         * set sequelize's query property type
         * helps sequelize to predict what kind of response it will get
         */
        return {type: this.sessions[this.sessionSelected].QueryTypes[type]};
    }

    intoTablesArray(results) {

        let tables;

        if (this.getDialect() === DIALECTS.SQLITE) {
            // sqlite returns an array by default
            tables = results;
        } else {
            /*
             * others return list of objects such as
             *  [ { Tables_in_testdb: 'consumercomplaints' },
             *    { Tables_in_testdb: 'test' } ]
             */
            tables = intoArray(results);
        }

        return tables;

    }

    raiseError(errorMessage, responseSender) {
        const errorLog = merge(errorMessage, {timestamp: timestamp()});
        this.log(errorMessage, 0);
        responseSender({error: errorLog}, 400);
    }

    getConnection(responseSender) {
        return () => responseSender({error: null});
    }

    createConnection(configuration) {
        const {
            username, password, database, port, dialect, storage, host
            } = configuration;

        let options = {dialect, host, port, storage};

        this.log(`Creating a connection for user ${username}`, 1);

        const subDialect = dialect;

        if (dialect === 'redshift') {
            // avoid auto-dection
            Sequelize.HSTORE.types.postgres.oids.push('dummy');
            // dialect will be changed to 'postgres' by REDSHIFT_OPTIONS
            options = merge(options, REDSHIFT_OPTIONS);
        }

        this.sessions[this.sessionSelected] = new Sequelize(
            database, username, password, options
        );

        if (subDialect === 'mssql') {
            setupMSSQLOptions(this.sessions[this.sessionSelected]);
        }

        rememberSubdialect(this.sessions[this.sessionSelected], subDialect);

    }
<commit_msg>:wrench: add ssl option to the backend<commit_after>import Sequelize from 'sequelize';
import {DIALECTS} from '../app/constants/constants';
import parse from './parse';
import {merge} from 'ramda';
import {ARGS} from './args';
import {APP_NOT_CONNECTED, AUTHENTICATION} from './errors';
import YAML from 'yamljs';

const PREBUILT_QUERY = {
    SHOW_DATABASES: 'SHOW_DATABASES',
    SHOW_TABLES: 'SHOW_TABLES',
    SHOW5ROWS: 'SHOW5ROWS'
};

const timestamp = () => (new Date()).toTimeString();

// http://stackoverflow.com/questions/32037385/using-sequelize-with-redshift
const REDSHIFT_OPTIONS = {
    dialect: 'postgres',
    pool: false,
    keepDefaultTimezone: true, // avoid SET TIMEZONE
    databaseVersion: '8.0.2', // avoid SHOW SERVER_VERSION
    dialectOptions: {
        ssl: true
    }
};

const setupMSSQLOptions = (connection) => {
    connection.config.dialectOptions = {encrypt: true};
};

const rememberSubdialect = (connection, subDialect) => {
    connection.config = merge(connection.config, {subDialect});
};

const EMPTY_TABLE = {
    columnnames: ['NA'],
    rows: [['empty table']],
    ncols: 1,
    nrows: 1
};

const isEmpty = (table) => {
    return table.length === 0;
};

const intoArray = (objects) => {
    return objects.map(obj => obj[Object.keys(obj)]);
};

const assembleTablesPreviewMessage = (tablePreviews) => {

    /*
        topRows is an array of one or many responses of top 5 rows queries
        [ {'table1':[top5rows]}, {'table2': [top5rows]} ...]
    */

    let parsedRows;

    return tablePreviews.map( (tablePreview) => {
        const tableName = Object.keys(tablePreview);
        const rawData = tablePreview[tableName];
        parsedRows = (isEmpty(rawData)) ? EMPTY_TABLE : parse(rawData);
        return {[tableName]: parsedRows};
    });

};

export class SequelizeManager {

    constructor(Logger) {
        this.log = Logger.log;
        this.sessionSelected = 0;
        this.sessions = {};
    }

    setSessionSelected(sessionSelected) {
        this.sessionSelected = sessionSelected;
    }

    getDialect() {
        return this.sessions[this.sessionSelected].options.dialect;
    }

    setQueryType(type) {
        /*
         * set sequelize's query property type
         * helps sequelize to predict what kind of response it will get
         */
        return {type: this.sessions[this.sessionSelected].QueryTypes[type]};
    }

    intoTablesArray(results) {

        let tables;

        if (this.getDialect() === DIALECTS.SQLITE) {
            // sqlite returns an array by default
            tables = results;
        } else {
            /*
             * others return list of objects such as
             *  [ { Tables_in_testdb: 'consumercomplaints' },
             *    { Tables_in_testdb: 'test' } ]
             */
            tables = intoArray(results);
        }

        return tables;

    }

    raiseError(errorMessage, responseSender) {
        const errorLog = merge(errorMessage, {timestamp: timestamp()});
        this.log(errorMessage, 0);
        responseSender({error: errorLog}, 400);
    }

    getConnection(responseSender) {
        return () => responseSender({error: null});
    }

    createConnection(configuration) {
        const {
            username, password, database, port, dialect, storage, host, ssl
            } = configuration;

        let options = {
            dialect, host, port, storage,
            dialectOptions: {ssl}
        };

        this.log(`Creating a connection for user ${username}`, 1);

        const subDialect = dialect;

        if (dialect === 'redshift') {
            // avoid auto-dection
            Sequelize.HSTORE.types.postgres.oids.push('dummy');
            // dialect will be changed to 'postgres' by REDSHIFT_OPTIONS
            options = merge(options, REDSHIFT_OPTIONS);
        }

        this.sessions[this.sessionSelected] = new Sequelize(
            database, username, password, options
        );

        if (subDialect === 'mssql') {
            setupMSSQLOptions(this.sessions[this.sessionSelected]);
        }

        rememberSubdialect(this.sessions[this.sessionSelected], subDialect);

    }

{'fraction_non_alphanumeric': 0.12408581179912238, 'fraction_numerical': 0.006582155046318869, 'mean_word_length': 2.5169309901414487, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, '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': '7028947', 'n_tokens_mistral': 2517, 'n_tokens_neox': 2401, 'n_words': 550}