Issue #48: Add route to return list of metrics and dimensions

Signed-off-by: Lucas Fernandes de Oliveira's avatarLucas Fernandes de Oliveira <lfo14@inf.ufpr.br>
parent 08f26ed4
Pipeline #12295 passed with stage
in 58 seconds
......@@ -112,75 +112,120 @@ schema:
name: "met:0"
dataType: "integer"
aggregation: "sum"
description: "No meaning, just used for test"
-
name: "met:1"
dataType: "integer"
aggregation: "avg"
description: "No meaning, just used for test"
-
name: "met:2"
dataType: "integer"
aggregation: "avg"
description: "No meaning, just used for test"
-
name: "met:3"
dataType: "integer"
aggregation: "sum"
description: "No meaning, just used for test"
-
name: "met:4"
dataType: "integer"
aggregation: "sum"
description: "No meaning, just used for test"
-
name: "met:5"
dataType: "integer"
aggregation: "avg"
description: "No meaning, just used for test"
-
name: "met:6"
dataType: "integer"
aggregation: "count"
description: "No meaning, just used for test"
-
name: "met:7"
dataType: "integer"
aggregation: "count"
description: "No meaning, just used for test"
-
name: "met:8"
dataType: "integer"
aggregation: "sum"
description: "No meaning, just used for test"
-
name: "met:9"
dataType: "integer"
aggregation: "count"
description: "No meaning, just used for test"
-
name: "met:10"
dataType: "integer"
aggregation: "max"
description: "No meaning, just used for test"
-
name: "met:11"
dataType: "integer"
aggregation: "min"
description: "No meaning, just used for test"
dimensions:
-
name: "dim:0"
dataType: "date"
description: "A dimension of Blendb. Has 5 possible values."
-
name: "dim:1"
dataType: "date"
description: "A dimension of Blendb. Has 5 possible values."
-
name: "dim:2"
dataType: "integer"
description: "A dimension of Blendb. Has 5 possible values."
-
name: "dim:3"
dataType: "string"
description: "A dimension of Blendb. Has 5 possible values."
-
name: "dim:4"
dataType: "string"
description: "A dimension of Blendb. Has 5 possible values."
-
name: "dim:5"
dataType: "boolean"
description: "A dimension of Blendb. Has 2 possible values."
-
name: "dim:6"
dataType: "integer"
description: "A dimension of Blendb. Has 5 possible values."
-
name: "dim:7"
dataType: "integer"
description: "A dimension of Blendb. Has 5 possible values."
-
name: "dim:8"
dataType: "integer"
description: "A dimension of Blendb. Has 5 possible values."
-
name: "dim:9"
dataType: "integer"
parent: "dim:0"
relation: "day"
description: "A dimension of Blendb. Has 30 possible values."
-
name: "dim:10"
dataType: "integer"
parent: "dim:0"
relation: "month"
description: "A dimension of Blendb. Has 12 possible values."
-
name: "dim:11"
dataType: "integer"
parent: "dim:0"
relation: "year"
description: "A dimension of Blendb. Has 1 possible value."
-
name: "dim:12"
dataType: "integer"
parent: "dim:0"
relation: "dayofweek"
description: "A dimension of Blendb. Has 7 possible values."
......@@ -70,7 +70,7 @@ describe("API data controller", () => {
.expect((res: any) => {
const message = "Query execution failed: " +
"Could not construct query with the paramters given.";
const error = "The dimension named dim:11 was not found";
const error = "The dimension named dim:-1 was not found";
expect(res.body).to.be.an("object");
expect(res.body).to.have.property("message");
expect(res.body).to.have.property("error");
......
/*
* Copyright (C) 2017 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of blendb.
*
* blendb 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.
*
* blendb 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 blendb. If not, see <http://www.gnu.org/licenses/>.
*/
import * as request from "supertest";
import { expect } from "chai";
import * as server from "../../main";
describe("API engine controller", () => {
it("should respond 200 and the list of metrics", (done) => {
request(server)
.get("/v1/metrics")
.expect(200)
.expect((res: any) => {
let result = res.body;
expect(result).to.be.an("array");
expect(result).to.have.length(12);
})
.end(done);
});
it("should respond 200 and the list of dimensions", (done) => {
request(server)
.get("/v1/dimensions")
.expect(200)
.expect((res: any) => {
let result = res.body;
expect(result).to.be.an("array");
expect(result).to.have.length(13);
})
.end(done);
});
});
/*
* Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of blendb.
*
* blendb 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.
*
* blendb 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 blendb. If not, see <http://www.gnu.org/licenses/>.
*/
import * as express from "express";
import { Request } from "../types";
export class EngineCtrl {
public static metrics(req: Request, res: express.Response, next: express.NextFunction) {
res.status(200).json(req.engine.getMetricsDescription());
}
public static dimensions(req: Request, res: express.Response, next: express.NextFunction) {
res.status(200).json(req.engine.getDimensionsDescription());
}
}
......@@ -23,8 +23,11 @@ const osprey = require("osprey");
// import controllers
import { DataCtrl } from "./controllers/data";
import { CollectCtrl } from "./controllers/collect";
import { EngineCtrl } from "./controllers/engine";
export const router = osprey.Router();
router.get("/metrics", EngineCtrl.metrics);
router.get("/dimensions", EngineCtrl.dimensions);
router.get("/data", DataCtrl.read);
router.post("/collect/{class}", CollectCtrl.write);
......@@ -25,6 +25,15 @@ export interface DimensionOptions {
dataType: string;
parent?: Dimension;
relation?: RelationType;
description?: string;
}
export interface DimensionStrOptions {
name: string;
dataType: string;
parent?: string;
relation?: string;
description?: string;
}
export class Dimension {
......@@ -32,11 +41,63 @@ export class Dimension {
public readonly dataType: string;
public readonly parent: Dimension;
public readonly relation: RelationType;
public readonly description: string;
constructor(options: DimensionOptions) {
this.name = options.name;
this.dataType = options.dataType;
this.relation = (options.relation) ? options.relation : RelationType.NONE;
this.parent = (options.parent) ? options.parent : null;
this.description = (options.description) ? options.description : "";
}
public strOptions(): DimensionStrOptions {
if (this.relation === RelationType.NONE) {
return {
name: this.name,
dataType: this.dataType,
description: this.description
};
}
else {
return {
name: this.name,
dataType: this.dataType,
parent: this.parent.name,
relation: Dimension.stringifyRelationType(this.relation),
description: this.description
};
}
}
public static parseRelationType(r: string): RelationType {
switch (r) {
case "day":
return RelationType.DAY;
case "month":
return RelationType.MONTH;
case "year":
return RelationType.YEAR;
case "dayofweek":
return RelationType.DAYOFWEEK;
default:
return RelationType.NONE;
}
}
public static stringifyRelationType(r: RelationType): string {
switch (r) {
case RelationType.DAY:
return "day";
case RelationType.MONTH:
return "month";
case RelationType.YEAR:
return "year";
case RelationType.DAYOFWEEK:
return "dayofweek";
default:
return "";
}
}
}
......@@ -55,7 +55,7 @@ describe("engine class", () => {
expect(optimalView.dimensions).to.be.an("array");
expect(optimalView.childViews).to.be.an("array");
expect(optimalView.metrics).to.have.length(12);
expect(optimalView.dimensions).to.have.length(9);
expect(optimalView.dimensions).to.have.length(13);
});
it("should throw an exception, query with non-existent metric", () => {
let error: boolean = false;
......
......@@ -43,6 +43,14 @@ export class Engine {
return this.views;
}
public getMetricsDescription() {
return this.metrics.map((i) => i.strOptions());
}
public getDimensionsDescription() {
return this.dimensions.map((i) => i.strOptions());
}
public addView(view: View) {
if (this.graph.addView(view)) {
this.views.push(view);
......
......@@ -24,16 +24,69 @@ export interface MetricOptions {
name: string;
aggregation: AggregationType;
dataType: string;
description?: string;
}
export interface MetricStrOptions {
name: string;
aggregation: string;
dataType: string;
description?: string;
}
export class Metric {
public readonly name: string;
public readonly aggregation: AggregationType;
public readonly dataType: string;
public readonly description: string;
constructor(options: MetricOptions) {
this.name = options.name;
this.aggregation = options.aggregation;
this.dataType = options.dataType;
this.description = (options.description) ? options.description : "";
}
public strOptions(): MetricStrOptions {
return {
name: this.name,
aggregation: Metric.stringifyAggrType(this.aggregation),
dataType: this.dataType,
description: this.description
};
}
public static stringifyAggrType(a: AggregationType): string {
switch (a) {
case AggregationType.SUM:
return "sum";
case AggregationType.AVG:
return "avg";
case AggregationType.COUNT:
return "count";
case AggregationType.MAX:
return "max";
case AggregationType.MIN:
return "min";
default:
return "";
}
}
public static parseAggrType (str: string): AggregationType {
switch (str) {
case "sum":
return AggregationType.SUM;
case "avg":
return AggregationType.AVG;
case "count":
return AggregationType.COUNT;
case "min":
return AggregationType.MIN;
case "max":
return AggregationType.MAX;
default:
return AggregationType.NONE;
}
}
}
......@@ -20,8 +20,8 @@
import { expect } from "chai";
import { ConfigParser, ViewParsingOptions, DimensionStrOptions } from "./configParser";
import { Dimension } from "../core/dimension";
import { ConfigParser, ViewParsingOptions } from "./configParser";
import { Dimension, DimensionStrOptions } from "../core/dimension";
import { RelationType } from "../common/types";
function strToRelationType (str: string): RelationType {
......
......@@ -18,10 +18,10 @@
* along with blendb. If not, see <http://www.gnu.org/licenses/>.
*/
import { Metric, MetricOptions } from "../core/metric";
import { Dimension, DimensionOptions } from "../core/dimension";
import { Metric, MetricOptions, MetricStrOptions } from "../core/metric";
import { Dimension, DimensionOptions, DimensionStrOptions } from "../core/dimension";
import { View, ViewOptions, LoadView } from "../core/view";
import { AggregationType, RelationType } from "../common/types";
import { RelationType } from "../common/types";
import { Filter } from "../core/filter";
import { Clause } from "../core/clause";
import { PoolConfig } from "pg";
......@@ -39,19 +39,6 @@ export interface ViewParsingOptions {
keys?: string[];
}
interface MetricStrOptions {
name: string;
aggregation: string;
dataType: string;
}
export interface DimensionStrOptions {
name: string;
dataType: string;
parent?: string;
relation?: string;
}
interface ConfigSchema {
views: ViewParsingOptions[];
metrics: MetricStrOptions[];
......@@ -216,8 +203,9 @@ export class ConfigParser {
return {
name: opts.name,
dataType: opts.dataType,
description: opts.description,
parent: dims[i],
relation: this.strToRelationType(opts.relation)
relation: Dimension.parseRelationType(opts.relation)
};
}
}
......@@ -227,6 +215,7 @@ export class ConfigParser {
return {
name: opts.name,
dataType: opts.dataType,
description: opts.description,
parent: null,
relation: RelationType.NONE
};
......@@ -235,8 +224,9 @@ export class ConfigParser {
private static parseMetOpts (opts: MetricStrOptions): MetricOptions {
return {
name: opts.name,
aggregation: this.strToAggregationType(opts.aggregation),
dataType : opts.dataType
aggregation: Metric.parseAggrType(opts.aggregation),
dataType : opts.dataType,
description: opts.description
};
}
......@@ -277,35 +267,4 @@ export class ConfigParser {
});
}
private static strToAggregationType (str: string): AggregationType {
switch (str) {
case "sum":
return AggregationType.SUM;
case "avg":
return AggregationType.AVG;
case "count":
return AggregationType.COUNT;
case "min":
return AggregationType.MIN;
case "max":
return AggregationType.MAX;
default:
return AggregationType.NONE;
}
}
private static strToRelationType (str: string): RelationType {
switch (str) {
case "day":
return RelationType.DAY;
case "month":
return RelationType.MONTH;
case "year":
return RelationType.YEAR;
case "dayofweek":
return RelationType.DAYOFWEEK;
default:
return RelationType.NONE;
}
}
}
......@@ -153,7 +153,7 @@ const wrongMet = new Metric({
aggregation: AggregationType.COUNT,
dataType: "integer"
});
const wrongDim = new Dimension({ name: "dim:11", dataType: "integer" });
const wrongDim = new Dimension({ name: "dim:-1", dataType: "integer" });
const subdimAux = new Dimension({
name: "sub:0",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment