From 1cb6f4c8092774b467fdf556217b2443669f1bc5 Mon Sep 17 00:00:00 2001 From: Shuduo Sang Date: Tue, 8 Feb 2022 12:08:59 +0800 Subject: [PATCH] [TD2769]: nodejs 17 to support taos connector (#10107) --- src/connector/nodejs/nodetaos/cinterface.js | 51 +++++++++++++++----- src/connector/nodejs/package.json | 7 +-- src/connector/nodejs/readme.md | 6 ++- tests/examples/nodejs/nodejsChecker.js | 52 ++++++++++----------- 4 files changed, 74 insertions(+), 42 deletions(-) diff --git a/src/connector/nodejs/nodetaos/cinterface.js b/src/connector/nodejs/nodetaos/cinterface.js index 2403ffa4c6..ae75038615 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 481d113a9e..398ed59522 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 26a28afbdd..0077c557f1 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 e634a54ea1..1b391e55a0 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); } -- GitLab