diff --git a/src/connector/nodejs/nodetaos/cinterface.js b/src/connector/nodejs/nodetaos/cinterface.js index 2403ffa4c68ca9571f2ec583fa263765208bfb2b..ae75038615e0ac46e47d52c3f68160c46b159be5 100644 --- a/src/connector/nodejs/nodetaos/cinterface.js +++ b/src/connector/nodejs/nodetaos/cinterface.js @@ -6,8 +6,8 @@ const ref = require('ref-napi'); const os = require('os'); const ffi = require('ffi-napi'); -const ArrayType = require('ref-array-napi'); -const Struct = require('ref-struct-napi'); +const ArrayType = require('ref-array-di')(ref); +const Struct = require('ref-struct-di')(ref); const FieldTypes = require('./constants'); const errors = require('./error'); const _ = require('lodash') @@ -20,6 +20,7 @@ const TAOSFIELD = { BYTES_OFFSET: 66, STRUCT_SIZE: 68, } + function convertTimestamp(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -31,6 +32,7 @@ function convertTimestamp(data, num_of_rows, nbytes = 0, offset = 0, precision = } return res; } + function convertBool(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = new Array(data.length); @@ -47,6 +49,7 @@ function convertBool(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { } return res; } + function convertTinyint(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -58,6 +61,7 @@ function convertTinyint(data, num_of_rows, nbytes = 0, offset = 0, precision = 0 } return res; } + function convertTinyintUnsigned(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -81,6 +85,7 @@ function convertSmallint(data, num_of_rows, nbytes = 0, offset = 0, precision = } return res; } + function convertSmallintUnsigned(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -104,6 +109,7 @@ function convertInt(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { } return res; } + function convertIntUnsigned(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -116,7 +122,6 @@ function convertIntUnsigned(data, num_of_rows, nbytes = 0, offset = 0, precision return res; } - function convertBigint(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -128,6 +133,7 @@ function convertBigint(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) } return res; } + function convertBigintUnsigned(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -140,7 +146,6 @@ function convertBigintUnsigned(data, num_of_rows, nbytes = 0, offset = 0, precis return res; } - function convertFloat(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -152,6 +157,7 @@ function convertFloat(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) } return res; } + function convertDouble(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) { data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset); let res = []; @@ -329,7 +335,7 @@ function CTaosInterface(config = null, pass = false) { //void taos_close_stream(TAOS_STREAM *tstr); 'taos_close_stream': [ref.types.void, [ref.types.void_ptr]], - //Schemaless insert + //Schemaless insert //TAOS_RES* taos_schemaless_insert(TAOS* taos, char* lines[], int numLines, int protocol,int precision) // 'taos_schemaless_insert': [ref.types.void_ptr, [ref.types.void_ptr, ref.types.char_ptr, ref.types.int, ref.types.int, ref.types.int]] 'taos_schemaless_insert': [ref.types.void_ptr, [ref.types.void_ptr, smlLine, 'int', 'int', 'int']] @@ -355,9 +361,11 @@ function CTaosInterface(config = null, pass = false) { } return this; } + 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 { @@ -399,10 +407,12 @@ CTaosInterface.prototype.connect = function connect(host = null, user = "root", } 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) { return this.libtaos.taos_query(connection, ref.allocCString(sql)); } @@ -410,6 +420,7 @@ CTaosInterface.prototype.query = function query(connection, sql) { CTaosInterface.prototype.affectedRows = function affectedRows(result) { return this.libtaos.taos_affected_rows(result); } + CTaosInterface.prototype.useResult = function useResult(result) { let fields = []; @@ -427,6 +438,7 @@ CTaosInterface.prototype.useResult = function useResult(result) { } return fields; } + CTaosInterface.prototype.fetchBlock = function fetchBlock(result, fields) { let pblock = ref.NULL_POINTER; let num_of_rows = this.libtaos.taos_fetch_block(result, pblock); @@ -467,31 +479,39 @@ CTaosInterface.prototype.fetchBlock = function fetchBlock(result, fields) { } return { blocks: blocks, num_of_rows } } + CTaosInterface.prototype.fetchRow = function fetchRow(result, fields) { let row = this.libtaos.taos_fetch_row(result); return row; } + CTaosInterface.prototype.freeResult = function freeResult(result) { this.libtaos.taos_free_result(result); result = null; } + /** Number of fields returned in this result handle, must use with async */ CTaosInterface.prototype.numFields = function numFields(result) { return this.libtaos.taos_num_fields(result); } + // Fetch fields count by connection, the latest query CTaosInterface.prototype.fieldsCount = function fieldsCount(result) { return this.libtaos.taos_field_count(result); } + CTaosInterface.prototype.fetchFields = function fetchFields(result) { return this.libtaos.taos_fetch_fields(result); } + CTaosInterface.prototype.errno = function errno(result) { return this.libtaos.taos_errno(result); } + CTaosInterface.prototype.errStr = function errStr(result) { return ref.readCString(this.libtaos.taos_errstr(result)); } + // Async CTaosInterface.prototype.query_a = function query_a(connection, sql, callback, param = ref.ref(ref.NULL)) { // void taos_query_a(TAOS *taos, char *sqlstr, void (*fp)(void *param, TAOS_RES *, int), void *param) @@ -550,6 +570,7 @@ CTaosInterface.prototype.fetch_rows_a = function fetch_rows_a(result, callback, this.libtaos.taos_fetch_rows_a(result, asyncCallbackWrapper, param); return param; } + // Fetch field meta data by result handle CTaosInterface.prototype.fetchFields_a = function fetchFields_a(result) { let pfields = this.fetchFields(result); @@ -567,6 +588,7 @@ CTaosInterface.prototype.fetchFields_a = function fetchFields_a(result) { } return fields; } + // Stop a query by result handle CTaosInterface.prototype.stopQuery = function stopQuery(result) { if (result != null) { @@ -576,9 +598,11 @@ CTaosInterface.prototype.stopQuery = function stopQuery(result) { throw new errors.ProgrammingError("No result handle passed to stop query"); } } + CTaosInterface.prototype.getServerInfo = function getServerInfo(connection) { return ref.readCString(this.libtaos.taos_get_server_info(connection)); } + CTaosInterface.prototype.getClientInfo = function getClientInfo() { return ref.readCString(this.libtaos.taos_get_client_info()); } @@ -644,6 +668,7 @@ CTaosInterface.prototype.consume = function consume(subscription) { } return { data: data, fields: fields, result: result }; } + CTaosInterface.prototype.unsubscribe = function unsubscribe(subscription) { //void taos_unsubscribe(TAOS_SUB *tsub); this.libtaos.taos_unsubscribe(subscription); @@ -688,23 +713,25 @@ CTaosInterface.prototype.openStream = function openStream(connection, sql, callb return streamHandle; } } + CTaosInterface.prototype.closeStream = function closeStream(stream) { this.libtaos.taos_close_stream(stream); console.log("Closed stream"); } -//Schemaless insert API + +//Schemaless insert API /** * TAOS* taos, char* lines[], int numLines, int protocol,int precision) - * using taos_errstr get error info, taos_errno get error code. Remmember - * to release taos_res, otherwile will lead memory leak. + * using taos_errstr get error info, taos_errno get error code. Remember + * to release taos_res, otherwise will lead memory leak. * TAOS schemaless insert api * @param {*} connection a valid database connection - * @param {*} lines string data, which statisfied with line proctocol + * @param {*} lines string data, which satisfied with line protocol * @param {*} numLines number of rows in param lines. - * @param {*} protocal Line protocol, enum type (0,1,2,3),indicate different line protocol + * @param {*} protocol Line protocol, enum type (0,1,2,3),indicate different line protocol * @param {*} precision timestamp precision in lines, enum type (0,1,2,3,4,5,6) - * @returns TAOS_RES - * + * @returns TAOS_RES + * */ CTaosInterface.prototype.schemalessInsert = function schemalessInsert(connection, lines, protocal, precision) { let _numLines = null; diff --git a/src/connector/nodejs/package.json b/src/connector/nodejs/package.json index 481d113a9edfb790e109a3fb5e50101868722494..398ed59522ae9c31a26ee7db73dca5b02b517c9e 100644 --- a/src/connector/nodejs/package.json +++ b/src/connector/nodejs/package.json @@ -4,6 +4,7 @@ "description": "A Node.js connector for TDengine.", "main": "tdengine.js", "directories": { + "example": "examples", "test": "test" }, "scripts": { @@ -29,9 +30,9 @@ "dependencies": { "ffi-napi": "^3.1.0", "lodash": "^4.17.21", - "ref-array-napi": "^1.2.1", - "ref-napi": "^1.5.2", - "ref-struct-napi": "^1.1.1" + "ref-array-di": "^1.2.1", + "ref-napi": "^3.0.2", + "ref-struct-di": "^1.1.1" }, "devDependencies": { "jest": "^27.4.7" diff --git a/src/connector/nodejs/readme.md b/src/connector/nodejs/readme.md index 26a28afbdd514ad97e969302e7d790f6240bb770..0077c557f15806e66bb9ed0685c75f2e61382442 100644 --- a/src/connector/nodejs/readme.md +++ b/src/connector/nodejs/readme.md @@ -1,4 +1,5 @@ # TDengine Node.js connector + [![minzip](https://img.shields.io/bundlephobia/minzip/td2.0-connector.svg)](https://github.com/taosdata/TDengine/tree/master/src/connector/nodejs) [![NPM](https://img.shields.io/npm/l/td2.0-connector.svg)](https://github.com/taosdata/TDengine/#what-is-tdengine) This is the Node.js library that lets you connect to [TDengine](https://www.github.com/taosdata/tdengine) 2.0 version. It is built so that you can use as much of it as you want or as little of it as you want through providing an extensive API. If you want the raw data in the form of an array of arrays for the row data retrieved from a table, you can do that. If you want to wrap that data with objects that allow you easily manipulate and display data such as using a prettifier function, you can do that! @@ -106,6 +107,7 @@ promise.then(function(result) { ``` You can also query by binding parameters to a query by filling in the question marks in a string as so. The query will automatically parse what was binded and convert it to the proper format for use with TDengine + ```javascript var query = cursor.query('select * from meterinfo.meters where ts <= ? and areaid = ?;').bind(new Date(), 5); query.execute().then(function(result) { @@ -114,6 +116,7 @@ query.execute().then(function(result) { ``` The TaosQuery object can also be immediately executed upon creation by passing true as the second argument, returning a promise instead of a TaosQuery. + ```javascript var promise = cursor.query('select * from meterinfo.meters where v1 = 30;', true) promise.then(function(result) { @@ -121,7 +124,8 @@ promise.then(function(result) { }) ``` -If you want to execute queries without objects being wrapped around the data, use ```cursor.execute()``` directly and ```cursor.fetchall()``` to retrieve data if there is any. +If you want to execute queries without objects being wrapped around the data, use `cursor.execute()` directly and `cursor.fetchall()` to retrieve data if there is any. + ```javascript cursor.execute('select count(*), avg(v1), min(v2) from meterinfo.meters where ts >= \"2019-07-20 00:00:00.000\";'); var data = cursor.fetchall(); diff --git a/tests/examples/nodejs/nodejsChecker.js b/tests/examples/nodejs/nodejsChecker.js index e634a54ea1c56310bae7d38188590a0d7862f953..1b391e55a07b1e86a9c7dc92f6bfba23b147c822 100644 --- a/tests/examples/nodejs/nodejsChecker.js +++ b/tests/examples/nodejs/nodejsChecker.js @@ -1,29 +1,29 @@ -const taos = require('td2.0-connector'); -//const taos = require('../../../src/connector/nodejs/'); +//const taos = require('td2.0-connector'); +const taos = require('../../../src/connector/nodejs/'); var host = null; var port = 6030; for(var i = 2; i < global.process.argv.length; i++){ - var key = global.process.argv[i].split("=")[0]; - var value = global.process.argv[i].split("=")[1]; - - if("host" == key){ - host = value; - } - if("port" == key){ - port = value; - } + var key = global.process.argv[i].split("=")[0]; + var value = global.process.argv[i].split("=")[1]; + + if("host" == key){ + host = value; + } + if("port" == key){ + port = value; + } } if(host == null){ - console.log("Usage: node nodejsChecker.js host= port="); - process.exit(0); + console.log("Usage: node nodejsChecker.js host= port="); + process.exit(0); } // establish connection var conn = taos.connect({host:host, user:"root", password:"taosdata",port:port}); -var cursor = conn.cursor(); +var cursor = conn.cursor(); // create database executeSql("create database if not exists test", 0); // use db @@ -40,22 +40,22 @@ executeQuery("select * from test.weather"); conn.close(); function executeQuery(sql){ - var start = new Date().getTime(); - var promise = cursor.query(sql, true); - var end = new Date().getTime(); - promise.then(function(result){ - printSql(sql, result != null,(end - start)); - result.pretty(); - }); + var start = new Date().getTime(); + var promise = cursor.query(sql, true); + var end = new Date().getTime(); + promise.then(function(result){ + printSql(sql, result != null,(end - start)); + result.pretty(); + }); } function executeSql(sql, affectRows){ - var start = new Date().getTime(); - var promise = cursor.execute(sql); - var end = new Date().getTime(); - printSql(sql, promise == affectRows, (end - start)); + var start = new Date().getTime(); + var promise = cursor.execute(sql); + var end = new Date().getTime(); + printSql(sql, promise == affectRows, (end - start)); } function printSql(sql, succeed, cost){ - console.log("[ "+(succeed ? "OK" : "ERROR!")+" ] time cost: " + cost + " ms, execute statement ====> " + sql); + console.log("[ "+(succeed ? "OK" : "ERROR!")+" ] time cost: " + cost + " ms, execute statement ====> " + sql); }