未验证 提交 defb4739 编写于 作者: H hzcheng 提交者: GitHub

Merge pull request #170 from StoneT2000/master

Added node.js connector and example usage of node.js
......@@ -95,6 +95,7 @@ TDengine provides abundant developing tools for users to develop on TDengine. Fo
- [Python](https://www.taosdata.com/en/documentation/connector/#Python-Connector)
- [Go](https://www.taosdata.com/en/documentation/connector/#Go-Connector)
- [RESTful API](https://www.taosdata.com/en/documentation/connector/#RESTful-Connector)
- [Node.js](https://www.taosdata.com/en/documentation/connector/#Node.js-Connector)
# TDengine Roadmap
- Support event-driven stream computing
......
const ref = require('ref');
const ffi = require('ffi');
const ArrayType = require('ref-array');
const Struct = require('ref-struct');
const fieldTypes = require('./constants');
const errors = require ('./error')
module.exports = CTaosInterface;
function convertMillisecondsToDatetime(time) {
return new Date(time);
}
function convertMicrosecondsToDatetime(time) {
return new Date(time * 0.001);
}
function convertTimestamp(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
timestampConverter = convertMillisecondsToDatetime;
if (micro == true) {
timestampConverter = convertMicrosecondsToDatetime;
}
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
while (currOffset < data.length) {
let queue = [];
let time = 0;
for (let i = currOffset; i < currOffset + nbytes; i++) {
queue.push(data[i]);
if (data[i] == 0) {
break;
}
}
for (let i = queue.length - 1; i >= 0; i--) {
time += queue[i] * Math.pow(16, i * 2);
}
currOffset += nbytes;
res.push(timestampConverter(time));
}
return res;
}
function convertBool(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = new Array(data.length);
for (let i = 0; i < data.length; i++) {
if (data[i] == 0) {
res[i] = false;
}
else {
res[i] = true;
}
}
return res;
}
function convertTinyint(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
while (currOffset < data.length) {
res.push(data.readIntLE(currOffset,1));
currOffset += nbytes;
}
return res;
}
function convertSmallint(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
while (currOffset < data.length) {
res.push(data.readIntLE(currOffset,2));
currOffset += nbytes;
}
return res;
}
function convertInt(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
while (currOffset < data.length) {
res.push(data.readInt32LE(currOffset));
currOffset += nbytes;
}
return res;
}
function readBigInt64LE(buffer, offset = 0) {
const first = buffer[offset];
const last = buffer[offset + 7];
if (first === undefined || last === undefined)
boundsError(offset, buffer.length - 8);
const val = buffer[offset + 4] + buffer[offset + 5] * 2 ** 8 + buffer[offset + 6] * 2 ** 16 + (last << 24); // Overflow
return ((BigInt(val) << 32n) + BigInt(first + buffer[++offset] * 2 ** 8 + buffer[++offset] * 2 ** 16 + buffer[++offset] * 2 ** 24));
}
function convertBigint(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
while (currOffset < data.length) {
res.push(BigInt(data.readInt64LE(currOffset)));
currOffset += nbytes;
}
return res;
}
function convertFloat(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
while (currOffset < data.length) {
res.push(parseFloat(data.readFloatLE(currOffset).toFixed(7)));
currOffset += nbytes;
}
return res;
}
function convertDouble(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
while (currOffset < data.length) {
res.push(parseFloat(data.readDoubleLE(currOffset).toFixed(16)));
currOffset += nbytes;
}
return res;
}
function convertBinary(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
while (currOffset < data.length) {
let dataEntry = data.slice(currOffset, currOffset + nbytes); //one entry in a row under a column;
res.push(ref.readCString(dataEntry));
currOffset += nbytes;
}
return res;
}
function convertNchar(data, num_of_rows, nbytes = 0, offset = 0, micro=false) {
data = ref.reinterpret(data.deref().deref(), nbytes * num_of_rows, offset);
let res = [];
let currOffset = 0;
//every 4;
while (currOffset < data.length) {
let dataEntry = data.slice(currOffset, currOffset + nbytes); //one entry in a row under a column;
res.push(dataEntry.toString("utf16le").replace(/\u0000/g, ""));
currOffset += nbytes;
}
return res;
}
//Object with all the relevant converters from pblock data to javascript data
let convertFunctions = {
[fieldTypes.C_BOOL] : convertBool,
[fieldTypes.C_TINYINT] : convertTinyint,
[fieldTypes.C_SMALLINT] : convertSmallint,
[fieldTypes.C_INT] : convertInt,
[fieldTypes.C_BIGINT] : convertBigint,
[fieldTypes.C_FLOAT] : convertFloat,
[fieldTypes.C_DOUBLE] : convertDouble,
[fieldTypes.C_BINARY] : convertBinary,
[fieldTypes.C_TIMESTAMP] : convertTimestamp,
[fieldTypes.C_NCHAR] : convertNchar
}
// Define TaosField structure
var char_arr = ArrayType(ref.types.char);
var TaosField = Struct({
'name': char_arr,
});
TaosField.fields.name.type.size = 64;
TaosField.defineProperty('bytes', ref.types.short);
TaosField.defineProperty('type', ref.types.char);
//The C interface with the Taos TSDB
function CTaosInterface (config = null, pass = false) {
ref.types.char_ptr = ref.refType(ref.types.char);
ref.types.void_ptr = ref.refType(ref.types.void);
/*Declare a bunch of functions first*/
this.libtaos = ffi.Library('libtaos', {
'taos_options': [ ref.types.int, [ ref.types.int , ref.types.void_ptr ] ],
'taos_init': [ ref.types.void, [ ] ],
//TAOS *taos_connect(char *ip, char *user, char *pass, char *db, int port)
'taos_connect': [ ref.types.void_ptr, [ ref.types.char_ptr, ref.types.char_ptr, ref.types.char_ptr, ref.types.char_ptr, ref.types.int ] ],
//void taos_close(TAOS *taos)
'taos_close': [ ref.types.void, [ ref.types.void_ptr ] ],
//TAOS_RES *taos_use_result(TAOS *taos);
'taos_use_result': [ ref.types.void_ptr, [ ref.types.void_ptr ] ],
//int taos_query(TAOS *taos, char *sqlstr)
'taos_query': [ ref.types.int, [ ref.types.void_ptr, ref.types.char_ptr ] ],
//int taos_affected_rows(TAOS *taos)
'taos_affected_rows': [ ref.types.int, [ ref.types.void_ptr] ],
//int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows)
'taos_fetch_block': [ ref.types.int, [ ref.types.void_ptr, ref.types.void_ptr] ],
//int taos_result_precision(TAOS_RES *res)
'taos_result_precision': [ ref.types.int, [ ref.types.void_ptr ] ],
//void taos_free_result(TAOS_RES *res)
'taos_free_result': [ ref.types.void, [ ref.types.void_ptr] ],
//int taos_field_count(TAOS *taos)
'taos_field_count': [ ref.types.int, [ ref.types.void_ptr ] ],
//TAOS_FIELD *taos_fetch_fields(TAOS_RES *res)
'taos_fetch_fields': [ ref.refType(TaosField), [ ref.types.void_ptr ] ],
//int taos_errno(TAOS *taos)
'taos_errno': [ ref.types.int, [ ref.types.void_ptr] ],
//char *taos_errstr(TAOS *taos)
'taos_errstr': [ ref.types.char, [ ref.types.void_ptr] ]
});
if (pass == false) {
if (config == null) {
//check this buffer
this._config = ref.alloc(ref.types.char_ptr, ref.NULL);
}
else {
try {
this._config = ref.allocCString(config);;
}
catch(err){
throw "Attribute Error: config is expected as a str";
}
}
if (config != null) {
this.libtaos.taos_options(3, this._config);
}
this.libtaos.taos_init();
}
}
CTaosInterface.prototype.config = function config() {
return this._config;
}
CTaosInterface.prototype.connect = function connect(host=null, user="root", password="taosdata", db=null, port=0) {
let _host,_user,_password,_db,_port;
try {
_host = host != null ? ref.allocCString(host) : ref.alloc(ref.types.char_ptr, ref.NULL);
}
catch(err) {
throw "Attribute Error: host is expected as a str";
}
try {
_user = ref.allocCString(user)
}
catch(err) {
throw "Attribute Error: user is expected as a str";
}
try {
_password = ref.allocCString(password);
}
catch(err) {
throw "Attribute Error: password is expected as a str";
}
try {
_db = db != null ? ref.allocCString(db) : ref.alloc(ref.types.char_ptr, ref.NULL);
}
catch(err) {
throw "Attribute Error: db is expected as a str";
}
try {
_port = ref.alloc(ref.types.int, port);
}
catch(err) {
throw TypeError("port is expected as an int")
}
let connection = this.libtaos.taos_connect(_host, _user, _password, _db, _port);
if (ref.isNull(connection)) {
throw new errors.TDError('Failed to connect to TDengine');
}
else {
console.log('Successfully connected to TDengine');
}
return connection;
}
CTaosInterface.prototype.close = function close(connection) {
this.libtaos.taos_close(connection);
console.log("Connection is closed");
}
CTaosInterface.prototype.query = function query(connection, sql) {
let res = this.libtaos.taos_query(connection, ref.allocCString(sql));
return res;
}
CTaosInterface.prototype.affectedRows = function affectedRows(connection) {
return this.libtaos.taos_affected_rows(connection);
}
CTaosInterface.prototype.useResult = function useResult(connection) {
let result = this.libtaos.taos_use_result(connection);
let fields = [];
let pfields = this.fetchFields(result);
if (ref.isNull(pfields) == false) {
let fullpfields = ref.reinterpret(pfields, this.fieldsCount(connection) * 68, 0);
for (let i = 0; i < fullpfields.length; i += 68) {
//0 - 63 = name //64 - 65 = bytes, 66 - 67 = type
fields.push( {
name: ref.readCString(ref.reinterpret(fullpfields,64,i)),
bytes: fullpfields[i + 64],
type: fullpfields[i + 66]
})
}
}
return {result:result, fields:fields}
}
CTaosInterface.prototype.fetchBlock = function fetchBlock(result, fields) {
let pblock = ref.ref(ref.ref(ref.NULL));
let num_of_rows = this.libtaos.taos_fetch_block(result, pblock)
if (num_of_rows == 0) {
return {block:null, num_of_rows:0};
}
let isMicro = (this.libtaos.taos_result_precision(result) == fieldTypes.C_TIMESTAMP_MICRO)
let blocks = new Array(fields.length);
blocks.fill(null);
num_of_rows = Math.abs(num_of_rows);
let offset = 0;
for (let i = 0; i < fields.length; i++) {
if (!convertFunctions[fields[i]['type']] ) {
throw new errors.DatabaseError("Invalid data type returned from database");
}
let data = ref.reinterpret(pblock.deref().deref(), fields[i]['bytes'], offset);
blocks[i] = convertFunctions[fields[i]['type']](pblock, num_of_rows, fields[i]['bytes'], offset, isMicro);
offset += fields[i]['bytes'] * num_of_rows;
}
return {blocks: blocks, num_of_rows:Math.abs(num_of_rows)}
}
CTaosInterface.prototype.freeResult = function freeResult(result) {
this.libtaos.taos_free_result(result);
result = null;
}
CTaosInterface.prototype.fieldsCount = function fieldsCount(connection) {
return this.libtaos.taos_field_count(connection);
}
CTaosInterface.prototype.fetchFields = function fetchFields(result) {
return this.libtaos.taos_fetch_fields(result);
}
CTaosInterface.prototype.errno = function errno(connection) {
return this.libtaos.taos_errno(connection);
}
CTaosInterface.prototype.errStr = function errStr(connection) {
return (this.libtaos.taos_errstr(connection));
}
const TDengineCursor = require('./cursor')
const CTaosInterface = require('./cinterface')
module.exports = TDengineConnection;
/*
* TDengine Connection object
* @param {Object.<string, string>} options - Options for configuring the connection with TDengine
* @return {TDengineConnection}
*
*
*/
function TDengineConnection(options) {
this._conn = null;
this._host = null;
this._user = "root"; //The default user
this._password = "taosdata"; //The default password
this._database = null;
this._port = 0;
this._config = null;
this._chandle = null;
this.config(options)
return this;
}
TDengineConnection.prototype.config = function config(options) {
if (options['host']) {
this._host = options['host'];
}
if (options['user']) {
this._user = options['user'];
}
if (options['password']) {
this._password = options['password'];
}
if (options['database']) {
this._database = options['database'];
}
if (options['port']) {
this._port = options['port'];
}
if (options['config']) {
this._config = options['config'];
}
this._chandle = new CTaosInterface(this._config);
this._conn = this._chandle.connect(this._host, this._user, this._password, this._database, this._port);
}
TDengineConnection.prototype.close = function close() {
return this._chandle.close(this._conn);
}
TDengineConnection.prototype.cursor = function cursor() {
//Pass the connection object to the cursor
return new TDengineCursor(this);
}
TDengineConnection.prototype.commit = function commit() {
return this;
}
TDengineConnection.prototype.rollback = function rollback() {
return this;
}
TDengineConnection.prototype.clear_result_set = function clear_result_set() {
var result = this._chandle.useResult(this._conn).result;
if (result) {
this._chandle.freeResult(result)
}
}
/*
* TDengine Field Types
*
*
*/
module.exports = {
// Type Code
C_NULL : 0,
C_BOOL : 1,
C_TINYINT : 2,
C_SMALLINT : 3,
C_INT : 4,
C_BIGINT : 5,
C_FLOAT : 6,
C_DOUBLE : 7,
C_BINARY : 8,
C_TIMESTAMP : 9,
C_NCHAR : 10,
// NULL value definition
// NOTE: These values should change according to C definition in tsdb.h
C_BOOL_NULL : 0x02,
C_TINYINT_NULL : -128,
C_SMALLINT_NULL : -32768,
C_INT_NULL : -2147483648,
C_BIGINT_NULL : -9223372036854775808,
C_TIMESTAMP_MILLI : 0,
C_TIMESTAMP_MICRO : 1,
}
const CTaosInterface = require('./cinterface')
const errors = require ('./error')
module.exports = TDengineCursor;
function TDengineCursor(connection=null) {
this._description = null;
this._rowcount = -1;
this._connection = null;
this._result = null;
this._fields = null;
this.data = null;
this.fieldNames = null;
this.chandle = new CTaosInterface(null, true); //pass through, just need library loaded.
if (connection != null) {
this._connection = connection
}
}
TDengineCursor.prototype.description = function description() {
return this._description;
}
TDengineCursor.prototype.rowcount = function rowcount() {
return this._rowcount;
}
TDengineCursor.prototype.callproc = function callproc() {
return;
}
TDengineCursor.prototype.close = function close() {
if (this._connection == null) {
return false;
}
this._connection.clear_result_set();
this._reset_result();
this._connection = null;
return true;
}
TDengineCursor.prototype.execute = function execute(operation, params=null) {
if (operation == undefined) {
return null;
}
if (this._connection == null) {
throw new errors.ProgrammingError('Cursor is not connected');
}
this._connection.clear_result_set();
this._reset_result();
let stmt = operation;
if (params != null) {
//why pass?
}
res = this.chandle.query(this._connection._conn, stmt);
if (res == 0) {
let fieldCount = this.chandle.fieldsCount(this._connection._conn);
if (fieldCount == 0) {
return this.chandle.affectedRows(this._connection._conn); //return num of affected rows, common with insert, use statements
}
else {
let resAndField = this.chandle.useResult(this._connection._conn, fieldCount)
this._result = resAndField.result;
this._fields = resAndField.fields;
this.fieldNames = resAndField.fields.map(fieldData => fieldData.name);
return this._handle_result(); //return a pointer
}
}
else {
throw new errors.ProgrammingError(this.chandle.errStr(this._connection._conn))
}
}
TDengineCursor.prototype.executemany = function executemany() {
}
TDengineCursor.prototype.fetchone = function fetchone() {
}
TDengineCursor.prototype.fetchmany = function fetchmany() {
}
TDengineCursor.prototype.fetchall = function fetchall() {
if (this._result == null || this._fields == null) {
throw new errors.OperationalError("Invalid use of fetchall, either result or fields from query are null");
}
let data = [];
this._rowcount = 0;
let k = 0;
while(true) {
k+=1;
let blockAndRows = this.chandle.fetchBlock(this._result, this._fields);
let block = blockAndRows.blocks;
let num_of_rows = blockAndRows.num_of_rows;
if (num_of_rows == 0) {
break;
}
this._rowcount += num_of_rows;
for (let i = 0; i < num_of_rows; i++) {
data.push([]);
for (let j = 0; j < this._fields.length; j++) {
data[data.length-1].push(block[j][i]);
}
}
}
this._connection.clear_result_set();
this.data = data;
return data; //data[i] returns the ith row, with all the data
}
TDengineCursor.prototype.nextset = function nextset() {
return;
}
TDengineCursor.prototype.setinputsize = function setinputsize() {
return;
}
TDengineCursor.prototype.setoutputsize = function setoutputsize(size, column=null) {
return;
}
TDengineCursor.prototype._reset_result = function _reset_result() {
this._description = null;
this._rowcount = -1;
this._result = null;
this._fields = null;
this.data = null;
this.fieldNames = null;
}
TDengineCursor.prototype._handle_result = function _handle_result() {
this._description = [];
for (let field of this._fields) {
this._description.push([field.name, field.type, null, null, null, null, false]);
}
return this._result;
}
/*
Classes for exceptions
Note: All exceptions thrown by Node.js or the JavaScript runtime will be instances of Error.
https://nodejs.org/api/errors.html#errors_exceptions_vs_errors
*/
class TDError extends Error {
constructor(args) {
super(args)
this.name = "TDError";
}
}
class Warning extends Error {
// Exception raised for important warnings like data truncations while inserting.
constructor(args) {
super(args)
this.name = "Warning";
}
}
class InterfaceError extends TDError {
// Exception raised for errors that are related to the database interface rather than the database itself.
constructor(args) {
super(args)
this.name = "TDError.InterfaceError";
}
}
class DatabaseError extends TDError {
// Exception raised for errors that are related to the database.
constructor(args) {
super(args)
this.name = "TDError.DatabaseError";
}
}
class DataError extends DatabaseError {
// Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range.
constructor(args) {
super(args)
this.name = "TDError.DatabaseError.DataError";
}
}
class OperationalError extends DatabaseError {
// Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer
constructor(args) {
super(args)
this.name = "TDError.DatabaseError.OperationalError";
}
}
class IntegrityError extends DatabaseError {
// Exception raised when the relational integrity of the database is affected.
constructor(args) {
super(args)
this.name = "TDError.DatabaseError.IntegrityError";
}
}
class InternalError extends DatabaseError {
// Exception raised when the database encounters an internal error.
constructor(args) {
super(args)
this.name = "TDError.DatabaseError.InternalError";
}
}
class ProgrammingError extends DatabaseError {
// Exception raised for programming errors.
constructor(args) {
super(args)
this.name = "TDError.DatabaseError.ProgrammingError";
}
}
class NotSupportedError extends DatabaseError {
// Exception raised in case a method or database API was used which is not supported by the database.
constructor(args) {
super(args)
this.name = "TDError.DatabaseError.NotSupportedError";
}
}
module.exports = {
TDError, Warning, InterfaceError, DatabaseError, DataError, OperationalError, IntegrityError, InternalError, ProgrammingError, NotSupportedError
};
此差异已折叠。
{
"name": "td-connector",
"version": "1.0.5",
"description": "A Node.js connector for TDengine.",
"main": "tdengine.js",
"scripts": {
"test": "node test/test.js"
},
"keywords": [
"TDengine",
"TAOS Data",
"Time Series Database",
"Connector"
],
"author": "StoneT2000",
"license": "AGPL-3.0",
"dependencies": {
"ffi": "^2.3.0",
"node-gyp": "^5.0.2",
"ref": "^1.3.5",
"ref-array": "^1.2.0"
},
"homepage": "https://github.com/taosdata/tdengine",
"bugs": {
"url": "https://github.com/taosdata/tdengine/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/taosdata/tdengine.git"
}
}
# TDengine Node.js connector
This is the Node.js library that lets you connect to [TDengine](https://www.github.com/taosdata/tdengine).
## Installation
To get started, just type in the following to install the connector through [npm](https://www.npmjs.com/)
```cmd
npm install td-connector
```
To interact with TDengine, we make use of the [node-gyp[(https://github.com/nodejs/node-gyp)] library. To install, you will need to install the following depending on platform (the following instructions are quoted from node-gyp)
### On Unix
- `python` (`v2.7` recommended, `v3.x.x` is **not** supported)
- `make`
- A proper C/C++ compiler toolchain, like [GCC](https://gcc.gnu.org)
### On macOS
- `python` (`v2.7` recommended, `v3.x.x` is **not** supported) (already installed on macOS)
- Xcode
- You also need to install the
```
Command Line Tools
```
via Xcode. You can find this under the menu
```
Xcode -> Preferences -> Locations
```
(or by running
```
xcode-select --install
```
in your Terminal)
- This step will install `gcc` and the related toolchain containing `make`
### On Windows
#### Option 1
Install all the required tools and configurations using Microsoft's [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) using `npm install --global --production windows-build-tools` from an elevated PowerShell or CMD.exe (run as Administrator).
#### Option 2
Install tools and configuration manually:
- Install Visual C++ Build Environment: [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools) (using "Visual C++ build tools" workload) or [Visual Studio 2017 Community](https://visualstudio.microsoft.com/pl/thank-you-downloading-visual-studio/?sku=Community) (using the "Desktop development with C++" workload)
- Install [Python 2.7](https://www.python.org/downloads/) (`v3.x.x` is not supported), and run `npm config set python python2.7` (or see below for further instructions on specifying the proper Python version and path.)
- Launch cmd, `npm config set msvs_version 2017`
If the above steps didn't work for you, please visit [Microsoft's Node.js Guidelines for Windows](https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md#compiling-native-addon-modules) for additional tips.
To target native ARM64 Node.js on Windows 10 on ARM, add the components "Visual C++ compilers and libraries for ARM64" and "Visual C++ ATL for ARM64".
## Usage
To use the connector, first request the library ```td-connector```. Running the function ```taos.connect``` with the connection options passed in as an object will return a TDengine connection object. A cursor needs to be intialized in order to interact with TDengine from node.
```javascript
const taos = require('td-connector');
var conn = taos.connect({host:"127.0.0.1", user:"root", password:"taosdata", config:"/etc/taos",port:0})
var c1 = conn.cursor(); // Initializing a new cursor
```
We can now start executing queries through the ```cursor.execute``` function.
```javascript
c1.execute('show databases;')
```
We can get the results of the queries by doing the following
```javascript
var data = c1.fetchall();
console.log(c1.fieldNames); // Returns the names of the columns/fields
console.log(data); // Logs all the data from the query as an array of arrays, each of which represents a row and data[row_number] is sorted in order of the fields
```
## Example
The following is an example use of the connector showing how to make a table with weather data, insert random data, and then retrieve it.
```javascript
// Get the td-connector package
const taos = require('td-connector');
/* We will connect to TDengine by passing an object comprised of connection options to taos.connect and store the
* connection to the variable conn
*/
/*
* Connection Options
* host: the host to connect to
* user: the use to login as
* password: the password for the above user to login
* config: the location of the taos.cfg file, by default it is in /etc/taos
* port: the port we connect through
*/
var conn = taos.connect({host:"127.0.0.1", user:"root", password:"taosdata", config:"/etc/taos",port:0});
// Initialize our TDengineCursor, which we use to interact with TDengine
var c1 = conn.cursor();
// c1.execute(query) will execute the query
// Let's create a database named db
try {
c1.execute('create database db;');
}
catch(err) {
conn.close();
throw err;
}
// Now we will use database db
try {
c1.execute('use db;');
}
catch (err) {
conn.close();
throw err;
}
// Let's create a table called weather
// which stores some weather data like humidity, AQI (air quality index), temperature, and some notes as text
try {
c1.execute('create table if not exists weather (ts timestamp, humidity smallint, aqi int, temperature float, notes binary(30));');
}
catch (err) {
conn.close();
throw err;
}
// Let's get the description of the table weather
try {
c1.execute('describe db.weather');
}
catch (err) {
conn.close();
throw err;
}
// To get results, we run the function c1.fetchall()
// It only returns the query results as an array of result rows, but also stores the latest results in c1.data
try {
var tableDesc = c1.fetchall(); // The description variable here is equal to c1.data;
console.log(tableDesc);
}
catch (err) {
conn.close();
throw err;
}
// Let's try to insert some random generated data to test with
let stime = new Date();
let interval = 1000;
// Timestamps must be in the form of "YYYY-MM-DD HH:MM:SS.MMM" if they are in milliseconds
// "YYYY-MM-DD HH:MM:SS.MMMMMM" if they are in microseconds
// Thus, we create the following function to convert a javascript Date object to the correct formatting
function convertDateToTS(date) {
let tsArr = date.toISOString().split("T")
return "\"" + tsArr[0] + " " + tsArr[1].substring(0, tsArr[1].length-1) + "\"";
}
try {
for (let i = 0; i < 10000; i++) {
stime.setMilliseconds(stime.getMilliseconds() + interval);
let insertData = [convertDateToTS(stime),
parseInt(Math.random()*100),
parseInt(Math.random()*300),
parseFloat(Math.random()*10 + 30),
"\"random note!\""];
c1.execute('insert into db.weather values(' + insertData.join(',') + ' );');
}
}
catch (err) {
conn.close();
throw err;
}
// Now let's look at our newly inserted data
var retrievedData;
try {
c1.execute('select * from db.weather;')
retrievedData = c1.fetchall();
// c1.fieldNames stores the names of each column retrieved
console.log(c1.fieldNames);
console.log(retrievedData);
// timestamps retrieved are always JS Date Objects
// Numbers are numbers, big ints are big ints, and strings are strings
}
catch (err) {
conn.close();
throw err;
}
// Let's try running some basic functions
try {
c1.execute('select count(*), avg(temperature), max(temperature), min(temperature), stddev(temperature) from db.weather;')
c1.fetchall();
console.log(c1.fieldNames);
console.log(c1.data);
}
catch(err) {
conn.close();
throw err;
}
conn.close();
// Feel free to fork this repository or copy this code and start developing your own apps and backends with NodeJS and TDengine!
```
## Contributing to TDengine
Please follow the [contribution guidelines](https://github.com/taosdata/TDengine/blob/master/CONTRIBUTING.md) to contribute to the project.
## License
[GNU AGPL v3.0](http://www.gnu.org/licenses/agpl-3.0.html)
\ No newline at end of file
var TDengineConnection = require('./nodetaos/connection.js')
module.exports.connect = function (connection=null) {
return new TDengineConnection(connection);
}
const taos = require('td-connector');
var conn = taos.connect({host:"127.0.0.1", user:"root", password:"taosdata", config:"/etc/taos",port:0});
var c1 = conn.cursor();
let stime = new Date();
let interval = 1000;
// Timestamps must be in the form of "YYYY-MM-DD HH:MM:SS.MMM" if they are in milliseconds
// "YYYY-MM-DD HH:MM:SS.MMMMMM" if they are in microseconds
// Thus, we create the following function to convert a javascript Date object to the correct formatting
function convertDateToTS(date) {
let tsArr = date.toISOString().split("T")
return "\"" + tsArr[0] + " " + tsArr[1].substring(0, tsArr[1].length-1) + "\"";
}
function R(l,r) {
return Math.random() * (r - l) - r;
}
function randomBool() {
if (Math.random() < 0.5) {
return true;
}
return false;
}
c1.execute('create database td_connector_test;');
c1.execute('use td_connector_test;')
c1.execute('create table if not exists all_types (ts timestamp, _int int, _bigint bigint, _float float, _double double, _binary binary(40), _smallint smallint, _tinyint tinyint, _bool bool, _nchar nchar(40));');
for (let i = 0; i < 10000; i++) {
stime.setMilliseconds(stime.getMilliseconds() + interval);
let insertData = [convertDateToTS(stime), // Timestamp
parseInt( R(-Math.pow(2,31) + 1 , Math.pow(2,31) - 1) ), // Int
parseInt( R(-Math.pow(2,31) + 1 , Math.pow(2,31) - 1) ), // BigInt
parseFloat( R(-3.4E38, 3.4E38) ), // Float
parseFloat( R(-1.7E308, 1.7E308) ), // Double
"\"Long Binary\"", // Binary
parseInt( R(-32767, 32767) ), // Small Int
parseInt( R(-127, 127) ), // Tiny Int
randomBool(),
"\"Nchars 一些中文字幕\""]; // Bool
c1.execute('insert into td_connector_test.all_types values(' + insertData.join(',') + ' );');
}
c1.execute('select * from td_connector_test.all_types limit 10 offset 1000;');
var d = c1.fetchall();
console.log(c1.fieldNames);
console.log(d);
c1.execute('select count(*), avg(_int), sum(_float), max(_bigint), min(_double) from td_connector_test.all_types;');
var d = c1.fetchall();
console.log(c1.fieldNames);
console.log(d);
c1.execute('drop database td_connector_test;')
conn.close();
// Get the td-connector package
const taos = require('td-connector');
/* We will connect to TDengine by passing an object comprised of connection options to taos.connect and store the
* connection to the variable conn
*/
/*
* Connection Options
* host: the host to connect to
* user: the use to login as
* password: the password for the above user to login
* config: the location of the taos.cfg file, by default it is in /etc/taos
* port: the port we connect through
*/
var conn = taos.connect({host:"127.0.0.1", user:"root", password:"taosdata", config:"/etc/taos",port:0});
// Initialize our TDengineCursor, which we use to interact with TDengine
var c1 = conn.cursor();
// c1.execute(query) will execute the query
// Let's create a database named db
try {
c1.execute('create database db;');
}
catch(err) {
conn.close();
throw err;
}
// Now we will use database db
try {
c1.execute('use db;');
}
catch (err) {
conn.close();
throw err;
}
// Let's create a table called weather
// which stores some weather data like humidity, AQI (air quality index), temperature, and some notes as text
try {
c1.execute('create table if not exists weather (ts timestamp, humidity smallint, aqi int, temperature float, notes binary(30));');
}
catch (err) {
conn.close();
throw err;
}
// Let's get the description of the table weather
try {
c1.execute('describe db.weather');
}
catch (err) {
conn.close();
throw err;
}
// To get results, we run the function c1.fetchall()
// It only returns the query results as an array of result rows, but also stores the latest results in c1.data
try {
var tableDesc = c1.fetchall(); // The description variable here is equal to c1.data;
console.log(tableDesc);
}
catch (err) {
conn.close();
throw err;
}
// Let's try to insert some random generated data to test with
let stime = new Date();
let interval = 1000;
// Timestamps must be in the form of "YYYY-MM-DD HH:MM:SS.MMM" if they are in milliseconds
// "YYYY-MM-DD HH:MM:SS.MMMMMM" if they are in microseconds
// Thus, we create the following function to convert a javascript Date object to the correct formatting
function convertDateToTS(date) {
let tsArr = date.toISOString().split("T")
return "\"" + tsArr[0] + " " + tsArr[1].substring(0, tsArr[1].length-1) + "\"";
}
try {
for (let i = 0; i < 10000; i++) {
stime.setMilliseconds(stime.getMilliseconds() + interval);
let insertData = [convertDateToTS(stime),
parseInt(Math.random()*100),
parseInt(Math.random()*300),
parseFloat(Math.random()*10 + 30),
"\"random note!\""];
c1.execute('insert into db.weather values(' + insertData.join(',') + ' );');
}
}
catch (err) {
conn.close();
throw err;
}
// Now let's look at our newly inserted data
var retrievedData;
try {
c1.execute('select * from db.weather;')
retrievedData = c1.fetchall();
// c1.fieldNames stores the names of each column retrieved
console.log(c1.fieldNames);
console.log(retrievedData);
// timestamps retrieved are always JS Date Objects
// Numbers are numbers, big ints are big ints, and strings are strings
}
catch (err) {
conn.close();
throw err;
}
// Let's try running some basic functions
try {
c1.execute('select count(*), avg(temperature), max(temperature), min(temperature), stddev(temperature) from db.weather;')
c1.fetchall();
console.log(c1.fieldNames);
console.log(c1.data);
}
catch(err) {
conn.close();
throw err;
}
conn.close();
// Feel free to fork this repository or copy this code and start developing your own apps and backends with NodeJS and TDengine!
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册