Skip to content
Snippets Groups Projects
Commit ca428c12 authored by Eduardo L. Buratti's avatar Eduardo L. Buratti
Browse files

Move to TypeScript as main language

parent a97d836f
Branches
No related tags found
No related merge requests found
*.log
*.out
*.pid
*.js
*.js.map
/.trash
/pids
/logs
......@@ -10,3 +12,4 @@
/config/*.yaml
/doc/build
/coverage
/typings
......@@ -4,7 +4,10 @@
"description": "BlenDB",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"prestart": "tsc",
"start": "node build/src/boot",
"pretest": "tsc",
"test": "mocha"
},
"repository": {
"type": "git",
......@@ -31,7 +34,9 @@
"jshint": "^2.9.2",
"mongodb": "^2.2.5",
"osprey": "^0.3.2",
"raml2html": "^2.4.0"
"raml2html": "^2.4.0",
"typescript": "^1.8.10",
"typings": "^1.3.2"
},
"devDependencies": {
"chai": "^3.5.0",
......
......@@ -18,25 +18,17 @@
* along with blendb. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
import * as express from "express";
const MongoClient = require('mongodb').MongoClient;
class Mongo {
constructor() {
this.db = undefined;
}
connect(connectionString) {
MongoClient.connect(connectionString, (err, db) => {
if (err) {
console.error(err);
export class CollectCtrl {
static write(req: express.Request, res: express.Response, next: express.NextFunction) {
if ('_id' in req.body) {
res.status(400)
.json({ message: 'Property named \'_id\' is protected.' });
return;
}
this.db = db;
});
res.status(500)
.json({ message: 'Error while writing to the database.' });
}
}
module.exports = new Mongo();
/*
* 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";
export class DataCtrl {
static read(req: express.Request, res: express.Response, next: express.NextFunction) {
let metrics = req.query.metrics.split(',');
let dimensions = req.query.dimensions.split(',');
res.status(500).json({ message: 'Query execution failed ' +
'because of an unknown error.' });
}
}
......@@ -18,15 +18,13 @@
* along with blendb. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
const osprey = require('osprey');
// import controllers
const data = require('./controllers/data');
const collect = require('./controllers/collect');
import { DataCtrl } from './controllers/data';
import { CollectCtrl } from './controllers/collect';
const router = module.exports = osprey.Router();
export const router = osprey.Router();
router.get('/data', data.read);
router.post('/collect/{class}', collect.write);
router.get('/data', DataCtrl.read);
router.post('/collect/{class}', CollectCtrl.write);
#!/usr/bin/env node
/*
* Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
......@@ -18,26 +19,41 @@
* along with blendb. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
// external libraries
import express = require('express');
import path = require('path');
const aggregator = require('core/aggregator');
const osprey = require('osprey');
const ramlParser = require('raml-parser');
class Data {
read(req, res, next) {
let metrics = req.query.metrics.split(',');
let dimensions = req.query.dimensions.split(',');
// create a new express app
const app = module.exports = express();
aggregator.query(metrics, dimensions, (err, data) => {
if (err) {
console.error(err);
res.status(500).json({ message: 'Query execution failed ' +
'because of an unknown error.' });
return;
}
// load router
import { router } from './api/router-v1';
res.json({ data });
});
// parse the RAML spec and load osprey middleware
ramlParser.loadFile('specs/blendb-api-v1.raml')
.then((raml: any) => {
app.use('/v1',
osprey.security(raml),
osprey.server(raml),
router);
if (!module.parent) {
let port = process.env.PORT || 3000;
app.listen(port);
if (app.get('env') === 'development') {
console.log('Server listening on port ' + port + '.');
}
}
module.exports = new Data();
else {
// signalize to the test suite that the server is ready to be tested
app.locals.ready = true;
}
},
(err: any) => {
console.error('RAML Parsing Error: ' + err.message);
process.exit(1);
});
......@@ -18,30 +18,23 @@
* along with blendb. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
import { expect } from 'chai';
const mongo = require('core/mongo');
import { Aggregate } from './aggregate';
class Collect {
write(req, res, next) {
let collection = mongo.db.collection('raw.' + req.params.class);
if ('_id' in req.body) {
res.status(400)
.json({ message: 'Property named \'_id\' is protected.' });
return;
}
collection.insertOne(req.body, function (err, r) {
if (err) {
res.status(500)
.json({ message: 'Error while writing to the database.' });
return;
}
describe('aggregate class', () => {
it('should be instantiated with an array metrics and one of dimensions', () => {
let aggr = new Aggregate(['met:one'], ['dim:one', 'dim:two']);
expect(aggr).to.be.an('object');
});
res.status(200).json({ _id: r.insertedId });
it('should not be instantiated with an empty array of metrics', () => {
let aggr = new Aggregate([], ['dim:one', 'dim:two']);
expect(aggr).to.be.an('object');
});
}
}
module.exports = new Collect();
it('should not be instantiated with an empty array of dimensions', () => {
let aggr = new Aggregate(['met:one'], []);
expect(aggr).to.be.an('object');
});
});
......@@ -18,17 +18,19 @@
* along with blendb. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
export class Aggregate {
metrics: string[];
dimensions: string[];
data: any[];
class Aggregate {
constructor(metrics, dimensions, options) {
constructor(metrics: string[], dimensions: string[], options?: any) {
this.metrics = metrics;
this.dimensions = dimensions;
this.data = [];
}
push(data) {
push(data: any) {
this.data.push(data);
}
......@@ -36,5 +38,3 @@ class Aggregate {
this.data = [];
}
}
module.exports = Aggregate;
......@@ -20,20 +20,24 @@
'use strict';
const hash = require('util/hash');
import { Hash } from '../util/hash';
const Source = require('core/source');
const Transformer = require('core/transformer');
const Aggregate = require('core/aggregate');
import { Source } from './source';
import { Transformer } from './transformer';
import { Aggregate } from './aggregate';
export class Server {
sources: Map<string,Source>;
transformers: Map<string,Transformer>;
aggregates: Map<string,Aggregate>;
class BlenDB {
constructor() {
this.sources = new Map();
this.transformers = new Map();
this.aggregates = new Map();
}
source(name, options) {
source(name: string, options?: any) {
if (this.sources.has(name)) {
return this.sources.get(name);
}
......@@ -44,7 +48,7 @@ class BlenDB {
}
}
transformer(name, options) {
transformer(name: string, options?: any) {
if (this.transformers.has(name)) {
return this.transformers.get(name);
}
......@@ -55,11 +59,8 @@ class BlenDB {
}
}
aggregate(metrics, dimensions, options) {
metrics = Array.from(metrics);
dimensions = Array.from(dimensions);
const id = hash.sha1(metrics.sort() + dimensions.sort());
aggregate(metrics: string[], dimensions: string[], options?: any) {
const id = Hash.sha1(metrics.sort(), dimensions.sort());
if (this.aggregates.has(id)) {
return this.aggregates.get(id);
......@@ -72,12 +73,12 @@ class BlenDB {
}
process() {
this.transformers.forEach((transformer) => {
this.transformers.forEach((transformer: Transformer) => {
const source = this.source(transformer.source);
const aggr = this.aggregate(transformer.metrics,
transformer.dimensions);
source.forEach((doc) => {
source.forEach((doc: any) => {
aggr.push({
metrics: transformer.extractMetrics(doc),
dimensions: transformer.extractDimensions(doc)
......@@ -93,5 +94,3 @@ class BlenDB {
console.log(this.aggregates);
}
}
module.exports = { BlenDB, Source, Transformer };
......@@ -20,20 +20,23 @@
'use strict';
class Source {
constructor(name, options) {
export class Source {
name: string;
data: any[];
constructor(name: string, options: any) {
this.name = name;
this.data = [];
}
push(doc) {
push(doc: any) {
this.data.push(doc);
}
forEach(callback) {
this.data.forEach(callback);
forEach(callback: Function) {
this.data.forEach((value: any, index: number, array: any[]) => {
callback(value);
});
}
}
module.exports = Source;
......@@ -20,24 +20,27 @@
'use strict';
class Transformer {
constructor(name, options) {
export class Transformer {
source: string;
metrics: string[];
dimensions: string[];
extractors: any;
constructor(name: string, options: any) {
this.source = options.source || null;
this.metrics = options.metrics || [];
this.dimensions = options.dimensions || [];
this.extractors = {
metrics: options.extractors.metrics || ((doc) => null),
dimensions: options.extractors.dimensions || ((doc) => null)
metrics: options.extractors.metrics || ((doc: any): any => null),
dimensions: options.extractors.dimensions || ((doc: any): any => null)
};
}
extractMetrics(doc) {
extractMetrics(doc: any) {
return this.extractors.metrics(doc);
}
extractDimensions(doc) {
extractDimensions(doc: any) {
return this.extractors.dimensions(doc);
}
}
module.exports = Transformer;
......@@ -18,26 +18,21 @@
* along with blendb. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
import { expect } from 'chai';
/* globals expect */
/* jshint -W024 */
/* jshint expr:true, maxlen:false */
/* jscs:disable maximumLineLength */
const hash = require('util/hash');
import { Hash } from './hash';
describe('hash utility library', () => {
it('should generate a sha1 hash for a collection of objects', () => {
let h = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
expect(h).to.be.a('string');
expect(h).to.not.be.empty;
});
it('should generate the same hash for the same input', () => {
let h1 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h2 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h1 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h2 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
expect(h1).to.be.a('string');
expect(h2).to.be.a('string');
......@@ -45,8 +40,8 @@ describe('hash utility library', () => {
});
it('should generate the same hash for different order of input', () => {
let h1 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h2 = hash.sha1('test', ['list', 'of', 'things'], { obj: 'test' });
let h1 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h2 = Hash.sha1('test', ['list', 'of', 'things'], { obj: 'test' });
expect(h1).to.be.a('string');
expect(h2).to.be.a('string');
......@@ -54,8 +49,8 @@ describe('hash utility library', () => {
});
it('should not generate the same hash for distinct input', () => {
let h1 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h2 = hash.sha1('test', { obj: 'test', x: true },
let h1 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h2 = Hash.sha1('test', { obj: 'test', x: true },
['list', 'of', 'things']);
expect(h1).to.be.a('string');
......@@ -64,8 +59,8 @@ describe('hash utility library', () => {
});
it('should not generate the same hash for different order in deep lists', () => {
let h1 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h2 = hash.sha1('test', { obj: 'test' }, ['of', 'list', 'things']);
let h1 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
let h2 = Hash.sha1('test', { obj: 'test' }, ['of', 'list', 'things']);
expect(h1).to.be.a('string');
expect(h2).to.be.a('string');
......
......@@ -20,10 +20,10 @@
'use strict';
const crypto = require('crypto');
import crypto = require('crypto');
class Hash {
sha1(...objects) {
export class Hash {
static sha1(...objects: any[]): string {
let hash = crypto.createHash('sha1');
objects
......@@ -46,5 +46,3 @@ class Hash {
return hash.digest('hex');
}
}
module.exports = new Hash();
......@@ -18,12 +18,4 @@
* along with blendb. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
process.env.NODE_ENV = 'test';
global.expect = require('chai').expect;
// Add the ./src directory to require's search path to facilitate import
// modules later on (avoiding the require('../../../../module') problem).
require('app-module-path').addPath(__dirname + '/../src');
--require ./test/global.js
--require ./build/test/global.js
--reporter spec
--ui bdd
--recursive
......@@ -7,3 +7,4 @@
--slow 300
--check-leaks
--globals expect
./build/**/*.spec.js
{
"compilerOptions": {
"pretty": true,
"target": "es5",
"module": "commonjs",
"outDir": "./build",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true
},
"exclude": [
"node_modules"
],
"compileOnSave": false
}
{
"globalDependencies": {
"chai": "registry:dt/chai#3.4.0+20160601211834",
"express": "registry:dt/express#4.0.0+20160708185218",
"express-serve-static-core": "registry:dt/express-serve-static-core#4.0.0+20160817171221",
"mime": "registry:dt/mime#0.0.0+20160316155526",
"mocha": "registry:env/mocha#2.2.5+20160723033700",
"node": "registry:env/node#6.0.0+20160813135048",
"serve-static": "registry:dt/serve-static#0.0.0+20160606155157"
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment