Commit 14f01727 authored by Lucas Fernandes de Oliveira's avatar Lucas Fernandes de Oliveira

Merge branch 'issue/83' into 'develop'

Issue #83:Fix test Monet and Postgres

See merge request !67
parents 1e9df086 dfeb7db4
Pipeline #16350 passed with stages
in 1 minute and 29 seconds
......@@ -118,6 +118,29 @@ export class MonetAdapter extends SQLAdapter {
});
pool.close();
}
/**
* Asynchronously executes a query from Source and get its resut
* @param query - Query (SQL format) to be executed.
* @param cb - Callback function which contains the data read.
* @param cb.error - Error information when the method fails.
* @param cb.result - Query result.
*/
private executeQuerySource(query: string, cb: (error: Error, result?: any[]) => void): void {
let pool: any = new MDB(this.config);
pool.connect();
pool.query(query).then((result: any) => {
if (result) {
cb(null, result);
}
else {
cb(null, null);
}
}).fail((err: Error) => {
cb(err, null);
});
pool.close();
}
/**
* Materialize a given view.
......@@ -136,7 +159,7 @@ export class MonetAdapter extends SQLAdapter {
*/
public insertIntoSource(source: Source, data: any[], cb: (err: Error, result: any[]) => void): void {
const query = this.getQueryFromSource(source, data);
this.executeQuery(query, cb);
this.executeQuerySource(query, cb);
}
/**
......
......@@ -25,11 +25,10 @@ import { MonetAdapter, MonetConfig } from "./monet";
import { Adapter } from "../core/adapter";
import { Fixture as FixPostgres } from "../../test/postgres/fixture";
import { Fixture as FixMonet } from "../../test/monet/fixture";
import { ConfigParser } from "../util/configParser";
import { adapterScenario } from "../../test/scenario";
describe("postgres adapter", () => {
describe("Sql adapter", () => {
// Initializing
let config: any;
......@@ -38,6 +37,7 @@ describe("postgres adapter", () => {
before(function (done): void {
// Arrow function not used to get acces to this and skip the test
config = ConfigParser.parse("config/test.yaml");
if (config.adapter === "postgres") {
fixture = new FixPostgres(config.connection);
fixture.load(config.loadViews, (err) => {
......@@ -50,7 +50,7 @@ describe("postgres adapter", () => {
}
else if (config.adapter === "monet") {
fixture = new FixMonet(config.connection);
fixture.load(config.loadViews, config.struct.create, (err) => {
fixture.load(config.loadViews, (err) => {
if (err) {
throw err;
}
......
......@@ -468,7 +468,7 @@ export abstract class SQLAdapter extends Adapter {
consult = consult.concat(colums.join("\",\""));
consult = consult.concat("\") VALUES ('");
consult = consult.concat(values.join("' , '"));
consult = consult.concat("');");
consult = consult.concat("')");
return consult;
}
......
......@@ -49,7 +49,7 @@ describe("API collect controller", () => {
}
else if (config.adapter === "monet") {
fixture = new FixMonet(config.connection);
fixture.load(config.sources, config.struct.create, (err) => {
fixture.loadSource(config.sources, (err) => {
if (err) {
throw err;
}
......
......@@ -20,16 +20,12 @@
const MDB = require("monetdb")();
import { View, LoadView } from "../../src/core/view";
import { Source } from "../../src/core/source";
import { each, series } from "async";
import { Connection } from "../../src/util/configParser";
import * as fs from "fs";
import { DataType } from "../../src/common/types";
interface TransSet {
init: string;
data: string[];
}
export interface Schema {
alias?: string;
query?: string;
......@@ -46,7 +42,7 @@ export class Fixture {
this.database = config.database;
}
public load(schemas: LoadView[], create: boolean, cb: (err: Error) => void): void {
public load(schemas: LoadView[], cb: (err: Error) => void): void {
let client = new MDB({
user: this.config.user,
dbname: this.config.database,
......@@ -58,19 +54,12 @@ export class Fixture {
/*
Loading data has 2 steps:
1 - Create a table or truncate a existing one.
Create or truncate dependes from a parameter in the configure
file, this parameter reaches this function as the create
parameter.
2 - Insert data.
*/
let init: string[] = [];
let data: string[] = [];
for (let i = 0; i < schemas.length; ++i) {
let table: TransSet = this.createTransSet(schemas[i].view, schemas[i].data, create);
init.push(table.init);
data = data.concat(table.data);
data = data.concat(this.extractDataView(schemas[i].view, schemas[i].data));
}
client.connect();
/*
Tables must be creates before data could be inserted, so the
......@@ -78,11 +67,21 @@ export class Fixture {
To garantee that tables exists before start insert data, series
is used. Inside series each query is executed, using each;
*/
series([(callback: (err: Error) => void) => {
each(init, (query, cback) => {
return client.query(query).then((result: any) => cback())
.fail((err: Error) => (cback(err)));
}, (errQuery: Error) => callback(errQuery));
each(schemas, (query, cback) => {
client.query(this.createTransSet(query.view, query.data, true)).then((result: any) => cback())
.fail((errCreate: Error) => {
if (errCreate){
let regex = new RegExp(/42s01!create table: name \'.*\' already in use/);
if (regex.test(errCreate.message.toLocaleLowerCase())){
return client.query(this.createTransSet(query.view, query.data, false)).then((result: any) => cback())
.fail((errTrunc: Error) => (cback(errTrunc)));
}
}
return cback(errCreate);
});
}, (errQuery: Error) => callback(errQuery));
}, (callback: (err: Error) => void) => {
each(data, (query, cback) => {
return client.query(query).then((result: any) => cback())
......@@ -92,6 +91,7 @@ export class Fixture {
client.close();
cb(errQuery);
});
}
private typeConvertion(t: DataType): string {
......@@ -104,47 +104,52 @@ export class Fixture {
return "TEXT";
case DataType.BOOLEAN:
return "BOOLEAN";
case DataType.FLOAT:
return "DOUBLE PRECISION";
default:
return "";
return "TEXT";
}
}
private createTransSet(view: View, filePath: string, create: boolean): TransSet {
let props = [];
private extractDataView(view: View, filePath: string): string[]{
let name = "view_" + view.id;
let data: string[] = [];
let rows = JSON.parse(fs.readFileSync(filePath, {encoding : "utf8"}));
for (let i = 0; i < rows.length; ++i) {
let values = [];
let keys = [];
for (let key of Object.keys(rows[i])) {
keys.push("\"" + key + "\"");
values.push("'" + this.boolCast(rows[i][key]) + "'");
}
data.push("INSERT INTO " + name +
"(" + keys.join(", ") + ") " +
"VALUES (" + values.join(", ") + ")");
}
return data;
}
private createTransSet(view: View, filePath: string, create: boolean): string {
let name = "view_" + view.id;
let init: string = "";
let props = [];
for (let i = 0; i < view.metrics.length; ++i) {
let met = view.metrics[i];
props.push("\"" + met.name + "\" " + this.typeConvertion(met.dataType));
}
for (let i = 0; i < view.dimensions.length; ++i) {
let dim = view.dimensions[i];
props.push("\"" + dim.name + "\" " + this.typeConvertion(dim.dataType));
}
let name = "view_" + view.id;
let transaction: TransSet = {init: "", data: []};
if (create) {
transaction.init = "CREATE TABLE " + name + "(" + props.join(", ") + ")";
init = "CREATE TABLE " + name + "(" + props.join(", ") + ")";
}
else {
transaction.init = "DELETE FROM " + name;
}
transaction.data = [];
let rows = JSON.parse(fs.readFileSync(filePath, {encoding : "utf8"}));
for (let i = 0; i < rows.length; ++i) {
let values = [];
let keys = [];
for (let key of Object.keys(rows[i])) {
keys.push("\"" + key + "\"");
values.push("'" + this.boolCast(rows[i][key]) + "'");
}
transaction.data.push("INSERT INTO " + name +
"(" + keys.join(", ") + ") " +
"VALUES (" + values.join(", ") + ")");
init = "DELETE FROM " + name;
}
return transaction;
return init;
}
private boolCast(text: string): string {
......@@ -160,4 +165,62 @@ export class Fixture {
return text;
}
}
public loadSource(source: Source[] , cb: (err: Error) => void): void {
let client = new MDB({
user: this.config.user,
dbname: this.config.database,
password: this.config.password,
host: this.config.host,
port: this.config.port,
});
client.connect();
series([(callback: (err: Error) => void) => {
each(source, (insere, cback) => {
client.query(this.extractData(insere, true)).then((result: any) => cback())
.fail((errCreate: Error) => {
if (errCreate) {
let regex = new RegExp(/42s01!create table: name \'.*\' already in use/);
if (regex.test(errCreate.message.toLocaleLowerCase())){
return client.query(this.extractData(insere, false)).then((result: any) => cback())
.fail((errTrunc: Error) => (cback(errTrunc)));
}
}
return cback(errCreate);
});
}, (errQuery: Error) => callback(errQuery));
}], (errQuery: Error) => {
client.close();
cb(errQuery);
});
}
private extractData(data: Source, create: boolean): string{
let name: string;
let type: DataType[];
let fields: string[];
let consult: string;
name = data.name;
type = data.fields.map((item) => item.dataType);
fields = data.fields.map((item) => item.name);
if (create){
consult = "CREATE TABLE " + name + " (" + '"';
for (let i = 0; i < fields.length; i++){
fields[i] = fields[i].concat('"' + " " + this.typeConvertion(type[i]));
}
consult = consult.concat(fields.join(", " + '"'));
consult = consult.concat(");");
}
else{
consult = "DELETE FROM " + name + ";";
}
return consult;
}
}
......@@ -114,6 +114,8 @@ export class Fixture {
return "TEXT";
case DataType.BOOLEAN:
return "BOOLEAN";
case DataType.FLOAT:
return "DOUBLE PRECISION";
default:
return "TEXT";
}
......
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