<commit_before>class DysonFanState {

    constructor(heatAvailable) {
        this.heatAvailable = heatAvailable;

    }

    getFieldValue(newState, field) {
        var state = newState["product-state"];
        if(state instanceof Object)
        {
            return state[field];
        }
        else
        {
            return newState[field];
        }
    }

    updateState(newState) {
        this._fan = this.getFieldValue(newState, "fmod") === "FAN" ||
                    this.getFieldValue(newState, "fmod") === "AUTO" ||
                    this.getFieldValue(newState, "fpwr") === "ON" ;

        this._auto = this.getFieldValue(newState, "fmod") === "AUTO" ||
                    (this.getFieldValue(newState, "auto") === "ON" && this._fan);

        this._rotate = this.getFieldValue(newState, "oson") === "ON";
        this._nightMode = this.getFieldValue(newState, "nmod") === "ON";
        this._speed = (Number.parseInt(this.getFieldValue(newState, "fnsp"))||5) * 10;
        if (this.heatAvailable) {
            this._heat = this.getFieldValue(newState, "hmod") === "HEAT";
            this._focus = this.getFieldValue(newState, "ffoc") === "ON";
            this._heatThreshold = Number.parseFloat(this.getFieldValue(newState, "hmax")) /10 - 273;
        }
        // this._fanState = 0;
        // if (this._auto) {
        //     this._fanState = 3;
        // }
        // else if (this._fan) {
        //     this._fanState = 2;
        // }
        // else if (this.heatAvailable && this._heat) {
        //     this._fanState = 1;
        // }
        // With TP04 models average cflr and hflr
        let filterReading = this.getFieldValue(newState, "filf") ||
            (this.getFieldValue(newState, "cflr") + this.getFieldValue(newState, "cflr"))/2;
        // Assuming the max life is 12 * 365 = 4380 hrs
        this._filterLife = Number.parseInt(filterReading) * 100 / 4380;
        // Set to chang the filter when the life is below 10%
        this._filterChange = this._filterLife <10 ;

        // The value property of CurrentHeaterCoolerState must be one of the following:
        // Characteristic.CurrentHeaterCoolerState.INACTIVE = 0;
        // Characteristic.CurrentHeaterCoolerState.IDLE = 1;
        // Characteristic.CurrentHeaterCoolerState.HEATING = 2;
        // Characteristic.CurrentHeaterCoolerState.COOLING = 3;
        switch(this.getFieldValue(newState, "fmod")||this.getFieldValue(newState, "fpwr")){
            case "OFF":
                this._currentHeaterCoolerState = 0;
                break;
            case "AUTO":
            case "ON":
            case "FAN":
                this._currentHeaterCoolerState = 3;
                break;
        }

        if(this._fan){
            this._targetHeaterCoolerState = 2;
        }
        if (this.heatAvailable && this._heat){
            this._currentHeaterCoolerState = 2;
            this._targetHeaterCoolerState = 1;
        }
        if(this._auto) {
            this._targetHeaterCoolerState = 0;
        }

    }

    get fanOn() { return this._fan; }
    get fanAuto() {return this._auto;}
    get fanRotate() {return this._rotate;}
    get fanSpeed() {return this._speed;}
    get fanHeat() {return this._heat;}
    get fanState() {return this._fanState;}
    get nightMode() {return this._nightMode;}
    get fanFocused() {return this._focus;}
    get filterLife() {return this._filterLife;}
    get filterChangeRequired() {return this._filterChange;}
    get heaterCoolerState() { return this._currentHeaterCoolerState; }
    get targetHeaterCoolerState() { return this._targetHeaterCoolerState;}
    get heatThreshold() { return this._heatThreshold;}

}

module.exports = { DysonFanState };<commit_msg>remove unnecessary blank lines<commit_after>class DysonFanState {

    constructor(heatAvailable) {
        this.heatAvailable = heatAvailable;
    }

    getFieldValue(newState, field) {
        var state = newState["product-state"];
        if(state instanceof Object)
        {
            return state[field];
        }
        else
        {
            return newState[field];
        }
    }

    updateState(newState) {
        this._fan = this.getFieldValue(newState, "fmod") === "FAN" ||
                    this.getFieldValue(newState, "fmod") === "AUTO" ||
                    this.getFieldValue(newState, "fpwr") === "ON" ;

        this._auto = this.getFieldValue(newState, "fmod") === "AUTO" ||
                    (this.getFieldValue(newState, "auto") === "ON" && this._fan);

        this._rotate = this.getFieldValue(newState, "oson") === "ON";
        this._nightMode = this.getFieldValue(newState, "nmod") === "ON";
        this._speed = (Number.parseInt(this.getFieldValue(newState, "fnsp"))||5) * 10;
        if (this.heatAvailable) {
            this._heat = this.getFieldValue(newState, "hmod") === "HEAT";
            this._focus = this.getFieldValue(newState, "ffoc") === "ON";
            this._heatThreshold = Number.parseFloat(this.getFieldValue(newState, "hmax")) /10 - 273;
        }
        // this._fanState = 0;
        // if (this._auto) {
        //     this._fanState = 3;
        // }
        // else if (this._fan) {
        //     this._fanState = 2;
        // }
        // else if (this.heatAvailable && this._heat) {
        //     this._fanState = 1;
        // }
        // With TP04 models average cflr and hflr
        let filterReading = this.getFieldValue(newState, "filf") ||
            (this.getFieldValue(newState, "cflr") + this.getFieldValue(newState, "cflr"))/2;
        // Assuming the max life is 12 * 365 = 4380 hrs
        this._filterLife = Number.parseInt(filterReading) * 100 / 4380;
        // Set to chang the filter when the life is below 10%
        this._filterChange = this._filterLife <10 ;
        // The value property of CurrentHeaterCoolerState must be one of the following:
        // Characteristic.CurrentHeaterCoolerState.INACTIVE = 0;
        // Characteristic.CurrentHeaterCoolerState.IDLE = 1;
        // Characteristic.CurrentHeaterCoolerState.HEATING = 2;
        // Characteristic.CurrentHeaterCoolerState.COOLING = 3;
        switch(this.getFieldValue(newState, "fmod")||this.getFieldValue(newState, "fpwr")){
            case "OFF":
                this._currentHeaterCoolerState = 0;
                break;
            case "AUTO":
            case "ON":
            case "FAN":
                this._currentHeaterCoolerState = 3;
                break;
        }
        if(this._fan){
            this._targetHeaterCoolerState = 2;
        }
        if (this.heatAvailable && this._heat){
            this._currentHeaterCoolerState = 2;
            this._targetHeaterCoolerState = 1;
        }
        if(this._auto) {
            this._targetHeaterCoolerState = 0;
        }
    }

    get fanOn() { return this._fan; }
    get fanAuto() {return this._auto;}
    get fanRotate() {return this._rotate;}
    get fanSpeed() {return this._speed;}
    get fanHeat() {return this._heat;}
    get fanState() {return this._fanState;}
    get nightMode() {return this._nightMode;}
    get fanFocused() {return this._focus;}
    get filterLife() {return this._filterLife;}
    get filterChangeRequired() {return this._filterChange;}
    get heaterCoolerState() { return this._currentHeaterCoolerState; }
    get targetHeaterCoolerState() { return this._targetHeaterCoolerState;}
    get heatThreshold() { return this._heatThreshold;}
}

module.exports = { DysonFanState };<|endoftext|>


<commit_before>/*---------------------------------------------------------
 * OpenERP base_graph
 *---------------------------------------------------------*/

openerp.base_graph = function (openerp) {
QWeb.add_template('/base_graph/static/src/xml/base_graph.xml');
openerp.base.views.add('graph', 'openerp.base_graph.GraphView');
openerp.base_graph.GraphView = openerp.base.Controller.extend({

    init: function(view_manager, session, element_id, dataset, view_id) {
        this._super(session, element_id);
        this.view_manager = view_manager;
        this.dataset = dataset;
        this.model = this.dataset.model;
        this.view_id = view_id;
    },
    do_show: function () {
        // TODO: re-trigger search
        this.$element.show();
    },
    do_hide: function () {
        this.$element.hide();
    },
    start: function() {
        this.rpc("/base_graph/graphview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },
    on_loaded: function(data) {
        var self = this;
        this.all_fields = data.all_fields;
        this.fields_view = data.fields_view;
        this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
        this.view_id = this.fields_view.view_id;
        this.chart = this.fields_view.arch.attrs.type || 'pie';
        this.fields = this.fields_view.fields;
        this.chart_info_fields = [];
        this.operator_field = '';
        this.operator_field_one = '';
        this.operator = [];
        this.group_field = '';
        this.orientation = this.fields_view.arch.attrs.orientation || '';

        for(fld in this.fields_view.arch.children) {
            if (this.fields_view.arch.children[fld].attrs.operator) {
                this.operator.push(this.fields_view.arch.children[fld].attrs.name);
            }
            else if (this.fields_view.arch.children[fld].attrs.group) {
                this.group_field = this.fields_view.arch.children[fld].attrs.name;
            }
            else {
                this.chart_info_fields.push(this.fields_view.arch.children[fld].attrs.name);
            }
        }
        this.operator_field = this.operator[0];
        if(this.operator.length > 1){
            this.operator_field_one = this.operator[1];
        }
        if(this.operator == ''){
            this.operator_field = this.chart_info_fields[1];
        }
        this.chart_info = this.chart_info_fields[0];
        this.x_title = this.fields[this.chart_info_fields[0]]['string'];
        this.y_title = this.fields[this.operator_field]['string'];
        self.load_chart();
    },

    load_chart: function(data) {
        var self = this;
        if(data){
            this.x_title = this.all_fields[this.chart_info_fields]['string'];
            this.y_title = this.all_fields[this.operator_field]['string'];
            self.schedule_chart(data);
        }else{
            this.dataset.read_ids(
                this.dataset.ids,
                {},
                function(res) {
                    self.schedule_chart(res);
                }
            );
        }
    },

    schedule_chart: function(result) {
        this.$element.html(QWeb.render("GraphView", {"fields_view": this.fields_view, "chart": this.chart,'view_id': this.view_id}));
        this.opration_fld = {};
        if (result.length){
            for(var res in result) {
                for(var fld in result[res]) {
                    if (typeof result[res][fld] == 'object') {
                        result[res][fld] = result[res][fld][result[res][fld].length - 1];
                    }
                    if (typeof result[res][fld] == 'string'){
                        if (this.all_fields[fld]['selection']){
                            for (i in this.all_fields[fld]['selection']){
                                if(result[res][fld] == this.all_fields[fld]['selection'][i][0]){
                                   result[res][fld] = this.all_fields[fld]['selection'][i];
                                }
                            }
                        }
                    }
                }
            }

            for (var i in result){
                var gen_key = result[i][this.chart_info_fields]+"_"+result[i][this.group_field];
                if (this.opration_fld[gen_key] == undefined){
                    var map_val = {};
                    map_val[this.operator_field] = result[i][this.operator_field];
                    if (this.operator.length > 1){
                        map_val[this.operator_field_one] = result[i][this.operator_field_one];
                    }
                    map_val[this.chart_info_fields] = result[i][this.chart_info_fields];
                    if (this.group_field){
                        map_val[this.group_field] = (typeof result[i][this.group_field] == 'object')?result[i][this.group_field][1]:result[i][this.group_field];
                    }
                    this.opration_fld[gen_key] = map_val;
                }else{
                    map_val = this.opration_fld[gen_key];
                    map_val[this.operator_field] += result[i][this.operator_field];
                    if (this.operator.length > 1){
                        map_val[this.operator_field_one] += result[i][this.operator_field_one];
                    }
                    this.opration_fld[gen_key] = map_val;
                }
            }
            result = [];
            for (i in this.opration_fld){
                result.push(this.opration_fld[i]);
            }

            if(this.chart == 'bar') {
                return this.schedule_bar(result);
            } else if(this.chart == "pie") {
                return this.schedule_pie(result);
            }
        }
    },

    schedule_bar: function(result) {
        var self = this;
        var view_chart = '';
        var xystr = {};
        var xyname = {};
        var res = [];
        this.group_list = [];
        var newkey = '';

        var COLOR_PALETTE = ['#cc99ff', '#ccccff', '#48D1CC', '#CFD784', '#8B7B8B', '#75507b', '#b0008c', '#ff0000', '#ff8e00', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
                     '#905000', '#9b0000', '#840067', '#9abe00', '#ffc900', '#510090', '#0000c9', '#009b00',
                     '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400', '#fcaf3e', '#ef2929', '#ff00c9',
                     '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', '#f57900', '#cc0000', '#d400a8'];

        if(self.group_field && (this.operator.length <= 1)){
            view_chart = self.orientation == 'horizontal'? 'stackedBarH' : 'stackedBar';
        }else{
            view_chart = self.orientation == 'horizontal'? 'barH' : 'bar';
        }

        for (i in result){
            if (self.group_field && (this.operator.length <= 1)){
                newkey =result[i][self.group_field].split(' ').join('_');
            }else{
                newkey = "val";
            }

            if (jQuery.inArray(newkey, self.group_list) == -1){
                self.group_list.push(newkey);
                if(this.operator.length > 1){
                    var newkey_one = "val1";
                    self.group_list.push(newkey_one);
                }
            }
        }

        for (i in result){
            var xystring = result[i][self.chart_info_fields];
            if (self.group_field && (self.operator.length <= 1)){
                newkey =result[i][self.group_field].split(' ').join('_');
            }else{
                newkey = "val";
            }
            if (xystr[xystring] == undefined){
                xyname = {};
                xyname[self.chart_info_fields] = xystring;
                for (var j in self.group_list){
                    xyname[self.group_list[j]] = 0.0001;
                }
                xyname[newkey] = result[i][self.operator_field];
                if (self.operator.length > 1){
                    xyname[newkey_one] = result[i][self.operator_field_one];
                }
                xystr[xystring] = xyname;
            }
            else{
                xyname = {};
                xyname = xystr[xystring];
                xyname[newkey] = result[i][self.operator_field];
                if (self.operator.length > 1){
                    xyname[newkey_one] = result[i][self.operator_field_one];
                }
                xystr[xystring] = xyname;
            }
        }
        for (i in xystr){
            res.push(xystr[i]);
        }

        //for legend color
        var grp_color = [];
        for (var i in self.group_list){
            var legend = {};
            if (self.group_list[i] == "val"){
                legend['text'] = self.fields[self.operator_field]['string']
            }else if(self.group_list[i] == "val1"){
                legend['text'] = self.fields[self.operator_field_one]['string']
            }else{
                legend['text'] = self.group_list[i];
            }
            legend['color'] = COLOR_PALETTE[i];
            grp_color.push(legend);
        }

        //for axis's value and title
        var temp_ax = {};
        var oth_ax = {};
        temp_ax['template'] = self.chart_info_fields;
        temp_ax['title'] = ""+self.x_title+"" ;
        oth_ax['lines'] = true;
        oth_ax['title'] = ""+self.y_title+"";

        if (self.orientation == 'horizontal'){
             var x_ax = oth_ax;
             var y_ax = temp_ax;
        }else{
             var x_ax = temp_ax;
             var y_ax = oth_ax;
        }

        var bar_chart = new dhtmlxchartChart({
            view: view_chart,
            container: self.view_id+"-barchart",
            value:"#"+self.group_list[0]+"#",
            gradient: "3d",
            border: false,
            width: 1024,
            radius: 0,
            color:grp_color[0]['color'],
            origin:0,
            xAxis:{
                template:function(obj){
                    if(x_ax['template']){
                        var val = obj[x_ax['template']];
                        val = (typeof val == 'object')?val[1]:(val==false?'Undefined':val);
                        return val;
                    }else{
                        return obj;
                    }
                },
                title:x_ax['title'],
                lines:x_ax['lines']
            },
            yAxis:{
                template:function(obj){
                    if(y_ax['template']){
                        var vals = obj[y_ax['template']];
                        vals = (typeof vals == 'object')?vals[1]:(vals==false?'Undefined':vals);
                        return vals;
                    }else{
                        return obj;
                    }
                },
                title:y_ax['title'],
                lines: y_ax['lines']
            },
            padding: {
                left: 75
            },
            legend: {
                values: grp_color,
                align:"left",
                valign:"top",
                layout: "x",
                marker:{
                    type:"round",
                    width:12
                }
            }
        });
        for (var i = 1; i<self.group_list.length;i++){
            bar_chart.addSeries({
                value: "#"+self.group_list[i]+"#",
                color: grp_color[i]['color']
            });
        }
        bar_chart.parse(res,"json");
        bar_chart.attachEvent("onItemClick", function(id) {
            var id = bar_chart.get(id);
            self.open_list_view(id);
        });
    },
    schedule_pie: function(result) {
        var self = this;
        var chart =  new dhtmlxchartChart({
            view:"pie3D",
            container:self.view_id+"-piechart",
            value:"#"+self.operator_field+"#",
            pieInnerText:function(obj) {
                var sum = chart.sum("#"+self.operator_field+"#");
                var val = obj[self.operator_field] / sum * 100 ;
                return Math.round(val * 10)/10 + "%";
            },
            gradient:"3d",
            height: 20,
            radius: 200,
            legend: {
                width: 300,
                align:"left",
                valign:"top",
                layout: "x",
                marker:{
                    type:"round",
                    width:12
                },
                template:function(obj){
                    var val = obj[self.chart_info_fields];
                    val = (typeof val == 'object')?val[1]:val;
                    return val;
                }
            }
        });
        chart.parse(result,"json");
        chart.attachEvent("onItemClick", function(id) {
            var id = chart.get(id);
            self.open_list_view(id);
        });
    },
    open_list_view : function (id){
        var self = this;
        var id = id[self.chart_info_fields];
        if (typeof id == 'object'){
            id = id[0];
        }else{
            id = id;
        }
        if(this.view_manager.action.context){
           this.view_manager.action.context = {};
        }
        if(!this.view_manager.action.domain) {
            this.view_manager.action.domain = [[self.chart_info_fields, '=', id],['id','in',self.dataset.ids]];
        } else {
            this.view_manager.action.domain.push([self.chart_info_fields, '=', id],['id','in',self.dataset.ids]);
        }
        var action_manager = new openerp.base.ActionManager(this.view_manager.session, this.view_manager.element_id);
        action_manager.start();
        action_manager.do_action(this.view_manager.action);
    },
    do_search: function(domains, contexts, groupbys) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: groupbys
        }, function (results) {
            // TODO: handle non-empty results.group_by with read_group
            if(results.group_by  && results.group_by != ''){
                self.chart_info_fields = results.group_by[0];
            }else{
                self.chart_info_fields = self.chart_info;
            }
            self.dataset.context = self.context = results.context;
            self.dataset.domain = self.domain = results.domain;
            self.dataset.read_slice({}, 0, self.limit,function(response){
                self.load_chart(response);
            });
        });
    }

});

// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them

};

// vim:et fdc=0 fdl=0:
<commit_msg>[FIX] don't make explicit boolean comparisons without identity<commit_after>/*---------------------------------------------------------
 * OpenERP base_graph
 *---------------------------------------------------------*/

openerp.base_graph = function (openerp) {
QWeb.add_template('/base_graph/static/src/xml/base_graph.xml');
openerp.base.views.add('graph', 'openerp.base_graph.GraphView');
openerp.base_graph.GraphView = openerp.base.Controller.extend({

    init: function(view_manager, session, element_id, dataset, view_id) {
        this._super(session, element_id);
        this.view_manager = view_manager;
        this.dataset = dataset;
        this.model = this.dataset.model;
        this.view_id = view_id;
    },
    do_show: function () {
        // TODO: re-trigger search
        this.$element.show();
    },
    do_hide: function () {
        this.$element.hide();
    },
    start: function() {
        this.rpc("/base_graph/graphview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },
    on_loaded: function(data) {
        var self = this;
        this.all_fields = data.all_fields;
        this.fields_view = data.fields_view;
        this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
        this.view_id = this.fields_view.view_id;
        this.chart = this.fields_view.arch.attrs.type || 'pie';
        this.fields = this.fields_view.fields;
        this.chart_info_fields = [];
        this.operator_field = '';
        this.operator_field_one = '';
        this.operator = [];
        this.group_field = '';
        this.orientation = this.fields_view.arch.attrs.orientation || '';

        for(fld in this.fields_view.arch.children) {
            if (this.fields_view.arch.children[fld].attrs.operator) {
                this.operator.push(this.fields_view.arch.children[fld].attrs.name);
            }
            else if (this.fields_view.arch.children[fld].attrs.group) {
                this.group_field = this.fields_view.arch.children[fld].attrs.name;
            }
            else {
                this.chart_info_fields.push(this.fields_view.arch.children[fld].attrs.name);
            }
        }
        this.operator_field = this.operator[0];
        if(this.operator.length > 1){
            this.operator_field_one = this.operator[1];
        }
        if(this.operator == ''){
            this.operator_field = this.chart_info_fields[1];
        }
        this.chart_info = this.chart_info_fields[0];
        this.x_title = this.fields[this.chart_info_fields[0]]['string'];
        this.y_title = this.fields[this.operator_field]['string'];
        self.load_chart();
    },

    load_chart: function(data) {
        var self = this;
        if(data){
            this.x_title = this.all_fields[this.chart_info_fields]['string'];
            this.y_title = this.all_fields[this.operator_field]['string'];
            self.schedule_chart(data);
        }else{
            this.dataset.read_ids(
                this.dataset.ids,
                {},
                function(res) {
                    self.schedule_chart(res);
                }
            );
        }
    },

    schedule_chart: function(result) {
        this.$element.html(QWeb.render("GraphView", {"fields_view": this.fields_view, "chart": this.chart,'view_id': this.view_id}));
        this.opration_fld = {};
        if (result.length){
            for(var res in result) {
                for(var fld in result[res]) {
                    if (typeof result[res][fld] == 'object') {
                        result[res][fld] = result[res][fld][result[res][fld].length - 1];
                    }
                    if (typeof result[res][fld] == 'string'){
                        if (this.all_fields[fld]['selection']){
                            for (i in this.all_fields[fld]['selection']){
                                if(result[res][fld] == this.all_fields[fld]['selection'][i][0]){
                                   result[res][fld] = this.all_fields[fld]['selection'][i];
                                }
                            }
                        }
                    }
                }
            }

            for (var i in result){
                var gen_key = result[i][this.chart_info_fields]+"_"+result[i][this.group_field];
                if (this.opration_fld[gen_key] == undefined){
                    var map_val = {};
                    map_val[this.operator_field] = result[i][this.operator_field];
                    if (this.operator.length > 1){
                        map_val[this.operator_field_one] = result[i][this.operator_field_one];
                    }
                    map_val[this.chart_info_fields] = result[i][this.chart_info_fields];
                    if (this.group_field){
                        map_val[this.group_field] = (typeof result[i][this.group_field] == 'object')?result[i][this.group_field][1]:result[i][this.group_field];
                    }
                    this.opration_fld[gen_key] = map_val;
                }else{
                    map_val = this.opration_fld[gen_key];
                    map_val[this.operator_field] += result[i][this.operator_field];
                    if (this.operator.length > 1){
                        map_val[this.operator_field_one] += result[i][this.operator_field_one];
                    }
                    this.opration_fld[gen_key] = map_val;
                }
            }
            result = [];
            for (i in this.opration_fld){
                result.push(this.opration_fld[i]);
            }

            if(this.chart == 'bar') {
                return this.schedule_bar(result);
            } else if(this.chart == "pie") {
                return this.schedule_pie(result);
            }
        }
    },

    schedule_bar: function(result) {
        var self = this;
        var view_chart = '';
        var xystr = {};
        var xyname = {};
        var res = [];
        this.group_list = [];
        var newkey = '';

        var COLOR_PALETTE = ['#cc99ff', '#ccccff', '#48D1CC', '#CFD784', '#8B7B8B', '#75507b', '#b0008c', '#ff0000', '#ff8e00', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
                     '#905000', '#9b0000', '#840067', '#9abe00', '#ffc900', '#510090', '#0000c9', '#009b00',
                     '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400', '#fcaf3e', '#ef2929', '#ff00c9',
                     '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', '#f57900', '#cc0000', '#d400a8'];

        if(self.group_field && (this.operator.length <= 1)){
            view_chart = self.orientation == 'horizontal'? 'stackedBarH' : 'stackedBar';
        }else{
            view_chart = self.orientation == 'horizontal'? 'barH' : 'bar';
        }

        for (i in result){
            if (self.group_field && (this.operator.length <= 1)){
                newkey =result[i][self.group_field].split(' ').join('_');
            }else{
                newkey = "val";
            }

            if (jQuery.inArray(newkey, self.group_list) == -1){
                self.group_list.push(newkey);
                if(this.operator.length > 1){
                    var newkey_one = "val1";
                    self.group_list.push(newkey_one);
                }
            }
        }

        for (i in result){
            var xystring = result[i][self.chart_info_fields];
            if (self.group_field && (self.operator.length <= 1)){
                newkey =result[i][self.group_field].split(' ').join('_');
            }else{
                newkey = "val";
            }
            if (xystr[xystring] == undefined){
                xyname = {};
                xyname[self.chart_info_fields] = xystring;
                for (var j in self.group_list){
                    xyname[self.group_list[j]] = 0.0001;
                }
                xyname[newkey] = result[i][self.operator_field];
                if (self.operator.length > 1){
                    xyname[newkey_one] = result[i][self.operator_field_one];
                }
                xystr[xystring] = xyname;
            }
            else{
                xyname = {};
                xyname = xystr[xystring];
                xyname[newkey] = result[i][self.operator_field];
                if (self.operator.length > 1){
                    xyname[newkey_one] = result[i][self.operator_field_one];
                }
                xystr[xystring] = xyname;
            }
        }
        for (i in xystr){
            res.push(xystr[i]);
        }

        //for legend color
        var grp_color = [];
        for (var i in self.group_list){
            var legend = {};
            if (self.group_list[i] == "val"){
                legend['text'] = self.fields[self.operator_field]['string']
            }else if(self.group_list[i] == "val1"){
                legend['text'] = self.fields[self.operator_field_one]['string']
            }else{
                legend['text'] = self.group_list[i];
            }
            legend['color'] = COLOR_PALETTE[i];
            grp_color.push(legend);
        }

        //for axis's value and title
        var temp_ax = {};
        var oth_ax = {};
        temp_ax['template'] = self.chart_info_fields;
        temp_ax['title'] = ""+self.x_title+"" ;
        oth_ax['lines'] = true;
        oth_ax['title'] = ""+self.y_title+"";

        if (self.orientation == 'horizontal'){
             var x_ax = oth_ax;
             var y_ax = temp_ax;
        }else{
             var x_ax = temp_ax;
             var y_ax = oth_ax;
        }

        var bar_chart = new dhtmlxchartChart({
            view: view_chart,
            container: self.view_id+"-barchart",
            value:"#"+self.group_list[0]+"#",
            gradient: "3d",
            border: false,
            width: 1024,
            radius: 0,
            color:grp_color[0]['color'],
            origin:0,
            xAxis:{
                template:function(obj){
                    if(x_ax['template']){
                        var val = obj[x_ax['template']];
                        val = (typeof val == 'object')?val[1]:(!val?'Undefined':val);
                        return val;
                    }else{
                        return obj;
                    }
                },
                title:x_ax['title'],
                lines:x_ax['lines']
            },
            yAxis:{
                template:function(obj){
                    if(y_ax['template']){
                        var vals = obj[y_ax['template']];
                        vals = (typeof vals == 'object')?vals[1]:(!vals?'Undefined':vals);
                        return vals;
                    }else{
                        return obj;
                    }
                },
                title:y_ax['title'],
                lines: y_ax['lines']
            },
            padding: {
                left: 75
            },
            legend: {
                values: grp_color,
                align:"left",
                valign:"top",
                layout: "x",
                marker:{
                    type:"round",
                    width:12
                }
            }
        });
        for (var i = 1; i<self.group_list.length;i++){
            bar_chart.addSeries({
                value: "#"+self.group_list[i]+"#",
                color: grp_color[i]['color']
            });
        }
        bar_chart.parse(res,"json");
        bar_chart.attachEvent("onItemClick", function(id) {
            var id = bar_chart.get(id);
            self.open_list_view(id);
        });
    },
    schedule_pie: function(result) {
        var self = this;
        var chart =  new dhtmlxchartChart({
            view:"pie3D",
            container:self.view_id+"-piechart",
            value:"#"+self.operator_field+"#",
            pieInnerText:function(obj) {
                var sum = chart.sum("#"+self.operator_field+"#");
                var val = obj[self.operator_field] / sum * 100 ;
                return Math.round(val * 10)/10 + "%";
            },
            gradient:"3d",
            height: 20,
            radius: 200,
            legend: {
                width: 300,
                align:"left",
                valign:"top",
                layout: "x",
                marker:{
                    type:"round",
                    width:12
                },
                template:function(obj){
                    var val = obj[self.chart_info_fields];
                    val = (typeof val == 'object')?val[1]:val;
                    return val;
                }
            }
        });
        chart.parse(result,"json");
        chart.attachEvent("onItemClick", function(id) {
            var id = chart.get(id);
            self.open_list_view(id);
        });
    },
    open_list_view : function (id){
        var self = this;
        var id = id[self.chart_info_fields];
        if (typeof id == 'object'){
            id = id[0];
        }else{
            id = id;
        }
        if(this.view_manager.action.context){
           this.view_manager.action.context = {};
        }
        if(!this.view_manager.action.domain) {
            this.view_manager.action.domain = [[self.chart_info_fields, '=', id],['id','in',self.dataset.ids]];
        } else {
            this.view_manager.action.domain.push([self.chart_info_fields, '=', id],['id','in',self.dataset.ids]);
        }
        var action_manager = new openerp.base.ActionManager(this.view_manager.session, this.view_manager.element_id);
        action_manager.start();
        action_manager.do_action(this.view_manager.action);
    },
    do_search: function(domains, contexts, groupbys) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: groupbys
        }, function (results) {
            // TODO: handle non-empty results.group_by with read_group
            if(results.group_by  && results.group_by != ''){
                self.chart_info_fields = results.group_by[0];
            }else{
                self.chart_info_fields = self.chart_info;
            }
            self.dataset.context = self.context = results.context;
            self.dataset.domain = self.domain = results.domain;
            self.dataset.read_slice({}, 0, self.limit,function(response){
                self.load_chart(response);
            });
        });
    }

});

// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them

};

// vim:et fdc=0 fdl=0:
<|endoftext|>


<commit_before>(function(window) {
  'use strict';

  // Public: Create a new SelectorSet.
  function SelectorSet() {
    if (!(this instanceof SelectorSet)) {
      return new SelectorSet();
    }

    // Public: Number of selectors added to the set
    this.size = 0;

    // Internal: Incrementing ID counter
    this.uid = 0;

    // Internal: Array of String selectors in the set
    this.selectors = [];

    this.indexes = Object.create(this.indexes);

    // Internal: Object index String names mapping to Index objects.
    this.activeIndexes = {};
  }

  var docElem = window.document.documentElement;
  var matches = (docElem.webkitMatchesSelector ||
                  docElem.mozMatchesSelector ||
                  docElem.oMatchesSelector ||
                  docElem.msMatchesSelector);

  // Public: Check if element matches selector.
  //
  // Maybe overridden with custom Element.matches function.
  //
  // el       - An Element
  // selector - String CSS selector
  //
  // Returns true or false.
  SelectorSet.prototype.matchesSelector = function(el, selector) {
    return matches.call(el, selector);
  };

  // Public: Find all elements in the context that match the selector.
  //
  // Maybe overridden with custom querySelectorAll function.
  //
  // selectors - String CSS selectors.
  // context   - Element context
  //
  // Returns non-live list of Elements.
  SelectorSet.prototype.querySelectorAll = function(selectors, context) {
    return context.querySelectorAll(selectors);
  };

  // Public: Array of indexes.
  //
  // name     - Unique String name
  // selector - Function that takes a String selector and returns a String key
  //            or undefined if it can't be used by the index.
  // element  - Function that takes an Element and returns an Array of String
  //            keys that point to indexed values.
  //
  SelectorSet.prototype.indexes = [];

  // Index by element id
  var idRe = /^#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.prototype.indexes.push({
    name: 'ID',
    selector: function matchIdSelector(sel) {
      var m;
      if (m = sel.match(idRe)) {
        return m[0].slice(1);
      }
    },
    element: function getElementId(el) {
      if (el.id) {
        return [el.id];
      }
    }
  });

  // Index by all of its class names
  var classRe = /^\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.prototype.indexes.push({
    name: 'CLASS',
    selector: function matchClassSelector(sel) {
      var m;
      if (m = sel.match(classRe)) {
        return m[0].slice(1);
      }
    },
    element: function getElementClassNames(el) {
      var className = el.className;
      if (className) {
        if (typeof className === 'string') {
          return className.split(/\s/);
        } else if (className instanceof SVGAnimatedString) {
          return className.baseVal.split(/\s/);
        }
      }
    }
  });

  // Index by tag/node name: `DIV`, `FORM`, `A`
  var tagRe = /^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.prototype.indexes.push({
    name: 'TAG',
    selector: function matchTagSelector(sel) {
      var m;
      if (m = sel.match(tagRe)) {
        return m[0].toUpperCase();
      }
    },
    element: function getElementTagName(el) {
      return [el.nodeName.toUpperCase()];
    }
  });

  // Default index just contains a single array of elements.
  SelectorSet.prototype.indexes['default'] = {
    name: 'UNIVERSAL',
    selector: function() {
      return true;
    },
    element: function() {
      return [true];
    }
  };

  // Use ES Maps when supported
  var Map;
  if (typeof window.Map === 'function') {
    Map = window.Map;
  } else {
    Map = (function() {
      function Map() {
        this.map = {};
      }
      Map.prototype.get = function(key) {
        return this.map[key + ' '];
      };
      Map.prototype.set = function(key, value) {
        this.map[key + ' '] = value;
      };
      return Map;
    })();
  }

  // Regexps adopted from Sizzle
  //   https://github.com/jquery/sizzle/blob/1.7/sizzle.js
  //
  var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g;

  // Internal: Get indexes for selector.
  //
  // selector - String CSS selector
  //
  // Returns Array of {index, key}.
  SelectorSet.prototype.selectorIndexes = function(selector) {
    var allIndexes = this.indexes.slice(0).concat(this.indexes['default']),
        allIndexesLen = allIndexes.length,
        i, m, rest = selector,
        key, index, indexes = [];

    do {
      chunker.exec('');
      if (m = chunker.exec(rest)) {
        rest = m[3];
        if (m[2] || !rest) {
          for (i = 0; i < allIndexesLen; i++) {
            index = allIndexes[i];
            if (key = index.selector(m[1])) {
              indexes.push({index: index, key: key});
              break;
            }
          }
        }
      }
    } while (m);

    return indexes;
  };

  // Public: Log when added selector falls under the default index.
  //
  // This API should not be considered stable. May change between
  // minor versions.
  //
  // obj - {selector, data} Object
  //
  //   SelectorSet.prototype.logDefaultIndexUsed = function(obj) {
  //     console.warn(obj.selector, "could not be indexed");
  //   };
  //
  // Returns nothing.
  SelectorSet.prototype.logDefaultIndexUsed = function() {};

  // Public: Add selector to set.
  //
  // selector - String CSS selector
  // data     - Optional data Object (default: undefined)
  //
  // Returns nothing.
  SelectorSet.prototype.add = function(selector, data) {
    var obj, i, index, key, selIndex, objs,
        selectorIndexes, selectorIndex,
        indexes = this.activeIndexes,
        selectors = this.selectors;

    if (typeof selector !== 'string') {
      return;
    }

    obj = {
      id: this.uid++,
      selector: selector,
      data: data
    };

    selectorIndexes = this.selectorIndexes(selector);
    for (i = 0; i < selectorIndexes.length; i++) {
      selectorIndex = selectorIndexes[i];
      key = selectorIndex.key;
      index = selectorIndex.index;
      selIndex = indexes[index.name];
      if (!selIndex) {
        selIndex = indexes[index.name] = Object.create(index);
        selIndex.keys = new Map();
      }
      if (index === this.indexes['default']) {
        this.logDefaultIndexUsed(obj);
      }
      objs = selIndex.keys.get(key);
      if (!objs) {
        objs = [];
        selIndex.keys.set(key, objs);
      }
      objs.push(obj);
    }

    this.size++;
    selectors.push(selector);
  };

  // Public: Remove selector from set.
  //
  // selector - String CSS selector
  // data     - Optional data Object (default: undefined)
  //
  // Returns nothing.
  SelectorSet.prototype.remove = function(selector, data) {
    if (typeof selector !== 'string') {
      return;
    }

    var selectorIndexes, selectorIndex, i, j, key, index, selIndex, objs, obj;
    var indexes = this.activeIndexes;
    var removedIds = {};
    var removeAll = arguments.length === 1;

    selectorIndexes = this.selectorIndexes(selector);
    for (i = 0; i < selectorIndexes.length; i++) {
      selectorIndex = selectorIndexes[i];
      key = selectorIndex.key;
      index = selectorIndex.index;
      selIndex = indexes[index.name];

      if (selIndex) {
        objs = selIndex.keys.get(key);
        if (objs) {
          j = objs.length;
          while (j--) {
            obj = objs[j];
            if (obj.selector === selector && (removeAll || obj.data === data)) {
              objs.splice(j, 1);
              removedIds[obj.id] = true;
            }
          }
        }
      }
    }

    this.size -= Object.keys(removedIds).length;
  };

  // Sort by id property handler.
  //
  // a - Selector obj.
  // b - Selector obj.
  //
  // Returns Number.
  function sortById(a, b) {
    return a.id - b.id;
  }

  // Public: Find all matching decendants of the context element.
  //
  // context - An Element
  //
  // Returns Array of {selector, data, elements} matches.
  SelectorSet.prototype.queryAll = function(context) {
    if (!this.selectors.length) {
      return [];
    }

    var matches = {};

    var els = this.querySelectorAll(this.selectors.join(', '), context);

    var i, j, len, len2, el, m, obj;
    for (i = 0, len = els.length; i < len; i++) {
      el = els[i];
      m = this.matches(el);
      for (j = 0, len2 = m.length; j < len2; j++) {
        obj = m[j];
        if (!matches[obj.id]) {
          matches[obj.id] = {
            id: obj.id,
            selector: obj.selector,
            data: obj.data,
            elements: []
          };
        }
        matches[obj.id].elements.push(el);
      }
    }

    var results = [];
    for (m in matches) {
      results.push(matches[m]);
    }

    return results.sort(sortById);
  };

  // Public: Match element against all selectors in set.
  //
  // el - An Element
  //
  // Returns Array of {selector, data} matches.
  SelectorSet.prototype.matches = function(el) {
    if (!el) {
      return [];
    }

    var i, j, len, len2, indexName, index, keys, objs, obj, id;
    var indexes = this.activeIndexes, matchedIds = {}, matches = [];

    for (indexName in indexes) {
      index = indexes[indexName];
      keys = index.element(el);
      if (keys) {
        for (i = 0, len = keys.length; i < len; i++) {
          if (objs = index.keys.get(keys[i])) {
            for (j = 0, len2 = objs.length; j < len2; j++) {
              obj = objs[j];
              id = obj.id;
              if (!matchedIds[id] && this.matchesSelector(el, obj.selector)) {
                matchedIds[id] = true;
                matches.push(obj);
              }
            }
          }
        }
      }
    }

    return matches.sort(sortById);
  };

  window.SelectorSet = SelectorSet;
})(window);
<commit_msg>More inline docs<commit_after>(function(window) {
  'use strict';

  // Public: Create a new SelectorSet.
  function SelectorSet() {
    // Construct new SelectorSet if called as a function.
    if (!(this instanceof SelectorSet)) {
      return new SelectorSet();
    }

    // Public: Number of selectors added to the set
    this.size = 0;

    // Internal: Incrementing ID counter
    this.uid = 0;

    // Internal: Array of String selectors in the set
    this.selectors = [];

    // Internal: All Object index String names mapping to Index objects.
    this.indexes = Object.create(this.indexes);

    // Internal: Used Object index String names mapping to Index objects.
    this.activeIndexes = {};
  }

  // Detect prefixed Element#matches function.
  var docElem = window.document.documentElement;
  var matches = (docElem.webkitMatchesSelector ||
                  docElem.mozMatchesSelector ||
                  docElem.oMatchesSelector ||
                  docElem.msMatchesSelector);

  // Public: Check if element matches selector.
  //
  // Maybe overridden with custom Element.matches function.
  //
  // el       - An Element
  // selector - String CSS selector
  //
  // Returns true or false.
  SelectorSet.prototype.matchesSelector = function(el, selector) {
    return matches.call(el, selector);
  };

  // Public: Find all elements in the context that match the selector.
  //
  // Maybe overridden with custom querySelectorAll function.
  //
  // selectors - String CSS selectors.
  // context   - Element context
  //
  // Returns non-live list of Elements.
  SelectorSet.prototype.querySelectorAll = function(selectors, context) {
    return context.querySelectorAll(selectors);
  };

  // Public: Array of indexes.
  //
  // name     - Unique String name
  // selector - Function that takes a String selector and returns a String key
  //            or undefined if it can't be used by the index.
  // element  - Function that takes an Element and returns an Array of String
  //            keys that point to indexed values.
  //
  SelectorSet.prototype.indexes = [];

  // Index by element id
  var idRe = /^#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.prototype.indexes.push({
    name: 'ID',
    selector: function matchIdSelector(sel) {
      var m;
      if (m = sel.match(idRe)) {
        return m[0].slice(1);
      }
    },
    element: function getElementId(el) {
      if (el.id) {
        return [el.id];
      }
    }
  });

  // Index by all of its class names
  var classRe = /^\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.prototype.indexes.push({
    name: 'CLASS',
    selector: function matchClassSelector(sel) {
      var m;
      if (m = sel.match(classRe)) {
        return m[0].slice(1);
      }
    },
    element: function getElementClassNames(el) {
      var className = el.className;
      if (className) {
        if (typeof className === 'string') {
          return className.split(/\s/);
        } else if (className instanceof SVGAnimatedString) {
          return className.baseVal.split(/\s/);
        }
      }
    }
  });

  // Index by tag/node name: `DIV`, `FORM`, `A`
  var tagRe = /^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.prototype.indexes.push({
    name: 'TAG',
    selector: function matchTagSelector(sel) {
      var m;
      if (m = sel.match(tagRe)) {
        return m[0].toUpperCase();
      }
    },
    element: function getElementTagName(el) {
      return [el.nodeName.toUpperCase()];
    }
  });

  // Default index just contains a single array of elements.
  SelectorSet.prototype.indexes['default'] = {
    name: 'UNIVERSAL',
    selector: function() {
      return true;
    },
    element: function() {
      return [true];
    }
  };

  // Use ES Maps when supported
  var Map;
  if (typeof window.Map === 'function') {
    Map = window.Map;
  } else {
    Map = (function() {
      function Map() {
        this.map = {};
      }
      Map.prototype.get = function(key) {
        return this.map[key + ' '];
      };
      Map.prototype.set = function(key, value) {
        this.map[key + ' '] = value;
      };
      return Map;
    })();
  }

  // Regexps adopted from Sizzle
  //   https://github.com/jquery/sizzle/blob/1.7/sizzle.js
  //
  var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g;

  // Internal: Get indexes for selector.
  //
  // selector - String CSS selector
  //
  // Returns Array of {index, key}.
  SelectorSet.prototype.selectorIndexes = function(selector) {
    var allIndexes = this.indexes.slice(0).concat(this.indexes['default']),
        allIndexesLen = allIndexes.length,
        i, m, rest = selector,
        key, index, indexes = [];

    do {
      chunker.exec('');
      if (m = chunker.exec(rest)) {
        rest = m[3];
        if (m[2] || !rest) {
          for (i = 0; i < allIndexesLen; i++) {
            index = allIndexes[i];
            if (key = index.selector(m[1])) {
              indexes.push({index: index, key: key});
              break;
            }
          }
        }
      }
    } while (m);

    return indexes;
  };

  // Public: Log when added selector falls under the default index.
  //
  // This API should not be considered stable. May change between
  // minor versions.
  //
  // obj - {selector, data} Object
  //
  //   SelectorSet.prototype.logDefaultIndexUsed = function(obj) {
  //     console.warn(obj.selector, "could not be indexed");
  //   };
  //
  // Returns nothing.
  SelectorSet.prototype.logDefaultIndexUsed = function() {};

  // Public: Add selector to set.
  //
  // selector - String CSS selector
  // data     - Optional data Object (default: undefined)
  //
  // Returns nothing.
  SelectorSet.prototype.add = function(selector, data) {
    var obj, i, index, key, selIndex, objs,
        selectorIndexes, selectorIndex,
        indexes = this.activeIndexes,
        selectors = this.selectors;

    if (typeof selector !== 'string') {
      return;
    }

    obj = {
      id: this.uid++,
      selector: selector,
      data: data
    };

    selectorIndexes = this.selectorIndexes(selector);
    for (i = 0; i < selectorIndexes.length; i++) {
      selectorIndex = selectorIndexes[i];
      key = selectorIndex.key;
      index = selectorIndex.index;
      selIndex = indexes[index.name];
      if (!selIndex) {
        selIndex = indexes[index.name] = Object.create(index);
        selIndex.keys = new Map();
      }
      if (index === this.indexes['default']) {
        this.logDefaultIndexUsed(obj);
      }
      objs = selIndex.keys.get(key);
      if (!objs) {
        objs = [];
        selIndex.keys.set(key, objs);
      }
      objs.push(obj);
    }

    this.size++;
    selectors.push(selector);
  };

  // Public: Remove selector from set.
  //
  // selector - String CSS selector
  // data     - Optional data Object (default: undefined)
  //
  // Returns nothing.
  SelectorSet.prototype.remove = function(selector, data) {
    if (typeof selector !== 'string') {
      return;
    }

    var selectorIndexes, selectorIndex, i, j, key, index, selIndex, objs, obj;
    var indexes = this.activeIndexes;
    var removedIds = {};
    var removeAll = arguments.length === 1;

    selectorIndexes = this.selectorIndexes(selector);
    for (i = 0; i < selectorIndexes.length; i++) {
      selectorIndex = selectorIndexes[i];
      key = selectorIndex.key;
      index = selectorIndex.index;
      selIndex = indexes[index.name];

      if (selIndex) {
        objs = selIndex.keys.get(key);
        if (objs) {
          j = objs.length;
          while (j--) {
            obj = objs[j];
            if (obj.selector === selector && (removeAll || obj.data === data)) {
              objs.splice(j, 1);
              removedIds[obj.id] = true;
            }
          }
        }
      }
    }

    this.size -= Object.keys(removedIds).length;
  };

  // Sort by id property handler.
  //
  // a - Selector obj.
  // b - Selector obj.
  //
  // Returns Number.
  function sortById(a, b) {
    return a.id - b.id;
  }

  // Public: Find all matching decendants of the context element.
  //
  // context - An Element
  //
  // Returns Array of {selector, data, elements} matches.
  SelectorSet.prototype.queryAll = function(context) {
    if (!this.selectors.length) {
      return [];
    }

    var matches = {};

    var els = this.querySelectorAll(this.selectors.join(', '), context);

    var i, j, len, len2, el, m, obj;
    for (i = 0, len = els.length; i < len; i++) {
      el = els[i];
      m = this.matches(el);
      for (j = 0, len2 = m.length; j < len2; j++) {
        obj = m[j];
        if (!matches[obj.id]) {
          matches[obj.id] = {
            id: obj.id,
            selector: obj.selector,
            data: obj.data,
            elements: []
          };
        }
        matches[obj.id].elements.push(el);
      }
    }

    var results = [];
    for (m in matches) {
      results.push(matches[m]);
    }

    return results.sort(sortById);
  };

  // Public: Match element against all selectors in set.
  //
  // el - An Element
  //
  // Returns Array of {selector, data} matches.
  SelectorSet.prototype.matches = function(el) {
    if (!el) {
      return [];
    }

    var i, j, len, len2, indexName, index, keys, objs, obj, id;
    var indexes = this.activeIndexes, matchedIds = {}, matches = [];

    for (indexName in indexes) {
      index = indexes[indexName];
      keys = index.element(el);
      if (keys) {
        for (i = 0, len = keys.length; i < len; i++) {
          if (objs = index.keys.get(keys[i])) {
            for (j = 0, len2 = objs.length; j < len2; j++) {
              obj = objs[j];
              id = obj.id;
              if (!matchedIds[id] && this.matchesSelector(el, obj.selector)) {
                matchedIds[id] = true;
                matches.push(obj);
              }
            }
          }
        }
      }
    }

    return matches.sort(sortById);
  };

  // Public: Expose SelectorSet as a global on window.
  window.SelectorSet = SelectorSet;
})(window);
<|endoftext|>


<commit_before>(function() {
  'use strict';

  function SelectorSet() {
    if (!(this instanceof SelectorSet)) {
      return new SelectorSet();
    }

    this.size = 0;
    this.selectors = [];
    this.indexes = {};
  }

  var docElem = document.documentElement;
  var matches = (docElem.webkitMatchesSelector ||
                  docElem.mozMatchesSelector ||
                  docElem.oMatchesSelector ||
                  docElem.msMatchesSelector);

  // Public: Check if element matches selector.
  //
  // Maybe overridden with custom Element.matches function.
  //
  // el       - An Element
  // selector - String CSS selector
  //
  // Returns true or false.
  SelectorSet.matches = function(el, selector) {
    return matches.call(el, selector);
  };

  // Public: Find all elements in the context that match the selector.
  //
  // Maybe overridden with custom querySelectorAll function.
  //
  // selectors - String CSS selectors.
  // context   - Element context
  //
  // Returns non-live list of Elements.
  SelectorSet.queryAll = function(selectors, context) {
    return context.querySelectorAll(selectors);
  };

  SelectorSet.indexes = [];

  var idRe = /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.indexes.push({
    name: 'ID',
    selector: function matchIdSelector(sel) {
      var m;
      if (m = sel.match(idRe)) {
        return m[0].slice(1);
      }
    },
    element: function getElementId(el) {
      if (el.id) {
        return [el.id];
      }
    }
  });

  var classRe = /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.indexes.push({
    name: 'CLASS',
    selector: function matchClassSelector(sel) {
      var m;
      if (m = sel.match(classRe)) {
        return m[0].slice(1);
      }
    },
    element: function getElementClassNames(el) {
      if (el.className) {
        return el.className.split(/\s/);
      }
    }
  });

  var tagRe = /^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.indexes.push({
    name: 'TAG',
    selector: function matchTagSelector(sel) {
      var m;
      if (m = sel.match(tagRe)) {
        return m[0].toUpperCase();
      }
    },
    element: function getElementTagName(el) {
      return [el.nodeName];
    }
  });

  SelectorSet.indexes.push({
    name: 'UNIVERSAL',
    selector: function() {
      return '*';
    },
    element: function() {
      return ['*'];
    }
  });

  // Public: Add selector to set.
  //
  // selector - String CSS selector
  // data     - Optional data Object (default: undefined)
  //
  // Returns nothing.
  SelectorSet.prototype.add = function(selector, data) {
    var obj, i, len, selIndexes, sel, indexName,
        indexes = this.indexes,
        selectors = this.selectors;

    if (typeof selector !== 'string') {
      return;
    }

    obj = {
      id: this.size++,
      selector: selector,
      data: data
    };

    selIndexes = getSelectorIndexes(selector);
    for (i = 0, len = selIndexes.length; i < len; i++) {
      sel = selIndexes[i];
      indexName = sel.index.name;
      if (!indexes[indexName]) {
        indexes[indexName] = { index: sel.index, keys: {} };
      }
      if (!indexes[indexName].keys[sel.key]) {
        indexes[indexName].keys[sel.key] = [];
      }
      indexes[indexName].keys[sel.key].push(obj);
    }

    selectors.push(selector);
  };

  // Public: Find all matching decendants of the context element.
  //
  // context - An Element
  //
  // Returns Array of {selector, data, elements} matches.
  SelectorSet.prototype.queryAll = function(context) {
    var matches = {};

    var els = SelectorSet.queryAll(this.selectors.join(', '), context);

    var i, j, len, len2, el, m, obj;
    for (i = 0, len = els.length; i < len; i++) {
      el = els[i];
      m = this.matches(el);
      for (j = 0, len2 = m.length; j < len2; j++) {
        obj = m[j];
        if (!matches[obj.id]) {
          matches[obj.id] = {
            id: obj.id,
            selector: obj.selector,
            data: obj.data,
            elements: []
          };
        }
        matches[obj.id].elements.push(el);
      }
    }

    var results = [];
    for (m in matches) {
      results.push(matches[m]);
    }

    return results.sort(sortById);
  };

  // Public: Match element against all selectors in set.
  //
  // el - An Element
  //
  // Returns Array of {selector, data} matches.
  SelectorSet.prototype.matches = function(el) {
    if (!el) {
      return [];
    }

    var i, j, len, len2, indexName, index, keys, objs, obj, id;
    var indexes = this.indexes, matchedIds = {}, matches = [];

    for (indexName in indexes) {
      index = indexes[indexName];
      keys = index.index.element(el);
      if (keys) {
        for (i = 0, len = keys.length; i < len; i++) {
          if (objs = index.keys[keys[i]]) {
            for (j = 0, len2 = objs.length; j < len2; j++) {
              obj = objs[j];
              id = obj.id;
              if (!matchedIds[id] && SelectorSet.matches(el, obj.selector)) {
                matchedIds[id] = true;
                matches.push(obj);
              }
            }
          }
        }
      }
    }

    return matches.sort(sortById);
  };

  // Sort by id property handler.
  //
  // a - Selector obj.
  // b - Selector obj.
  //
  // Returns Number.
  function sortById(a, b) {
    return a.id - b.id;
  }

  // Regexps adopted from Sizzle
  //   https://github.com/jquery/sizzle/blob/1.7/sizzle.js
  //
  var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g;

  // Find best selector indexes for CSS selectors.
  //
  // selectors - CSS selector String.
  //
  // Returns an Array of {index, key} objects.
  function getSelectorIndexes(selectors) {
    var m, i, len, index, key;
    var indexes = SelectorSet.indexes;
    var rest = selectors, selIndexes = [];

    do {
      chunker.exec('');
      if (m = chunker.exec(rest)) {
        rest = m[3];
        if (m[2] || !rest) {
          for (i = 0, len = indexes.length; i < len; i++) {
            index = indexes[i];
            if (key = index.selector(m[1])) {
              selIndexes.push({index: index, key: key});
              break;
            }
          }
        }
      }
    } while (m);

    return selIndexes;
  }

  window.SelectorSet = SelectorSet;
})();
<commit_msg>Inline selector indexes<commit_after>(function() {
  'use strict';

  function SelectorSet() {
    if (!(this instanceof SelectorSet)) {
      return new SelectorSet();
    }

    this.size = 0;
    this.selectors = [];
    this.indexes = {};
  }

  var docElem = document.documentElement;
  var matches = (docElem.webkitMatchesSelector ||
                  docElem.mozMatchesSelector ||
                  docElem.oMatchesSelector ||
                  docElem.msMatchesSelector);

  // Public: Check if element matches selector.
  //
  // Maybe overridden with custom Element.matches function.
  //
  // el       - An Element
  // selector - String CSS selector
  //
  // Returns true or false.
  SelectorSet.matches = function(el, selector) {
    return matches.call(el, selector);
  };

  // Public: Find all elements in the context that match the selector.
  //
  // Maybe overridden with custom querySelectorAll function.
  //
  // selectors - String CSS selectors.
  // context   - Element context
  //
  // Returns non-live list of Elements.
  SelectorSet.queryAll = function(selectors, context) {
    return context.querySelectorAll(selectors);
  };

  SelectorSet.indexes = [];

  var idRe = /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.indexes.push({
    name: 'ID',
    selector: function matchIdSelector(sel) {
      var m;
      if (m = sel.match(idRe)) {
        return m[0].slice(1);
      }
    },
    element: function getElementId(el) {
      if (el.id) {
        return [el.id];
      }
    }
  });

  var classRe = /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.indexes.push({
    name: 'CLASS',
    selector: function matchClassSelector(sel) {
      var m;
      if (m = sel.match(classRe)) {
        return m[0].slice(1);
      }
    },
    element: function getElementClassNames(el) {
      if (el.className) {
        return el.className.split(/\s/);
      }
    }
  });

  var tagRe = /^((?:[\w\u00c0-\uFFFF\-]|\\.)+)/g;
  SelectorSet.indexes.push({
    name: 'TAG',
    selector: function matchTagSelector(sel) {
      var m;
      if (m = sel.match(tagRe)) {
        return m[0].toUpperCase();
      }
    },
    element: function getElementTagName(el) {
      return [el.nodeName];
    }
  });

  SelectorSet.indexes.push({
    name: 'UNIVERSAL',
    selector: function() {
      return '*';
    },
    element: function() {
      return ['*'];
    }
  });

  // Regexps adopted from Sizzle
  //   https://github.com/jquery/sizzle/blob/1.7/sizzle.js
  //
  var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g;

  // Public: Add selector to set.
  //
  // selector - String CSS selector
  // data     - Optional data Object (default: undefined)
  //
  // Returns nothing.
  SelectorSet.prototype.add = function(selector, data) {
    var obj, i, m, index, key, indexName, selIndex, objs,
        allIndexes = SelectorSet.indexes,
        allIndexesLen = allIndexes.length,
        indexes = this.indexes,
        selectors = this.selectors,
        rest = selector;

    if (typeof selector !== 'string') {
      return;
    }

    obj = {
      id: this.size++,
      selector: selector,
      data: data
    };

    do {
      chunker.exec('');
      if (m = chunker.exec(rest)) {
        rest = m[3];
        if (m[2] || !rest) {
          for (i = 0; i < allIndexesLen; i++) {
            index = allIndexes[i];
            if (key = index.selector(m[1])) {
              indexName = index.name;
              selIndex = indexes[indexName];
              if (!selIndex) {
                selIndex = indexes[indexName] = { index: index, keys: {} };
              }
              objs = selIndex.keys[key];
              if (!objs) {
                objs = selIndex.keys[key] = [];
              }
              objs.push(obj);
              break;
            }
          }
        }
      }
    } while (m);

    selectors.push(selector);
  };

  // Sort by id property handler.
  //
  // a - Selector obj.
  // b - Selector obj.
  //
  // Returns Number.
  function sortById(a, b) {
    return a.id - b.id;
  }

  // Public: Find all matching decendants of the context element.
  //
  // context - An Element
  //
  // Returns Array of {selector, data, elements} matches.
  SelectorSet.prototype.queryAll = function(context) {
    var matches = {};

    var els = SelectorSet.queryAll(this.selectors.join(', '), context);

    var i, j, len, len2, el, m, obj;
    for (i = 0, len = els.length; i < len; i++) {
      el = els[i];
      m = this.matches(el);
      for (j = 0, len2 = m.length; j < len2; j++) {
        obj = m[j];
        if (!matches[obj.id]) {
          matches[obj.id] = {
            id: obj.id,
            selector: obj.selector,
            data: obj.data,
            elements: []
          };
        }
        matches[obj.id].elements.push(el);
      }
    }

    var results = [];
    for (m in matches) {
      results.push(matches[m]);
    }

    return results.sort(sortById);
  };

  // Public: Match element against all selectors in set.
  //
  // el - An Element
  //
  // Returns Array of {selector, data} matches.
  SelectorSet.prototype.matches = function(el) {
    if (!el) {
      return [];
    }

    var i, j, len, len2, indexName, index, keys, objs, obj, id;
    var indexes = this.indexes, matchedIds = {}, matches = [];

    for (indexName in indexes) {
      index = indexes[indexName];
      keys = index.index.element(el);
      if (keys) {
        for (i = 0, len = keys.length; i < len; i++) {
          if (objs = index.keys[keys[i]]) {
            for (j = 0, len2 = objs.length; j < len2; j++) {
              obj = objs[j];
              id = obj.id;
              if (!matchedIds[id] && SelectorSet.matches(el, obj.selector)) {
                matchedIds[id] = true;
                matches.push(obj);
              }
            }
          }
        }
      }
    }

    return matches.sort(sortById);
  };

  window.SelectorSet = SelectorSet;
})();
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var _ = require('lodash');

var SelectBuilder = require('./select');
var WhereBuilder = require('./where');
var utils = require('./lib/utils');

/**
 * Sequel generator
 *
 * Given a Waterline Query Object build a SQL query.
 */

var Sequel = module.exports = function(schema, options) {

  // Store the schema values for the database structure
  this.schema = schema || {};

  // To solve a query, multiple query strings may be needed.
  this.queries = [];

  // Flag whether queries should be built using parameterized queries or not.
  // Default is true.
  this.parameterized = options && utils.object.hasOwnProperty(options, 'parameterized') ? options.parameterized : true;

  // Flag if things should be cast, useful for averages
  this.cast = options && utils.object.hasOwnProperty(options, 'casting') ? options.casting : false;

  // Flag whether the database is case-sensitive or not.
  // Default is true.
  // NOTE: This does not mean that your queries will be case sensitive. It just flags if the queries
  // should use lower or regex logic for querying.
  this.caseSensitive = options && utils.object.hasOwnProperty(options, 'caseSensitive') ? options.caseSensitive : true;

  // Set the escape character, default is "
  this.escapeCharacter = options && utils.object.hasOwnProperty(options, 'escapeCharacter') ? options.escapeCharacter : '"';

  // Set if the database can return values from things such as an insert
  this.canReturnValues = options && utils.object.hasOwnProperty(options, 'canReturnValues') ? options.canReturnValues : false;

  // Determine if insert values should be escaped or not
  this.escapeInserts = options && utils.object.hasOwnProperty(options, 'escapeInserts') ? options.escapeInserts : false;

  // Determine if aliased tablenames in DELETE queries need to be referenced before the FROM, e.g.
  // DELETE `tableName` FROM `tableName` as `otherTableName` WHERE `otherTableName`.`foo` = "bar"
  // MySQL and Oracle require this, but it doesn't work in Postgresql.
  this.declareDeleteAlias = options && utils.object.hasOwnProperty(options, 'declareDeleteAlias') ? options.declareDeleteAlias : true;

  this.explicitTableAs = options && utils.object.hasOwnProperty(options, 'explicitTableAs') ? options.explicitTableAs : true;

  this.prefixAlias = options && utils.object.hasOwnProperty(options, 'prefixAlias') ? options.prefixAlias : '__';

  this.tableAs = this.explicitTableAs ? ' AS ' : ' ';

  this.stringDelimiter = options && utils.object.hasOwnProperty(options, 'stringDelimiter') ? options.stringDelimiter : '"';

  this.rownum = options && utils.object.hasOwnProperty(options, 'rownum') ? options.rownum : false;

  // Waterline NEXT
  // These are flags that can be toggled today and expose future features. If any of the following are turned
  // on the adapter tests will probably not pass. If you toggle these know what you are getting into.
  var wlNext = options && utils.object.hasOwnProperty(options, 'wlNext') ? options.wlNext : {};
  this.wlNext = {

    // Case sensitive - false
    // In the next version of WL queries will be case sensitive by default.
    // Set this to true to experiement with that feature today.
    caseSensitive: utils.object.hasOwnProperty(wlNext, 'caseSensitive') ? wlNext.caseSensitive : false

  };

  this.values = [];

  return this;
};

/**
 * Build a SQL Find Query using the defined schema.
 */

Sequel.prototype.find = function find(currentTable, queryObject) {

  // Step 1:
  // Build out the Select statements
  var selectObject = this.select(currentTable, queryObject);
  this.queries = selectObject.select;

  var whereObject;
  var childQueries;
  var query;
  var values;

  /**
   * Step 2 - Build out the parent query.
   */

  whereObject = this.simpleWhere(currentTable, queryObject);

  this.queries[0] += ' ' + whereObject.query;
  this.values[0] = whereObject.values;

  /**
   * Step 3 - Build out the child query templates.
   */

  childQueries = this.complexWhere(currentTable, queryObject);
  this.queries = this.queries.concat(childQueries);

  return {
    query: this.queries,
    values: this.values
  };

};

/**
 * Build a SQL Count Query using the defined schema.
 */

Sequel.prototype.count = function count(currentTable, queryObject) {

  // Escape table name
  var tableName = utils.escapeName(this.schema[currentTable].tableName, this.escapeCharacter);

  // Step 1:
  // Build out the Count statements
  this.queries = ['SELECT COUNT(*) as count FROM '];

  var subQuery = 'SELECT * FROM ' + tableName;

  var whereObject;
  var childQueries;
  var query;
  var values;

  /**
   * Step 2 - Build out the WHERE part of the query.
   */

  whereObject = this.simpleWhere(currentTable, queryObject);

  // Append the sub-query to the COUNT so you end up with something that looks like:
  // SELECT count(*) as count FROM (SELECT * FROM table LIMIT 10 OFFSET 10) AS tableAlias;
  this.queries[0] += '(SELECT * FROM ' + tableName + ' ' + whereObject.query + ') AS ' + tableName;
  this.values[0] = whereObject.values;

  /**
   * Step 3 - Build out the child query templates.
   */

  childQueries = this.complexWhere(currentTable, queryObject);
  this.queries = this.queries.concat(childQueries);

  return {
    query: this.queries,
    values: this.values
  };

};

/**
 * Build a SQL Create Query.
 */

Sequel.prototype.create = function create(currentTable, data) {

  var options = {
    parameterized: this.parameterized,
    escapeCharacter: this.escapeCharacter,
    escapeInserts: this.escapeInserts
  };

  // Transform the Data object into arrays used in a parameterized query
  var attributes = utils.mapAttributes(data, options);
  var columnNames = attributes.keys.join(', ');
  var paramValues = attributes.params.join(', ');

  // Build Query
  var query = 'INSERT INTO ' + utils.escapeName(currentTable, this.escapeCharacter) + ' (' + columnNames + ') values (' + paramValues + ')';

  if(this.canReturnValues) {
    query += ' RETURNING *';
  }

  return { query: query, values: attributes.values };
};

/**
 * Build a SQL Update Query.
 */

Sequel.prototype.update = function update(currentTable, queryObject, data) {

  var options = {
    parameterized: this.parameterized,
    escapeCharacter: this.escapeCharacter,
    escapeInserts: this.escapeInserts
  };

  // Get the attribute identity (as opposed to the table name)
  var identity = currentTable;
  // Create the query with the tablename aliased as the identity (in case they are different)
  var query = 'UPDATE ' + utils.escapeName(currentTable, this.escapeCharacter) + this.tableAs + utils.escapeName(identity, this.escapeCharacter) + ' ';

  // Transform the Data object into arrays used in a parameterized query
  var attributes = utils.mapAttributes(data, options);

  // Update the paramCount
  var paramCount = attributes.params.length + 1;

  // Build SET string
  var str = '';
  for(var i=0; i < attributes.keys.length; i++) {
    str += attributes.keys[i] + ' = ' + attributes.params[i] + ', ';
  }

  // Remove trailing comma
  str = str.slice(0, -2);

  query += 'SET ' + str + ' ';

  // Add data values to this._values
  var values = attributes.values;

  // Build Criteria clause
  var whereObject = this.simpleWhere(currentTable, queryObject, { paramCount: paramCount });

  query += ' ' + whereObject.query;
  values = values.concat(whereObject.values);

  if(this.canReturnValues) {
    query += ' RETURNING *';
  }

  return {
    query: query,
    values: values
  };
};

/**une chaine vide
 * Build Delete SQL query.
 */

Sequel.prototype.destroy = function destroy(currentTable, queryObject) {

  // Get the attribute identity (as opposed to the table name)
  var identity = currentTable;

  var query = 'DELETE ' + (this.declareDeleteAlias ? utils.escapeName(identity, this.escapeCharacter) : '') + ' FROM ' + utils.escapeName(currentTable, this.escapeCharacter) + this.tableAs + utils.escapeName(identity, this.escapeCharacter) + ' ';

  // Build Criteria clause
  var whereObject = this.simpleWhere(currentTable, queryObject);

  query += ' ' + whereObject.query;
  var values = whereObject.values;

  if(this.canReturnValues) {
    query += ' RETURNING *';
  }

  return {
    query: query,
    values: values
  };
};

/**
 * Build the select statements for a query.
 */

Sequel.prototype.select = function select(currentTable, queryObject) {
  var options = {
    escapeCharacter: this.escapeCharacter,
    caseSensitive: this.caseSensitive,
    cast: this.cast,
	explicitTableAs: this.explicitTableAs,
    prefixAlias: this.prefixAlias,
    stringDelimiter: this.stringDelimiter,
    rownum: this.rownum,
    wlNext: this.wlNext
  };

  return new SelectBuilder(this.schema, currentTable, queryObject, options);
};

/**
 * Build the where statements for a query.
 */

Sequel.prototype.simpleWhere = function simpleWhere(currentTable, queryObject, options) {
  var _options = {
    parameterized: this.parameterized,
    caseSensitive: this.caseSensitive,
    escapeCharacter: this.escapeCharacter,
	explicitTableAs: this.explicitTableAs,
    prefixAlias: this.prefixAlias,
    stringDelimiter: this.stringDelimiter,
    wlNext: this.wlNext
  };

  var where = new WhereBuilder(this.schema, currentTable, _options);
  return where.single(queryObject, options);
};

Sequel.prototype.complexWhere = function complexWhere(currentTable, queryObject, options) {
  var _options = {
    parameterized: this.parameterized,
    caseSensitive: this.caseSensitive,
    escapeCharacter: this.escapeCharacter,
	explicitTableAs: this.explicitTableAs,
    prefixAlias: this.prefixAlias,
    stringDelimiter: this.stringDelimiter
  };

  var where = new WhereBuilder(this.schema, currentTable, _options);
  return where.complex(queryObject, options);
};
<commit_msg>Add some comments<commit_after>/**
 * Module dependencies
 */

var _ = require('lodash');

var SelectBuilder = require('./select');
var WhereBuilder = require('./where');
var utils = require('./lib/utils');

/**
 * Sequel generator
 *
 * Given a Waterline Query Object build a SQL query.
 */

var Sequel = module.exports = function(schema, options) {

  // Store the schema values for the database structure
  this.schema = schema || {};

  // To solve a query, multiple query strings may be needed.
  this.queries = [];

  // Flag whether queries should be built using parameterized queries or not.
  // Default is true.
  this.parameterized = options && utils.object.hasOwnProperty(options, 'parameterized') ? options.parameterized : true;

  // Flag if things should be cast, useful for averages
  this.cast = options && utils.object.hasOwnProperty(options, 'casting') ? options.casting : false;

  // Flag whether the database is case-sensitive or not.
  // Default is true.
  // NOTE: This does not mean that your queries will be case sensitive. It just flags if the queries
  // should use lower or regex logic for querying.
  this.caseSensitive = options && utils.object.hasOwnProperty(options, 'caseSensitive') ? options.caseSensitive : true;

  // Set the escape character, default is "
  this.escapeCharacter = options && utils.object.hasOwnProperty(options, 'escapeCharacter') ? options.escapeCharacter : '"';

  // Set if the database can return values from things such as an insert
  this.canReturnValues = options && utils.object.hasOwnProperty(options, 'canReturnValues') ? options.canReturnValues : false;

  // Determine if insert values should be escaped or not
  this.escapeInserts = options && utils.object.hasOwnProperty(options, 'escapeInserts') ? options.escapeInserts : false;

  // Determine if aliased tablenames in DELETE queries need to be referenced before the FROM, e.g.
  // DELETE `tableName` FROM `tableName` as `otherTableName` WHERE `otherTableName`.`foo` = "bar"
  // MySQL and Oracle require this, but it doesn't work in Postgresql.
  this.declareDeleteAlias = options && utils.object.hasOwnProperty(options, 'declareDeleteAlias') ? options.declareDeleteAlias : true;

  // Determinie if an explicite 'AS' is written between the tableName and its aliasName, e.g
  // SELECT * FROM `tableName` `otherTableName`
  // Oracle require this
  this.explicitTableAs = options && utils.object.hasOwnProperty(options, 'explicitTableAs') ? options.explicitTableAs : true;

  // Set the prefix string use on aliasName in associations, default is __
  this.prefixAlias = options && utils.object.hasOwnProperty(options, 'prefixAlias') ? options.prefixAlias : '__';

  // Set the character used before and after string value to delimit them, default is "
  this.stringDelimiter = options && utils.object.hasOwnProperty(options, 'stringDelimiter') ? options.stringDelimiter : '"';

  // Determine if SELECT queries include a ROWNUM column for skip and limit them, e.q
  // SELECT ROWNUM AS LINE_NUMBER, * FROM `tableName`
  // Oracle require this for limit and skip
  this.rownum = options && utils.object.hasOwnProperty(options, 'rownum') ? options.rownum : false;

  this.tableAs = this.explicitTableAs ? ' AS ' : ' ';

  // Waterline NEXT
  // These are flags that can be toggled today and expose future features. If any of the following are turned
  // on the adapter tests will probably not pass. If you toggle these know what you are getting into.
  var wlNext = options && utils.object.hasOwnProperty(options, 'wlNext') ? options.wlNext : {};
  this.wlNext = {

    // Case sensitive - false
    // In the next version of WL queries will be case sensitive by default.
    // Set this to true to experiement with that feature today.
    caseSensitive: utils.object.hasOwnProperty(wlNext, 'caseSensitive') ? wlNext.caseSensitive : false

  };

  this.values = [];
  return this;
};

/**
 * Build a SQL Find Query using the defined schema.
 */

Sequel.prototype.find = function find(currentTable, queryObject) {

  // Step 1:
  // Build out the Select statements
  var selectObject = this.select(currentTable, queryObject);
  this.queries = selectObject.select;

  var whereObject;
  var childQueries;
  var query;
  var values;

  /**
   * Step 2 - Build out the parent query.
   */

  whereObject = this.simpleWhere(currentTable, queryObject);

  this.queries[0] += ' ' + whereObject.query;
  this.values[0] = whereObject.values;

  /**
   * Step 3 - Build out the child query templates.
   */

  childQueries = this.complexWhere(currentTable, queryObject);
  this.queries = this.queries.concat(childQueries);

  return {
    query: this.queries,
    values: this.values
  };

};

/**
 * Build a SQL Count Query using the defined schema.
 */

Sequel.prototype.count = function count(currentTable, queryObject) {

  // Escape table name
  var tableName = utils.escapeName(this.schema[currentTable].tableName, this.escapeCharacter);

  // Step 1:
  // Build out the Count statements
  this.queries = ['SELECT COUNT(*) as count FROM '];

  var subQuery = 'SELECT * FROM ' + tableName;

  var whereObject;
  var childQueries;
  var query;
  var values;

  /**
   * Step 2 - Build out the WHERE part of the query.
   */

  whereObject = this.simpleWhere(currentTable, queryObject);

  // Append the sub-query to the COUNT so you end up with something that looks like:
  // SELECT count(*) as count FROM (SELECT * FROM table LIMIT 10 OFFSET 10) AS tableAlias;
  this.queries[0] += '(SELECT * FROM ' + tableName + ' ' + whereObject.query + ') AS ' + tableName;
  this.values[0] = whereObject.values;

  /**
   * Step 3 - Build out the child query templates.
   */

  childQueries = this.complexWhere(currentTable, queryObject);
  this.queries = this.queries.concat(childQueries);

  return {
    query: this.queries,
    values: this.values
  };

};

/**
 * Build a SQL Create Query.
 */

Sequel.prototype.create = function create(currentTable, data) {

  var options = {
    parameterized: this.parameterized,
    escapeCharacter: this.escapeCharacter,
    escapeInserts: this.escapeInserts
  };

  // Transform the Data object into arrays used in a parameterized query
  var attributes = utils.mapAttributes(data, options);
  var columnNames = attributes.keys.join(', ');
  var paramValues = attributes.params.join(', ');

  // Build Query
  var query = 'INSERT INTO ' + utils.escapeName(currentTable, this.escapeCharacter) + ' (' + columnNames + ') values (' + paramValues + ')';

  if(this.canReturnValues) {
    query += ' RETURNING *';
  }

  return { query: query, values: attributes.values };
};

/**
 * Build a SQL Update Query.
 */

Sequel.prototype.update = function update(currentTable, queryObject, data) {

  var options = {
    parameterized: this.parameterized,
    escapeCharacter: this.escapeCharacter,
    escapeInserts: this.escapeInserts
  };

  // Get the attribute identity (as opposed to the table name)
  var identity = currentTable;
  // Create the query with the tablename aliased as the identity (in case they are different)
  var query = 'UPDATE ' + utils.escapeName(currentTable, this.escapeCharacter) + this.tableAs + utils.escapeName(identity, this.escapeCharacter) + ' ';

  // Transform the Data object into arrays used in a parameterized query
  var attributes = utils.mapAttributes(data, options);

  // Update the paramCount
  var paramCount = attributes.params.length + 1;

  // Build SET string
  var str = '';
  for(var i=0; i < attributes.keys.length; i++) {
    str += attributes.keys[i] + ' = ' + attributes.params[i] + ', ';
  }

  // Remove trailing comma
  str = str.slice(0, -2);

  query += 'SET ' + str + ' ';

  // Add data values to this._values
  var values = attributes.values;

  // Build Criteria clause
  var whereObject = this.simpleWhere(currentTable, queryObject, { paramCount: paramCount });

  query += ' ' + whereObject.query;
  values = values.concat(whereObject.values);

  if(this.canReturnValues) {
    query += ' RETURNING *';
  }

  return {
    query: query,
    values: values
  };
};

/**
 * Build Delete SQL query.
 */

Sequel.prototype.destroy = function destroy(currentTable, queryObject) {

  // Get the attribute identity (as opposed to the table name)
  var identity = currentTable;

  var query = 'DELETE ' + (this.declareDeleteAlias ? utils.escapeName(identity, this.escapeCharacter) : '') + ' FROM ' + utils.escapeName(currentTable, this.escapeCharacter) + this.tableAs + utils.escapeName(identity, this.escapeCharacter) + ' ';

  // Build Criteria clause
  var whereObject = this.simpleWhere(currentTable, queryObject);

  query += ' ' + whereObject.query;
  var values = whereObject.values;

  if(this.canReturnValues) {
    query += ' RETURNING *';
  }

  return {
    query: query,
    values: values
  };
};

/**
 * Build the select statements for a query.
 */

Sequel.prototype.select = function select(currentTable, queryObject) {
  var options = {
    escapeCharacter: this.escapeCharacter,
    caseSensitive: this.caseSensitive,
    cast: this.cast,
    explicitTableAs: this.explicitTableAs,
    prefixAlias: this.prefixAlias,
    stringDelimiter: this.stringDelimiter,
    rownum: this.rownum,
    wlNext: this.wlNext
  };

  return new SelectBuilder(this.schema, currentTable, queryObject, options);
};

/**
 * Build the where statements for a query.
 */

Sequel.prototype.simpleWhere = function simpleWhere(currentTable, queryObject, options) {
  var _options = {
    parameterized: this.parameterized,
    caseSensitive: this.caseSensitive,
    escapeCharacter: this.escapeCharacter,
    explicitTableAs: this.explicitTableAs,
    prefixAlias: this.prefixAlias,
    stringDelimiter: this.stringDelimiter,
    wlNext: this.wlNext
  };

  var where = new WhereBuilder(this.schema, currentTable, _options);
  return where.single(queryObject, options);
};

Sequel.prototype.complexWhere = function complexWhere(currentTable, queryObject, options) {
  var _options = {
    parameterized: this.parameterized,
    caseSensitive: this.caseSensitive,
    escapeCharacter: this.escapeCharacter,
    explicitTableAs: this.explicitTableAs,
    prefixAlias: this.prefixAlias,
    stringDelimiter: this.stringDelimiter
  };

  var where = new WhereBuilder(this.schema, currentTable, _options);
  return where.complex(queryObject, options);
};
<|endoftext|>