<commit_before>/*global ace*/

import React, { Component, PropTypes } from "react";

import _ from "underscore";

import DataSelector from './DataSelector.jsx';
import Icon from "metabase/components/Icon.jsx";

function getModeInfo(query, databases) {
    let databaseID = query ? query.database : null,
        database   = _.findWhere(databases, { id: databaseID }),
        engine     = database ? database.engine : null;

    return {
        mode: engine === 'druid' || engine === 'mongo' ? 'ace/mode/json'  :
              engine === 'mysql'                       ? 'ace/mode/mysql' :
              engine === 'postgres'                    ? 'ace/mode/pgsql' :
              engine === 'sqlserver'                   ? 'ace/mode/sqlserver' :
                                                         'ace/mode/sql',
        description: engine === 'druid' || engine === 'mongo' ? 'JSON' : 'SQL',
        requiresTable: engine === 'mongo'
    };
}


export default class NativeQueryEditor extends Component {
    constructor(props, context) {
        super(props, context);

        _.bindAll(this, 'onChange', 'toggleEditor', 'updateEditorMode', 'setDatabaseID', 'setTableID');
    }

    static propTypes = {
        databases: PropTypes.array.isRequired,
        query: PropTypes.object.isRequired,
        setQueryFn: PropTypes.func.isRequired,
        setDatabaseFn: PropTypes.func.isRequired,
        autocompleteResultsFn: PropTypes.func.isRequired,
        /// This should return an object with information about the mode the ACE Editor should use to edit the query.
        /// This object should have 2 properties:
        /// *  `mode` :         the ACE Editor mode name, e.g. 'ace/mode/json'
        /// *  `description`:   name used to describe the text written in that mode, e.g. 'JSON'. Used to fill in the blank in 'This question is written in _______'.
        /// *  `requiresTable`: whether the DB selector should be a DB + Table selector. Mongo needs both DB + Table.
        isOpen: PropTypes.bool
    };

    static defaultProps = {
        isOpen: false
    }

    componentWillMount() {
        this.setState({
            showEditor: this.props.isOpen
        });
    }

    componentDidMount() {
        this.loadAceEditor();
    }

    componentDidUpdate() {
        var editor = ace.edit("id_sql");
        if (editor.getValue() !== this.props.query.native.query) {
            editor.setValue(this.props.query.native.query)
        }
    }

    /// Update the mode of the ACE Editor to something like `ace/mode/sql` or `ace/mode/json`.
    /// The appropriate mode to use is fetched via the delegation pattern with the function `getModeInfo()`, described in detail above
    updateEditorMode() {
        let modeInfo = getModeInfo(this.props.query, this.props.databases);
        if (!modeInfo) return;

        console.log('Setting ACE Editor mode to:', modeInfo.mode);

        let editor = ace.edit("id_sql");
        editor.getSession().setMode(modeInfo.mode);
    }

    loadAceEditor() {
        var editor = ace.edit("id_sql");

        this.updateEditorMode();

        // listen to onChange events
        editor.getSession().on('change', this.onChange);

        // initialize the content
        editor.setValue(this.props.query.native.query);

        // clear the editor selection, otherwise we start with the whole editor selected
        editor.clearSelection();

        // hmmm, this could be dangerous
        editor.focus();

        this.setState({
            editor: editor
        });

        var aceLanguageTools = ace.require('ace/ext/language_tools');
        editor.setOptions({
            enableBasicAutocompletion: true,
            enableSnippets: true,
            enableLiveAutocompletion: true,
            showPrintMargin: false,
            highlightActiveLine: false,
            highlightGutterLine: false,
            showLineNumbers: true
        });

        var autocompleteFn = this.props.autocompleteResultsFn;
        aceLanguageTools.addCompleter({
            getCompletions: function(editor, session, pos, prefix, callback) {
                if (prefix.length < 2) {
                    callback(null, []);
                    return;
                }

                autocompleteFn(prefix).then(function (results) {
                    // transform results of the API call into what ACE expects
                    var js_results = results.map(function(result) {
                        return {
                            name: result[0],
                            value: result[0],
                            meta: result[1]
                        };
                    });
                    callback(null, js_results);

                }, function (error) {
                    console.log('error getting autocompletion data', error);
                    callback(null, []);
                });
            }
        });
    }

    setQuery(dataset_query) {
        this.props.setQueryFn(dataset_query);
    }

    onChange(event) {
        if (this.state.editor) {
            var query = this.props.query;
            query.native.query = this.state.editor.getValue();
            this.setQuery(query);
        }
    }

    toggleEditor() {
        this.setState({ showEditor: !this.state.showEditor })
    }

    /// Change the Database we're currently editing a query for.
    setDatabaseID(databaseID) {
        this.props.setDatabaseFn(databaseID);
        this.updateEditorMode();
    }
<commit_msg>fix issue where ace editor was not updating mode to match current db properly.<commit_after>/*global ace*/

import React, { Component, PropTypes } from "react";

import _ from "underscore";

import DataSelector from './DataSelector.jsx';
import Icon from "metabase/components/Icon.jsx";

// This should return an object with information about the mode the ACE Editor should use to edit the query.
// This object should have 2 properties:
// *  `mode` :         the ACE Editor mode name, e.g. 'ace/mode/json'
// *  `description`:   name used to describe the text written in that mode, e.g. 'JSON'. Used to fill in the blank in 'This question is written in _______'.
// *  `requiresTable`: whether the DB selector should be a DB + Table selector. Mongo needs both DB + Table.
function getModeInfo(query, databases) {
    let databaseID = query ? query.database : null,
        database   = _.findWhere(databases, { id: databaseID }),
        engine     = database ? database.engine : null;

    return {
        mode: engine === 'druid' || engine === 'mongo' ? 'ace/mode/json'  :
              engine === 'mysql'                       ? 'ace/mode/mysql' :
              engine === 'postgres'                    ? 'ace/mode/pgsql' :
              engine === 'sqlserver'                   ? 'ace/mode/sqlserver' :
                                                         'ace/mode/sql',
        description: engine === 'druid' || engine === 'mongo' ? 'JSON' : 'SQL',
        requiresTable: engine === 'mongo'
    };
}


export default class NativeQueryEditor extends Component {
    constructor(props, context) {
        super(props, context);

        _.bindAll(this, 'onChange', 'toggleEditor', 'updateEditorMode', 'setDatabaseID', 'setTableID');
    }

    static propTypes = {
        databases: PropTypes.array.isRequired,
        query: PropTypes.object.isRequired,
        setQueryFn: PropTypes.func.isRequired,
        setDatabaseFn: PropTypes.func.isRequired,
        autocompleteResultsFn: PropTypes.func.isRequired,
        isOpen: PropTypes.bool
    };

    static defaultProps = {
        isOpen: false
    }

    componentWillMount() {
        this.setState({
            showEditor: this.props.isOpen
        });
    }

    componentDidMount() {
        this.loadAceEditor();
    }

    componentWillReceiveProps(nextProps) {
        this.updateEditorMode(nextProps);
    }

    componentDidUpdate() {
        var editor = ace.edit("id_sql");
        if (editor.getValue() !== this.props.query.native.query) {
            editor.setValue(this.props.query.native.query)
        }
    }

    /// Update the mode of the ACE Editor to something like `ace/mode/sql` or `ace/mode/json`.
    /// The appropriate mode to use is fetched via the delegation pattern with the function `getModeInfo()`, described in detail above
    updateEditorMode(props) {
        let modeInfo = getModeInfo(props.query, props.databases);
        if (!modeInfo) return;

        console.log('Setting ACE Editor mode to:', modeInfo.mode);

        let editor = ace.edit("id_sql");
        editor.getSession().setMode(modeInfo.mode);
    }

    loadAceEditor() {
        var editor = ace.edit("id_sql");

        this.updateEditorMode(this.props);

        // listen to onChange events
        editor.getSession().on('change', this.onChange);

        // initialize the content
        editor.setValue(this.props.query.native.query);

        // clear the editor selection, otherwise we start with the whole editor selected
        editor.clearSelection();

        // hmmm, this could be dangerous
        editor.focus();

        this.setState({
            editor: editor
        });

        var aceLanguageTools = ace.require('ace/ext/language_tools');
        editor.setOptions({
            enableBasicAutocompletion: true,
            enableSnippets: true,
            enableLiveAutocompletion: true,
            showPrintMargin: false,
            highlightActiveLine: false,
            highlightGutterLine: false,
            showLineNumbers: true
        });

        var autocompleteFn = this.props.autocompleteResultsFn;
        aceLanguageTools.addCompleter({
            getCompletions: function(editor, session, pos, prefix, callback) {
                if (prefix.length < 2) {
                    callback(null, []);
                    return;
                }

                autocompleteFn(prefix).then(function (results) {
                    // transform results of the API call into what ACE expects
                    var js_results = results.map(function(result) {
                        return {
                            name: result[0],
                            value: result[0],
                            meta: result[1]
                        };
                    });
                    callback(null, js_results);

                }, function (error) {
                    console.log('error getting autocompletion data', error);
                    callback(null, []);
                });
            }
        });
    }

    setQuery(dataset_query) {
        this.props.setQueryFn(dataset_query);
    }

    onChange(event) {
        if (this.state.editor) {
            var query = this.props.query;
            query.native.query = this.state.editor.getValue();
            this.setQuery(query);
        }
    }

    toggleEditor() {
        this.setState({ showEditor: !this.state.showEditor })
    }

    /// Change the Database we're currently editing a query for.
    setDatabaseID(databaseID) {
        this.props.setDatabaseFn(databaseID);
    }

{'fraction_non_alphanumeric': 0.10887605989536352, 'fraction_numerical': 0.0009020386072523904, 'mean_word_length': 1.8655983458257948, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3312129', 'n_tokens_mistral': 2936, 'n_tokens_neox': 2835, 'n_words': 740}