Skip to content
Snippets Groups Projects
Select Git revision
  • develop default protected
  • simmc-based
  • drill-experiment
  • tg-felipe
  • issue/97
  • issue/63
  • icde-2019-experiments
  • issue/85
  • master protected
  • issue/20
  • refactor/engine
  • issue/6
  • feature/diagrams
  • wip-transformers
14 results

engine.ts

Blame
  • engine.ts 3.65 KiB
    /*
     * Copyright (C) 2016 Centro de Computacao Cientifica e Software Livre
     * Departamento de Informatica - Universidade Federal do Parana
     *
     * This file is part of blend.
     *
     * blend is free software: you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation, either version 3 of the License, or
     * (at your option) any later version.
     *
     * blend is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with blend.  If not, see <http://www.gnu.org/licenses/>.
     */
    
    import { Dimension } from "./dimension";
    import { Metric } from "./metric";
    import { View } from "./view";
    import { Query } from "../common/query";
    import { Graph } from "../util/graph";
    
    export class Engine {
        private views: View[] = [];
        private metrics: Metric[] = [];
        private dimensions: Dimension[] = [];
        private graph: Graph;
    
        constructor () {
            this.views = [];
            this.metrics = [];
            this.dimensions = [];
            this.graph = new Graph();
        }
    
        public getViews() {
            return this.views;
        }
    
        public addView(view: View) {
            if (this.graph.addView(view)) {
                this.views.push(view);
                return view;
            }
    
            return null;
        }
    
        public addMetric(metric: Metric) {
            if (this.graph.addMetric(metric)) {
                this.metrics.push(metric);
                return metric;
            }
    
            return null;
        }
    
        public getMetricByName(name: string) {
            let result = this.metrics.find(metric => metric.name === name);
    
            if (!result) {
                throw new Error("The metric named " + name + " was not found");
            }
    
            return result;
        }
    
        public addDimension(dimension: Dimension) {
            if (this.graph.addDimension(dimension)) {
                this.dimensions.push(dimension);
                return dimension;
            }
    
            return null;
        }
    
        public getDimensionByName(name: string) {
            let result = this.dimensions.find(dimension => dimension.name === name);
    
            if (!result) {
                throw new Error("The dimension named " + name + " was not found");
            }
    
            return result;
        }
    
        public query (q: Query) {
            return this.selectOptimalView(q);
        }
    
        private selectOptimalView (q: Query) {
            let optimalViews = this.graph.cover(q.metrics, q.dimensions);
            if (optimalViews.length === 0) {
                throw new Error ("Engine views cannot cover the query");
            }
    
            // If all the metrics and dimensions are the same and only exist one child view
            // return this single child view
            if (optimalViews.length === 1 &&
                optimalViews[0].view.metrics.length === q.metrics.length &&
                optimalViews[0].view.dimensions.length === q.dimensions.length &&
                optimalViews[0].view.metrics.every((item) => q.metrics.indexOf(item) !== -1) &&
                optimalViews[0].view.dimensions.every((item) => q.dimensions.indexOf(item) !== -1)) {
                return optimalViews[0].view;
            }
            else {
                let options = {
                    metrics: q.metrics,
                    dimensions: q.dimensions,
                    materialized: false,
                    origin: false, // Never a dynamic generated view will be origin
                    childViews: optimalViews
                };
    
                let view = new View(options);
                this.addView(view);
                return view;
            }
        }
    }