Initial commit
This commit is contained in:
476
lib/aggregate.js
Normal file
476
lib/aggregate.js
Normal file
@@ -0,0 +1,476 @@
|
||||
/* jshint -W097 */// jshint strict:false
|
||||
/*jslint node: true */
|
||||
"use strict";
|
||||
// THIS file should be identical with sql and history adapter's one
|
||||
|
||||
function initAggregate(options) {
|
||||
|
||||
//step; // 1 Step is 1 second
|
||||
if (options.step === null) {
|
||||
options.step = (options.end - options.start) / options.count;
|
||||
}
|
||||
|
||||
// Limit 2000
|
||||
if ((options.end - options.start) / options.step > options.limit) {
|
||||
options.step = (options.end - options.start) / options.limit;
|
||||
}
|
||||
|
||||
options.maxIndex = Math.ceil(((options.end - options.start) / options.step) - 1);
|
||||
options.result = [];
|
||||
options.averageCount = [];
|
||||
options.aggregate = options.aggregate || 'minmax';
|
||||
options.overallLength = 0;
|
||||
|
||||
// pre-fill the result with timestamps (add one before start and one after end)
|
||||
for (var i = 0; i <= options.maxIndex + 2; i++){
|
||||
|
||||
options.result[i] = {
|
||||
val: {ts: null, val: null},
|
||||
max: {ts: null, val: null},
|
||||
min: {ts: null, val: null},
|
||||
start: {ts: null, val: null},
|
||||
end: {ts: null, val: null}
|
||||
};
|
||||
|
||||
if (options.aggregate === 'average') options.averageCount[i] = 0;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function aggregation(options, data) {
|
||||
var index;
|
||||
var preIndex;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (!data[i]) continue;
|
||||
if (typeof data[i].ts !== 'number') data[i].ts = parseInt(data[i].ts, 10);
|
||||
if (data[i].ts < 946681200000) data[i].ts *= 1000;
|
||||
|
||||
preIndex = Math.floor((data[i].ts - options.start) / options.step);
|
||||
|
||||
// store all border values
|
||||
if (preIndex < 0) {
|
||||
index = 0;
|
||||
} else if (preIndex > options.maxIndex) {
|
||||
index = options.maxIndex + 2;
|
||||
} else {
|
||||
index = preIndex + 1;
|
||||
}
|
||||
options.overallLength++;
|
||||
|
||||
if (!options.result[index]) {
|
||||
console.error('Cannot find index ' + index);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options.aggregate === 'max') {
|
||||
if (!options.result[index].val.ts) options.result[index].val.ts = Math.round(options.start + (((index - 1) + 0.5) * options.step));
|
||||
if (options.result[index].val.val === null || options.result[index].val.val < data[i].val) options.result[index].val.val = data[i].val;
|
||||
} else if (options.aggregate === 'min') {
|
||||
if (!options.result[index].val.ts) options.result[index].val.ts = Math.round(options.start + (((index - 1) + 0.5) * options.step));
|
||||
if (options.result[index].val.val === null || options.result[index].val.val > data[i].val) options.result[index].val.val = data[i].val;
|
||||
} else if (options.aggregate === 'average') {
|
||||
if (!options.result[index].val.ts) options.result[index].val.ts = Math.round(options.start + (((index - 1) + 0.5) * options.step));
|
||||
options.result[index].val.val += parseFloat(data[i].val);
|
||||
options.averageCount[index]++;
|
||||
} else if (options.aggregate === 'total') {
|
||||
if (!options.result[index].val.ts) options.result[index].val.ts = Math.round(options.start + (((index - 1) + 0.5) * options.step));
|
||||
options.result[index].val.val += parseFloat(data[i].val);
|
||||
} else if (options.aggregate === 'minmax') {
|
||||
if (options.result[index].min.ts === null) {
|
||||
options.result[index].min.ts = data[i].ts;
|
||||
options.result[index].min.val = data[i].val;
|
||||
|
||||
options.result[index].max.ts = data[i].ts;
|
||||
options.result[index].max.val = data[i].val;
|
||||
|
||||
options.result[index].start.ts = data[i].ts;
|
||||
options.result[index].start.val = data[i].val;
|
||||
|
||||
options.result[index].end.ts = data[i].ts;
|
||||
options.result[index].end.val = data[i].val;
|
||||
} else {
|
||||
if (data[i].val !== null) {
|
||||
if (data[i].val > options.result[index].max.val) {
|
||||
options.result[index].max.ts = data[i].ts;
|
||||
options.result[index].max.val = data[i].val;
|
||||
} else if (data[i].val < options.result[index].min.val) {
|
||||
options.result[index].min.ts = data[i].ts;
|
||||
options.result[index].min.val = data[i].val;
|
||||
}
|
||||
if (data[i].ts > options.result[index].end.ts) {
|
||||
options.result[index].end.ts = data[i].ts;
|
||||
options.result[index].end.val = data[i].val;
|
||||
}
|
||||
} else {
|
||||
if (data[i].ts > options.result[index].end.ts) {
|
||||
options.result[index].end.ts = data[i].ts;
|
||||
options.result[index].end.val = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {result: options.result, step: options.step, sourceLength: data.length} ;
|
||||
}
|
||||
|
||||
function finishAggregation(options) {
|
||||
if (options.aggregate === 'minmax') {
|
||||
for (var ii = options.result.length - 1; ii >= 0; ii--) {
|
||||
// no one value in this period
|
||||
if (options.result[ii].start.ts === null) {
|
||||
options.result.splice(ii, 1);
|
||||
} else {
|
||||
// just one value in this period: max == min == start == end
|
||||
if (options.result[ii].start.ts === options.result[ii].end.ts) {
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} else
|
||||
if (options.result[ii].min.ts === options.result[ii].max.ts) {
|
||||
// if just 2 values: start == min == max, end
|
||||
if (options.result[ii].start.ts === options.result[ii].min.ts ||
|
||||
options.result[ii].end.ts === options.result[ii].min.ts) {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} // if just 3 values: start, min == max, end
|
||||
else {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].max.ts,
|
||||
val: options.result[ii].max.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
}
|
||||
} else
|
||||
if (options.result[ii].start.ts === options.result[ii].max.ts) {
|
||||
// just one value in this period: start == max, min == end
|
||||
if (options.result[ii].min.ts === options.result[ii].end.ts) {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} // start == max, min, end
|
||||
else {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].min.ts,
|
||||
val: options.result[ii].min.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
}
|
||||
} else
|
||||
if (options.result[ii].end.ts === options.result[ii].max.ts) {
|
||||
// just one value in this period: start == min, max == end
|
||||
if (options.result[ii].min.ts === options.result[ii].start.ts) {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} // start, min, max == end
|
||||
else {
|
||||
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].min.ts,
|
||||
val: options.result[ii].min.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
}
|
||||
} else
|
||||
if (options.result[ii].start.ts === options.result[ii].min.ts ||
|
||||
options.result[ii].end.ts === options.result[ii].min.ts) {
|
||||
// just one value in this period: start == min, max, end
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].max.ts,
|
||||
val: options.result[ii].max.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
} else {
|
||||
// just one value in this period: start == min, max, end
|
||||
if (options.result[ii].max.ts > options.result[ii].min.ts) {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].min.ts,
|
||||
val: options.result[ii].min.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].max.ts,
|
||||
val: options.result[ii].max.val
|
||||
});
|
||||
} else {
|
||||
options.result.splice(ii + 1, 0, {
|
||||
ts: options.result[ii].max.ts,
|
||||
val: options.result[ii].max.val
|
||||
});
|
||||
options.result.splice(ii + 2, 0, {
|
||||
ts: options.result[ii].min.ts,
|
||||
val: options.result[ii].min.val
|
||||
});
|
||||
}
|
||||
options.result.splice(ii + 3, 0, {
|
||||
ts: options.result[ii].end.ts,
|
||||
val: options.result[ii].end.val
|
||||
});
|
||||
options.result[ii] = {
|
||||
ts: options.result[ii].start.ts,
|
||||
val: options.result[ii].start.val
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (options.aggregate === 'average') {
|
||||
for (var k = options.result.length - 1; k >= 0; k--) {
|
||||
if (options.result[k].val.ts) {
|
||||
options.result[k] = {
|
||||
ts: options.result[k].val.ts,
|
||||
val: (options.result[k].val.val !== null) ? Math.round(options.result[k].val.val / options.averageCount[k] * 100) / 100 : null
|
||||
};
|
||||
} else {
|
||||
// no one value in this interval
|
||||
options.result.splice(k, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var j = options.result.length - 1; j >= 0; j--) {
|
||||
if (options.result[j].val.ts) {
|
||||
options.result[j] = {
|
||||
ts: options.result[j].val.ts,
|
||||
val: options.result[j].val.val
|
||||
};
|
||||
} else {
|
||||
// no one value in this interval
|
||||
options.result.splice(j, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
beautify(options);
|
||||
}
|
||||
|
||||
function beautify(options) {
|
||||
var preFirstValue = null;
|
||||
var postLastValue = null;
|
||||
if (options.ignoreNull === 'true') options.ignoreNull = true; // include nulls and replace them with last value
|
||||
if (options.ignoreNull === 'false') options.ignoreNull = false; // include nulls
|
||||
if (options.ignoreNull === '0') options.ignoreNull = 0; // include nulls and replace them with 0
|
||||
if (options.ignoreNull !== true && options.ignoreNull !== false && options.ignoreNull !== 0) options.ignoreNull = false;
|
||||
|
||||
// process null values, remove points outside the span and find first points after end and before start
|
||||
for (var i = 0; i < options.result.length; i++) {
|
||||
if (options.ignoreNull !== false) {
|
||||
// if value is null
|
||||
if (options.result[i].val === null) {
|
||||
// null value must be replaced with last not null value
|
||||
if (options.ignoreNull === true) {
|
||||
// remove value
|
||||
options.result.splice(i, 1);
|
||||
i--;
|
||||
continue;
|
||||
} else {
|
||||
// null value must be replaced with 0
|
||||
options.result[i].val = options.ignoreNull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove all not requested points
|
||||
if (options.result[i].ts < options.start) {
|
||||
preFirstValue = options.result[i].val !== null ? options.result[i] : null;
|
||||
options.result.splice(i, 1);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
postLastValue = options.result[i].val !== null ? options.result[i] : null;
|
||||
|
||||
if (options.result[i].ts > options.end) {
|
||||
options.result.splice(i, options.result.length - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check start and stop
|
||||
if (options.result.length && options.aggregate !== 'none') {
|
||||
var firstTS = options.result[0].ts;
|
||||
|
||||
if (firstTS > options.start) {
|
||||
if (preFirstValue) {
|
||||
var firstY = options.result[0].val;
|
||||
// if steps
|
||||
if (options.aggregate === 'onchange' || !options.aggregate) {
|
||||
if (preFirstValue.ts !== firstTS) {
|
||||
options.result.unshift({ts: options.start, val: preFirstValue.val});
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.unshift({ts: options.start, val: firstY});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (preFirstValue.ts !== firstTS) {
|
||||
if (firstY !== null) {
|
||||
// interpolate
|
||||
var y = preFirstValue.val + (firstY - preFirstValue.val) * (options.start - preFirstValue.ts) / (firstTS - preFirstValue.ts);
|
||||
options.result.unshift({ts: options.start, val: y});
|
||||
} else {
|
||||
options.result.unshift({ts: options.start, val: null});
|
||||
}
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.unshift({ts: options.start, val: firstY});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.unshift({ts: options.start, val: options.result[0].val});
|
||||
} else {
|
||||
options.result.unshift({ts: options.start, val: null});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lastTS = options.result[options.result.length - 1].ts;
|
||||
if (lastTS < options.end) {
|
||||
if (postLastValue) {
|
||||
// if steps
|
||||
if (options.aggregate === 'onchange' || !options.aggregate) {
|
||||
// if more data following, draw line to the end of chart
|
||||
if (postLastValue.ts !== lastTS) {
|
||||
options.result.push({ts: options.end, val: postLastValue.val});
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.push({ts: options.end, val: postLastValue.val});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (postLastValue.ts !== lastTS) {
|
||||
var lastY = options.result[options.result.length - 1].val;
|
||||
if (lastY !== null) {
|
||||
// make interpolation
|
||||
var _y = lastY + (postLastValue.val - lastY) * (options.end - lastTS) / (postLastValue.ts - lastTS);
|
||||
options.result.push({ts: options.end, val: _y});
|
||||
} else {
|
||||
options.result.push({ts: options.end, val: null});
|
||||
}
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
options.result.push({ts: options.end, val: postLastValue.val});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (options.ignoreNull) {
|
||||
var lastY = options.result[options.result.length - 1].val;
|
||||
// if no more data, that means do not draw line
|
||||
options.result.push({ts: options.end, val: lastY});
|
||||
} else {
|
||||
// if no more data, that means do not draw line
|
||||
options.result.push({ts: options.end, val: null});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (options.aggregate === 'none') {
|
||||
if ((options.count) && (options.result.length > options.count)) {
|
||||
options.result = options.result.slice(0, options.count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendResponse(adapter, msg, options, data, startTime) {
|
||||
var aggregateData;
|
||||
if (typeof data === 'string') {
|
||||
adapter.log.error(data);
|
||||
return adapter.sendTo(msg.from, msg.command, {
|
||||
result: [],
|
||||
step: 0,
|
||||
error: data,
|
||||
sessionId: options.sessionId
|
||||
}, msg.callback);
|
||||
}
|
||||
|
||||
if (options.count && !options.start && data.length > options.count) {
|
||||
data.splice(0, data.length - options.count);
|
||||
}
|
||||
if (data[0]) {
|
||||
options.start = options.start || data[0].ts;
|
||||
|
||||
if (!options.aggregate || options.aggregate === 'onchange' || options.aggregate === 'none') {
|
||||
aggregateData = {result: data, step: 0, sourceLength: data.length};
|
||||
|
||||
// convert ack from 0/1 to false/true
|
||||
if (options.ack && aggregateData.result) {
|
||||
for (var i = 0; i < aggregateData.result.length; i++) {
|
||||
aggregateData.result[i].ack = !!aggregateData.result[i].ack;
|
||||
}
|
||||
}
|
||||
options.result = aggregateData.result;
|
||||
beautify(options);
|
||||
if ((options.aggregate === 'none') && (options.count) && (options.result.length > options.count)) {
|
||||
options.result = options.result.slice(0, options.count);
|
||||
}
|
||||
aggregateData.result = options.result;
|
||||
} else {
|
||||
initAggregate(options);
|
||||
aggregateData = aggregation(options, data);
|
||||
finishAggregation(options);
|
||||
aggregateData.result = options.result;
|
||||
}
|
||||
|
||||
adapter.log.debug('Send: ' + aggregateData.result.length + ' of: ' + aggregateData.sourceLength + ' in: ' + (new Date().getTime() - startTime) + 'ms');
|
||||
adapter.sendTo(msg.from, msg.command, {
|
||||
result: aggregateData.result,
|
||||
step: aggregateData.step,
|
||||
error: null,
|
||||
sessionId: options.sessionId
|
||||
}, msg.callback);
|
||||
} else {
|
||||
adapter.log.info('No Data');
|
||||
adapter.sendTo(msg.from, msg.command, {result: [], step: null, error: null, sessionId: options.sessionId}, msg.callback);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.sendResponse = sendResponse;
|
||||
module.exports.initAggregate = initAggregate;
|
||||
module.exports.aggregation = aggregation;
|
||||
module.exports.beautify = beautify;
|
||||
module.exports.finishAggregation = finishAggregation;
|
||||
86
lib/mssql-client.js
Normal file
86
lib/mssql-client.js
Normal file
@@ -0,0 +1,86 @@
|
||||
// Generated by CoffeeScript 1.10.0
|
||||
(function() {
|
||||
var ConnectionFactory, SQLClient, SQLClientPool, MSSQLClient, MSSQLClientPool, MSSQLConnectionFactory, mssql,
|
||||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty,
|
||||
slice = [].slice;
|
||||
|
||||
SQLClient = require('sql-client/lib/sql-client').SQLClient;
|
||||
|
||||
SQLClientPool = require('sql-client/lib/sql-client-pool').SQLClientPool;
|
||||
|
||||
ConnectionFactory = require('sql-client/lib/connection-factory').ConnectionFactory;
|
||||
|
||||
mssql = require('mssql');
|
||||
|
||||
MSSQLConnectionFactory = (function(superClass) {
|
||||
extend(MSSQLConnectionFactory, superClass);
|
||||
|
||||
function MSSQLConnectionFactory() {
|
||||
this.execute = bind(this.execute, this);
|
||||
this.open_connection = bind(this.open_connection, this);
|
||||
return MSSQLConnectionFactory.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
MSSQLConnectionFactory.prototype.open_connection = function(config, callback) {
|
||||
var connection;
|
||||
var pos = config.server.indexOf(':');
|
||||
if (pos != -1) {
|
||||
config.port = parseInt(config.server.substring(pos + 1), 10);
|
||||
config.server = config.server.substring(0, pos);
|
||||
}
|
||||
|
||||
return connection = new mssql.Connection(config, function (err) {
|
||||
if (err != null) {
|
||||
return callback(err);
|
||||
} else {
|
||||
return callback(null, connection);
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
MSSQLConnectionFactory.prototype.execute = function(connection, sql, bindvars, callback) {
|
||||
var request = new mssql.Request(connection);
|
||||
return request.query(sql, function(err, recordset) {
|
||||
callback(err, recordset);
|
||||
});
|
||||
};
|
||||
|
||||
return MSSQLConnectionFactory;
|
||||
|
||||
})(ConnectionFactory);
|
||||
|
||||
MSSQLClient = (function(superClass) {
|
||||
extend(MSSQLClient, superClass);
|
||||
|
||||
function MSSQLClient() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
MSSQLClient.__super__.constructor.apply(this, slice.call(options).concat([new MSSQLConnectionFactory()]));
|
||||
}
|
||||
|
||||
return MSSQLClient;
|
||||
|
||||
})(SQLClient);
|
||||
|
||||
MSSQLClientPool = (function(superClass) {
|
||||
extend(MSSQLClientPool, superClass);
|
||||
|
||||
function MSSQLClientPool() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
MSSQLClientPool.__super__.constructor.apply(this, slice.call(options).concat([new MSSQLConnectionFactory()]));
|
||||
}
|
||||
|
||||
return MSSQLClientPool;
|
||||
|
||||
})(SQLClientPool);
|
||||
|
||||
exports.MSSQLConnectionFactory = MSSQLConnectionFactory;
|
||||
|
||||
exports.MSSQLClient = MSSQLClient;
|
||||
|
||||
exports.MSSQLClientPool = MSSQLClientPool;
|
||||
|
||||
}).call(this);
|
||||
151
lib/mssql.js
Normal file
151
lib/mssql.js
Normal file
@@ -0,0 +1,151 @@
|
||||
exports.init = function (dbname) {
|
||||
return [
|
||||
"CREATE DATABASE " + dbname + ";",
|
||||
"CREATE TABLE " + dbname + ".dbo.sources (id INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1), name varchar(255));",
|
||||
"CREATE TABLE " + dbname + ".dbo.datapoints (id INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1), name varchar(255), type INTEGER);",
|
||||
"CREATE TABLE " + dbname + ".dbo.ts_number (id INTEGER, ts BIGINT, val REAL, ack BIT, _from INTEGER, q INTEGER);",
|
||||
"CREATE TABLE " + dbname + ".dbo.ts_string (id INTEGER, ts BIGINT, val TEXT, ack BIT, _from INTEGER, q INTEGER);",
|
||||
"CREATE TABLE " + dbname + ".dbo.ts_bool (id INTEGER, ts BIGINT, val BIT, ack BIT, _from INTEGER, q INTEGER);"
|
||||
];
|
||||
};
|
||||
|
||||
exports.destroy = function (dbname) {
|
||||
return [
|
||||
"DROP TABLE " + dbname + ".dbo.ts_number;",
|
||||
"DROP TABLE " + dbname + ".dbo.ts_string;",
|
||||
"DROP TABLE " + dbname + ".dbo.ts_bool;",
|
||||
"DROP TABLE " + dbname + ".dbo.sources;",
|
||||
"DROP TABLE " + dbname + ".dbo.datapoints;",
|
||||
"DROP DATABASE " + dbname + ";",
|
||||
"DBCC FREEPROCCACHE;"
|
||||
];
|
||||
};
|
||||
|
||||
exports.getFirstTs = function (dbname, db) {
|
||||
return "SELECT id, MIN(ts) AS ts FROM " + dbname + ".dbo." + db + " GROUP BY id;";
|
||||
};
|
||||
|
||||
exports.insert = function (dbname, index, state, from, db) {
|
||||
if (state.val === null) state.val = 'NULL';
|
||||
else if (db === "ts_bool") state.val = state.val ? 1 : 0;
|
||||
else if (db === "ts_string") state.val = "'" + state.val.toString().replace(/'/g, '') + "'";
|
||||
|
||||
return "INSERT INTO " + dbname + ".dbo." + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (state.ack ? 1 : 0) + ", " + (from || 0) + ", " + (state.q || 0) + ");";
|
||||
};
|
||||
|
||||
exports.retention = function (dbname, index, db, retention) {
|
||||
var d = new Date();
|
||||
d.setSeconds(-retention);
|
||||
var query = "DELETE FROM " + dbname + ".dbo." + db + " WHERE";
|
||||
query += " id=" + index;
|
||||
query += " AND ts < " + d.getTime();
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.getIdSelect = function (dbname, name) {
|
||||
if (!name) {
|
||||
return "SELECT id, type, name FROM " + dbname + ".dbo.datapoints;";
|
||||
} else {
|
||||
return "SELECT id, type, name FROM " + dbname + ".dbo.datapoints WHERE name='" + name + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getIdInsert = function (dbname, name, type) {
|
||||
return "INSERT INTO " + dbname + ".dbo.datapoints (name, type) VALUES('" + name + "', " + type + ");";
|
||||
};
|
||||
|
||||
exports.getIdUpdate = function (dbname, id, type) {
|
||||
return "UPDATE " + dbname + ".dbo.datapoints SET type = " + type + " WHERE id = " + id + ";";
|
||||
};
|
||||
|
||||
exports.getFromSelect = function (dbname, from) {
|
||||
return "SELECT id FROM " + dbname + ".dbo.sources WHERE name='" + from + "';";
|
||||
};
|
||||
|
||||
exports.getFromInsert = function (dbname, from) {
|
||||
return "INSERT INTO " + dbname + ".dbo.sources (name) VALUES('" + from + "');";
|
||||
};
|
||||
|
||||
exports.getHistory = function (dbname, db, options) {
|
||||
var query = "SELECT ";
|
||||
if (!options.start && options.count) {
|
||||
query += " TOP " + options.count;
|
||||
}
|
||||
query += " ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", " + dbname + ".dbo.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + dbname + ".dbo." + db;
|
||||
|
||||
if (options.from) {
|
||||
query += " INNER JOIN " + dbname + ".dbo.sources ON " + dbname + ".dbo.sources.id=" + dbname + ".dbo." + db + "._from";
|
||||
}
|
||||
|
||||
var where = "";
|
||||
|
||||
if (options.id) {
|
||||
where += " " + dbname + ".dbo." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.end) {
|
||||
where += (where ? " AND" : "") + " " + dbname + ".dbo." + db + ".ts < " + options.end;
|
||||
}
|
||||
if (options.start) {
|
||||
where += (where ? " AND" : "") + " " + dbname + ".dbo." + db + ".ts >= " + options.start;
|
||||
|
||||
// add last value before start
|
||||
var subQuery;
|
||||
var subWhere;
|
||||
subQuery = " SELECT TOP 1 ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", " + dbname + ".dbo.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + dbname + ".dbo." + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN " + dbname + ".dbo.sources ON " + dbname + ".dbo.sources.id=" + dbname + ".dbo." + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + dbname + ".dbo." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + dbname + ".dbo." + db + ".ts < " + options.start;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + dbname + ".dbo." + db + ".ts DESC";
|
||||
where += " UNION SELECT * FROM (" + subQuery + ") a";
|
||||
|
||||
// add next value after end
|
||||
subQuery = " SELECT TOP 1 ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", " + dbname + ".dbo.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + dbname + ".dbo." + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN " + dbname + ".dbo.sources ON " + dbname + ".dbo.sources.id=" + dbname + ".dbo." + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + dbname + ".dbo." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + dbname + ".dbo." + db + ".ts >= " + options.end;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + dbname + ".dbo." + db + ".ts ASC";
|
||||
where += " UNION SELECT * FROM (" + subQuery + ") b";
|
||||
}
|
||||
|
||||
if (where) query += " WHERE " + where;
|
||||
|
||||
query += " ORDER BY ts";
|
||||
if (!options.start && options.count) {
|
||||
query += " DESC";
|
||||
} else {
|
||||
query += " ASC";
|
||||
}
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
146
lib/mysql.js
Normal file
146
lib/mysql.js
Normal file
@@ -0,0 +1,146 @@
|
||||
exports.init = function (dbname) {
|
||||
return [
|
||||
"CREATE DATABASE `" + dbname + "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;",
|
||||
"CREATE TABLE `" + dbname + "`.sources (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name TEXT);",
|
||||
"CREATE TABLE `" + dbname + "`.datapoints (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name TEXT, type INTEGER);",
|
||||
"CREATE TABLE `" + dbname + "`.ts_number (id INTEGER, ts BIGINT, val REAL, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE `" + dbname + "`.ts_string (id INTEGER, ts BIGINT, val TEXT, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE `" + dbname + "`.ts_bool (id INTEGER, ts BIGINT, val BOOLEAN, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));"
|
||||
];
|
||||
};
|
||||
|
||||
exports.destroy = function (dbname) {
|
||||
return [
|
||||
"DROP TABLE `" + dbname + "`.ts_number;",
|
||||
"DROP TABLE `" + dbname + "`.ts_string;",
|
||||
"DROP TABLE `" + dbname + "`.ts_bool;",
|
||||
"DROP TABLE `" + dbname + "`.sources;",
|
||||
"DROP TABLE `" + dbname + "`.datapoints;",
|
||||
"DROP DATABASE `" + dbname + "`;"
|
||||
];
|
||||
};
|
||||
|
||||
exports.getFirstTs = function (dbname, db) {
|
||||
return "SELECT id, MIN(ts) AS ts FROM `" + dbname + "`." + db + " GROUP BY id;";
|
||||
};
|
||||
|
||||
exports.insert = function (dbname, index, state, from, db) {
|
||||
if (state.val === null) state.val = 'NULL';
|
||||
else if (db === "ts_string") state.val = "'" + state.val.toString().replace(/'/g, '') + "'";
|
||||
return "INSERT INTO `" + dbname + "`." + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (state.ack ? 1 : 0) + ", " + (from || 0) + ", " + (state.q || 0) + ");";
|
||||
};
|
||||
|
||||
exports.retention = function (dbname, index, db, retention) {
|
||||
var d = new Date();
|
||||
d.setSeconds(-retention);
|
||||
var query = "DELETE FROM `" + dbname + "`." + db + " WHERE";
|
||||
query += " id=" + index;
|
||||
query += " AND ts < " + d.getTime();
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.getIdSelect = function (dbname, name) {
|
||||
if (!name) {
|
||||
return "SELECT id, type, name FROM `" + dbname + "`.datapoints;";
|
||||
} else {
|
||||
return "SELECT id, type, name FROM `" + dbname + "`.datapoints WHERE name='" + name + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getIdInsert = function (dbname, name, type) {
|
||||
return "INSERT INTO `" + dbname + "`.datapoints (name, type) VALUES('" + name + "', " + type + ");";
|
||||
};
|
||||
|
||||
exports.getIdUpdate = function (dbname, id, type) {
|
||||
return "UPDATE `" + dbname + "`.datapoints SET type = " + type + " WHERE id = " + id + ";";
|
||||
};
|
||||
|
||||
exports.getFromSelect = function (dbname, from) {
|
||||
return "SELECT id FROM `" + dbname + "`.sources WHERE name='" + from + "';";
|
||||
};
|
||||
|
||||
exports.getFromInsert = function (dbname, from) {
|
||||
return "INSERT INTO `" + dbname + "`.sources (name) VALUES('" + from + "');";
|
||||
};
|
||||
|
||||
exports.getHistory = function (dbname, db, options) {
|
||||
var query = "SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", `" + dbname + "`.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM `" + dbname + "`." + db;
|
||||
|
||||
if (options.from) {
|
||||
query += " INNER JOIN `" + dbname + "`.sources ON `" + dbname + "`.sources.id=`" + dbname + "`." + db + "._from";
|
||||
}
|
||||
|
||||
var where = "";
|
||||
|
||||
if (options.id) {
|
||||
where += " `" + dbname + "`." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.end) {
|
||||
where += (where ? " AND" : "") + " `" + dbname + "`." + db + ".ts < " + options.end;
|
||||
}
|
||||
if (options.start) {
|
||||
where += (where ? " AND" : "") + " `" + dbname + "`." + db + ".ts >= " + options.start;
|
||||
|
||||
var subQuery;
|
||||
var subWhere;
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", `" + dbname + "`.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM `" + dbname + "`." + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN `" + dbname + "`.sources ON `" + dbname + "`.sources.id=`" + dbname + "`." + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " `" + dbname + "`." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " `" + dbname + "`." + db + ".ts < " + options.start;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY `" + dbname + "`." + db + ".ts DESC LIMIT 1";
|
||||
where += " UNION (" + subQuery + ")";
|
||||
|
||||
//add next value after end
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", `" + dbname + "`.sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM `" + dbname + "`." + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN `" + dbname + "`.sources ON `" + dbname + "`.sources.id=`" + dbname + "`." + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " `" + dbname + "`." + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " `" + dbname + "`." + db + ".ts >= " + options.end;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY `" + dbname + "`." + db + ".ts ASC LIMIT 1";
|
||||
where += " UNION (" + subQuery + ")";
|
||||
|
||||
}
|
||||
|
||||
if (where) query += " WHERE " + where;
|
||||
|
||||
query += " ORDER BY ts";
|
||||
|
||||
if (!options.start && options.count) {
|
||||
query += " DESC LIMIT " + options.count;
|
||||
} else {
|
||||
query += " ASC";
|
||||
}
|
||||
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
158
lib/postgresql-client.js
Normal file
158
lib/postgresql-client.js
Normal file
@@ -0,0 +1,158 @@
|
||||
// Generated by CoffeeScript 1.10.0
|
||||
(function() {
|
||||
var ConnectionFactory, PostgreSQLClient, PostgreSQLClient2, PostgreSQLClientPool, PostgreSQLClientPool2, PostgreSQLConnectionFactory, PostgreSQLConnectionFactory2, SQLClient, SQLClientPool, pg,
|
||||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty,
|
||||
slice = [].slice;
|
||||
|
||||
SQLClient = require('sql-client/lib/sql-client').SQLClient;
|
||||
|
||||
SQLClientPool = require('sql-client/lib/sql-client-pool').SQLClientPool;
|
||||
|
||||
ConnectionFactory = require('sql-client/lib/connection-factory').ConnectionFactory;
|
||||
|
||||
pg = require('pg');
|
||||
try {
|
||||
if ((pg != null ? pg["native"] : void 0) != null) {
|
||||
pg = pg["native"];
|
||||
}
|
||||
} catch(err) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
PostgreSQLConnectionFactory = (function(superClass) {
|
||||
extend(PostgreSQLConnectionFactory, superClass);
|
||||
|
||||
function PostgreSQLConnectionFactory() {
|
||||
this.pre_process_sql = bind(this.pre_process_sql, this);
|
||||
this.open_connection = bind(this.open_connection, this);
|
||||
return PostgreSQLConnectionFactory.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
PostgreSQLConnectionFactory.prototype.open_connection = function(connect_string, callback) {
|
||||
var connection;
|
||||
connection = new pg.Client(connect_string);
|
||||
return connection.connect((function(_this) {
|
||||
return function(err) {
|
||||
return callback(err, connection);
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
PostgreSQLConnectionFactory.prototype.pre_process_sql = function(sql, bindvars, callback) {
|
||||
var index;
|
||||
if ((sql != null) && (bindvars != null)) {
|
||||
index = 1;
|
||||
sql = sql.replace(/\?/g, (function() {
|
||||
return '$' + index++;
|
||||
}));
|
||||
}
|
||||
return callback(null, sql, bindvars);
|
||||
};
|
||||
|
||||
return PostgreSQLConnectionFactory;
|
||||
|
||||
})(ConnectionFactory);
|
||||
|
||||
PostgreSQLClient = (function(superClass) {
|
||||
extend(PostgreSQLClient, superClass);
|
||||
|
||||
function PostgreSQLClient() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
PostgreSQLClient.__super__.constructor.apply(this, slice.call(options).concat([new PostgreSQLConnectionFactory()]));
|
||||
}
|
||||
|
||||
return PostgreSQLClient;
|
||||
|
||||
})(SQLClient);
|
||||
|
||||
PostgreSQLClientPool = (function(superClass) {
|
||||
extend(PostgreSQLClientPool, superClass);
|
||||
|
||||
function PostgreSQLClientPool() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
PostgreSQLClientPool.__super__.constructor.apply(this, slice.call(options).concat([new PostgreSQLConnectionFactory()]));
|
||||
}
|
||||
|
||||
return PostgreSQLClientPool;
|
||||
|
||||
})(SQLClientPool);
|
||||
|
||||
exports.PostgreSQLConnectionFactory = PostgreSQLConnectionFactory;
|
||||
|
||||
exports.PostgreSQLClient = PostgreSQLClient;
|
||||
|
||||
exports.PostgreSQLClientPool = PostgreSQLClientPool;
|
||||
|
||||
PostgreSQLConnectionFactory2 = (function(superClass) {
|
||||
extend(PostgreSQLConnectionFactory2, superClass);
|
||||
|
||||
function PostgreSQLConnectionFactory2() {
|
||||
this.close_connection = bind(this.close_connection, this);
|
||||
this.open_connection = bind(this.open_connection, this);
|
||||
return PostgreSQLConnectionFactory2.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
PostgreSQLConnectionFactory2.prototype.open_connection = function(connect_string, callback) {
|
||||
return pg.connect(connect_string, (function(_this) {
|
||||
return function(err, client, done_fn) {
|
||||
var connection;
|
||||
connection = client;
|
||||
if (connection != null) {
|
||||
connection._sqlclient_done = done_fn;
|
||||
}
|
||||
return callback(err, connection);
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
PostgreSQLConnectionFactory2.prototype.close_connection = function(connection, callback) {
|
||||
if ((connection != null ? connection._sqlclient_done : void 0) != null) {
|
||||
connection._sqlclient_done();
|
||||
return typeof callback === "function" ? callback(null) : void 0;
|
||||
} else {
|
||||
return PostgreSQLConnectionFactory2.__super__.close_connection.apply(this, arguments).close_connection(connection, callback);
|
||||
}
|
||||
};
|
||||
|
||||
return PostgreSQLConnectionFactory2;
|
||||
|
||||
})(PostgreSQLConnectionFactory);
|
||||
|
||||
PostgreSQLClient2 = (function(superClass) {
|
||||
extend(PostgreSQLClient2, superClass);
|
||||
|
||||
function PostgreSQLClient2() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
PostgreSQLClient2.__super__.constructor.apply(this, slice.call(options).concat([new PostgreSQLConnectionFactory2()]));
|
||||
}
|
||||
|
||||
return PostgreSQLClient2;
|
||||
|
||||
})(SQLClient);
|
||||
|
||||
PostgreSQLClientPool2 = (function(superClass) {
|
||||
extend(PostgreSQLClientPool2, superClass);
|
||||
|
||||
function PostgreSQLClientPool2() {
|
||||
var options;
|
||||
options = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||
PostgreSQLClientPool2.__super__.constructor.apply(this, slice.call(options).concat([new PostgreSQLConnectionFactory2()]));
|
||||
}
|
||||
|
||||
return PostgreSQLClientPool2;
|
||||
|
||||
})(SQLClientPool);
|
||||
|
||||
exports.PostgreSQLConnectionFactory2 = PostgreSQLConnectionFactory2;
|
||||
|
||||
exports.PostgreSQLClient2 = PostgreSQLClient2;
|
||||
|
||||
exports.PostgreSQLClientPool2 = PostgreSQLClientPool2;
|
||||
|
||||
}).call(this);
|
||||
145
lib/postgresql.js
Normal file
145
lib/postgresql.js
Normal file
@@ -0,0 +1,145 @@
|
||||
exports.init = function (dbname) {
|
||||
return [
|
||||
"CREATE TABLE sources (id SERIAL NOT NULL PRIMARY KEY, name TEXT);",
|
||||
"CREATE TABLE datapoints (id SERIAL NOT NULL PRIMARY KEY, name TEXT, type INTEGER);",
|
||||
"CREATE TABLE ts_number (id INTEGER NOT NULL, ts BIGINT, val REAL, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE ts_string (id INTEGER NOT NULL, ts BIGINT, val TEXT, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE ts_bool (id INTEGER NOT NULL, ts BIGINT, val BOOLEAN, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));"
|
||||
];
|
||||
};
|
||||
|
||||
exports.destroy = function (dbname) {
|
||||
return [
|
||||
"DROP TABLE ts_number;",
|
||||
"DROP TABLE ts_string;",
|
||||
"DROP TABLE ts_bool;",
|
||||
"DROP TABLE sources;",
|
||||
"DROP TABLE datapoints;"
|
||||
];
|
||||
};
|
||||
|
||||
exports.getFirstTs = function (dbname, db) {
|
||||
return "SELECT id, MIN(ts) AS ts FROM " + db + " GROUP BY id;";
|
||||
};
|
||||
|
||||
exports.insert = function (dbname, index, state, from, db) {
|
||||
if (state.val === null) state.val = 'NULL';
|
||||
else if (db === "ts_string") state.val = "'" + state.val.toString().replace(/'/g, '') + "'";
|
||||
return "INSERT INTO " + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (!!state.ack) + ", " + (from || 0) + ", " + (state.q || 0) + ");";
|
||||
};
|
||||
|
||||
exports.retention = function (dbname, index, db, retention) {
|
||||
var d = new Date();
|
||||
d.setSeconds(-retention);
|
||||
var query = "DELETE FROM " + db + " WHERE";
|
||||
query += " id=" + index;
|
||||
query += " AND ts < " + d.getTime();
|
||||
query += ";";
|
||||
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.getIdSelect = function (dbname, name) {
|
||||
if (!name) {
|
||||
return "SELECT id, type, name FROM datapoints;";
|
||||
} else {
|
||||
return "SELECT id, type, name FROM datapoints WHERE name='" + name + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getIdInsert = function (dbname, name, type) {
|
||||
return "INSERT INTO datapoints (name, type) VALUES('" + name + "', " + type + ");";
|
||||
};
|
||||
|
||||
exports.getIdUpdate = function (dbname, id, type) {
|
||||
return "UPDATE datapoints SET type = " + type + " WHERE id = " + id + ";";
|
||||
};
|
||||
|
||||
exports.getFromSelect = function (dbname, from) {
|
||||
return "SELECT id FROM sources WHERE name='" + from + "';";
|
||||
};
|
||||
|
||||
exports.getFromInsert = function (dbname, from) {
|
||||
return "INSERT INTO sources (name) VALUES('" + from + "');";
|
||||
};
|
||||
exports.getHistory = function (dbname, db, options) {
|
||||
var query = "SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as from") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
|
||||
if (options.from) {
|
||||
query += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
|
||||
var where = "";
|
||||
|
||||
if (options.id) {
|
||||
where += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.end) {
|
||||
where += (where ? " AND" : "") + " " + db + ".ts < " + options.end;
|
||||
}
|
||||
if (options.start) {
|
||||
where += (where ? " AND" : "") + " " + db + ".ts >= " + options.start;
|
||||
|
||||
//add last value before start
|
||||
var subQuery;
|
||||
var subWhere;
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as from") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + db + ".ts < " + options.start;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + db + ".ts DESC LIMIT 1";
|
||||
where += " UNION (" + subQuery + ")";
|
||||
|
||||
//add next value after end
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as from") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + db + ".ts >= " + options.end;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + db + ".ts ASC LIMIT 1";
|
||||
where += " UNION (" + subQuery + ")";
|
||||
}
|
||||
|
||||
if (where) query += " WHERE " + where;
|
||||
|
||||
|
||||
query += " ORDER BY ts";
|
||||
|
||||
if (!options.start && options.count) {
|
||||
query += " DESC LIMIT " + options.count;
|
||||
} else {
|
||||
query += " ASC";
|
||||
}
|
||||
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
149
lib/sqlite.js
Normal file
149
lib/sqlite.js
Normal file
@@ -0,0 +1,149 @@
|
||||
exports.init = function (dbname) {
|
||||
return [
|
||||
"CREATE TABLE sources (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT);",
|
||||
"CREATE TABLE datapoints (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT, type INTEGER);",
|
||||
"CREATE TABLE ts_number (id INTEGER, ts INTEGER, val REAL, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE ts_string (id INTEGER, ts INTEGER, val TEXT, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));",
|
||||
"CREATE TABLE ts_bool (id INTEGER, ts INTEGER, val BOOLEAN, ack BOOLEAN, _from INTEGER, q INTEGER, PRIMARY KEY(id, ts));"
|
||||
];
|
||||
};
|
||||
|
||||
exports.destroy = function (dbname) {
|
||||
return [
|
||||
"DROP TABLE ts_number;",
|
||||
"DROP TABLE ts_string;",
|
||||
"DROP TABLE ts_bool;",
|
||||
"DROP TABLE sources;",
|
||||
"DROP TABLE datapoints;"
|
||||
];
|
||||
};
|
||||
|
||||
exports.getFirstTs = function (dbname, db) {
|
||||
return "SELECT id, MIN(ts) AS ts FROM " + db + " GROUP BY id;";
|
||||
};
|
||||
|
||||
exports.insert = function (dbname, index, state, from, db) {
|
||||
if (state.val === null) state.val = 'NULL';
|
||||
else if (db === "ts_bool") state.val = state.val ? 1 : 0;
|
||||
else if (db === "ts_string") state.val = "'" + state.val.toString().replace(/'/g, '') + "'";
|
||||
return "INSERT INTO " + db + " (id, ts, val, ack, _from, q) VALUES(" + index + ", " + state.ts + ", " + state.val + ", " + (state.ack ? 1 : 0) + ", " + (from || 0) + ", " + (state.q || 0) + ");";
|
||||
};
|
||||
|
||||
exports.retention = function (dbname, index, db, retention) {
|
||||
var d = new Date();
|
||||
d.setSeconds(-retention);
|
||||
var query = "DELETE FROM " + db + " WHERE";
|
||||
query += " id=" + index;
|
||||
query += " AND ts < " + d.getTime();
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.getIdSelect = function (dbname, name) {
|
||||
if (!name) {
|
||||
return "SELECT id, type, name FROM datapoints;";
|
||||
} else {
|
||||
return "SELECT id, type, name FROM datapoints WHERE name='" + name + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getIdInsert = function (dbname, name, type) {
|
||||
return "INSERT INTO datapoints (name, type) VALUES('" + name + "', " + type + ");";
|
||||
};
|
||||
|
||||
exports.getIdUpdate = function (dbname, id, type) {
|
||||
return "UPDATE datapoints SET type = " + type + " WHERE id = " + id + ";";
|
||||
};
|
||||
|
||||
exports.getFromSelect = function (dbname, from) {
|
||||
if (!from) {
|
||||
return "SELECT id, name FROM sources;";
|
||||
} else {
|
||||
return "SELECT id FROM sources WHERE name='" + from + "';";
|
||||
}
|
||||
};
|
||||
|
||||
exports.getFromInsert = function (dbname, from) {
|
||||
return "INSERT INTO sources (name) VALUES('" + from + "');";
|
||||
};
|
||||
|
||||
exports.getHistory = function (dbname, db, options) {
|
||||
var query = "SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
|
||||
if (options.from) {
|
||||
query += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
|
||||
var where = "";
|
||||
|
||||
if (options.id) {
|
||||
where += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.end) {
|
||||
where += (where ? " AND" : "") + " " + db + ".ts < " + options.end;
|
||||
}
|
||||
if (options.start) {
|
||||
where += (where ? " AND" : "") + " " + db + ".ts >= " + options.start;
|
||||
|
||||
//add last value before start
|
||||
var subQuery;
|
||||
var subWhere;
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + db + ".ts < " + options.start;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + db + ".ts DESC LIMIT 1";
|
||||
where += " UNION SELECT * from (" + subQuery + ")";
|
||||
|
||||
//add next value after end
|
||||
subQuery = " SELECT ts, val" +
|
||||
(!options.id ? (", " + db + ".id as id") : "") +
|
||||
(options.ack ? ", ack" : "") +
|
||||
(options.from ? (", sources.name as 'from'") : "") +
|
||||
(options.q ? ", q" : "") + " FROM " + db;
|
||||
if (options.from) {
|
||||
subQuery += " INNER JOIN sources ON sources.id=" + db + "._from";
|
||||
}
|
||||
subWhere = "";
|
||||
if (options.id) {
|
||||
subWhere += " " + db + ".id=" + options.id;
|
||||
}
|
||||
if (options.ignoreNull) {
|
||||
//subWhere += (subWhere ? " AND" : "") + " val <> NULL";
|
||||
}
|
||||
subWhere += (subWhere ? " AND" : "") + " " + db + ".ts >= " + options.end;
|
||||
if (subWhere) subQuery += " WHERE " + subWhere;
|
||||
subQuery += " ORDER BY " + db + ".ts ASC LIMIT 1";
|
||||
where += " UNION SELECT * from (" + subQuery + ") ";
|
||||
}
|
||||
|
||||
if (where) query += " WHERE " + where;
|
||||
|
||||
query += " ORDER BY ts";
|
||||
|
||||
if (!options.start && options.count) {
|
||||
query += " DESC LIMIT " + options.count;
|
||||
} else {
|
||||
query += " ASC";
|
||||
}
|
||||
|
||||
query += ";";
|
||||
return query;
|
||||
};
|
||||
83
lib/utils.js
Normal file
83
lib/utils.js
Normal file
@@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
let controllerDir;
|
||||
let appName;
|
||||
|
||||
/**
|
||||
* returns application name
|
||||
*
|
||||
* The name of the application can be different and this function finds it out.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
function getAppName() {
|
||||
const parts = __dirname.replace(/\\/g, '/').split('/');
|
||||
return parts[parts.length - 2].split('.')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* looks for js-controller home folder
|
||||
*
|
||||
* @param {boolean} isInstall
|
||||
* @returns {string}
|
||||
*/
|
||||
function getControllerDir(isInstall) {
|
||||
// Find the js-controller location
|
||||
const possibilities = [
|
||||
'yunkong2.js-controller',
|
||||
'yunkong2.js-controller',
|
||||
];
|
||||
/** @type {string} */
|
||||
let controllerPath;
|
||||
for (const pkg of possibilities) {
|
||||
try {
|
||||
const possiblePath = require.resolve(pkg);
|
||||
if (fs.existsSync(possiblePath)) {
|
||||
controllerPath = possiblePath;
|
||||
break;
|
||||
}
|
||||
} catch (e) { /* not found */ }
|
||||
}
|
||||
if (controllerPath == null) {
|
||||
if (!isInstall) {
|
||||
console.log('Cannot find js-controller');
|
||||
process.exit(10);
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
// we found the controller
|
||||
return path.dirname(controllerPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads controller base settings
|
||||
*
|
||||
* @alias getConfig
|
||||
* @returns {object}
|
||||
*/
|
||||
function getConfig() {
|
||||
let configPath;
|
||||
if (fs.existsSync(
|
||||
configPath = path.join(controllerDir, 'conf', appName + '.json')
|
||||
)) {
|
||||
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
} else if (fs.existsSync(
|
||||
configPath = path.join(controllerDir, 'conf', + appName.toLowerCase() + '.json')
|
||||
)) {
|
||||
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
} else {
|
||||
throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
|
||||
}
|
||||
}
|
||||
appName = getAppName();
|
||||
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);
|
||||
const adapter = require(path.join(controllerDir, 'lib/adapter.js'));
|
||||
|
||||
exports.controllerDir = controllerDir;
|
||||
exports.getConfig = getConfig;
|
||||
exports.Adapter = adapter;
|
||||
exports.appName = appName;
|
||||
Reference in New Issue
Block a user