Comparing version 4.2.2 to 4.2.3
@@ -10,3 +10,3 @@ # How to contribute | ||
* You need a [GitHub account](https://github.com/signup/free) | ||
* Submit an [issue ticket](https://github.com/anselmh/CONTRIBUTING.md/issues) for your issue if there is no one yet. | ||
* Submit an [issue ticket](https://github.com/node-influx/node-influx/issues) for your issue if there is no one yet. | ||
* Describe the issue and include steps to reproduce if it's a bug. | ||
@@ -35,3 +35,3 @@ * Ensure to mention the earliest version that you know is affected. | ||
* Open a pull request to the original repository and choose the right original branch you want to patch. | ||
_Advanced users may install the `hub` gem and use the [`hub pull-request` command](https://github.com/defunkt/hub#git-pull-request)._ | ||
_Advanced users may install the `hub` gem and use the [`hub pull-request` command](https://hub.github.com/hub.1.html)._ | ||
* If not done in commit messages (which you really should do) please reference and update your issue with the code changes. But _please do not close the issue yourself_. | ||
@@ -44,3 +44,3 @@ _Notice: You can [turn your previously filed issues into a pull-request here](http://issue2pr.herokuapp.com/)._ | ||
* [General GitHub documentation](http://help.github.com/) | ||
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/) | ||
* [GitHub pull request documentation](https://help.github.com/articles/about-pull-requests/) | ||
* [Read the Issue Guidelines by @necolas](https://github.com/necolas/issue-guidelines/blob/master/CONTRIBUTING.md) for more details |
@@ -163,3 +163,3 @@ export = influx; | ||
writePoint(seriesName: string, values: PointValues, callback?: (err: Error) => void): void; | ||
/** | ||
@@ -256,3 +256,3 @@ * Writes a point to a series - requires database user privileges | ||
type TimePrecision = "ns"|"us"|"ms"|"s"|"m"|"h"|"d"|"w"|"m"|"y"; | ||
type TimePrecision = "ns"|"u"|"ms"|"s"|"m"|"h"|"d"|"w"|"m"|"y"; | ||
@@ -358,2 +358,2 @@ interface Options { | ||
} | ||
} | ||
} |
77
index.js
@@ -26,3 +26,3 @@ var InfluxRequest = require('./lib/InfluxRequest.js') | ||
function escape (s) { | ||
return s.replace(/[ ,=]/g, '\\$&') | ||
return s.replace(/[,= ]/g, '\\$&') | ||
} | ||
@@ -51,2 +51,9 @@ | ||
/** | ||
* Figure out if the user passed an options object or not. | ||
* This only exists because we're not using ES6 default parameters. | ||
* @param options | ||
* @param callback | ||
* @returns {{callback: (*|_.noop), options: (*|{})}} | ||
*/ | ||
function resolveOptCallback (options, callback) { | ||
@@ -114,5 +121,17 @@ if (typeof options === 'function') { | ||
if (res.statusCode < 200 || res.statusCode >= 300) { | ||
return callback(new Error(body.error || (typeof body === 'object' ? JSON.stringify(body) : (body || res.statusCode)))) | ||
var errorMessage | ||
if (!body) { | ||
errorMessage = 'No body received with status code ' + res.statusCode + ' from Influx.' | ||
} else if (body.error) { | ||
errorMessage = body.error | ||
} else if (typeof body === 'object') { | ||
errorMessage = JSON.stringify(body) | ||
} else { | ||
errorMessage = body | ||
} | ||
return callback(new Error(errorMessage)) | ||
} | ||
// Look for errors in the response body | ||
if (_.isObject(body) && body.results && _.isArray(body.results)) { | ||
@@ -176,9 +195,25 @@ for (var i = 0; i <= body.results.length; ++i) { | ||
/** | ||
* Send a POST request. Used for commands that have side effects, e.g. | ||
* 'CREATE DATABASE' or 'DROP USER'. GET is now deprecated for these. | ||
* @param query | ||
* @param options | ||
* @param callback | ||
*/ | ||
InfluxDB.prototype.updateDB = function (query, options, callback) { | ||
var args = resolveOptCallback(options, callback) | ||
this.request.post({ | ||
url: this.url('query', args.options, {q: query}), | ||
json: true | ||
}, this._parseCallback(args.callback)) | ||
} | ||
// creates a new database | ||
InfluxDB.prototype.createDatabase = function (databaseName, callback) { | ||
this.queryDB('create database "' + databaseName + '"', callback) | ||
this.updateDB('create database "' + databaseName + '"', callback) | ||
} | ||
InfluxDB.prototype.dropDatabase = function (databaseName, callback) { | ||
this.queryDB('drop database "' + databaseName + '"', callback) | ||
this.updateDB('drop database "' + databaseName + '"', callback) | ||
} | ||
@@ -259,7 +294,7 @@ | ||
InfluxDB.prototype.dropMeasurement = function (measurementName, callback) { | ||
this.queryDB('drop measurement "' + measurementName + '"', callback) | ||
this.updateDB('drop measurement "' + measurementName + '"', callback) | ||
} | ||
InfluxDB.prototype.dropSeries = function (seriesId, callback) { | ||
this.queryDB('drop series ' + seriesId, callback) | ||
this.updateDB('drop series ' + seriesId, callback) | ||
} | ||
@@ -270,2 +305,4 @@ | ||
// TODO strip unused arguments from quoery. Now we have: | ||
// query?u=...&p=...&q=show%20users&precision=ms&db=...&rp=... | ||
this.queryDB('show users', function (err, results) { | ||
@@ -291,27 +328,27 @@ if (err) { | ||
} | ||
this.queryDB(query, callback) | ||
this.updateDB(query, callback) | ||
} | ||
InfluxDB.prototype.setPassword = function (username, password, callback) { | ||
this.queryDB('set password for "' + username + '" = \'' + password + "'", callback) | ||
this.updateDB('set password for "' + username + '" = \'' + password + "'", callback) | ||
} | ||
InfluxDB.prototype.grantPrivilege = function (privilege, databaseName, userName, callback) { | ||
this.queryDB('grant ' + privilege + ' on "' + databaseName + '" to "' + userName + '"', callback) | ||
this.updateDB('grant ' + privilege + ' on "' + databaseName + '" to "' + userName + '"', callback) | ||
} | ||
InfluxDB.prototype.revokePrivilege = function (privilege, databaseName, userName, callback) { | ||
this.queryDB('revoke ' + privilege + ' on "' + databaseName + '" from "' + userName + '"', callback) | ||
this.updateDB('revoke ' + privilege + ' on "' + databaseName + '" from "' + userName + '"', callback) | ||
} | ||
InfluxDB.prototype.grantAdminPrivileges = function (userName, callback) { | ||
this.queryDB('grant all privileges to "' + userName + '"', callback) | ||
this.updateDB('grant all privileges to "' + userName + '"', callback) | ||
} | ||
InfluxDB.prototype.revokeAdminPrivileges = function (userName, callback) { | ||
this.queryDB('revoke all privileges from "' + userName + '"', callback) | ||
this.updateDB('revoke all privileges from "' + userName + '"', callback) | ||
} | ||
InfluxDB.prototype.dropUser = function (username, callback) { | ||
this.queryDB('drop user "' + username + '"', callback) | ||
this.updateDB('drop user "' + username + '"', callback) | ||
} | ||
@@ -371,4 +408,6 @@ | ||
line += ' ' + timestamp.getTime() | ||
} else if (/^[0-9]+$/.test(timestamp)) { | ||
line += ' ' + timestamp // UNIX timestamp | ||
} else { | ||
line += ' ' + timestamp | ||
line += ' ' + new Date(timestamp).getTime() // hopefully an RFC3339 string | ||
} | ||
@@ -402,3 +441,3 @@ } | ||
url: this.url('write', args.options), | ||
pool: typeof args.options.pool !== 'undefined' ? args.options.pool : {}, | ||
pool: typeof args.options.pool !== 'undefined' ? args.options.pool : undefined, | ||
body: this._prepareValues(series) | ||
@@ -454,3 +493,3 @@ }, this._parseCallback(args.callback)) | ||
' END' | ||
this.queryDB(query, callback) | ||
this.updateDB(query, callback) | ||
} | ||
@@ -471,3 +510,3 @@ | ||
} | ||
this.queryDB('DROP CONTINUOUS QUERY "' + queryName + '" ON "' + databaseName + '"', callback) | ||
this.updateDB('DROP CONTINUOUS QUERY "' + queryName + '" ON "' + databaseName + '"', callback) | ||
} | ||
@@ -484,3 +523,3 @@ | ||
this.queryDB(query, callback) | ||
this.updateDB(query, callback) | ||
} | ||
@@ -505,3 +544,3 @@ | ||
this.queryDB(query, callback) | ||
this.updateDB(query, callback) | ||
} | ||
@@ -508,0 +547,0 @@ |
{ | ||
"name": "influx", | ||
"version": "4.2.2", | ||
"version": "4.2.3", | ||
"description": "InfluxDB Client", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -45,4 +45,4 @@ # node-influx | ||
host: 'localhost', | ||
port: 8060, //optional. default 8086 | ||
protocol: 'http' //optional. default 'http' | ||
port: 8060, // Optional, default 8086 | ||
protocol: 'http' // Optional, default 'http'. Specify 'https' to use SSL. | ||
} | ||
@@ -52,4 +52,4 @@ ], | ||
host: 'localhost', | ||
port: 8086, // optional, default 8086 | ||
protocol: 'http', // optional, default 'http' | ||
port: 8086, | ||
protocol: 'http', | ||
username: 'dbuser', | ||
@@ -96,3 +96,3 @@ password: 'f4ncyp4ass', | ||
| hosts [optional] | Array of hosts for cluster configuration, e.g. [ {host: 'localhost', port: 8086},...] Port is optional | | ||
| depreciatedLogging [optional] | logging function for depreciated warnings, defaults to console.log | | ||
| depreciatedLogging [optional] | logging function for deprecated warnings, defaults to console.log | | ||
| failoverTimeout [optional] | number of ms node-influx will take a host out of the balancing after a request failed, default: 60000 | | ||
@@ -263,3 +263,3 @@ | requestTimeout [optional] | number of ms to wait before a request times out. defaults to 'null' (waits until connection is closed). Use with caution! | | ||
```js | ||
client.writePoint(seriesName, values, tags, [options], function (err) { }) | ||
client.writePoint(measurementName, values, tags, [options], function (err) { }) | ||
``` | ||
@@ -281,12 +281,12 @@ | ||
//write a single point with two values and two tags. time is omitted | ||
client.writePoint(info.series.name, {value: 232, value2: 123}, {foo: 'bar', foobar: 'baz'}, done) | ||
client.writePoint(info.measurement.name, {value: 232, value2: 123}, {foo: 'bar', foobar: 'baz'}, done) | ||
//write a single point with the value "1". The value "1" corresponds to {value: 1} | ||
client.writePoint(info.series.name, 1, {foo: 'bar', foobar: 'baz'}, done) | ||
client.writePoint(info.measurement.name, 1, {foo: 'bar', foobar: 'baz'}, done) | ||
//write a single point, providing an integer timestamp and time precision 's' for seconds | ||
client.writePoint(info.series.name, {time: 1234567890, value: 232}, null, {precision: 's'}, done) | ||
client.writePoint(info.measurement.name, {time: 1234567890, value: 232}, null, {precision: 's'}, done) | ||
//write a single point, providing a Date object. Precision is set to default 'ms' for milliseconds. | ||
client.writePoint(info.series.name, {time: new Date(), value: 232}, null, done) | ||
client.writePoint(info.measurement.name, {time: new Date(), value: 232}, null, done) | ||
@@ -300,3 +300,3 @@ | ||
```js | ||
client.writePoints(seriesName, points, [options], function (err) { }) | ||
client.writePoints(measurementName, points, [options], function (err) { }) | ||
``` | ||
@@ -316,3 +316,3 @@ | ||
]; | ||
client.writePoints(seriesName, points, [options], callback) | ||
client.writePoints(measurementName, points, [options], callback) | ||
``` | ||
@@ -326,3 +326,3 @@ | ||
##### writeSeries | ||
Writes multiple point to multiple series - requires database user privileges | ||
Writes multiple points to multiple series - requires database user privileges | ||
@@ -329,0 +329,0 @@ ```js |
82
test.js
@@ -98,3 +98,3 @@ /* eslint-env mocha */ | ||
describe('#noNetwork', function () { | ||
// Tests for library internals, do not send or recieve any data | ||
// Tests for library internals, do not send or receive any data | ||
@@ -124,4 +124,2 @@ describe('#url', function () { | ||
assert.equal(str, 'a=1,b=2') | ||
str = client._createKeyValueString({'temp=rature': 82, 'location place': 'us-midwest', 'comma, and quote': "'= "}) | ||
assert.equal(str, 'temp\\=rature=82,location\\ place="us-midwest",comma\\,\\ and\\ quote="\'= "') | ||
}) | ||
@@ -167,3 +165,3 @@ }) | ||
describe('#disabledHosts', function () { | ||
describe('#failedHost', function () { | ||
it('should return failed host', function (done) { | ||
@@ -378,2 +376,18 @@ // Issue any request so that library disables a host | ||
it('should write a point with RFC3339 timestamp and read it back', function (done) { | ||
var timestamp = '2016-10-02T20:50:00Z' | ||
dbClient.writePoint(info.series.numName, {time: timestamp, tag1: 'timestampRoundTrip'}, {}, function (err) { | ||
assert.equal(err, null) | ||
dbClient.query('SELECT * FROM ' + info.series.numName + " WHERE tag1='timestampRoundTrip';", function (err, res) { | ||
assert.equal(err, null) | ||
assert(res instanceof Array) | ||
assert.equal(res.length, 1, 'one series') | ||
assert.equal(res[0].length, 1, 'one result') | ||
assert.equal(res[0][0].tag1, 'timestampRoundTrip', 'incorrect point') | ||
assert.equal(res[0][0].time, timestamp, 'timestamp mismatch') | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('should write a point with time into the database', function (done) { | ||
@@ -499,18 +513,21 @@ dbClient.writePoint(info.series.numName, {time: new Date(), value: 232}, {}, done) | ||
it('should escape, write, read, and unescape a point', function (done) { | ||
dbClient.writePoint(info.series.numName, | ||
{'value,= 1': ',"= ', '"': 2}, | ||
{tag1: 'escapingRoundTrip', 'commas, and = signs': 'space != ,'}, function (err) { | ||
assert.equal(err, null) | ||
dbClient.query('SELECT * FROM ' + info.series.numName + " WHERE tag1='escapingRoundTrip';", function (err, res) { | ||
dbClient.writePoint( | ||
info.series.numName, | ||
{'value,= 1': ',"= ', ',= "': ',= "'}, | ||
{tag1: 'escapingRoundTrip', '"commas, and = signs"': '"space != ,"'}, | ||
function (err) { | ||
assert.equal(err, null) | ||
assert(res instanceof Array) | ||
assert.equal(res.length, 1, 'one series') | ||
assert.equal(res[0].length, 1, 'one result') | ||
assert.equal(res[0][0].tag1, 'escapingRoundTrip', 'the right result') | ||
assert.equal(res[0][0]['value,= 1'], ',"= ', '[,= ]-escaping field keys and values') | ||
assert.equal(res[0][0]['"'], 2, 'escaping quotes in field keys') | ||
assert.equal(res[0][0]['commas, and = signs'], 'space != ,', 'escaping tag keys and values') | ||
done() | ||
}) | ||
}) | ||
dbClient.query('SELECT * FROM ' + info.series.numName + " WHERE tag1='escapingRoundTrip';", function (err, res) { | ||
assert.equal(err, null) | ||
assert(res instanceof Array) | ||
assert.equal(res.length, 1, 'one series') | ||
assert.equal(res[0].length, 1, 'one result') | ||
assert.equal(res[0][0].tag1, 'escapingRoundTrip', 'incorrect point') | ||
assert.equal(res[0][0]['value,= 1'], ',"= ', '[,= ]-escaping field keys and values') | ||
assert.equal(res[0][0][',= "'], ',= "', 'escaping commas, equals, spaces, quotes in field keys and values') | ||
assert.equal(res[0][0]['"commas, and = signs"'], '"space != ,"', 'escaping tag keys and values') | ||
done() | ||
}) | ||
} | ||
) | ||
}) | ||
@@ -532,3 +549,3 @@ }) | ||
describe('#getSeries', function () { | ||
it('should return array of series', function (done) { | ||
it('getSeries without name should return array of series', function (done) { | ||
client.getSeries(function (err, series) { | ||
@@ -614,2 +631,27 @@ if (err) return done(err) | ||
describe('#specialCharacters', function () { | ||
var keyValues = [ | ||
{key: 'fieldKey', value: 'this space,that'}, | ||
{key: 'fieldKey', value: 'single\'double"quote'}, | ||
{key: 'key space, comma', value: 'value'}, | ||
{key: 'key sp "dquo \'squo, comma', value: 'value sp "dquo \'squo, comma'} | ||
] | ||
keyValues.forEach(function (field) { | ||
it('should write and read back point with field {' + field.key + ': ' + field.value + '}', function (done) { | ||
var fieldObject = {} | ||
fieldObject[field.key] = field.value | ||
dbClient.writePoint(info.series.strName, fieldObject, {}, function (err) { | ||
if (err) return done(err) | ||
var queryKey = field.key.replace(/[\\"]/g, '\\$&') | ||
dbClient.query('SELECT "' + queryKey + '" FROM ' + info.series.strName + ';', function (err, res) { | ||
if (err) return done(err) | ||
assert.equal(res[0][0][field.key], field.value) | ||
done() | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
describe('#createContinuousQuery', function () { | ||
@@ -616,0 +658,0 @@ it('should create a continuous query', function (done) { |
87786
1714