diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ac1f27cd..6809386c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -4,91 +4,87 @@ name: nodejs Release on: push: - branches: ['main'] + branches: ["main"] pull_request: - branches: ['main'] + branches: ["main"] jobs: build: - runs-on: ubuntu-22.04 strategy: matrix: - node-version: [16.x,20.x] + node-version: [16.x, 20.x] steps: + - name: Build Tools + run: | + sudo apt-get update + sudo apt-get install -y build-essential cmake + sudo apt-get install -y python3 python3-pip python-is-python3 - - name: Build Tools - run: | - sudo apt-get update - sudo apt-get install -y build-essential cmake - sudo apt-get install -y python3 python3-pip python-is-python3 - - - name: Checkout TDengine - uses: actions/checkout@v4 - with: + - name: Checkout TDengine + uses: actions/checkout@v4 + with: fetch-depth: 1 - repository: 'taosdata/TDengine' - path: 'TDengine' - ref: 'main' - submodules: 'recursive' - - - name: Install system dependencies - run: | - sudo apt update -y - sudo apt install -y build-essential cmake \ - libgeos-dev libjansson-dev libsnappy-dev liblzma-dev libz-dev \ - zlib1g pkg-config libssl-dev gawk - - - name: install TDengine - run: | - cd TDengine - mkdir debug - cd debug - cmake .. -DBUILD_HTTP=false -DBUILD_JDBC=false -DBUILD_TOOLS=false -DBUILD_TEST=off -DBUILD_DEPENDENCY_TESTS=false - make -j 4 - sudo make install - which taosd - which taosadapter - - - name: start taosd - run: | - nohup sudo taosd & + repository: "taosdata/TDengine" + path: "TDengine" + ref: "main" + submodules: "recursive" + + - name: Install system dependencies + run: | + sudo apt update -y + sudo apt install -y build-essential cmake \ + libgeos-dev libjansson-dev libsnappy-dev liblzma-dev libz-dev \ + zlib1g pkg-config libssl-dev gawk + + - name: install TDengine + run: | + cd TDengine + mkdir debug + cd debug + cmake .. -DBUILD_HTTP=false -DBUILD_JDBC=false -DBUILD_TOOLS=false -DBUILD_TEST=off -DBUILD_DEPENDENCY_TESTS=false + make -j 4 + sudo make install + which taosd + which taosadapter - - name: start taosadapter - run: | - nohup sudo taosadapter & + - name: start taosd + run: | + nohup sudo taosd & - - name: Checkout current repo - uses: actions/checkout@v4 - with: - path: 'nodejs-connector' - clean: true - set-safe-directory: true + - name: start taosadapter + run: | + nohup sudo taosadapter & + - name: Checkout current repo + uses: actions/checkout@v4 + with: + path: "nodejs-connector" + clean: true + set-safe-directory: true + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} + - name: test nodejs websocket + working-directory: nodejs-connector/nodejs + run: | + export TDENGINE_CLOUD_URL=${{ secrets.TDENGINE_CLOUD_URL }} + export TDENGINE_CLOUD_TOKEN=${{ secrets.TDENGINE_CLOUD_TOKEN }} + ls -al + npm install + npm list + npm run example + npm run test - - name: test nodejs websocket - working-directory: nodejs-connector/nodejs - run: | - export TDENGINE_CLOUD_URL=${{ secrets.TDENGINE_CLOUD_URL }} - export TDENGINE_CLOUD_TOKEN=${{ secrets.TDENGINE_CLOUD_TOKEN }} - ls -al - npm install - npm list - npm run example - npm run test - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - fail_ci_if_error: false - files: coverage/lcov.info - verbose: true - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + fail_ci_if_error: false + files: coverage/lcov.info + verbose: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/README-CN.md b/README-CN.md index d353e6ab..70b0a327 100644 --- a/README-CN.md +++ b/README-CN.md @@ -13,10 +13,8 @@ [![LinkedIn](https://img.shields.io/badge/Follow_LinkedIn--white?logo=linkedin&style=social)](https://www.linkedin.com/company/tdengine) [![StackOverflow](https://img.shields.io/badge/Ask_StackOverflow--white?logo=stackoverflow&style=social&logoColor=orange)](https://stackoverflow.com/questions/tagged/tdengine) - [English](README.md) | 简体中文 - ## 目录 @@ -35,7 +33,6 @@ - [9. 引用](#9-引用) - [10. 许可证](#10-许可证) - ## 1. 简介 @tdengine/websocket 是 TDengine 官方专为 Node.js 开发人员精心设计的一款高效连接器,它借助 taosAdapter 组件提供的 WebSocket API 与 TDengine 建立连接,摆脱了对 TDengine 客户端驱动的依赖 ,为开发者开辟了一条便捷的开发路径。凭借这一强大工具,开发人员能够轻松构建面向 TDengine 集群的应用程序。不管是执行复杂的 SQL 写入与查询任务,还是实现灵活的无模式写入操作,亦或是达成对实时性要求极高的订阅功能,这款连接器都能轻松胜任、完美实现,全方位满足多样化的数据交互需求。 @@ -44,13 +41,13 @@ - 使用 Node.js Connector, 请参考 [开发指南](https://docs.taosdata.com/develop/),包含了应用如何引入 @tdengine/websocket 和数据写入、查询、无模式写入、参数绑定和数据订阅等示例。 - 其他参考信息请看 [参考手册](https://docs.taosdata.com/reference/connector/node/),包含了版本历史、数据类型、示例程序汇总、API 说明和常见问题等。 -- 本README主要是为想自己贡献、编译、测试 Node.js Connector 的开发者写的。如果要学习 TDengine,可以浏览 [官方文档](https://docs.taosdata.com/)。 +- 本 README 主要是为想自己贡献、编译、测试 Node.js Connector 的开发者写的。如果要学习 TDengine,可以浏览 [官方文档](https://docs.taosdata.com/)。 ## 3. 前置条件 -- 安装 Node.js 开发环境, 使用14以上版本,[下载 Node.js](https://nodejs.org/en/download/)。 +- 安装 Node.js 开发环境, 使用 14 以上版本,[下载 Node.js](https://nodejs.org/en/download/)。 - 使用 npm 安装 TypeScript 5.3.3 以上版本。 -- 使用 npm 安装 Node.js 连接器依赖, 在项目的nodejs目录下执行 `npm install` 命令进行安装。 +- 使用 npm 安装 Node.js 连接器依赖, 在项目的 nodejs 目录下执行 `npm install` 命令进行安装。 - 本地已经部署 TDengine,具体步骤请参考 [部署服务端](https://docs.taosdata.com/get-started/package/),且已经启动 `taosd` 与 `taosAdapter`。 ## 4. 构建 @@ -80,6 +77,7 @@ Ran all test suites. 性能测试还在开发中。 ## 6. CI/CD + - [Build Workflow](https://github.com/taosdata/taos-connector-node/actions/workflows/build.yaml) - [Code Coverage](https://app.codecov.io/gh/taosdata/taos-connector-node) diff --git a/README.md b/README.md index 4287107e..58e7b2c8 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,11 @@ [![StackOverflow](https://img.shields.io/badge/Ask_StackOverflow--white?logo=stackoverflow&style=social&logoColor=orange)](https://stackoverflow.com/questions/tagged/tdengine) English | [简体中文](README-CN.md) + ## Table of Contents + - [1. Introduction](#1-introduction) - [2. Documentation](#2-documentation) - [3. Prerequisites](#3-prerequisites) diff --git a/nodejs/example/all_type_query.ts b/nodejs/example/all_type_query.ts index ce6c9ee1..31c90150 100644 --- a/nodejs/example/all_type_query.ts +++ b/nodejs/example/all_type_query.ts @@ -1,80 +1,95 @@ -import { WSConfig } from '../src/common/config'; -import { sqlConnect, destroy, setLogLevel } from '../src' +import { WSConfig } from "../src/common/config"; +import { sqlConnect, destroy, setLogLevel } from "../src"; -let dsn = 'ws://127.0.0.1:6041'; +let dsn = "ws://127.0.0.1:6041"; async function json_tag_example() { let wsSql = null; try { - let conf = new WSConfig(dsn); - conf.setUser('root'); - conf.setPwd('taosdata'); + conf.setUser("root"); + conf.setPwd("taosdata"); wsSql = await sqlConnect(conf); console.log("Connected to " + dsn + " successfully."); - + // create database - await wsSql.exec('CREATE DATABASE IF NOT EXISTS example_json_tag'); + await wsSql.exec("CREATE DATABASE IF NOT EXISTS example_json_tag"); console.log("Create database example_json_tag successfully."); - + // create table - await wsSql.exec('create table if not exists example_json_tag.stb (ts timestamp, v int) tags(jt json)'); + await wsSql.exec( + "create table if not exists example_json_tag.stb (ts timestamp, v int) tags(jt json)" + ); console.log("Create stable example_json_tag.stb successfully"); - let insertQuery = 'INSERT INTO ' + + let insertQuery = + "INSERT INTO " + 'example_json_tag.tb1 USING example_json_tag.stb TAGS(\'{"name":"value"}\') ' + "values(now, 1) "; let taosResult = await wsSql.exec(insertQuery); - console.log("Successfully inserted " + taosResult.getAffectRows() + " rows to example_json_tag.stb."); + console.log( + "Successfully inserted " + + taosResult.getAffectRows() + + " rows to example_json_tag.stb." + ); - let sql = 'SELECT ts, v, jt FROM example_json_tag.stb limit 100'; + let sql = "SELECT ts, v, jt FROM example_json_tag.stb limit 100"; let wsRows = await wsSql.query(sql); while (await wsRows.next()) { let row = wsRows.getData(); if (row) { - console.log('ts: ' + row[0] + ', v: ' + row[1] + ', jt: ' + row[2]); + console.log( + "ts: " + row[0] + ", v: " + row[1] + ", jt: " + row[2] + ); } } - } catch (err: any) { - console.error(`Failed to create database example_json_tag or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}`); + console.error( + `Failed to create database example_json_tag or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}` + ); } finally { if (wsSql) { await wsSql.close(); } } - } async function all_type_example() { let wsSql = null; try { let conf = new WSConfig(dsn); - conf.setUser('root'); - conf.setPwd('taosdata'); + conf.setUser("root"); + conf.setPwd("taosdata"); wsSql = await sqlConnect(conf); console.log("Connected to " + dsn + " successfully."); - + // create database - await wsSql.exec('CREATE DATABASE IF NOT EXISTS all_type_example'); + await wsSql.exec("CREATE DATABASE IF NOT EXISTS all_type_example"); console.log("Create database all_type_example successfully."); - + // create table - await wsSql.exec('create table if not exists all_type_example.stb (ts timestamp, ' + - 'int_col INT, double_col DOUBLE, bool_col BOOL, binary_col BINARY(100),' + - 'nchar_col NCHAR(100), varbinary_col VARBINARY(100), geometry_col GEOMETRY(100)) ' + - 'tags(int_tag INT, double_tag DOUBLE, bool_tag BOOL, binary_tag BINARY(100),' + - 'nchar_tag NCHAR(100), varbinary_tag VARBINARY(100), geometry_tag GEOMETRY(100));'); + await wsSql.exec( + "create table if not exists all_type_example.stb (ts timestamp, " + + "int_col INT, double_col DOUBLE, bool_col BOOL, binary_col BINARY(100)," + + "nchar_col NCHAR(100), varbinary_col VARBINARY(100), geometry_col GEOMETRY(100)) " + + "tags(int_tag INT, double_tag DOUBLE, bool_tag BOOL, binary_tag BINARY(100)," + + "nchar_tag NCHAR(100), varbinary_tag VARBINARY(100), geometry_tag GEOMETRY(100));" + ); console.log("Create stable all_type_example.stb successfully"); - let insertQuery = "INSERT INTO all_type_example.tb1 using all_type_example.stb " - + "tags(1, 1.1, true, 'binary_value', 'nchar_value', '\\x98f46e', 'POINT(100 100)') " - + "values(now, 1, 1.1, true, 'binary_value', 'nchar_value', '\\x98f46e', 'POINT(100 100)')"; + let insertQuery = + "INSERT INTO all_type_example.tb1 using all_type_example.stb " + + "tags(1, 1.1, true, 'binary_value', 'nchar_value', '\\x98f46e', 'POINT(100 100)') " + + "values(now, 1, 1.1, true, 'binary_value', 'nchar_value', '\\x98f46e', 'POINT(100 100)')"; let taosResult = await wsSql.exec(insertQuery); - console.log("Successfully inserted " + taosResult.getAffectRows() + " rows to all_type_example.stb."); + console.log( + "Successfully inserted " + + taosResult.getAffectRows() + + " rows to all_type_example.stb." + ); - let sql = 'SELECT * FROM all_type_example.stb limit 100'; + let sql = "SELECT * FROM all_type_example.stb limit 100"; let wsRows = await wsSql.query(sql); let meta = wsRows.getMeta(); console.log("wsRow:meta:=>", meta); @@ -82,21 +97,21 @@ async function all_type_example() { let row = wsRows.getData(); console.log(row); } - } catch (err: any) { - console.error(`Failed to create database all_type_example or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}`); + console.error( + `Failed to create database all_type_example or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}` + ); } finally { if (wsSql) { await wsSql.close(); } } - } async function test() { - await json_tag_example() - await all_type_example() + await json_tag_example(); + await all_type_example(); destroy(); } -test() +test(); diff --git a/nodejs/example/all_type_stmt.ts b/nodejs/example/all_type_stmt.ts index 64efe70f..f15d1b1e 100644 --- a/nodejs/example/all_type_stmt.ts +++ b/nodejs/example/all_type_stmt.ts @@ -1,25 +1,27 @@ -import { WSConfig } from '../src/common/config'; -import { sqlConnect, destroy, setLogLevel } from '../src' -import { setLevel } from '../src/common/log'; +import { WSConfig } from "../src/common/config"; +import { sqlConnect, destroy, setLogLevel } from "../src"; +import { setLevel } from "../src/common/log"; -let dsn = 'ws://127.0.0.1:6041'; +let dsn = "ws://127.0.0.1:6041"; async function json_tag_example() { let wsSql = null; try { let conf = new WSConfig(dsn); - conf.setUser('root'); - conf.setPwd('taosdata'); + conf.setUser("root"); + conf.setPwd("taosdata"); wsSql = await sqlConnect(conf); console.log("Connected to " + dsn + " successfully."); - + // create database - await wsSql.exec('CREATE DATABASE IF NOT EXISTS example_json_tag'); + await wsSql.exec("CREATE DATABASE IF NOT EXISTS example_json_tag"); console.log("Create database example_json_tag successfully."); - - await wsSql.exec('use example_json_tag'); + + await wsSql.exec("use example_json_tag"); // create table - await wsSql.exec('create table if not exists stb (ts timestamp, v int) tags(jt json)'); + await wsSql.exec( + "create table if not exists stb (ts timestamp, v int) tags(jt json)" + ); console.log("Create stable example_json_tag.stb successfully"); @@ -27,7 +29,7 @@ async function json_tag_example() { await stmt.prepare("INSERT INTO ? using stb tags(?) VALUES (?,?)"); await stmt.setTableName(`tb1`); let tagParams = stmt.newStmtParam(); - tagParams.setJson(['{"name":"value"}']) + tagParams.setJson(['{"name":"value"}']); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); const currentMillis = new Date().getTime(); @@ -38,24 +40,25 @@ async function json_tag_example() { await stmt.exec(); await stmt.close(); - let sql = 'SELECT ts, v, jt FROM example_json_tag.stb limit 100'; + let sql = "SELECT ts, v, jt FROM example_json_tag.stb limit 100"; let wsRows = await wsSql.query(sql); while (await wsRows.next()) { let row = wsRows.getData(); if (row) { - console.log('ts: ' + row[0] + ', v: ' + row[1] + ', jt: ' + row[2]); + console.log( + "ts: " + row[0] + ", v: " + row[1] + ", jt: " + row[2] + ); } - } - } catch (err: any) { - console.error(`Failed to create database example_json_tag or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}`); + console.error( + `Failed to create database example_json_tag or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}` + ); } finally { if (wsSql) { await wsSql.close(); } } - } async function all_type_example() { @@ -63,34 +66,40 @@ async function all_type_example() { let stmt = null; try { let conf = new WSConfig(dsn); - conf.setUser('root'); - conf.setPwd('taosdata'); + conf.setUser("root"); + conf.setPwd("taosdata"); wsSql = await sqlConnect(conf); console.log("Connected to " + dsn + " successfully."); - + // create database - await wsSql.exec('CREATE DATABASE IF NOT EXISTS all_type_example'); + await wsSql.exec("CREATE DATABASE IF NOT EXISTS all_type_example"); console.log("Create database all_type_example successfully."); - await wsSql.exec('use all_type_example'); + await wsSql.exec("use all_type_example"); // create table - await wsSql.exec('create table if not exists stb (ts timestamp, ' + - 'int_col INT, double_col DOUBLE, bool_col BOOL, binary_col BINARY(100),' + - 'nchar_col NCHAR(100), varbinary_col VARBINARY(100), geometry_col GEOMETRY(100)) ' + - 'tags(int_tag INT, double_tag DOUBLE, bool_tag BOOL, binary_tag BINARY(100),' + - 'nchar_tag NCHAR(100), varbinary_tag VARBINARY(100), geometry_tag GEOMETRY(100));'); + await wsSql.exec( + "create table if not exists stb (ts timestamp, " + + "int_col INT, double_col DOUBLE, bool_col BOOL, binary_col BINARY(100)," + + "nchar_col NCHAR(100), varbinary_col VARBINARY(100), geometry_col GEOMETRY(100)) " + + "tags(int_tag INT, double_tag DOUBLE, bool_tag BOOL, binary_tag BINARY(100)," + + "nchar_tag NCHAR(100), varbinary_tag VARBINARY(100), geometry_tag GEOMETRY(100));" + ); console.log("Create stable all_type_example.stb successfully"); - let geometryData = new Uint8Array([0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x59,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x40,]).buffer; - - const encoder = new TextEncoder(); + let geometryData = new Uint8Array([ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x59, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40, + ]).buffer; + + const encoder = new TextEncoder(); let vbData = encoder.encode(`Hello, world!`).buffer; - + stmt = await wsSql.stmtInit(); - await stmt.prepare("INSERT INTO ? using stb tags(?,?,?,?,?,?,?) VALUES (?,?,?,?,?,?,?,?)"); + await stmt.prepare( + "INSERT INTO ? using stb tags(?,?,?,?,?,?,?) VALUES (?,?,?,?,?,?,?,?)" + ); await stmt.setTableName(`tb1`); let tagParams = stmt.newStmtParam(); tagParams.setInt([1]); @@ -116,8 +125,8 @@ async function all_type_example() { await stmt.bind(bindParams); await stmt.batch(); await stmt.exec(); - - let sql = 'SELECT * FROM all_type_example.stb limit 100'; + + let sql = "SELECT * FROM all_type_example.stb limit 100"; let wsRows = await wsSql.query(sql); let meta = wsRows.getMeta(); console.log("wsRow:meta:=>", meta); @@ -125,9 +134,10 @@ async function all_type_example() { let row = wsRows.getData(); console.log(row); } - } catch (err: any) { - console.error(`Failed to create database all_type_example or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}`); + console.error( + `Failed to create database all_type_example or stable stb, ErrCode: ${err.code}, ErrMessage: ${err.message}` + ); } finally { if (stmt) { await stmt.close(); @@ -136,15 +146,13 @@ async function all_type_example() { await wsSql.close(); } } - } async function test() { - setLevel("debug") - await json_tag_example() - await all_type_example() + setLevel("debug"); + await json_tag_example(); + await all_type_example(); destroy(); } -test() - +test(); diff --git a/nodejs/example/basicBatchTmq.ts b/nodejs/example/basicBatchTmq.ts index 1060d219..0a3b5a69 100644 --- a/nodejs/example/basicBatchTmq.ts +++ b/nodejs/example/basicBatchTmq.ts @@ -3,10 +3,10 @@ import { TMQConstants } from "../src/tmq/constant"; import { destroy, setLogLevel, sqlConnect, tmqConnect } from "../src"; import { WsConsumer } from "../src/tmq/wsTmq"; -const db = 'power'; -const stable = 'meters'; -const url = 'ws://localhost:6041'; -const topic = 'topic_meters' +const db = "power"; +const stable = "meters"; +const url = "ws://localhost:6041"; +const topic = "topic_meters"; const topics = [topic]; const groupId = "group-50"; const clientId = "client-50"; @@ -19,25 +19,28 @@ async function createConsumer() { [TMQConstants.CONNECT_PASS, "taosdata"], [TMQConstants.AUTO_OFFSET_RESET, "earliest"], [TMQConstants.WS_URL, url], - [TMQConstants.ENABLE_AUTO_COMMIT, 'false'], - [TMQConstants.AUTO_COMMIT_INTERVAL_MS, '1000'] + [TMQConstants.ENABLE_AUTO_COMMIT, "false"], + [TMQConstants.AUTO_COMMIT_INTERVAL_MS, "1000"], ]); try { let conn = await tmqConnect(configMap); - console.log(`Create consumer successfully, host: ${url}, groupId: ${groupId}, clientId: ${clientId}`) + console.log( + `Create consumer successfully, host: ${url}, groupId: ${groupId}, clientId: ${clientId}` + ); return conn; } catch (err: any) { - console.error(`Failed to create websocket consumer, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`); + console.error( + `Failed to create websocket consumer, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}` + ); throw err; } - } -// ANCHOR_END: create_consumer +// ANCHOR_END: create_consumer async function prepare() { - let conf = new WSConfig('ws://localhost:6041'); - conf.setUser('root'); - conf.setPwd('taosdata'); + let conf = new WSConfig("ws://localhost:6041"); + conf.setUser("root"); + conf.setPwd("taosdata"); conf.setDb(db); const createDB = `CREATE DATABASE IF NOT EXISTS ${db}`; const createStable = `CREATE STABLE IF NOT EXISTS ${db}.${stable} (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);`; @@ -52,20 +55,24 @@ async function prepare() { } async function insert() { - let conf = new WSConfig('ws://localhost:6041'); - conf.setUser('root'); - conf.setPwd('taosdata'); + let conf = new WSConfig("ws://localhost:6041"); + conf.setUser("root"); + conf.setPwd("taosdata"); conf.setDb(db); let wsSql = await sqlConnect(conf); for (let i = 0; i < 10000; i++) { - await wsSql.exec(`INSERT INTO d1001 USING ${stable} (location, groupId) TAGS ("California.SanFrancisco", 3) VALUES (NOW + ${i}a, ${10 + i}, ${200 + i}, ${0.32 + i})`); + await wsSql.exec( + `INSERT INTO d1001 USING ${stable} (location, groupId) TAGS ("California.SanFrancisco", 3) VALUES (NOW + ${i}a, ${ + 10 + i + }, ${200 + i}, ${0.32 + i})` + ); } await wsSql.close(); - console.log("insert fininsh!!!!!") + console.log("insert fininsh!!!!!"); } async function subscribe(consumer: WsConsumer) { - // ANCHOR: commit + // ANCHOR: commit try { let count = 0; await consumer.subscribe(topics); @@ -76,25 +83,26 @@ async function subscribe(consumer: WsConsumer) { let res = await consumer.poll(100); for (let [key, value] of res) { // Add your data processing logic here - let data = value.getData(); + let data = value.getData(); if (data) { if (data.length == 0 && bBegin) { bFinish = true; break; - } else if(data.length > 0){ + } else if (data.length > 0) { bBegin = true; } - count += data.length - console.log("poll end ------>", count); + count += data.length; + console.log("poll end ------>", count); } - } // await consumer.commit(); } const endTime = new Date().getTime(); console.log(count, endTime - startTime); } catch (err: any) { - console.error(`Failed to poll data, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`); + console.error( + `Failed to poll data, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}` + ); throw err; } // ANCHOR_END: commit @@ -115,12 +123,12 @@ async function consumer() { await subscribe(consumer); await consumer.unsubscribe(); console.log("Consumer unsubscribed successfully."); - } - catch (err: any) { - console.error(`Failed to unsubscribe consumer, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}`); + } catch (err: any) { + console.error( + `Failed to unsubscribe consumer, topic: ${topic}, groupId: ${groupId}, clientId: ${clientId}, ErrCode: ${err.code}, ErrMessage: ${err.message}` + ); throw err; - } - finally { + } finally { if (consumer) { await consumer.close(); console.log("Consumer closed successfully."); @@ -131,7 +139,7 @@ async function consumer() { } async function test() { - await consumer(); + await consumer(); } -test() +test(); diff --git a/nodejs/example/basicSchemaless.ts b/nodejs/example/basicSchemaless.ts index 217d33d3..2c8cf8e4 100644 --- a/nodejs/example/basicSchemaless.ts +++ b/nodejs/example/basicSchemaless.ts @@ -1,43 +1,64 @@ -import { WSConfig } from '../src/common/config'; -import { Precision, SchemalessProto } from '../src/sql/wsProto'; -import { sqlConnect, destroy, setLogLevel } from '../src'; -let dsn = 'ws://root:taosdata@localhost:6041'; -let db = 'power' -let influxdbData = "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000" -let telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0" -let jsonData = "{\"metric\": \"meter_current\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}" -const dropDB = `drop database if exists ${db}` +import { WSConfig } from "../src/common/config"; +import { Precision, SchemalessProto } from "../src/sql/wsProto"; +import { sqlConnect, destroy, setLogLevel } from "../src"; +let dsn = "ws://root:taosdata@localhost:6041"; +let db = "power"; +let influxdbData = + 'st,t1=3i64,t2=4f64,t3="t3" c1=3i64,c3=L"passit",c2=false,c4=4f64 1626006833639000000'; +let telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0"; +let jsonData = + '{"metric": "meter_current","timestamp": 1626846400,"value": 10.3, "tags": {"groupid": 2, "location": "California.SanFrancisco", "id": "d1001"}}'; +const dropDB = `drop database if exists ${db}`; async function Prepare() { - let conf :WSConfig = new WSConfig(dsn) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await sqlConnect(conf) + let conf: WSConfig = new WSConfig(dsn); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await sqlConnect(conf); await wsSql.exec(dropDB); - await wsSql.exec('create database if not exists power KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;'); - await wsSql.exec('CREATE STABLE if not exists power.meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);'); + await wsSql.exec( + "create database if not exists power KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;" + ); + await wsSql.exec( + "CREATE STABLE if not exists power.meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);" + ); await wsSql.close(); } (async () => { - let wsSchemaless = null + let wsSchemaless = null; try { await Prepare(); - let conf :WSConfig = new WSConfig(dsn) - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power') + let conf: WSConfig = new WSConfig(dsn); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power"); wsSchemaless = await sqlConnect(conf); - await wsSchemaless.schemalessInsert([influxdbData], SchemalessProto.InfluxDBLineProtocol, Precision.NANO_SECONDS, 0); - await wsSchemaless.schemalessInsert([telnetData], SchemalessProto.OpenTSDBTelnetLineProtocol, Precision.SECONDS, 0); - await wsSchemaless.schemalessInsert([jsonData], SchemalessProto.OpenTSDBJsonFormatProtocol, Precision.SECONDS, 0); + await wsSchemaless.schemalessInsert( + [influxdbData], + SchemalessProto.InfluxDBLineProtocol, + Precision.NANO_SECONDS, + 0 + ); + await wsSchemaless.schemalessInsert( + [telnetData], + SchemalessProto.OpenTSDBTelnetLineProtocol, + Precision.SECONDS, + 0 + ); + await wsSchemaless.schemalessInsert( + [jsonData], + SchemalessProto.OpenTSDBJsonFormatProtocol, + Precision.SECONDS, + 0 + ); } catch (e) { console.error(e); - }finally { + } finally { if (wsSchemaless) { await wsSchemaless.close(); } - destroy() + destroy(); } })(); diff --git a/nodejs/example/basicSql.ts b/nodejs/example/basicSql.ts index f76d4048..eab43420 100644 --- a/nodejs/example/basicSql.ts +++ b/nodejs/example/basicSql.ts @@ -1,62 +1,68 @@ -import { WSConfig } from '../src/common/config'; -import { sqlConnect, destroy, setLogLevel } from '../src' +import { WSConfig } from "../src/common/config"; +import { sqlConnect, destroy, setLogLevel } from "../src"; -let dsn = 'ws://root:taosdata@localhost:6041'; +let dsn = "ws://root:taosdata@localhost:6041"; (async () => { let wsSql = null; let wsRows = null; let reqId = 0; try { - setLogLevel("debug") - let conf :WSConfig = new WSConfig(dsn) - conf.setUser('root') - conf.setPwd('taosdata') - wsSql = await sqlConnect(conf) + setLogLevel("debug"); + let conf: WSConfig = new WSConfig(dsn); + conf.setUser("root"); + conf.setPwd("taosdata"); + wsSql = await sqlConnect(conf); let version = await wsSql.version(); console.log(version); - let taosResult = await wsSql.exec('show databases', reqId++) + let taosResult = await wsSql.exec("show databases", reqId++); console.log(taosResult); - taosResult = await wsSql.exec('create database if not exists power KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;',reqId++); + taosResult = await wsSql.exec( + "create database if not exists power KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;", + reqId++ + ); console.log(taosResult); - taosResult = await wsSql.exec('use power',reqId++) + taosResult = await wsSql.exec("use power", reqId++); console.log(taosResult); - taosResult = await wsSql.exec('CREATE STABLE if not exists meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);', reqId++); + taosResult = await wsSql.exec( + "CREATE STABLE if not exists meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);", + reqId++ + ); console.log(taosResult); - taosResult = await wsSql.exec('describe meters', reqId++) + taosResult = await wsSql.exec("describe meters", reqId++); console.log(taosResult); - taosResult = await wsSql.exec('INSERT INTO d1001 USING meters TAGS ("California.SanFrancisco", 3) VALUES (NOW, 10.2, 219, 0.32)', reqId++) + taosResult = await wsSql.exec( + 'INSERT INTO d1001 USING meters TAGS ("California.SanFrancisco", 3) VALUES (NOW, 10.2, 219, 0.32)', + reqId++ + ); console.log(taosResult); - for (let i = 0; i< 100; i++) { - wsRows = await wsSql.query('select * from meters', reqId++); - let meta = wsRows.getMeta() + for (let i = 0; i < 100; i++) { + wsRows = await wsSql.query("select * from meters", reqId++); + let meta = wsRows.getMeta(); console.log("wsRow:meta:=>", meta); while (await wsRows.next()) { let result = wsRows.getData(); - console.log('queryRes.Scan().then=>', result); + console.log("queryRes.Scan().then=>", result); } - await wsRows.close() + await wsRows.close(); } - - } catch (err: any) { console.error(err.code, err.message); - } finally { if (wsRows) { await wsRows.close(); } if (wsSql) { - await wsSql.close(); + await wsSql.close(); } - destroy() - console.log("finish!") + destroy(); + console.log("finish!"); } })(); diff --git a/nodejs/example/basicStmt.ts b/nodejs/example/basicStmt.ts index e0df9ecf..537a3092 100644 --- a/nodejs/example/basicStmt.ts +++ b/nodejs/example/basicStmt.ts @@ -1,25 +1,28 @@ -import { WSConfig } from '../src/common/config'; -import { destroy, sqlConnect } from '../src'; +import { WSConfig } from "../src/common/config"; +import { destroy, sqlConnect } from "../src"; -let db = 'power' -let stable = 'meters' +let db = "power"; +let stable = "meters"; let numOfSubTable = 10; let numOfRow = 10; function getRandomInt(min: number, max: number): number { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min + 1)) + min; + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; } -let dsn = 'ws://root:taosdata@localhost:6041'; +let dsn = "ws://root:taosdata@localhost:6041"; async function Prepare() { - - let conf :WSConfig = new WSConfig(dsn) - let wsSql = await sqlConnect(conf) - await wsSql.exec(`create database if not exists ${db} KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;`) - await wsSql.exec(`CREATE STABLE if not exists ${db}.${stable} (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);`); - wsSql.close() + let conf: WSConfig = new WSConfig(dsn); + let wsSql = await sqlConnect(conf); + await wsSql.exec( + `create database if not exists ${db} KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;` + ); + await wsSql.exec( + `CREATE STABLE if not exists ${db}.${stable} (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);` + ); + wsSql.close(); } (async () => { @@ -28,49 +31,52 @@ async function Prepare() { try { await Prepare(); let wsConf = new WSConfig(dsn); - wsConf.setDb(db) + wsConf.setDb(db); connector = await sqlConnect(wsConf); - stmt = await connector.stmtInit() - await stmt.prepare(`INSERT INTO ? USING ${db}.${stable} (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)`); - + stmt = await connector.stmtInit(); + await stmt.prepare( + `INSERT INTO ? USING ${db}.${stable} (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)` + ); + for (let i = 0; i < numOfSubTable; i++) { await stmt.setTableName(`d_bind_${i}`); let tagParams = stmt.newStmtParam(); tagParams.setVarchar([`location_${i}`]); tagParams.setInt([i]); await stmt.setTags(tagParams); - let timestampParams:number[] = []; - let currentParams:number[] = []; - let voltageParams:number[] = []; - let phaseParams:number[] = []; + let timestampParams: number[] = []; + let currentParams: number[] = []; + let voltageParams: number[] = []; + let phaseParams: number[] = []; const currentMillis = new Date().getTime(); for (let j = 0; j < numOfRow; j++) { timestampParams.push(currentMillis + j); currentParams.push(Math.random() * 30); voltageParams.push(getRandomInt(100, 300)); - phaseParams.push(Math.random()) + phaseParams.push(Math.random()); } let bindParams = stmt.newStmtParam(); bindParams.setTimestamp(timestampParams); bindParams.setFloat(currentParams); bindParams.setInt(voltageParams); - bindParams.setFloat(phaseParams); + bindParams.setFloat(phaseParams); await stmt.bind(bindParams); await stmt.batch(); - await stmt.exec(); - console.log(`d_bind_${i} insert ` + stmt.getLastAffected() + " rows."); - + await stmt.exec(); + console.log( + `d_bind_${i} insert ` + stmt.getLastAffected() + " rows." + ); } } catch (e) { console.error(e); - }finally { + } finally { if (stmt) { await stmt.close(); } if (connector) { await connector.close(); } - destroy() + destroy(); } })(); diff --git a/nodejs/example/basicTmq.ts b/nodejs/example/basicTmq.ts index f4bbc9aa..fd8f55cc 100644 --- a/nodejs/example/basicTmq.ts +++ b/nodejs/example/basicTmq.ts @@ -2,27 +2,27 @@ import { WSConfig } from "../src/common/config"; import { TMQConstants } from "../src/tmq/constant"; import { destroy, setLogLevel, sqlConnect, tmqConnect } from "../src"; -const stable = 'meters'; -const db = 'power' -const topics:string[] = ['topic_ws_map'] -let dropTopic = `DROP TOPIC IF EXISTS ${topics[0]};` +const stable = "meters"; +const db = "power"; +const topics: string[] = ["topic_ws_map"]; +let dropTopic = `DROP TOPIC IF EXISTS ${topics[0]};`; let configMap = new Map([ [TMQConstants.GROUP_ID, "gId_11"], [TMQConstants.CONNECT_USER, "root"], [TMQConstants.CONNECT_PASS, "taosdata"], [TMQConstants.AUTO_OFFSET_RESET, "earliest"], - [TMQConstants.CLIENT_ID, 'test_tmq_client11'], - [TMQConstants.WS_URL, 'ws://localhost:6041'], - [TMQConstants.ENABLE_AUTO_COMMIT, 'false'], - [TMQConstants.AUTO_COMMIT_INTERVAL_MS, '1000'] + [TMQConstants.CLIENT_ID, "test_tmq_client11"], + [TMQConstants.WS_URL, "ws://localhost:6041"], + [TMQConstants.ENABLE_AUTO_COMMIT, "false"], + [TMQConstants.AUTO_COMMIT_INTERVAL_MS, "1000"], ]); -let dsn = 'ws://root:taosdata@localhost:6041'; +let dsn = "ws://root:taosdata@localhost:6041"; async function Prepare() { - let conf :WSConfig = new WSConfig(dsn) - const createDB = `create database if not exists ${db} KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;` - const createStable = `CREATE STABLE if not exists ${db}.${stable} (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);` - let createTopic = `create topic if not exists ${topics[0]} as select * from ${db}.${stable}` - const useDB = `use ${db}` + let conf: WSConfig = new WSConfig(dsn); + const createDB = `create database if not exists ${db} KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;`; + const createStable = `CREATE STABLE if not exists ${db}.${stable} (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);`; + let createTopic = `create topic if not exists ${topics[0]} as select * from ${db}.${stable}`; + const useDB = `use ${db}`; let ws = await sqlConnect(conf); await ws.exec(createDB); @@ -30,17 +30,20 @@ async function Prepare() { await ws.exec(createStable); await ws.exec(createTopic); for (let i = 0; i < 1000; i++) { - await ws.exec(`INSERT INTO d1001 USING ${stable} (location, groupId) TAGS ("California.SanFrancisco", 3) VALUES (NOW + ${i}a, ${10+i}, ${200+i}, ${0.32 + i})`) + await ws.exec( + `INSERT INTO d1001 USING ${stable} (location, groupId) TAGS ("California.SanFrancisco", 3) VALUES (NOW + ${i}a, ${ + 10 + i + }, ${200 + i}, ${0.32 + i})` + ); } - await ws.close() - + await ws.close(); } (async () => { - let consumer = null + let consumer = null; try { - setLogLevel("debug") - await Prepare() + setLogLevel("debug"); + await Prepare(); consumer = await tmqConnect(configMap); await consumer.subscribe(topics); for (let i = 0; i < 5; i++) { @@ -49,8 +52,8 @@ async function Prepare() { console.log(key, value.getMeta()); let data = value.getData(); if (data) { - console.log(data.length) - } + console.log(data.length); + } } // await consumer.commit(); } @@ -62,15 +65,13 @@ async function Prepare() { // for(let i in assignment) { // console.log("seek after:", assignment[i]) // } - await consumer.unsubscribe() + await consumer.unsubscribe(); } catch (e) { console.error(e); } finally { if (consumer) { - await consumer.close(); + await consumer.close(); } - destroy() + destroy(); } })(); - - diff --git a/nodejs/index.ts b/nodejs/index.ts index 2a278416..2531a5f4 100644 --- a/nodejs/index.ts +++ b/nodejs/index.ts @@ -1,25 +1,25 @@ -export * from "./src/client/wsClient" -export * from "./src/client/wsConnector" -export * from "./src/client/wsConnectorPool" -export * from "./src/client/wsEventCallback" -export * from "./src/client/wsResponse" -export * from "./src/common/config" -export * from "./src/common/constant" -export * from "./src/common/log" -export * from "./src/common/reqid" -export * from "./src/common/taosResult" -export * from "./src/common/ut8Helper" -export * from "./src/common/utils" -export * from "./src/common/wsError" -export * from "./src/common/wsOptions" -export * from "./src/index" -export * from "./src/sql/wsProto" -export * from "./src/sql/wsRows" -export * from "./src/sql/wsSql" -export * from "./src/stmt/wsParamsBase" -export * from "./src/stmt/wsProto" -export * from "./src/stmt/wsStmt" -export * from "./src/tmq/config" -export * from "./src/tmq/constant" -export * from "./src/tmq/tmqResponse" -export * from "./src/tmq/wsTmq" +export * from "./src/client/wsClient"; +export * from "./src/client/wsConnector"; +export * from "./src/client/wsConnectorPool"; +export * from "./src/client/wsEventCallback"; +export * from "./src/client/wsResponse"; +export * from "./src/common/config"; +export * from "./src/common/constant"; +export * from "./src/common/log"; +export * from "./src/common/reqid"; +export * from "./src/common/taosResult"; +export * from "./src/common/ut8Helper"; +export * from "./src/common/utils"; +export * from "./src/common/wsError"; +export * from "./src/common/wsOptions"; +export * from "./src/index"; +export * from "./src/sql/wsProto"; +export * from "./src/sql/wsRows"; +export * from "./src/sql/wsSql"; +export * from "./src/stmt/wsParamsBase"; +export * from "./src/stmt/wsProto"; +export * from "./src/stmt/wsStmt"; +export * from "./src/tmq/config"; +export * from "./src/tmq/constant"; +export * from "./src/tmq/tmqResponse"; +export * from "./src/tmq/wsTmq"; diff --git a/nodejs/jest.config.js b/nodejs/jest.config.js index b9050d08..2c1c09e8 100644 --- a/nodejs/jest.config.js +++ b/nodejs/jest.config.js @@ -1,8 +1,8 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { - preset: "ts-jest", - transform: {'^.+\\.ts?$': 'ts-jest'}, - testEnvironment: 'node', - testRegex: '/test/.*\\.(test|spec)?\\.(ts|tsx)$', - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], -}; \ No newline at end of file + preset: "ts-jest", + transform: { "^.+\\.ts?$": "ts-jest" }, + testEnvironment: "node", + testRegex: "/test/.*\\.(test|spec)?\\.(ts|tsx)$", + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], +}; diff --git a/nodejs/prepare.js b/nodejs/prepare.js index cb0d9cc7..d5928604 100644 --- a/nodejs/prepare.js +++ b/nodejs/prepare.js @@ -1,36 +1,38 @@ -const fs = require('fs').promises; +const fs = require("fs").promises; const { readFile, writeFile, readdir, lstat } = fs; -const path = require('path'); +const path = require("path"); const { resolve, parse } = path; -const tsFile = /\/src\/.*.ts$/ +const tsFile = /\/src\/.*.ts$/; async function dir(folder, ts = []) { - let files = await readdir(folder) + let files = await readdir(folder); for (let f of files) { - let path = resolve(folder, f).replace(/\\/g, '/') // fix windows path - let ls = await lstat(path) + let path = resolve(folder, f).replace(/\\/g, "/"); // fix windows path + let ls = await lstat(path); if (ls.isDirectory()) { - await dir(path, ts) + await dir(path, ts); } else if (tsFile.test(path)) { - let name = parse(path).name - if (!name.startsWith('_') && !name.endsWith('-back')) - ts.push(path) + let name = parse(path).name; + if (!name.startsWith("_") && !name.endsWith("-back")) ts.push(path); } } - return ts + return ts; } async function autoIndex() { - let ts = await dir('./src') - ts.sort() // make sure same sort on windows and unix - let improts = '', _dir = __dirname.replace(/\\/g, '/') // fix windows path + let ts = await dir("./src"); + ts.sort(); // make sure same sort on windows and unix + let improts = "", + _dir = __dirname.replace(/\\/g, "/"); // fix windows path for (let path of ts) { - improts += `export * from "${path.replace(_dir, '.').slice(0, -3)}"\r\n` + improts += `export * from "${path + .replace(_dir, ".") + .slice(0, -3)}"\r\n`; } - let content = await readFile(resolve(__dirname, './index.ts'), 'utf-8') + let content = await readFile(resolve(__dirname, "./index.ts"), "utf-8"); if (improts !== content) { - console.log('[autoIndex] index.ts') - await writeFile(resolve(__dirname, './index.ts'), improts) + console.log("[autoIndex] index.ts"); + await writeFile(resolve(__dirname, "./index.ts"), improts); } } @@ -38,4 +40,6 @@ async function main() { await autoIndex(); } -main().then(r => console.log('done')).catch(e => console.error(e)); +main() + .then((r) => console.log("done")) + .catch((e) => console.error(e)); diff --git a/nodejs/readme.md b/nodejs/readme.md index d7406452..58e7b2c8 100644 --- a/nodejs/readme.md +++ b/nodejs/readme.md @@ -14,6 +14,7 @@ [![StackOverflow](https://img.shields.io/badge/Ask_StackOverflow--white?logo=stackoverflow&style=social&logoColor=orange)](https://stackoverflow.com/questions/tagged/tdengine) English | [简体中文](README-CN.md) + ## Table of Contents diff --git a/nodejs/src/client/wsClient.ts b/nodejs/src/client/wsClient.ts index 1373e2b4..9fb3e1c6 100644 --- a/nodejs/src/client/wsClient.ts +++ b/nodejs/src/client/wsClient.ts @@ -1,39 +1,41 @@ -import JSONBig from 'json-bigint'; -import { WebSocketConnector } from './wsConnector'; -import { WebSocketConnectionPool } from './wsConnectorPool' -import { ErrorCode, TDWebSocketClientError, WebSocketInterfaceError, WebSocketQueryError } from '../common/wsError'; +import JSONBig from "json-bigint"; +import { WebSocketConnector } from "./wsConnector"; +import { WebSocketConnectionPool } from "./wsConnectorPool"; import { - WSVersionResponse, - WSQueryResponse, -} from './wsResponse'; -import { ReqId } from '../common/reqid'; -import logger from '../common/log'; -import { safeDecodeURIComponent, compareVersions} from '../common/utils'; -import { w3cwebsocket } from 'websocket'; -import { TSDB_OPTION_CONNECTION } from '../common/constant'; + ErrorCode, + TDWebSocketClientError, + WebSocketInterfaceError, + WebSocketQueryError, +} from "../common/wsError"; +import { WSVersionResponse, WSQueryResponse } from "./wsResponse"; +import { ReqId } from "../common/reqid"; +import logger from "../common/log"; +import { safeDecodeURIComponent, compareVersions } from "../common/utils"; +import { w3cwebsocket } from "websocket"; +import { TSDB_OPTION_CONNECTION } from "../common/constant"; export class WsClient { private _wsConnector?: WebSocketConnector; - private _timeout?:number | undefined | null; - private _timezone?:string | undefined | null; - private readonly _url:URL; + private _timeout?: number | undefined | null; + private _timezone?: string | undefined | null; + private readonly _url: URL; private static readonly _minVersion = "3.3.2.0"; private _version?: string | undefined | null; - constructor(url: URL, timeout ?:number | undefined | null) { + constructor(url: URL, timeout?: number | undefined | null) { this.checkURL(url); this._url = url; this._timeout = timeout; if (this._url.searchParams.has("timezone")) { - this._timezone = this._url.searchParams.get("timezone") || undefined; + this._timezone = + this._url.searchParams.get("timezone") || undefined; this._url.searchParams.delete("timezone"); } - } async connect(database?: string | undefined | null): Promise { let connMsg = { - action: 'conn', + action: "conn", args: { req_id: ReqId.getReqID(), user: safeDecodeURIComponent(this._url.username), @@ -42,42 +44,58 @@ export class WsClient { ...(this._timezone && { tz: this._timezone }), }, }; - logger.debug("[wsClient.connect.connMsg]===>" + JSONBig.stringify(connMsg)); - this._wsConnector = await WebSocketConnectionPool.instance().getConnection(this._url, this._timeout); + logger.debug( + "[wsClient.connect.connMsg]===>" + JSONBig.stringify(connMsg) + ); + this._wsConnector = + await WebSocketConnectionPool.instance().getConnection( + this._url, + this._timeout + ); if (this._wsConnector.readyState() === w3cwebsocket.OPEN) { return; - } + } try { await this._wsConnector.ready(); - let result: any = await this._wsConnector.sendMsg(JSON.stringify(connMsg)) - if (result.msg.code == 0) { + let result: any = await this._wsConnector.sendMsg( + JSON.stringify(connMsg) + ); + if (result.msg.code == 0) { return; } await this.close(); - throw(new WebSocketQueryError(result.msg.code, result.msg.message)); - + throw new WebSocketQueryError(result.msg.code, result.msg.message); } catch (e: any) { await this.close(); - logger.error(`connection creation failed, url: ${this._url}, code:${e.code}, msg:${e.message}`); - throw(new TDWebSocketClientError(ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, `connection creation failed, url: ${this._url}, code:${e.code}, msg:${e.message}`)); + logger.error( + `connection creation failed, url: ${this._url}, code:${e.code}, msg:${e.message}` + ); + throw new TDWebSocketClientError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, + `connection creation failed, url: ${this._url}, code:${e.code}, msg:${e.message}` + ); } - } - async setOptionConnection(option: TSDB_OPTION_CONNECTION, value: string | null): Promise { - logger.debug("[wsClient.setOptionConnection]===>" + option + ", " + value); + async setOptionConnection( + option: TSDB_OPTION_CONNECTION, + value: string | null + ): Promise { + logger.debug( + "[wsClient.setOptionConnection]===>" + option + ", " + value + ); let connMsg = { - action: 'options_connection', + action: "options_connection", args: { req_id: ReqId.getReqID(), options: [ { option: option, - value: value - } - ] - } + value: value, + }, + ], + }, }; try { await this.exec(JSONBig.stringify(connMsg), false); @@ -88,117 +106,197 @@ export class WsClient { } async execNoResp(queryMsg: string): Promise { - logger.debug('[wsQueryInterface.query.queryMsg]===>' + queryMsg); - if (this._wsConnector && this._wsConnector.readyState() === w3cwebsocket.OPEN) { - await this._wsConnector.sendMsgNoResp(queryMsg) + logger.debug("[wsQueryInterface.query.queryMsg]===>" + queryMsg); + if ( + this._wsConnector && + this._wsConnector.readyState() === w3cwebsocket.OPEN + ) { + await this._wsConnector.sendMsgNoResp(queryMsg); return; } - throw(new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "invalid websocket connect")) + throw new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "invalid websocket connect" + ); } // need to construct Response. - async exec(queryMsg: string, bSqlQuery:boolean = true): Promise { + async exec(queryMsg: string, bSqlQuery: boolean = true): Promise { return new Promise((resolve, reject) => { - logger.debug('[wsQueryInterface.query.queryMsg]===>' + queryMsg); - if (this._wsConnector && this._wsConnector.readyState() === w3cwebsocket.OPEN) { - this._wsConnector.sendMsg(queryMsg).then((e: any) => { - if (e.msg.code == 0) { - if (bSqlQuery) { - resolve(new WSQueryResponse(e)); - }else{ - resolve(e) + logger.debug("[wsQueryInterface.query.queryMsg]===>" + queryMsg); + if ( + this._wsConnector && + this._wsConnector.readyState() === w3cwebsocket.OPEN + ) { + this._wsConnector + .sendMsg(queryMsg) + .then((e: any) => { + if (e.msg.code == 0) { + if (bSqlQuery) { + resolve(new WSQueryResponse(e)); + } else { + resolve(e); + } + } else { + reject( + new WebSocketInterfaceError( + e.msg.code, + e.msg.message + ) + ); } - } else { - reject(new WebSocketInterfaceError(e.msg.code, e.msg.message)); - } - }).catch((e) => {reject(e);}); + }) + .catch((e) => { + reject(e); + }); } else { - reject(new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "invalid websocket connect")) + reject( + new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "invalid websocket connect" + ) + ); } }); } - // need to construct Response. - async sendBinaryMsg(reqId: bigint, action:string, message: ArrayBuffer, bSqlQuery:boolean = true, bResultBinary: boolean = false): Promise { + async sendBinaryMsg( + reqId: bigint, + action: string, + message: ArrayBuffer, + bSqlQuery: boolean = true, + bResultBinary: boolean = false + ): Promise { return new Promise((resolve, reject) => { - if (this._wsConnector && this._wsConnector.readyState() === w3cwebsocket.OPEN) { - this._wsConnector.sendBinaryMsg(reqId, action, message).then((e: any) => { - if (bResultBinary) { - resolve(e); - } - - if (e.msg.code == 0) { - if (bSqlQuery) { - resolve(new WSQueryResponse(e)); - }else{ + if ( + this._wsConnector && + this._wsConnector.readyState() === w3cwebsocket.OPEN + ) { + this._wsConnector + .sendBinaryMsg(reqId, action, message) + .then((e: any) => { + if (bResultBinary) { resolve(e); } - } else { - reject(new WebSocketInterfaceError(e.msg.code, e.msg.message)); - } - }).catch((e) => {reject(e);}); + + if (e.msg.code == 0) { + if (bSqlQuery) { + resolve(new WSQueryResponse(e)); + } else { + resolve(e); + } + } else { + reject( + new WebSocketInterfaceError( + e.msg.code, + e.msg.message + ) + ); + } + }) + .catch((e) => { + reject(e); + }); } else { - reject(new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "invalid websocket connect")) + reject( + new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "invalid websocket connect" + ) + ); } - }); } - getState() { if (this._wsConnector) { return this._wsConnector.readyState(); } return -1; - } async ready(): Promise { try { - this._wsConnector = await WebSocketConnectionPool.instance().getConnection(this._url, this._timeout); + this._wsConnector = + await WebSocketConnectionPool.instance().getConnection( + this._url, + this._timeout + ); if (this._wsConnector.readyState() !== w3cwebsocket.OPEN) { - await this._wsConnector.ready() + await this._wsConnector.ready(); } - logger.debug("ready status ", this._url, this._wsConnector.readyState()) - return; + logger.debug( + "ready status ", + this._url, + this._wsConnector.readyState() + ); + return; } catch (e: any) { - logger.error(`connection creation failed, url: ${this._url}, code: ${e.code}, message: ${e.message}`); - throw(new TDWebSocketClientError(ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, `connection creation failed, url: ${this._url}, code: ${e.code}, message: ${e.message}`)); - } - + logger.error( + `connection creation failed, url: ${this._url}, code: ${e.code}, message: ${e.message}` + ); + throw new TDWebSocketClientError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, + `connection creation failed, url: ${this._url}, code: ${e.code}, message: ${e.message}` + ); + } } - async sendMsg(msg:string): Promise { + async sendMsg(msg: string): Promise { return new Promise((resolve, reject) => { - logger.debug("[wsQueryInterface.sendMsg]===>" + msg) - if (this._wsConnector && this._wsConnector.readyState() === w3cwebsocket.OPEN) { - this._wsConnector.sendMsg(msg).then((e: any) => { - resolve(e); - }).catch((e) => reject(e)); + logger.debug("[wsQueryInterface.sendMsg]===>" + msg); + if ( + this._wsConnector && + this._wsConnector.readyState() === w3cwebsocket.OPEN + ) { + this._wsConnector + .sendMsg(msg) + .then((e: any) => { + resolve(e); + }) + .catch((e) => reject(e)); } else { - reject(new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "invalid websocket connect")); + reject( + new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "invalid websocket connect" + ) + ); } }); } async freeResult(res: WSQueryResponse) { let freeResultMsg = { - action: 'free_result', - args: { - req_id: ReqId.getReqID(), - id: res.id, - }, + action: "free_result", + args: { + req_id: ReqId.getReqID(), + id: res.id, + }, }; return new Promise((resolve, reject) => { let jsonStr = JSONBig.stringify(freeResultMsg); - logger.debug("[wsQueryInterface.freeResult.freeResultMsg]===>" + jsonStr) - if (this._wsConnector && this._wsConnector.readyState() === w3cwebsocket.OPEN) { - this._wsConnector.sendMsgNoResp(jsonStr) - .then((e: any) => {resolve(e);}) - .catch((e) => reject(e)); + logger.debug( + "[wsQueryInterface.freeResult.freeResultMsg]===>" + jsonStr + ); + if ( + this._wsConnector && + this._wsConnector.readyState() === w3cwebsocket.OPEN + ) { + this._wsConnector + .sendMsgNoResp(jsonStr) + .then((e: any) => { + resolve(e); + }) + .catch((e) => reject(e)); } else { - reject(new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "invalid websocket connect")); + reject( + new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "invalid websocket connect" + ) + ); } }); } @@ -207,45 +305,60 @@ export class WsClient { if (this._version) { return this._version; } - + let versionMsg = { - action: 'version', + action: "version", args: { - req_id: ReqId.getReqID() + req_id: ReqId.getReqID(), }, }; - + if (this._wsConnector) { try { if (this._wsConnector.readyState() !== w3cwebsocket.OPEN) { await this._wsConnector.ready(); } - let result:any = await this._wsConnector.sendMsg(JSONBig.stringify(versionMsg)); + let result: any = await this._wsConnector.sendMsg( + JSONBig.stringify(versionMsg) + ); if (result.msg.code == 0) { return new WSVersionResponse(result).version; - } - throw(new WebSocketInterfaceError(result.msg.code, result.msg.message)); + } + throw new WebSocketInterfaceError( + result.msg.code, + result.msg.message + ); } catch (e: any) { - logger.error(`connection creation failed, url: ${this._url}, code: ${e.code}, message: ${e.message}`); - throw(new TDWebSocketClientError(ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, `connection creation failed, url: ${this._url}, code: ${e.code}, message: ${e.message}`)); + logger.error( + `connection creation failed, url: ${this._url}, code: ${e.code}, message: ${e.message}` + ); + throw new TDWebSocketClientError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, + `connection creation failed, url: ${this._url}, code: ${e.code}, message: ${e.message}` + ); } } - throw(ErrorCode.ERR_CONNECTION_CLOSED, "invalid websocket connect"); + throw (ErrorCode.ERR_CONNECTION_CLOSED, "invalid websocket connect"); } - async close():Promise { + async close(): Promise { if (this._wsConnector) { - await WebSocketConnectionPool.instance().releaseConnection(this._wsConnector) - this._wsConnector = undefined + await WebSocketConnectionPool.instance().releaseConnection( + this._wsConnector + ); + this._wsConnector = undefined; // this._wsConnector.close(); } } checkURL(url: URL) { // Assert is cloud url - if (!url.searchParams.has('token')) { + if (!url.searchParams.has("token")) { if (!(url.username || url.password)) { - throw new WebSocketInterfaceError(ErrorCode.ERR_INVALID_AUTHENTICATION, 'invalid url, password or username needed.'); + throw new WebSocketInterfaceError( + ErrorCode.ERR_INVALID_AUTHENTICATION, + "invalid url, password or username needed." + ); } } } @@ -254,8 +367,13 @@ export class WsClient { this._version = await this.version(); let result = compareVersions(this._version, WsClient._minVersion); if (result < 0) { - logger.error(`TDengine version is too low, current version: ${this._version}, minimum required version: ${WsClient._minVersion}`); - throw(new WebSocketQueryError(ErrorCode.ERR_TDENIGNE_VERSION_IS_TOO_LOW, `Version mismatch. The minimum required TDengine version is ${WsClient._minVersion}`)); + logger.error( + `TDengine version is too low, current version: ${this._version}, minimum required version: ${WsClient._minVersion}` + ); + throw new WebSocketQueryError( + ErrorCode.ERR_TDENIGNE_VERSION_IS_TOO_LOW, + `Version mismatch. The minimum required TDengine version is ${WsClient._minVersion}` + ); } } } diff --git a/nodejs/src/client/wsConnector.ts b/nodejs/src/client/wsConnector.ts index 0af22807..f77fd250 100644 --- a/nodejs/src/client/wsConnector.ts +++ b/nodejs/src/client/wsConnector.ts @@ -1,8 +1,12 @@ -import { ICloseEvent, w3cwebsocket } from 'websocket'; -import { ErrorCode, TDWebSocketClientError, WebSocketQueryError } from '../common/wsError' -import { OnMessageType, WsEventCallback } from './wsEventCallback'; -import logger from '../common/log'; -import { ReqId } from '../common/reqid'; +import { ICloseEvent, w3cwebsocket } from "websocket"; +import { + ErrorCode, + TDWebSocketClientError, + WebSocketQueryError, +} from "../common/wsError"; +import { OnMessageType, WsEventCallback } from "./wsEventCallback"; +import logger from "../common/log"; +import { ReqId } from "../common/reqid"; export class WebSocketConnector { private _wsConn: w3cwebsocket; @@ -10,7 +14,7 @@ export class WebSocketConnector { _timeout = 5000; // create ws - constructor(url: URL, timeout :number | undefined | null) { + constructor(url: URL, timeout: number | undefined | null) { // return w3bsocket3 if (url) { this._wsURL = url; @@ -18,63 +22,106 @@ export class WebSocketConnector { let pathname = url.pathname; let search = url.search; if (timeout) { - this._timeout = timeout + this._timeout = timeout; } - this._wsConn = new w3cwebsocket(origin.concat(pathname).concat(search), undefined, undefined, undefined, undefined, {maxReceivedFrameSize:0x60000000, maxReceivedMessageSize:0x60000000}); - this._wsConn.onerror = function (err: Error) { logger.error(`webSocket connection failed, url: ${this.url}, error: ${err.message}`);} + this._wsConn = new w3cwebsocket( + origin.concat(pathname).concat(search), + undefined, + undefined, + undefined, + undefined, + { + maxReceivedFrameSize: 0x60000000, + maxReceivedMessageSize: 0x60000000, + } + ); + this._wsConn.onerror = function (err: Error) { + logger.error( + `webSocket connection failed, url: ${this.url}, error: ${err.message}` + ); + }; - this._wsConn.onclose = this._onclose + this._wsConn.onclose = this._onclose; - this._wsConn.onmessage = this._onmessage - this._wsConn._binaryType = "arraybuffer" + this._wsConn.onmessage = this._onmessage; + this._wsConn._binaryType = "arraybuffer"; } else { - throw new WebSocketQueryError(ErrorCode.ERR_INVALID_URL, "websocket URL must be defined") + throw new WebSocketQueryError( + ErrorCode.ERR_INVALID_URL, + "websocket URL must be defined" + ); } } async ready() { return new Promise((resolve, reject) => { let reqId = ReqId.getReqID(); - WsEventCallback.instance().registerCallback({ action: "websocket_connection", req_id: BigInt(reqId), - timeout:this._timeout, id: BigInt(reqId)}, resolve, reject); + WsEventCallback.instance().registerCallback( + { + action: "websocket_connection", + req_id: BigInt(reqId), + timeout: this._timeout, + id: BigInt(reqId), + }, + resolve, + reject + ); this._wsConn.onopen = () => { - logger.debug("websocket connection opened") - WsEventCallback.instance().handleEventCallback({id: BigInt(reqId), action:"websocket_connection", req_id:BigInt(reqId)}, - OnMessageType.MESSAGE_TYPE_CONNECTION, this); - } - }) + logger.debug("websocket connection opened"); + WsEventCallback.instance().handleEventCallback( + { + id: BigInt(reqId), + action: "websocket_connection", + req_id: BigInt(reqId), + }, + OnMessageType.MESSAGE_TYPE_CONNECTION, + this + ); + }; + }); } private async _onclose(e: ICloseEvent) { - logger.info("websocket connection closed") + logger.info("websocket connection closed"); } - private _onmessage(event: any) { let data = event.data; - logger.debug("wsClient._onMessage()====" + (Object.prototype.toString.call(data))) - if (Object.prototype.toString.call(data) === '[object ArrayBuffer]') { + logger.debug( + "wsClient._onMessage()====" + Object.prototype.toString.call(data) + ); + if (Object.prototype.toString.call(data) === "[object ArrayBuffer]") { let id = new DataView(data, 26, 8).getBigUint64(0, true); - WsEventCallback.instance().handleEventCallback({id:id, action:'', req_id:BigInt(0)}, - OnMessageType.MESSAGE_TYPE_ARRAYBUFFER, data); - - } else if (Object.prototype.toString.call(data) === '[object String]') { - let msg = JSON.parse(data) + WsEventCallback.instance().handleEventCallback( + { id: id, action: "", req_id: BigInt(0) }, + OnMessageType.MESSAGE_TYPE_ARRAYBUFFER, + data + ); + } else if (Object.prototype.toString.call(data) === "[object String]") { + let msg = JSON.parse(data); logger.debug("[_onmessage.stringType]==>:" + data); - WsEventCallback.instance().handleEventCallback({id:BigInt(0), action:msg.action, req_id:msg.req_id}, - OnMessageType.MESSAGE_TYPE_STRING, msg); + WsEventCallback.instance().handleEventCallback( + { id: BigInt(0), action: msg.action, req_id: msg.req_id }, + OnMessageType.MESSAGE_TYPE_STRING, + msg + ); } else { - throw new TDWebSocketClientError(ErrorCode.ERR_INVALID_MESSAGE_TYPE, `invalid message type ${Object.prototype.toString.call(data)}`); + throw new TDWebSocketClientError( + ErrorCode.ERR_INVALID_MESSAGE_TYPE, + `invalid message type ${Object.prototype.toString.call(data)}` + ); } } close() { if (this._wsConn) { this._wsConn.close(); - } else { - throw new TDWebSocketClientError(ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, "WebSocket connection is undefined.") + throw new TDWebSocketClientError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, + "WebSocket connection is undefined." + ); } } @@ -82,66 +129,104 @@ export class WebSocketConnector { return this._wsConn.readyState; } - async sendMsgNoResp(message: string):Promise { - logger.debug("[wsClient.sendMsgNoResp()]===>" + message) + async sendMsgNoResp(message: string): Promise { + logger.debug("[wsClient.sendMsgNoResp()]===>" + message); let msg = JSON.parse(message); if (msg.args.id !== undefined) { - msg.args.id = BigInt(msg.args.id) + msg.args.id = BigInt(msg.args.id); } return new Promise((resolve, reject) => { - if (this._wsConn && this._wsConn.readyState === w3cwebsocket.OPEN) { - this._wsConn.send(message) - resolve() + if (this._wsConn && this._wsConn.readyState === w3cwebsocket.OPEN) { + this._wsConn.send(message); + resolve(); } else { - reject(new WebSocketQueryError(ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, - `WebSocket connection is not ready,status :${this._wsConn?.readyState}`)) + reject( + new WebSocketQueryError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, + `WebSocket connection is not ready,status :${this._wsConn?.readyState}` + ) + ); } - }) + }); } - async sendMsg(message: string, register: Boolean = true) { - logger.debug("[wsClient.sendMessage()]===>" + message) + logger.debug("[wsClient.sendMessage()]===>" + message); let msg = JSON.parse(message); if (msg.args.id !== undefined) { - msg.args.id = BigInt(msg.args.id) + msg.args.id = BigInt(msg.args.id); } return new Promise((resolve, reject) => { if (this._wsConn && this._wsConn.readyState === w3cwebsocket.OPEN) { if (register) { - WsEventCallback.instance().registerCallback({ action: msg.action, req_id: msg.args.req_id, - timeout:this._timeout, id: msg.args.id === undefined ? msg.args.id : BigInt(msg.args.id) }, - resolve, reject); + WsEventCallback.instance().registerCallback( + { + action: msg.action, + req_id: msg.args.req_id, + timeout: this._timeout, + id: + msg.args.id === undefined + ? msg.args.id + : BigInt(msg.args.id), + }, + resolve, + reject + ); } - logger.debug(`[wsClient.sendMessage.msg]===> ${message}`) - this._wsConn.send(message) + logger.debug(`[wsClient.sendMessage.msg]===> ${message}`); + this._wsConn.send(message); } else { - reject(new WebSocketQueryError(ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, - `WebSocket connection is not ready,status :${this._wsConn?.readyState}`)) + reject( + new WebSocketQueryError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, + `WebSocket connection is not ready,status :${this._wsConn?.readyState}` + ) + ); } - }) + }); } - async sendBinaryMsg(reqId: bigint, action:string, message: ArrayBuffer, register: Boolean = true) { + async sendBinaryMsg( + reqId: bigint, + action: string, + message: ArrayBuffer, + register: Boolean = true + ) { return new Promise((resolve, reject) => { if (this._wsConn && this._wsConn.readyState === w3cwebsocket.OPEN) { if (register) { - WsEventCallback.instance().registerCallback({ action: action, req_id: reqId, - timeout:this._timeout, id: reqId}, resolve, reject); + WsEventCallback.instance().registerCallback( + { + action: action, + req_id: reqId, + timeout: this._timeout, + id: reqId, + }, + resolve, + reject + ); } - logger.debug("[wsClient.sendBinaryMsg()]===>" + reqId + action + message.byteLength) - this._wsConn.send(message) + logger.debug( + "[wsClient.sendBinaryMsg()]===>" + + reqId + + action + + message.byteLength + ); + this._wsConn.send(message); } else { - reject(new WebSocketQueryError(ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, - `WebSocket connection is not ready,status :${this._wsConn?.readyState}`)) + reject( + new WebSocketQueryError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, + `WebSocket connection is not ready,status :${this._wsConn?.readyState}` + ) + ); } - }) + }); } public getWsURL(): URL { return this._wsURL; } } - diff --git a/nodejs/src/client/wsConnectorPool.ts b/nodejs/src/client/wsConnectorPool.ts index 6124993c..b1707e00 100644 --- a/nodejs/src/client/wsConnectorPool.ts +++ b/nodejs/src/client/wsConnectorPool.ts @@ -6,10 +6,8 @@ import { w3cwebsocket } from "websocket"; const mutex = new Mutex(); - - export class WebSocketConnectionPool { - private static _instance?:WebSocketConnectionPool; + private static _instance?: WebSocketConnectionPool; private pool: Map = new Map(); private readonly _maxConnections: number; private static sharedBuffer: SharedArrayBuffer; @@ -18,21 +16,30 @@ export class WebSocketConnectionPool { private constructor(maxConnections: number = -1) { this._maxConnections = maxConnections; WebSocketConnectionPool.sharedBuffer = new SharedArrayBuffer(4); - WebSocketConnectionPool.sharedArray = new Int32Array(WebSocketConnectionPool.sharedBuffer); + WebSocketConnectionPool.sharedArray = new Int32Array( + WebSocketConnectionPool.sharedBuffer + ); Atomics.store(WebSocketConnectionPool.sharedArray, 0, 0); } - public static instance(maxConnections: number = -1):WebSocketConnectionPool { + public static instance( + maxConnections: number = -1 + ): WebSocketConnectionPool { if (!WebSocketConnectionPool._instance) { - WebSocketConnectionPool._instance = new WebSocketConnectionPool(maxConnections); + WebSocketConnectionPool._instance = new WebSocketConnectionPool( + maxConnections + ); } return WebSocketConnectionPool._instance; } - async getConnection(url:URL, timeout: number | undefined | null): Promise { - let connectAddr = url.origin.concat(url.pathname).concat(url.search) - let connector:WebSocketConnector | undefined; - const unlock = await mutex.acquire() + async getConnection( + url: URL, + timeout: number | undefined | null + ): Promise { + let connectAddr = url.origin.concat(url.pathname).concat(url.search); + let connector: WebSocketConnector | undefined; + const unlock = await mutex.acquire(); try { if (this.pool.has(connectAddr)) { const connectors = this.pool.get(connectAddr); @@ -41,58 +48,86 @@ export class WebSocketConnectionPool { if (!candidate) { continue; } - if (candidate && candidate.readyState() === w3cwebsocket.OPEN) { + if ( + candidate && + candidate.readyState() === w3cwebsocket.OPEN + ) { connector = candidate; break; } else if (candidate) { Atomics.add(WebSocketConnectionPool.sharedArray, 0, -1); candidate.close(); - logger.error(`getConnection, current connection status fail, url: ${connectAddr}`) + logger.error( + `getConnection, current connection status fail, url: ${connectAddr}` + ); } } } if (connector) { - logger.debug("get connection success:" + Atomics.load(WebSocketConnectionPool.sharedArray, 0)); + logger.debug( + "get connection success:" + + Atomics.load(WebSocketConnectionPool.sharedArray, 0) + ); return connector; } - if (this._maxConnections != -1 && Atomics.load(WebSocketConnectionPool.sharedArray, 0) > this._maxConnections) { - throw new TDWebSocketClientError(ErrorCode.ERR_WEBSOCKET_CONNECTION_ARRIVED_LIMIT, "websocket connect arrived limited:" + Atomics.load(WebSocketConnectionPool.sharedArray, 0)); + if ( + this._maxConnections != -1 && + Atomics.load(WebSocketConnectionPool.sharedArray, 0) > + this._maxConnections + ) { + throw new TDWebSocketClientError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_ARRIVED_LIMIT, + "websocket connect arrived limited:" + + Atomics.load(WebSocketConnectionPool.sharedArray, 0) + ); } Atomics.add(WebSocketConnectionPool.sharedArray, 0, 1); - logger.info("getConnection, new connection count:" + Atomics.load(WebSocketConnectionPool.sharedArray, 0) + ", connectAddr:" + connectAddr); + logger.info( + "getConnection, new connection count:" + + Atomics.load(WebSocketConnectionPool.sharedArray, 0) + + ", connectAddr:" + + connectAddr + ); return new WebSocketConnector(url, timeout); } finally { unlock(); } } - async releaseConnection(connector: WebSocketConnector):Promise { + async releaseConnection(connector: WebSocketConnector): Promise { if (connector) { const unlock = await mutex.acquire(); try { if (connector.readyState() === w3cwebsocket.OPEN) { let url = connector.getWsURL(); - let connectAddr = url.origin.concat(url.pathname).concat(url.search) + let connectAddr = url.origin + .concat(url.pathname) + .concat(url.search); let connectors = this.pool.get(connectAddr); if (!connectors) { connectors = new Array(); connectors.push(connector); - this.pool.set(connectAddr, connectors); - + this.pool.set(connectAddr, connectors); } else { connectors.push(connector); } - logger.info("releaseConnection, current connection count:" + connectors.length) + logger.info( + "releaseConnection, current connection count:" + + connectors.length + ); } else { Atomics.add(WebSocketConnectionPool.sharedArray, 0, -1); - connector.close() - logger.info("releaseConnection, current connection status fail:" + Atomics.load(WebSocketConnectionPool.sharedArray, 0)) + connector.close(); + logger.info( + "releaseConnection, current connection status fail:" + + Atomics.load(WebSocketConnectionPool.sharedArray, 0) + ); } } finally { unlock(); - } + } } } @@ -100,35 +135,43 @@ export class WebSocketConnectionPool { let num = 0; if (this.pool) { for (let values of this.pool.values()) { - for (let i in values ) { + for (let i in values) { num++; values[i].close(); } } } - logger.info("destroyed connect:" + Atomics.load(WebSocketConnectionPool.sharedArray, 0) + " current count:" + num); + logger.info( + "destroyed connect:" + + Atomics.load(WebSocketConnectionPool.sharedArray, 0) + + " current count:" + + num + ); Atomics.store(WebSocketConnectionPool.sharedArray, 0, 0); - this.pool = new Map() + this.pool = new Map(); } } - -process.on('exit', (code) => { - logger.info("begin destroy connect") - WebSocketConnectionPool.instance().destroyed() - process.exit() +process.on("exit", (code) => { + logger.info("begin destroy connect"); + WebSocketConnectionPool.instance().destroyed(); + process.exit(); }); -process.on('SIGINT', () => { - logger.info('Received SIGINT. Press Control-D to exit, begin destroy connect...'); - WebSocketConnectionPool.instance().destroyed() - process.exit() +process.on("SIGINT", () => { + logger.info( + "Received SIGINT. Press Control-D to exit, begin destroy connect..." + ); + WebSocketConnectionPool.instance().destroyed(); + process.exit(); }); -process.on('SIGTERM', () => { - logger.info('Received SIGINT. Press Control-D to exit, begin destroy connect'); - WebSocketConnectionPool.instance().destroyed() - process.exit() +process.on("SIGTERM", () => { + logger.info( + "Received SIGINT. Press Control-D to exit, begin destroy connect" + ); + WebSocketConnectionPool.instance().destroyed(); + process.exit(); }); -// process.kill(process.pid, 'SIGINT'); \ No newline at end of file +// process.kill(process.pid, 'SIGINT'); diff --git a/nodejs/src/client/wsEventCallback.ts b/nodejs/src/client/wsEventCallback.ts index 355576c3..3b78dc17 100644 --- a/nodejs/src/client/wsEventCallback.ts +++ b/nodejs/src/client/wsEventCallback.ts @@ -1,108 +1,133 @@ import { Mutex } from "async-mutex"; -import { ErrorCode, TDWebSocketClientError, WebSocketQueryError } from "../common/wsError"; +import { + ErrorCode, + TDWebSocketClientError, + WebSocketQueryError, +} from "../common/wsError"; import { MessageResp } from "../common/taosResult"; import logger from "../common/log"; interface MessageId { - action: string, - req_id: bigint, - id?: bigint, - timeout?:number + action: string; + req_id: bigint; + id?: bigint; + timeout?: number; } interface MessageAction { - reject: Function, - resolve: Function, - timer: ReturnType, - sendTime: number, + reject: Function; + resolve: Function; + timer: ReturnType; + sendTime: number; } export enum OnMessageType { MESSAGE_TYPE_ARRAYBUFFER = 1, MESSAGE_TYPE_BLOB = 2, MESSAGE_TYPE_STRING = 3, - MESSAGE_TYPE_CONNECTION = 4 + MESSAGE_TYPE_CONNECTION = 4, } const eventMutex = new Mutex(); export class WsEventCallback { - private static _instance?:WsEventCallback; - private static _msgActionRegister: Map = new Map(); - private constructor() { - } + private static _instance?: WsEventCallback; + private static _msgActionRegister: Map = + new Map(); + private constructor() {} - public static instance():WsEventCallback { + public static instance(): WsEventCallback { if (!WsEventCallback._instance) { WsEventCallback._instance = new WsEventCallback(); } return WsEventCallback._instance; } - async registerCallback(id: MessageId, res: (args: unknown) => void, rej: (reason: any) => void) { - let release = await eventMutex.acquire() + async registerCallback( + id: MessageId, + res: (args: unknown) => void, + rej: (reason: any) => void + ) { + let release = await eventMutex.acquire(); try { - WsEventCallback._msgActionRegister.set(id, - { - sendTime: new Date().getTime(), - reject: rej, - resolve: res, - timer: setTimeout(() => rej(new WebSocketQueryError(ErrorCode.ERR_WEBSOCKET_QUERY_TIMEOUT, - `action:${id.action},req_id:${id.req_id} timeout with ${id.timeout} milliseconds`)), id.timeout) - }); + WsEventCallback._msgActionRegister.set(id, { + sendTime: new Date().getTime(), + reject: rej, + resolve: res, + timer: setTimeout( + () => + rej( + new WebSocketQueryError( + ErrorCode.ERR_WEBSOCKET_QUERY_TIMEOUT, + `action:${id.action},req_id:${id.req_id} timeout with ${id.timeout} milliseconds` + ) + ), + id.timeout + ), + }); } finally { - release() - } + release(); + } } - async handleEventCallback(msg: MessageId, messageType:OnMessageType, data:any) { + async handleEventCallback( + msg: MessageId, + messageType: OnMessageType, + data: any + ) { let action: MessageAction | any = undefined; - let release = await eventMutex.acquire() - logger.debug(`HandleEventCallback get lock msg=${msg}, ${messageType}`) - logger.debug(WsEventCallback._msgActionRegister) + let release = await eventMutex.acquire(); + logger.debug(`HandleEventCallback get lock msg=${msg}, ${messageType}`); + logger.debug(WsEventCallback._msgActionRegister); try { - for (let [k, v] of WsEventCallback._msgActionRegister) { + for (let [k, v] of WsEventCallback._msgActionRegister) { if (messageType == OnMessageType.MESSAGE_TYPE_ARRAYBUFFER) { if (k.id == msg.id || k.req_id == msg.id) { - action = v - WsEventCallback._msgActionRegister.delete(k) + action = v; + WsEventCallback._msgActionRegister.delete(k); break; - } + } } else if (messageType == OnMessageType.MESSAGE_TYPE_BLOB) { if (k.id == msg.id || k.req_id == msg.id) { - action = v - WsEventCallback._msgActionRegister.delete(k) + action = v; + WsEventCallback._msgActionRegister.delete(k); break; - } + } } else if (messageType == OnMessageType.MESSAGE_TYPE_STRING) { if (k.req_id == msg.req_id && k.action == msg.action) { - action = v - WsEventCallback._msgActionRegister.delete(k) + action = v; + WsEventCallback._msgActionRegister.delete(k); break; } - } else if (messageType == OnMessageType.MESSAGE_TYPE_CONNECTION) { + } else if ( + messageType == OnMessageType.MESSAGE_TYPE_CONNECTION + ) { if (k.req_id == msg.req_id && k.action == msg.action) { - action = v - WsEventCallback._msgActionRegister.delete(k) + action = v; + WsEventCallback._msgActionRegister.delete(k); break; } } - } + } } finally { - release() + release(); } if (action) { - let currTime = new Date().getTime() - let resp:MessageResp = { - msg:data, - totalTime:Math.abs(currTime - action.sendTime), + let currTime = new Date().getTime(); + let resp: MessageResp = { + msg: data, + totalTime: Math.abs(currTime - action.sendTime), }; action.resolve(resp); } else { - logger.error("no find callback msg:=", msg) - throw new TDWebSocketClientError(ErrorCode.ERR_WS_NO_CALLBACK, - "no callback registered for fetch_block with req_id=" + msg.req_id + " action" + msg.action); - } + logger.error("no find callback msg:=", msg); + throw new TDWebSocketClientError( + ErrorCode.ERR_WS_NO_CALLBACK, + "no callback registered for fetch_block with req_id=" + + msg.req_id + + " action" + + msg.action + ); + } } - -} \ No newline at end of file +} diff --git a/nodejs/src/client/wsResponse.ts b/nodejs/src/client/wsResponse.ts index c5ebb3ff..78197460 100644 --- a/nodejs/src/client/wsResponse.ts +++ b/nodejs/src/client/wsResponse.ts @@ -10,7 +10,7 @@ export class WSVersionResponse { message: string; action: string; totalTime: number; - constructor(resp:MessageResp) { + constructor(resp: MessageResp) { this.version = resp.msg.version; this.code = resp.msg.code; this.message = resp.msg.message; @@ -36,12 +36,12 @@ export class WSQueryResponse { fields_precisions?: Array | null; fields_scales?: Array | null; precision?: number; - - constructor(resp:MessageResp) { - this.totalTime = resp.totalTime - this.initMsg(resp.msg) + + constructor(resp: MessageResp) { + this.totalTime = resp.totalTime; + this.initMsg(resp.msg); } - private initMsg(msg:any) { + private initMsg(msg: any) { this.code = msg.code; this.message = msg.message; this.action = msg.action; @@ -49,10 +49,10 @@ export class WSQueryResponse { this.timing = BigInt(msg.timing); if (msg.id) { this.id = BigInt(msg.id); - }else{ - this.id = BigInt(0) + } else { + this.id = BigInt(0); } - + this.is_update = msg.is_update; this.affected_rows = msg.affected_rows; this.fields_count = msg.fields_count; @@ -60,53 +60,56 @@ export class WSQueryResponse { this.fields_types = msg.fields_types; this.fields_lengths = msg.fields_lengths; this.precision = msg.precision; - this.fields_precisions = msg.fields_precisions ? msg.fields_precisions.map((p: number) => BigInt(p)) : []; - this.fields_scales = msg.fields_scales ? msg.fields_scales.map((s: number) => BigInt(s)) : []; + this.fields_precisions = msg.fields_precisions + ? msg.fields_precisions.map((p: number) => BigInt(p)) + : []; + this.fields_scales = msg.fields_scales + ? msg.fields_scales.map((s: number) => BigInt(s)) + : []; } } export class WSFetchBlockResponse { - data: DataView | undefined - action: bigint - timing: bigint - reqId: bigint - code: number - blockLen: number - message: string | undefined - resultId: bigint | undefined - finished: number | undefined - metaType: number | undefined - textDecoder: TextDecoder + data: DataView | undefined; + action: bigint; + timing: bigint; + reqId: bigint; + code: number; + blockLen: number; + message: string | undefined; + resultId: bigint | undefined; + finished: number | undefined; + metaType: number | undefined; + textDecoder: TextDecoder; constructor(msg: ArrayBuffer) { let dataView = new DataView(msg); - this.action = dataView.getBigUint64(8, true) - this.timing = dataView.getBigUint64(18, true) - this.reqId = dataView.getBigUint64(26, true) - this.code = dataView.getUint32(34, true) - this.textDecoder = new TextDecoder() + this.action = dataView.getBigUint64(8, true); + this.timing = dataView.getBigUint64(18, true); + this.reqId = dataView.getBigUint64(26, true); + this.code = dataView.getUint32(34, true); + this.textDecoder = new TextDecoder(); this.blockLen = 0; if (this.code != 0) { - let len = dataView.getUint32(38, true) + let len = dataView.getUint32(38, true); this.message = readVarchar(msg, 42, len, this.textDecoder); return; } - this.resultId = dataView.getBigUint64(42, true) - let offset = 50; + this.resultId = dataView.getBigUint64(42, true); + let offset = 50; if (this.action == BigInt(8)) { - this.metaType = dataView.getUint16(50, true) + this.metaType = dataView.getUint16(50, true); offset += 2; - }else { - this.finished = dataView.getUint8(50) + } else { + this.finished = dataView.getUint8(50); if (this.finished == 1) { return; - } + } offset += 1; } - this.blockLen = dataView.getUint32(offset, true) + this.blockLen = dataView.getUint32(offset, true); if (this.blockLen > 0) { this.data = new DataView(msg, offset + 4); - } - + } } } diff --git a/nodejs/src/common/config.ts b/nodejs/src/common/config.ts index 06951d1f..766fa52b 100644 --- a/nodejs/src/common/config.ts +++ b/nodejs/src/common/config.ts @@ -5,14 +5,14 @@ export class WSConfig { private _password: string | undefined | null; private _db: string | undefined | null; private _url: string; - private _timeout:number| undefined | null; - private _token:string | undefined | null; - private _timezone:string | undefined | null; - private _minStmt2Version:string; + private _timeout: number | undefined | null; + private _token: string | undefined | null; + private _timezone: string | undefined | null; + private _minStmt2Version: string; - constructor(url:string, minStmt2Version?:string) { + constructor(url: string, minStmt2Version?: string) { this._url = url; - if (!minStmt2Version){ + if (!minStmt2Version) { this._minStmt2Version = MinStmt2Version; } else { this._minStmt2Version = minStmt2Version; @@ -36,7 +36,7 @@ export class WSConfig { public getPwd(): string | undefined | null { return this._password; } - public setPwd(pws:string) { + public setPwd(pws: string) { this._password = pws; } @@ -54,12 +54,12 @@ export class WSConfig { public setUrl(url: string) { this._url = url; } - - public setTimeOut(ms : number) { - this._timeout = ms + + public setTimeOut(ms: number) { + this._timeout = ms; } public getTimeOut(): number | undefined | null { - return this._timeout + return this._timeout; } public setTimezone(timezone: string) { this._timezone = timezone; @@ -67,7 +67,7 @@ export class WSConfig { public getTimezone(): string | undefined | null { return this._timezone; } - public getMinStmt2Version(){ + public getMinStmt2Version() { return this._minStmt2Version; } } diff --git a/nodejs/src/common/constant.ts b/nodejs/src/common/constant.ts index 3b0f1892..d17b8e70 100644 --- a/nodejs/src/common/constant.ts +++ b/nodejs/src/common/constant.ts @@ -1,47 +1,46 @@ export interface IndexableString { - [index: number]: string + [index: number]: string; } export interface StringIndexable { - [index: string]: number + [index: string]: number; } export interface NumberIndexable { - [index: number]: number + [index: number]: number; } export const BinaryQueryMessage: bigint = BigInt(6); export const FetchRawBlockMessage: bigint = BigInt(7); -export const MinStmt2Version:string = "3.3.6.0"; +export const MinStmt2Version: string = "3.3.6.0"; export const TDengineTypeName: IndexableString = { - 0: 'NULL', - 1: 'BOOL', - 2: 'TINYINT', - 3: 'SMALLINT', - 4: 'INT', - 5: 'BIGINT', - 6: 'FLOAT', - 7: 'DOUBLE', - 8: 'VARCHAR', - 9: 'TIMESTAMP', - 10: 'NCHAR', - 11: 'TINYINT UNSIGNED', - 12: 'SMALLINT UNSIGNED', - 13: 'INT UNSIGNED', - 14: 'BIGINT UNSIGNED', - 15: 'JSON', - 16: 'VARBINARY', - 20: 'GEOMETRY', -} + 0: "NULL", + 1: "BOOL", + 2: "TINYINT", + 3: "SMALLINT", + 4: "INT", + 5: "BIGINT", + 6: "FLOAT", + 7: "DOUBLE", + 8: "VARCHAR", + 9: "TIMESTAMP", + 10: "NCHAR", + 11: "TINYINT UNSIGNED", + 12: "SMALLINT UNSIGNED", + 13: "INT UNSIGNED", + 14: "BIGINT UNSIGNED", + 15: "JSON", + 16: "VARBINARY", + 20: "GEOMETRY", +}; export const ColumnsBlockType: StringIndexable = { - 'SOLID': 0, - 'VARCHAR': 1, - 'NCHAR': 2, - 'GEOMETRY': 3, - 'VARBINARY':4, -} - + SOLID: 0, + VARCHAR: 1, + NCHAR: 2, + GEOMETRY: 3, + VARBINARY: 4, +}; export enum TDengineTypeCode { NULL = 0, @@ -68,10 +67,10 @@ export enum TDengineTypeCode { } export enum TSDB_OPTION_CONNECTION { - TSDB_OPTION_CONNECTION_CHARSET, // charset, Same as the scope supported by the system - TSDB_OPTION_CONNECTION_TIMEZONE, // timezone, Same as the scope supported by the system - TSDB_OPTION_CONNECTION_USER_IP, // user ip - TSDB_OPTION_CONNECTION_USER_APP, // user app + TSDB_OPTION_CONNECTION_CHARSET, // charset, Same as the scope supported by the system + TSDB_OPTION_CONNECTION_TIMEZONE, // timezone, Same as the scope supported by the system + TSDB_OPTION_CONNECTION_USER_IP, // user ip + TSDB_OPTION_CONNECTION_USER_APP, // user app } export enum FieldBindType { @@ -82,10 +81,10 @@ export enum FieldBindType { } export const TDenginePrecision: IndexableString = { - 0: 'MILLISECOND', + 0: "MILLISECOND", 1: "MICROSECOND", 2: "NANOSECOND", -} +}; export const TDengineTypeLength: NumberIndexable = { [TDengineTypeCode.BOOL]: 1, @@ -100,10 +99,10 @@ export const TDengineTypeLength: NumberIndexable = { [TDengineTypeCode.SMALLINT_UNSIGNED]: 2, [TDengineTypeCode.INT_UNSIGNED]: 4, [TDengineTypeCode.BIGINT_UNSIGNED]: 8, -} +}; export const PrecisionLength: StringIndexable = { - 'ms': 13, - 'us': 16, - 'ns': 19 -} + ms: 13, + us: 16, + ns: 19, +}; diff --git a/nodejs/src/common/log.ts b/nodejs/src/common/log.ts index 2308c106..4c879cb2 100644 --- a/nodejs/src/common/log.ts +++ b/nodejs/src/common/log.ts @@ -1,27 +1,33 @@ -import winston from 'winston'; -import DailyRotateFile from 'winston-daily-rotate-file'; +import winston from "winston"; +import DailyRotateFile from "winston-daily-rotate-file"; -const customFormat = winston.format.printf(({ level, message, label, timestamp }) => { - if (message && typeof message === 'object' && typeof (message as any).toJSON === 'function') { - message = (message as any).toJSON(); - } - return `${timestamp} [${label}] ${level}: ${message}`; -}); +const customFormat = winston.format.printf( + ({ level, message, label, timestamp }) => { + if ( + message && + typeof message === "object" && + typeof (message as any).toJSON === "function" + ) { + message = (message as any).toJSON(); + } + return `${timestamp} [${label}] ${level}: ${message}`; + } +); const transport = new DailyRotateFile({ - filename: './logs/app-%DATE%.log', // Here is the file name template - datePattern: 'YYYY-MM-DD', // date format + filename: "./logs/app-%DATE%.log", // Here is the file name template + datePattern: "YYYY-MM-DD", // date format zippedArchive: true, // Whether to compress the archive file into gzip format - maxSize: '20m', // Single file size limit - maxFiles: '14d', // Keep log files for 14 days + maxSize: "20m", // Single file size limit + maxFiles: "14d", // Keep log files for 14 days handleExceptions: true, // Whether to handle exceptions json: false, // Whether to output logs in JSON format format: winston.format.combine( - winston.format.label({ label: 'node.js websocket' }), + winston.format.label({ label: "node.js websocket" }), winston.format.timestamp(), customFormat ), - level: 'info', // set log level + level: "info", // set log level }); const logger = winston.createLogger({ @@ -29,8 +35,8 @@ const logger = winston.createLogger({ exitOnError: false, // Do not exit the process when an error occurs }); -export function setLevel(level:string) { - transport.level = level +export function setLevel(level: string) { + transport.level = level; } export default logger; diff --git a/nodejs/src/common/reqid.ts b/nodejs/src/common/reqid.ts index c03a87d5..87fee60b 100644 --- a/nodejs/src/common/reqid.ts +++ b/nodejs/src/common/reqid.ts @@ -1,61 +1,61 @@ -import { createHash } from 'crypto'; -import { v4 as uuidv4 } from 'uuid'; -import { pid } from 'node:process'; - -function hexStringToNumber(hexString: string): number { - const number = parseInt(hexString, 16); - if (isNaN(number)) { - throw new Error(`number ${hexString} parse int fail!`); - } - return number; +import { createHash } from "crypto"; +import { v4 as uuidv4 } from "uuid"; +import { pid } from "node:process"; + +function hexStringToNumber(hexString: string): number { + const number = parseInt(hexString, 16); + if (isNaN(number)) { + throw new Error(`number ${hexString} parse int fail!`); + } + return number; } -function uuidToHash(): number { - let uuid = uuidv4(); - // create SHA-256 hash - const hash = createHash('sha256'); - - // update hash contact - hash.update(uuid); - - // get hex hash code - const strHex = hash.digest('hex').substring(0, 8); - - let hex = hexStringToNumber(strHex) +function uuidToHash(): number { + let uuid = uuidv4(); + // create SHA-256 hash + const hash = createHash("sha256"); + + // update hash contact + hash.update(uuid); + + // get hex hash code + const strHex = hash.digest("hex").substring(0, 8); + + let hex = hexStringToNumber(strHex); return hex & 0xff; -} +} export class ReqId { private static _uuid = 0; - private static _pid = 0 - private static sharedBuffer = new SharedArrayBuffer(4); - private static int32View = new Int32Array(ReqId.sharedBuffer); + private static _pid = 0; + private static sharedBuffer = new SharedArrayBuffer(4); + private static int32View = new Int32Array(ReqId.sharedBuffer); static { this._uuid = uuidToHash(); if (pid) { - this._pid = pid & 0xf - }else{ + this._pid = pid & 0xf; + } else { this._pid = (Math.floor(Math.random() * 9000) + 1000) & 0xf; } - - Atomics.store(ReqId.int32View, 0, 0); + + Atomics.store(ReqId.int32View, 0, 0); } - public static getReqID(req_id?:number):number { + public static getReqID(req_id?: number): number { if (req_id) { return req_id; } - let no = Atomics.add(ReqId.int32View, 0, 1) + let no = Atomics.add(ReqId.int32View, 0, 1); const buffer = new ArrayBuffer(8); const view = new DataView(buffer); - let ts = new Date().getTime() >> 8 + let ts = new Date().getTime() >> 8; view.setUint8(6, this._uuid >> 4); - view.setUint8(5, (this._uuid & 0x0f) << 4 | this._pid); - view.setUint8(4, ts >> 16 & 0xff); - view.setUint16(2, ts & 0xffff, true); - view.setUint16(0, no & 0xffff, true) - let id = view.getBigInt64(0, true) + view.setUint8(5, ((this._uuid & 0x0f) << 4) | this._pid); + view.setUint8(4, (ts >> 16) & 0xff); + view.setUint16(2, ts & 0xffff, true); + view.setUint16(0, no & 0xffff, true); + let id = view.getBigInt64(0, true); return Number(id); - } -} \ No newline at end of file + } +} diff --git a/nodejs/src/common/taosResult.ts b/nodejs/src/common/taosResult.ts index b65d04c3..388b5927 100644 --- a/nodejs/src/common/taosResult.ts +++ b/nodejs/src/common/taosResult.ts @@ -1,30 +1,38 @@ import { WSFetchBlockResponse, WSQueryResponse } from "../client/wsResponse"; -import { ColumnsBlockType, TDengineTypeCode, TDengineTypeName } from './constant' -import { ErrorCode, TaosResultError, WebSocketQueryInterFaceError } from "./wsError"; -import { appendRune } from "./ut8Helper" +import { + ColumnsBlockType, + TDengineTypeCode, + TDengineTypeName, +} from "./constant"; +import { + ErrorCode, + TaosResultError, + WebSocketQueryInterFaceError, +} from "./wsError"; +import { appendRune } from "./ut8Helper"; import logger from "./log"; import { decimalToString } from "./utils"; import { TMQRawDataSchema } from "../tmq/constant"; export interface TDengineMeta { - name: string, - type: string, - length: number, + name: string; + type: string; + length: number; } interface ResponseMeta { - name: string, - type: number, - length: number, + name: string; + type: number; + length: number; } export interface MessageResp { - totalTime: number, - msg:any, + totalTime: number; + msg: any; } export class TaosResult { - private _topic?: string + private _topic?: string; private _meta: Array | null; private _data: Array> | null; @@ -37,56 +45,61 @@ export class TaosResult { /** unit nano seconds */ private _timing: bigint | null | undefined; constructor(queryResponse?: WSQueryResponse) { - if (queryResponse == null) { - this._meta = [] - this._data = [] - this._timing = BigInt(0) - return + this._meta = []; + this._data = []; + this._timing = BigInt(0); + return; } if (queryResponse.is_update == true) { - this._meta = null - this._data = null + this._meta = null; + this._data = null; } else { - if (queryResponse.fields_count && queryResponse.fields_names && queryResponse.fields_types && queryResponse.fields_lengths) { + if ( + queryResponse.fields_count && + queryResponse.fields_names && + queryResponse.fields_types && + queryResponse.fields_lengths + ) { let _meta = []; for (let i = 0; i < queryResponse.fields_count; i++) { _meta.push({ name: queryResponse.fields_names[i], type: queryResponse.fields_types[i], - length: queryResponse.fields_lengths[i] - }) + length: queryResponse.fields_lengths[i], + }); } this._meta = _meta; } else { - throw new TaosResultError(ErrorCode.ERR_INVALID_FETCH_MESSAGE_DATA, - `fields_count,fields_names,fields_types,fields_lengths of the update query response should be null`) + throw new TaosResultError( + ErrorCode.ERR_INVALID_FETCH_MESSAGE_DATA, + `fields_count,fields_names,fields_types,fields_lengths of the update query response should be null` + ); } this._data = []; } - this._affectRows = queryResponse.affected_rows - this._timing = queryResponse.timing - this._precision = queryResponse.precision - this._totalTime = queryResponse.totalTime - this.fields_precisions = queryResponse.fields_precisions - this.fields_scales = queryResponse.fields_scales + this._affectRows = queryResponse.affected_rows; + this._timing = queryResponse.timing; + this._precision = queryResponse.precision; + this._totalTime = queryResponse.totalTime; + this.fields_precisions = queryResponse.fields_precisions; + this.fields_scales = queryResponse.fields_scales; } public setPrecision(precision: number) { this._precision = precision; } - public setRowsAndTime(rows: number, timing?:bigint) { + public setRowsAndTime(rows: number, timing?: bigint) { if (this._affectRows) { this._affectRows += rows; - }else{ - this._affectRows = rows + } else { + this._affectRows = rows; } if (timing) { - this.setTiming(timing) + this.setTiming(timing); } - } public getTopic(): string { if (this._topic) { @@ -101,7 +114,7 @@ export class TaosResult { return this.getTDengineMeta(); } - public setMeta(metaData: ResponseMeta){ + public setMeta(metaData: ResponseMeta) { if (this._meta) { this._meta.push(metaData); } @@ -121,24 +134,24 @@ export class TaosResult { return this._meta; } - public getPrecision():number | null | undefined { + public getPrecision(): number | null | undefined { return this._precision; } public getTotalTime() { return this._totalTime; } - public addTotalTime(totalTime:number) { + public addTotalTime(totalTime: number) { this._totalTime += totalTime; } public setTiming(timing?: bigint) { if (!this._timing) { - this._timing = BigInt(0) + this._timing = BigInt(0); } if (timing) { - this._timing = this._timing + timing - } + this._timing = this._timing + timing; + } } public getFieldsScales(index: number): bigint | null { @@ -149,42 +162,45 @@ export class TaosResult { } /** - * Mapping the WebSocket response type code to TDengine's type name. + * Mapping the WebSocket response type code to TDengine's type name. */ private getTDengineMeta(): Array | null { if (this._meta) { - let tdMeta = new Array() - this._meta.forEach(m => { + let tdMeta = new Array(); + this._meta.forEach((m) => { tdMeta.push({ name: m.name, type: TDengineTypeName[m.type], - length: m.length - }) - }) + length: m.length, + }); + }); return tdMeta; - } - return null; + } + return null; } } -export function parseBlock(blocks: WSFetchBlockResponse, taosResult: TaosResult): TaosResult { - let metaList = taosResult.getTaosMeta() - let dataList = taosResult.getData() - let textDecoder = new TextDecoder() +export function parseBlock( + blocks: WSFetchBlockResponse, + taosResult: TaosResult +): TaosResult { + let metaList = taosResult.getTaosMeta(); + let dataList = taosResult.getData(); + let textDecoder = new TextDecoder(); if (metaList && dataList && blocks && blocks.data) { let rows = blocks.data.getUint32(8, true); if (rows == 0) { return taosResult; - } + } - taosResult.setTiming(blocks.timing) + taosResult.setTiming(blocks.timing); const INT_32_SIZE = 4; // Offset num of bytes from rawBlockBuffer. - let bufferOffset = (4 * 5) + 8 + (4 + 1) * metaList.length - let colLengthBlockSize = INT_32_SIZE * metaList.length - logger.debug("===colLengthBlockSize:" + colLengthBlockSize) + let bufferOffset = 4 * 5 + 8 + (4 + 1) * metaList.length; + let colLengthBlockSize = INT_32_SIZE * metaList.length; + logger.debug("===colLengthBlockSize:" + colLengthBlockSize); - let bitMapSize = (rows + (1 << 3) - 1) >> 3 + let bitMapSize = (rows + (1 << 3) - 1) >> 3; // whole raw block ArrayBuffer // let dataBuffer = blocks.data.slice(bufferOffset); @@ -198,45 +214,92 @@ export function parseBlock(blocks: WSFetchBlockResponse, taosResult: TaosResult) colBlockHead = 0 + colLengthBlockSize; // point to the head of columns's data in the block (include bitMap and offsetArray) let colDataHead = colBlockHead; - // traverse row after row. + // traverse row after row. for (let j = 0; j < metaList.length; j++) { - - let isVarType = _isVarType(metaList[j].type) + let isVarType = _isVarType(metaList[j].type); if (isVarType == ColumnsBlockType.SOLID) { - - colDataHead = colBlockHead + bitMapSize + metaList[j].length * i + colDataHead = + colBlockHead + bitMapSize + metaList[j].length * i; let byteArrayIndex = i >> 3; - let bitwiseOffset = 7 - (i & 7) + let bitwiseOffset = 7 - (i & 7); // let bitMapArr = dataBuffer.slice(colBlockHead, colBlockHead + bitMapSize) - let bitMapArr = new DataView(dataView.buffer, dataView.byteOffset + colBlockHead, bitMapSize); - let bitFlag = (bitMapArr.getUint8(byteArrayIndex) & (1 << bitwiseOffset)) >> bitwiseOffset + let bitMapArr = new DataView( + dataView.buffer, + dataView.byteOffset + colBlockHead, + bitMapSize + ); + let bitFlag = + (bitMapArr.getUint8(byteArrayIndex) & + (1 << bitwiseOffset)) >> + bitwiseOffset; if (bitFlag == 1) { - row.push("NULL") + row.push("NULL"); } else { - row.push(readSolidData(dataView, colDataHead, metaList[j], taosResult.getFieldsScales(j))); + row.push( + readSolidData( + dataView, + colDataHead, + metaList[j], + taosResult.getFieldsScales(j) + ) + ); } - - colBlockHead = colBlockHead + bitMapSize + dataView.getInt32(INT_32_SIZE * j, true) + colBlockHead = + colBlockHead + + bitMapSize + + dataView.getInt32(INT_32_SIZE * j, true); } else { // if null check - let varOffset = dataView.getInt32(colBlockHead + (INT_32_SIZE * i), true) + let varOffset = dataView.getInt32( + colBlockHead + INT_32_SIZE * i, + true + ); if (varOffset == -1) { - row.push("NULL") - colBlockHead = colBlockHead + INT_32_SIZE * rows + dataView.getInt32(j * INT_32_SIZE, true); + row.push("NULL"); + colBlockHead = + colBlockHead + + INT_32_SIZE * rows + + dataView.getInt32(j * INT_32_SIZE, true); } else { - colDataHead = colBlockHead + INT_32_SIZE * rows + varOffset + colDataHead = + colBlockHead + INT_32_SIZE * rows + varOffset; let dataLength = dataView.getInt16(colDataHead, true); if (isVarType == ColumnsBlockType.VARCHAR) { - row.push(readVarchar(dataView.buffer, dataView.byteOffset + colDataHead + 2, dataLength, textDecoder)) - } else if(isVarType == ColumnsBlockType.GEOMETRY || isVarType == ColumnsBlockType.VARBINARY) { - row.push(readBinary(dataView.buffer, dataView.byteOffset + colDataHead + 2, dataLength)) + row.push( + readVarchar( + dataView.buffer, + dataView.byteOffset + colDataHead + 2, + dataLength, + textDecoder + ) + ); + } else if ( + isVarType == ColumnsBlockType.GEOMETRY || + isVarType == ColumnsBlockType.VARBINARY + ) { + row.push( + readBinary( + dataView.buffer, + dataView.byteOffset + colDataHead + 2, + dataLength + ) + ); } else { - row.push(readNchar(dataView.buffer, dataView.byteOffset+ colDataHead + 2, dataLength)) + row.push( + readNchar( + dataView.buffer, + dataView.byteOffset + colDataHead + 2, + dataLength + ) + ); } - colBlockHead = colBlockHead + INT_32_SIZE * rows + dataView.getInt32(j * INT_32_SIZE, true); + colBlockHead = + colBlockHead + + INT_32_SIZE * rows + + dataView.getInt32(j * INT_32_SIZE, true); } } } @@ -244,140 +307,156 @@ export function parseBlock(blocks: WSFetchBlockResponse, taosResult: TaosResult) } return taosResult; } else { - throw new TaosResultError(ErrorCode.ERR_INVALID_FETCH_MESSAGE_DATA , - "cannot fetch block for an update query.") + throw new TaosResultError( + ErrorCode.ERR_INVALID_FETCH_MESSAGE_DATA, + "cannot fetch block for an update query." + ); } } export function _isVarType(metaType: number): Number { switch (metaType) { case TDengineTypeCode.NCHAR: { - return ColumnsBlockType['NCHAR'] + return ColumnsBlockType["NCHAR"]; } case TDengineTypeCode.VARCHAR: { - return ColumnsBlockType['VARCHAR'] + return ColumnsBlockType["VARCHAR"]; } case TDengineTypeCode.BINARY: { - return ColumnsBlockType['VARCHAR'] + return ColumnsBlockType["VARCHAR"]; } case TDengineTypeCode.JSON: { - return ColumnsBlockType['VARCHAR'] + return ColumnsBlockType["VARCHAR"]; } case TDengineTypeCode.GEOMETRY: { - return ColumnsBlockType['GEOMETRY'] + return ColumnsBlockType["GEOMETRY"]; } case TDengineTypeCode.VARBINARY: { - return ColumnsBlockType.VARBINARY + return ColumnsBlockType.VARBINARY; } default: { - return ColumnsBlockType['SOLID'] + return ColumnsBlockType["SOLID"]; } } } -export function readSolidDataToArray(dataBuffer: DataView, colBlockHead:number, - rows:number, metaType: number, bitMapArr: Uint8Array, startOffset: number, colIndex: number): any[] { - - let result:any[] = [] +export function readSolidDataToArray( + dataBuffer: DataView, + colBlockHead: number, + rows: number, + metaType: number, + bitMapArr: Uint8Array, + startOffset: number, + colIndex: number +): any[] { + let result: any[] = []; switch (metaType) { case TDengineTypeCode.BOOL: case TDengineTypeCode.TINYINT: - case TDengineTypeCode.TINYINT_UNSIGNED:{ + case TDengineTypeCode.TINYINT_UNSIGNED: { for (let i = 0; i < rows; i++, colBlockHead++) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ + } else { result.push(dataBuffer.getInt8(colBlockHead)); } - } break; } case TDengineTypeCode.SMALLINT: { - for (let i = 0; i < rows; i++, colBlockHead+=2) { + for (let i = 0; i < rows; i++, colBlockHead += 2) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ + } else { result.push(dataBuffer.getInt16(colBlockHead, true)); } } break; } case TDengineTypeCode.INT: { - for (let i = 0; i < rows; i++, colBlockHead+=4) { + for (let i = 0; i < rows; i++, colBlockHead += 4) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ + } else { result.push(dataBuffer.getInt32(colBlockHead, true)); } } break; } case TDengineTypeCode.BIGINT: { - for (let i = 0; i < rows; i++, colBlockHead+=8) { + for (let i = 0; i < rows; i++, colBlockHead += 8) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ + } else { result.push(dataBuffer.getBigInt64(colBlockHead, true)); } } break; } case TDengineTypeCode.SMALLINT_UNSIGNED: { - for (let i = 0; i < rows; i++, colBlockHead+=2) { + for (let i = 0; i < rows; i++, colBlockHead += 2) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ + } else { result.push(dataBuffer.getUint16(colBlockHead, true)); } } break; } case TDengineTypeCode.INT_UNSIGNED: { - for (let i = 0; i < rows; i++, colBlockHead+=4) { + for (let i = 0; i < rows; i++, colBlockHead += 4) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ + } else { result.push(dataBuffer.getUint32(colBlockHead, true)); } } break; } case TDengineTypeCode.BIGINT_UNSIGNED: { - for (let i = 0; i < rows; i++, colBlockHead+=8) { + for (let i = 0; i < rows; i++, colBlockHead += 8) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ + } else { result.push(dataBuffer.getBigUint64(colBlockHead, true)); } } break; } case TDengineTypeCode.FLOAT: { - for (let i = 0; i < rows; i++, colBlockHead+=4) { + for (let i = 0; i < rows; i++, colBlockHead += 4) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ - result.push(parseFloat(dataBuffer.getFloat32(colBlockHead, true).toFixed(5))); + } else { + result.push( + parseFloat( + dataBuffer.getFloat32(colBlockHead, true).toFixed(5) + ) + ); } } - break; + break; } case TDengineTypeCode.DOUBLE: { - for (let i = 0; i < rows; i++, colBlockHead += 8) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ - result.push(parseFloat(dataBuffer.getFloat64(colBlockHead, true).toFixed(15))); + } else { + result.push( + parseFloat( + dataBuffer + .getFloat64(colBlockHead, true) + .toFixed(15) + ) + ); } } - break; + break; } case TDengineTypeCode.TIMESTAMP: { for (let i = 0; i < rows; i++, colBlockHead += 8) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ + } else { result.push(dataBuffer.getBigInt64(colBlockHead, true)); } } @@ -388,9 +467,11 @@ export function readSolidDataToArray(dataBuffer: DataView, colBlockHead:number, for (let i = 0; i < rows; i++, colBlockHead += 8) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ - let decimalVal = dataBuffer.getBigInt64(colBlockHead, true) - result.push(decimalToString(decimalVal.toString(), BigInt(scale))); + } else { + let decimalVal = dataBuffer.getBigInt64(colBlockHead, true); + result.push( + decimalToString(decimalVal.toString(), BigInt(scale)) + ); } } break; @@ -400,27 +481,45 @@ export function readSolidDataToArray(dataBuffer: DataView, colBlockHead:number, for (let i = 0; i < rows; i++, colBlockHead += 16) { if (isNull(bitMapArr, i)) { result.push(null); - }else{ - let decimalHighPart = dataBuffer.getBigInt64(colBlockHead + 8, true); - const decimalLowPart = dataBuffer.getBigUint64(colBlockHead, true); - const decimalCombined = (decimalHighPart << 64n) | decimalLowPart; - result.push(decimalToString(decimalCombined.toString(), BigInt(scale))); + } else { + let decimalHighPart = dataBuffer.getBigInt64( + colBlockHead + 8, + true + ); + const decimalLowPart = dataBuffer.getBigUint64( + colBlockHead, + true + ); + const decimalCombined = + (decimalHighPart << 64n) | decimalLowPart; + result.push( + decimalToString( + decimalCombined.toString(), + BigInt(scale) + ) + ); } } break; } default: { - throw new WebSocketQueryInterFaceError(ErrorCode.ERR_UNSUPPORTED_TDENGINE_TYPE, `unsupported type ${metaType}`) + throw new WebSocketQueryInterFaceError( + ErrorCode.ERR_UNSUPPORTED_TDENGINE_TYPE, + `unsupported type ${metaType}` + ); } } return result; - } -export function readSolidData(dataBuffer: DataView, colDataHead: number, meta: ResponseMeta, fields_scale: bigint | null): Number | Boolean | BigInt | string { - +export function readSolidData( + dataBuffer: DataView, + colDataHead: number, + meta: ResponseMeta, + fields_scale: bigint | null +): Number | Boolean | BigInt | string { switch (meta.type) { case TDengineTypeCode.BOOL: { - return (Boolean)(dataBuffer.getInt8(colDataHead)); + return Boolean(dataBuffer.getInt8(colDataHead)); } case TDengineTypeCode.TINYINT: { return dataBuffer.getInt8(colDataHead); @@ -447,18 +546,22 @@ export function readSolidData(dataBuffer: DataView, colDataHead: number, meta: R return dataBuffer.getBigUint64(colDataHead, true); } case TDengineTypeCode.FLOAT: { - return parseFloat(dataBuffer.getFloat32(colDataHead, true).toFixed(5)); + return parseFloat( + dataBuffer.getFloat32(colDataHead, true).toFixed(5) + ); } case TDengineTypeCode.DOUBLE: { - return parseFloat(dataBuffer.getFloat64(colDataHead, true).toFixed(15)); + return parseFloat( + dataBuffer.getFloat64(colDataHead, true).toFixed(15) + ); } case TDengineTypeCode.TIMESTAMP: { return dataBuffer.getBigInt64(colDataHead, true); - // could change + // could change } case TDengineTypeCode.DECIMAL: { let decimalHighPart = dataBuffer.getBigInt64(colDataHead + 8, true); - const decimalLowPart = dataBuffer.getBigUint64(colDataHead, true); + const decimalLowPart = dataBuffer.getBigUint64(colDataHead, true); const decimalCombined = (decimalHighPart << 64n) | decimalLowPart; return decimalToString(decimalCombined.toString(), fields_scale); } @@ -467,75 +570,101 @@ export function readSolidData(dataBuffer: DataView, colDataHead: number, meta: R return decimalToString(decimalVal.toString(), fields_scale); } default: { - throw new WebSocketQueryInterFaceError(ErrorCode.ERR_UNSUPPORTED_TDENGINE_TYPE, `unsupported type ${meta.type} for column ${meta.name}`) + throw new WebSocketQueryInterFaceError( + ErrorCode.ERR_UNSUPPORTED_TDENGINE_TYPE, + `unsupported type ${meta.type} for column ${meta.name}` + ); } } } -export function readBinary(dataBuffer: ArrayBuffer, colDataHead: number, length: number): ArrayBuffer { - let buff = dataBuffer.slice(colDataHead, colDataHead + length) - return buff +export function readBinary( + dataBuffer: ArrayBuffer, + colDataHead: number, + length: number +): ArrayBuffer { + let buff = dataBuffer.slice(colDataHead, colDataHead + length); + return buff; } -export function readVarchar(dataBuffer: ArrayBuffer, colDataHead: number, length: number, textDecoder: TextDecoder): string { +export function readVarchar( + dataBuffer: ArrayBuffer, + colDataHead: number, + length: number, + textDecoder: TextDecoder +): string { // let buff = dataBuffer.slice(colDataHead, colDataHead + length) let dataView = new DataView(dataBuffer, colDataHead, length); return textDecoder.decode(dataView); } -export function readNchar(dataBuffer: ArrayBuffer, colDataHead: number, length: number): string { +export function readNchar( + dataBuffer: ArrayBuffer, + colDataHead: number, + length: number +): string { let data: string[] = []; // let buff: ArrayBuffer = dataBuffer.slice(colDataHead, colDataHead + length); let dataView = new DataView(dataBuffer, colDataHead, length); for (let i = 0; i < length / 4; i++) { data.push(appendRune(dataView.getUint32(i * 4, true))); - } - return data.join(''); + return data.join(""); } -export function getString(dataBuffer: DataView, colDataHead: number, length: number, textDecoder: TextDecoder): string { +export function getString( + dataBuffer: DataView, + colDataHead: number, + length: number, + textDecoder: TextDecoder +): string { // let buff = dataBuffer.slice(colDataHead, colDataHead + length - 1) - let dataView = new Uint8Array(dataBuffer.buffer, dataBuffer.byteOffset + colDataHead, length - 1); + let dataView = new Uint8Array( + dataBuffer.buffer, + dataBuffer.byteOffset + colDataHead, + length - 1 + ); return textDecoder.decode(dataView); } function iteratorBuff(arr: ArrayBuffer) { let buf = Buffer.from(arr); for (const value of buf) { - logger.debug(value.toString()) + logger.debug(value.toString()); } - } -function isNull(bitMapArr:ArrayBuffer, n:number) { +function isNull(bitMapArr: ArrayBuffer, n: number) { let c = new Uint8Array(bitMapArr); let position = n >>> 3; let index = n & 0x7; - return (c[position] & (1 << (7 - index))) == (1 << (7 - index)); + return (c[position] & (1 << (7 - index))) == 1 << (7 - index); } - -export function getCharOffset(n:number):number { - return n >> 3 +export function getCharOffset(n: number): number { + return n >> 3; } -export function setBitmapNull(c:number, n:number):number { - return c + (1 << (7 - bitPos(n))) +export function setBitmapNull(c: number, n: number): number { + return c + (1 << (7 - bitPos(n))); } -function bitPos(n:number):number { - return n & ((1 << 3) - 1) +function bitPos(n: number): number { + return n & ((1 << 3) - 1); } export function bitmapLen(n: number): number { - return ((n) + ((1 << 3) - 1)) >> 3 + return (n + ((1 << 3) - 1)) >> 3; } -function getScaleFromRowBlock(buffer: DataView, colIndex: number, startOffset: number): number { +function getScaleFromRowBlock( + buffer: DataView, + colIndex: number, + startOffset: number +): number { // for decimal: |___bytes___|__empty__|___prec___|__scale___| let backupPos = buffer.byteOffset + startOffset + 28 + colIndex * 5 + 1; let scaleBuffer = new DataView(buffer.buffer, backupPos); let scale = scaleBuffer.getInt32(0, true); - return scale & 0xFF; -} \ No newline at end of file + return scale & 0xff; +} diff --git a/nodejs/src/common/ut8Helper.ts b/nodejs/src/common/ut8Helper.ts index 18f3c364..430cc2ff 100644 --- a/nodejs/src/common/ut8Helper.ts +++ b/nodejs/src/common/ut8Helper.ts @@ -1,11 +1,11 @@ // Numbers fundamental to the encoding. // the "error" Rune or "Unicode replacement character" -const RuneError = '\uFFFD' +const RuneError = "\uFFFD"; // Maximum valid Unicode code point. -const MaxRune = '\U0010FFFF' +const MaxRune = "U0010FFFF"; // Code points in the surrogate range are not valid for UTF-8. -const surrogateMin = 0xD800 -const surrogateMax = 0xDFFF +const surrogateMin = 0xd800; +const surrogateMax = 0xdfff; const tx = 128; const t2 = 192; const t3 = 224; @@ -16,25 +16,33 @@ const rune1Max = (1 << 7) - 1; const rune2Max = (1 << 11) - 1; const rune3Max = (1 << 16) - 1; - // AppendRune appends the UTF-8 encoding of r to the end of p and // returns the extended buffer. If the rune is out of range, // it appends the encoding of RuneError. -export function appendRune(r:any) { - let p:Array = []; +export function appendRune(r: any) { + let p: Array = []; if (r <= rune1Max) { - p.push(r & 0xff); + p.push(r & 0xff); return Buffer.from(p).toString(); } if (r <= rune2Max) { - p.push(t2 | ((r >> 6) & 0xff), tx | (r & 0xff) & maskx) - } else if ((r > MaxRune) || (surrogateMax <= r && r <= surrogateMax)) { - p.push(RuneError) + p.push(t2 | ((r >> 6) & 0xff), tx | (r & 0xff & maskx)); + } else if (r > MaxRune || (surrogateMax <= r && r <= surrogateMax)) { + p.push(RuneError); } else if (r <= rune3Max) { - p.push(t3 | ((r >> 12) & 0xff), tx | ((r >> 6) & 0xff) & maskx, tx | (r & 0xff) & maskx) + p.push( + t3 | ((r >> 12) & 0xff), + tx | ((r >> 6) & 0xff & maskx), + tx | (r & 0xff & maskx) + ); } else { - p.push(t4 | ((r >> 18) & 0xff), tx | ((r >> 12) & 0xff) & maskx, tx | ((r >> 6) & 0xff) & maskx, tx | (r & 0xff) & maskx) + p.push( + t4 | ((r >> 18) & 0xff), + tx | ((r >> 12) & 0xff & maskx), + tx | ((r >> 6) & 0xff & maskx), + tx | (r & 0xff & maskx) + ); } return Buffer.from(p).toString(); -} \ No newline at end of file +} diff --git a/nodejs/src/common/utils.ts b/nodejs/src/common/utils.ts index e8ace1c1..57146c22 100644 --- a/nodejs/src/common/utils.ts +++ b/nodejs/src/common/utils.ts @@ -1,49 +1,53 @@ import { WSConfig } from "./config"; import { ErrorCode, TDWebSocketClientError } from "./wsError"; -export function getUrl(wsConfig:WSConfig):URL { - let url = new URL(wsConfig.getUrl()) +export function getUrl(wsConfig: WSConfig): URL { + let url = new URL(wsConfig.getUrl()); if (wsConfig.getUser()) { - url.username = wsConfig.getUser() || '' + url.username = wsConfig.getUser() || ""; } if (wsConfig.getPwd()) { - url.password = wsConfig.getPwd() || '' + url.password = wsConfig.getPwd() || ""; } - let token = wsConfig.getToken() + let token = wsConfig.getToken(); if (token) { - url.searchParams.set("token", token) + url.searchParams.set("token", token); } - let timezone = wsConfig.getTimezone() + let timezone = wsConfig.getTimezone(); if (timezone) { - url.searchParams.set("timezone", timezone) + url.searchParams.set("timezone", timezone); } - if (url.pathname && url.pathname !== '/') { - wsConfig.setDb(url.pathname.slice(1)) + if (url.pathname && url.pathname !== "/") { + wsConfig.setDb(url.pathname.slice(1)); } if (url.searchParams.has("timezone")) { - wsConfig.setTimezone(url.searchParams.get("timezone") || ''); + wsConfig.setTimezone(url.searchParams.get("timezone") || ""); } - url.pathname = '/ws' - return url + url.pathname = "/ws"; + return url; } - -export function isEmpty(value: any): boolean { - if (value === null || value === undefined) return true; - // if (typeof value === 'string' && value.trim() === '') return true; - if (Array.isArray(value) && value.length === 0) return true; - // if (typeof value === 'object' && Object.keys(value).length === 0) return true; - return false; +export function isEmpty(value: any): boolean { + if (value === null || value === undefined) return true; + // if (typeof value === 'string' && value.trim() === '') return true; + if (Array.isArray(value) && value.length === 0) return true; + // if (typeof value === 'object' && Object.keys(value).length === 0) return true; + return false; } -export function getBinarySql(action:bigint, reqId:bigint, resultId:bigint, sql?:string): ArrayBuffer{ +export function getBinarySql( + action: bigint, + reqId: bigint, + resultId: bigint, + sql?: string +): ArrayBuffer { // construct msg - + if (sql) { const encoder = new TextEncoder(); const buffer = encoder.encode(sql); @@ -60,8 +64,8 @@ export function getBinarySql(action:bigint, reqId:bigint, resultId:bigint, sql?: sqlView.setUint8(offset + i, buffer[i]); } return sqlBuffer; - } - + } + let messageLen = 26; let sqlBuffer = new ArrayBuffer(messageLen); let sqlView = new DataView(sqlBuffer); @@ -73,16 +77,19 @@ export function getBinarySql(action:bigint, reqId:bigint, resultId:bigint, sql?: } export function zigzagDecode(n: number): number { - return (n >> 1) ^ (-(n & 1)) + return (n >> 1) ^ -(n & 1); } export function safeDecodeURIComponent(str: string) { // Replace invalid "%" not followed by two hex characters with "%25" - const cleaned = str.replace(/%(?![0-9A-Fa-f]{2})/g, '%25'); + const cleaned = str.replace(/%(?![0-9A-Fa-f]{2})/g, "%25"); try { return decodeURIComponent(cleaned); } catch (e) { - throw(new TDWebSocketClientError(ErrorCode.ERR_INVALID_URL, `Decoding ${str} error: ${e}`)) + throw new TDWebSocketClientError( + ErrorCode.ERR_INVALID_URL, + `Decoding ${str} error: ${e}` + ); } } @@ -90,89 +97,93 @@ export function safeDecodeURIComponent(str: string) { * compare two semantic version numbers * @param v1 (e.g., "3.3.6.3-alpha") * @param v2 (e.g., "3.3.6.2") - * @returns + * @returns * 1 -> v1 > v2 * -1 -> v1 < v2 * 0 -> v1 === v2 */ export function compareVersions(v1: string, v2: string): number { - // analyze the core part of the version number and pre release tags - const [main1, pre1] = splitVersion(v1); - const [main2, pre2] = splitVersion(v2); + // analyze the core part of the version number and pre release tags + const [main1, pre1] = splitVersion(v1); + const [main2, pre2] = splitVersion(v2); - // compare the main version number section - const mainComparison = compareMainVersions(main1, main2); - if (mainComparison !== 0) return mainComparison; + // compare the main version number section + const mainComparison = compareMainVersions(main1, main2); + if (mainComparison !== 0) return mainComparison; - // comparing pre release tags with the same main version - return comparePreReleases(pre1, pre2); + // comparing pre release tags with the same main version + return comparePreReleases(pre1, pre2); } /** * Split version number into main version and pre release tags */ function splitVersion(version: string): [number[], string | null] { - // split main version and pre release tags - const parts = version.split('-'); - const main = parts[0]; - const prerelease = parts.length > 1 ? parts[1] : null; - - // split the main version into a numerical array - const mainParts = main.split('.').map(Number); - - return [mainParts, prerelease]; + // split main version and pre release tags + const parts = version.split("-"); + const main = parts[0]; + const prerelease = parts.length > 1 ? parts[1] : null; + + // split the main version into a numerical array + const mainParts = main.split(".").map(Number); + + return [mainParts, prerelease]; } /** * compare the main version number section */ function compareMainVersions(v1: number[], v2: number[]): number { - const maxLength = Math.max(v1.length, v2.length); - - for (let i = 0; i < maxLength; i++) { - // if partially missing, it is considered as 0 - const part1 = v1[i] || 0; - const part2 = v2[i] || 0; - - if (part1 > part2) return 1; - if (part1 < part2) return -1; - } - - return 0; + const maxLength = Math.max(v1.length, v2.length); + + for (let i = 0; i < maxLength; i++) { + // if partially missing, it is considered as 0 + const part1 = v1[i] || 0; + const part2 = v2[i] || 0; + + if (part1 > part2) return 1; + if (part1 < part2) return -1; + } + + return 0; } /** * compare pre release tags */ function comparePreReleases(pre1: string | null, pre2: string | null): number { - // both have no pre release tags → equal - if (pre1 === null && pre2 === null) return 0; + // both have no pre release tags → equal + if (pre1 === null && pre2 === null) return 0; - // versions with pre release tags have lower priority - if (pre1 === null) return 1; // v1 is stable > v2 - if (pre2 === null) return -1; // v2 is stable > v1 + // versions with pre release tags have lower priority + if (pre1 === null) return 1; // v1 is stable > v2 + if (pre2 === null) return -1; // v2 is stable > v1 - // compare pre release tag strings - return pre1.localeCompare(pre2); + // compare pre release tag strings + return pre1.localeCompare(pre2); } -export function decimalToString(valueStr: string, fields_scale: bigint | null): string { +export function decimalToString( + valueStr: string, + fields_scale: bigint | null +): string { let decimalStr = valueStr; if (fields_scale && fields_scale > 0) { const scale = Number(fields_scale); - const isNegative = decimalStr.startsWith('-'); + const isNegative = decimalStr.startsWith("-"); const absStr = isNegative ? decimalStr.slice(1) : decimalStr; - + if (absStr.length <= scale) { // If the length of the number is less than or equal to the precision, add 0 before it. - const paddedStr = absStr.padStart(scale + 1, '0'); - decimalStr = (isNegative ? '-' : '') + '0.' + paddedStr.slice(1); + const paddedStr = absStr.padStart(scale + 1, "0"); + decimalStr = (isNegative ? "-" : "") + "0." + paddedStr.slice(1); } else { // 在指定位置插入小数点 const integerPart = absStr.slice(0, absStr.length - scale); const decimalPart = absStr.slice(absStr.length - scale); - decimalStr = (isNegative ? '-' : '') + integerPart + '.' + decimalPart; + decimalStr = + (isNegative ? "-" : "") + integerPart + "." + decimalPart; } } return decimalStr; -} \ No newline at end of file +} diff --git a/nodejs/src/common/wsError.ts b/nodejs/src/common/wsError.ts index 358a3b91..56fe15a1 100644 --- a/nodejs/src/common/wsError.ts +++ b/nodejs/src/common/wsError.ts @@ -1,24 +1,24 @@ export class TDWebSocketClientError extends Error { - code:number = 0; - constructor(code:number, message: string = '') { + code: number = 0; + constructor(code: number, message: string = "") { super(message); this.name = new.target.name; - this.code = code - if (typeof (Error as any).captureStackTrace === 'function') { + this.code = code; + if (typeof (Error as any).captureStackTrace === "function") { (Error as any).captureStackTrace(this, new.target); } - if (typeof Object.setPrototypeOf === 'function') { + if (typeof Object.setPrototypeOf === "function") { Object.setPrototypeOf(this, new.target.prototype); } else { (this as any).__proto__ = new.target.prototype; } } } -export class WebSocketQueryError extends TDWebSocketClientError { } +export class WebSocketQueryError extends TDWebSocketClientError {} export class WebSocketInterfaceError extends TDWebSocketClientError {} -export class WebSocketQueryInterFaceError extends WebSocketInterfaceError{} -export class TaosResultError extends TDWebSocketClientError{} -export class TaosError extends TDWebSocketClientError{} +export class WebSocketQueryInterFaceError extends WebSocketInterfaceError {} +export class TaosResultError extends TDWebSocketClientError {} +export class TaosError extends TDWebSocketClientError {} export enum ErrorCode { ERR_INVALID_PARAMS = 100, @@ -35,4 +35,3 @@ export enum ErrorCode { ERR_PARTITIONS_TOPIC_VGROUP_LENGTH_NOT_EQUAL = 111, ERR_TDENIGNE_VERSION_IS_TOO_LOW = 112, } - diff --git a/nodejs/src/common/wsOptions.ts b/nodejs/src/common/wsOptions.ts index b29fbe51..1d9f5f32 100644 --- a/nodejs/src/common/wsOptions.ts +++ b/nodejs/src/common/wsOptions.ts @@ -7,7 +7,7 @@ export interface Uri { scheme: string; url?: string; host?: string | undefined | null; - path: '/rest/sql/' | string; + path: "/rest/sql/" | string; port?: number | undefined | null; query?: { [key: string]: string }; fragment?: string | undefined | null; diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 9950cb4e..62cd82fe 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -1,9 +1,9 @@ -import { WsSql } from './sql/wsSql' -import { WSConfig } from './common/config'; -import { WsConsumer } from './tmq/wsTmq'; -import logger, { setLevel } from "./common/log" +import { WsSql } from "./sql/wsSql"; +import { WSConfig } from "./common/config"; +import { WsConsumer } from "./tmq/wsTmq"; +import logger, { setLevel } from "./common/log"; -import { WebSocketConnectionPool } from './client/wsConnectorPool'; +import { WebSocketConnectionPool } from "./client/wsConnectorPool"; let sqlConnect = async (conf: WSConfig) => { try { @@ -12,7 +12,6 @@ let sqlConnect = async (conf: WSConfig) => { logger.error(err); throw err; } - }; let tmqConnect = async (configMap: Map) => { @@ -25,10 +24,10 @@ let tmqConnect = async (configMap: Map) => { }; let setLogLevel = (level: string) => { - setLevel(level) + setLevel(level); }; let destroy = () => { - WebSocketConnectionPool.instance().destroyed() + WebSocketConnectionPool.instance().destroyed(); }; export { sqlConnect, tmqConnect, setLogLevel, destroy }; diff --git a/nodejs/src/sql/wsProto.ts b/nodejs/src/sql/wsProto.ts index 557a7c94..74cc49b5 100644 --- a/nodejs/src/sql/wsProto.ts +++ b/nodejs/src/sql/wsProto.ts @@ -12,17 +12,17 @@ export interface SchemalessParamsInfo { } export enum Precision { - NOT_CONFIGURED = '', - HOURS = 'h', - MINUTES = 'm', - SECONDS = 's', - MILLI_SECONDS = 'ms', - MICRO_SECONDS = 'u', - NANO_SECONDS = 'ns', + NOT_CONFIGURED = "", + HOURS = "h", + MINUTES = "m", + SECONDS = "s", + MILLI_SECONDS = "ms", + MICRO_SECONDS = "u", + NANO_SECONDS = "ns", } export enum SchemalessProto { - InfluxDBLineProtocol = 1, + InfluxDBLineProtocol = 1, OpenTSDBTelnetLineProtocol = 2, - OpenTSDBJsonFormatProtocol = 3 -} \ No newline at end of file + OpenTSDBJsonFormatProtocol = 3, +} diff --git a/nodejs/src/sql/wsRows.ts b/nodejs/src/sql/wsRows.ts index a606ada1..a3dd260d 100644 --- a/nodejs/src/sql/wsRows.ts +++ b/nodejs/src/sql/wsRows.ts @@ -1,34 +1,40 @@ -import { TDengineMeta, TaosResult, parseBlock } from '../common/taosResult'; -import { TaosResultError } from '../common/wsError'; -import { WSFetchBlockResponse, WSQueryResponse } from '../client/wsResponse'; -import { WsClient } from '../client/wsClient'; -import logger from '../common/log'; -import { ReqId } from '../common/reqid'; -import { getBinarySql } from '../common/utils'; -import { BinaryQueryMessage, FetchRawBlockMessage } from '../common/constant'; +import { TDengineMeta, TaosResult, parseBlock } from "../common/taosResult"; +import { TaosResultError } from "../common/wsError"; +import { WSFetchBlockResponse, WSQueryResponse } from "../client/wsResponse"; +import { WsClient } from "../client/wsClient"; +import logger from "../common/log"; +import { ReqId } from "../common/reqid"; +import { getBinarySql } from "../common/utils"; +import { BinaryQueryMessage, FetchRawBlockMessage } from "../common/constant"; export class WSRows { private _wsClient: WsClient; private readonly _wsQueryResponse: WSQueryResponse; private _taosResult: TaosResult; - private _isClose : boolean; - + private _isClose: boolean; + constructor(wsInterface: WsClient, resp: WSQueryResponse) { this._wsClient = wsInterface; this._wsQueryResponse = resp; this._taosResult = new TaosResult(resp); - this._isClose = false + this._isClose = false; } async next(): Promise { if (this._wsQueryResponse.is_update || this._isClose) { - logger.debug(`WSRows::Next::End=> ${this._taosResult}, ${this._isClose}`); + logger.debug( + `WSRows::Next::End=> ${this._taosResult}, ${this._isClose}` + ); return false; } - + let data = this._taosResult.getData(); if (this._taosResult && data != null) { - if (data && Array.isArray(this._taosResult.getData()) && data.length > 0) { + if ( + data && + Array.isArray(this._taosResult.getData()) && + data.length > 0 + ) { return true; } } @@ -40,21 +46,35 @@ export class WSRows { return false; } - private async getBlockData():Promise { + private async getBlockData(): Promise { try { if (this._wsQueryResponse.id) { let bigintReqId = BigInt(ReqId.getReqID()); - let resp = await this._wsClient.sendBinaryMsg(bigintReqId, - "binary_query", getBinarySql(FetchRawBlockMessage, bigintReqId, BigInt(this._wsQueryResponse.id)), false, true); - - this._taosResult.addTotalTime(resp.totalTime) + let resp = await this._wsClient.sendBinaryMsg( + bigintReqId, + "binary_query", + getBinarySql( + FetchRawBlockMessage, + bigintReqId, + BigInt(this._wsQueryResponse.id) + ), + false, + true + ); + + this._taosResult.addTotalTime(resp.totalTime); let wsResponse = new WSFetchBlockResponse(resp.msg); if (wsResponse.code != 0) { await this.close(); - logger.error(`Executing SQL statement returns error: ${wsResponse.code}, ${wsResponse.message}`); - throw new TaosResultError(wsResponse.code, wsResponse.message); + logger.error( + `Executing SQL statement returns error: ${wsResponse.code}, ${wsResponse.message}` + ); + throw new TaosResultError( + wsResponse.code, + wsResponse.message + ); } - + if (wsResponse.finished == 1) { await this.close(); this._taosResult.setData(null); @@ -63,23 +83,25 @@ export class WSRows { } } return this._taosResult; - } catch (err:any){ + } catch (err: any) { try { await this.close(); - } catch (closeErr:any) { - logger.error(`GetBlockData encountered an exception while calling the close method, reason: ${closeErr.message}`); + } catch (closeErr: any) { + logger.error( + `GetBlockData encountered an exception while calling the close method, reason: ${closeErr.message}` + ); } throw new TaosResultError(err.code, err.message); - } + } } - - getMeta():Array | null { + + getMeta(): Array | null { return this._taosResult.getMeta(); } getData(): Array | undefined { if (this._wsQueryResponse.is_update) { - return undefined; + return undefined; } let data = this._taosResult.getData(); @@ -87,16 +109,15 @@ export class WSRows { if (Array.isArray(data) && data.length > 0) { return data.pop(); } - } + } return undefined; } - async close():Promise { + async close(): Promise { if (this._isClose) { - return + return; } - this._isClose = true - await this._wsClient.freeResult(this._wsQueryResponse) + this._isClose = true; + await this._wsClient.freeResult(this._wsQueryResponse); } - } diff --git a/nodejs/src/sql/wsSql.ts b/nodejs/src/sql/wsSql.ts index 14bd92a6..4354596e 100644 --- a/nodejs/src/sql/wsSql.ts +++ b/nodejs/src/sql/wsSql.ts @@ -1,46 +1,66 @@ -import { WSRows } from './wsRows' -import { parseBlock, TaosResult } from '../common/taosResult' -import { WsClient } from '../client/wsClient' -import { ErrorCode, TDWebSocketClientError, TaosResultError, WebSocketInterfaceError } from '../common/wsError' -import { WSConfig } from '../common/config' -import { compareVersions, getBinarySql, getUrl } from '../common/utils' -import { WSFetchBlockResponse, WSQueryResponse } from '../client/wsResponse' -import { Precision, SchemalessMessageInfo, SchemalessProto } from './wsProto' -import { ReqId } from '../common/reqid' -import { BinaryQueryMessage, FetchRawBlockMessage, MinStmt2Version, PrecisionLength, TSDB_OPTION_CONNECTION } from '../common/constant' -import logger from '../common/log' -import { WsStmt } from '../stmt/wsStmt' -import { WsStmt1 } from '../stmt/wsStmt1' -import { WsStmt2 } from '../stmt/wsStmt2' - -export class WsSql{ - private wsConfig:WSConfig; - private _wsClient: WsClient; - constructor(wsConfig:WSConfig) { +import { WSRows } from "./wsRows"; +import { parseBlock, TaosResult } from "../common/taosResult"; +import { WsClient } from "../client/wsClient"; +import { + ErrorCode, + TDWebSocketClientError, + TaosResultError, + WebSocketInterfaceError, +} from "../common/wsError"; +import { WSConfig } from "../common/config"; +import { compareVersions, getBinarySql, getUrl } from "../common/utils"; +import { WSFetchBlockResponse, WSQueryResponse } from "../client/wsResponse"; +import { Precision, SchemalessMessageInfo, SchemalessProto } from "./wsProto"; +import { ReqId } from "../common/reqid"; +import { + BinaryQueryMessage, + FetchRawBlockMessage, + MinStmt2Version, + PrecisionLength, + TSDB_OPTION_CONNECTION, +} from "../common/constant"; +import logger from "../common/log"; +import { WsStmt } from "../stmt/wsStmt"; +import { WsStmt1 } from "../stmt/wsStmt1"; +import { WsStmt2 } from "../stmt/wsStmt2"; + +export class WsSql { + private wsConfig: WSConfig; + private _wsClient: WsClient; + constructor(wsConfig: WSConfig) { let url = getUrl(wsConfig); this._wsClient = new WsClient(url, wsConfig.getTimeOut()); this.wsConfig = wsConfig; } - static async open(wsConfig:WSConfig):Promise { + static async open(wsConfig: WSConfig): Promise { if (!wsConfig.getUrl()) { - throw new WebSocketInterfaceError(ErrorCode.ERR_INVALID_URL, 'invalid url, password or username needed.'); + throw new WebSocketInterfaceError( + ErrorCode.ERR_INVALID_URL, + "invalid url, password or username needed." + ); } let wsSql = new WsSql(wsConfig); let database = wsConfig.getDb(); try { await wsSql._wsClient.connect(database); await wsSql._wsClient.checkVersion(); - if(database && database.length > 0) { + if (database && database.length > 0) { await wsSql.exec(`use ${database}`); } else { - await wsSql.exec('use information_schema'); + await wsSql.exec("use information_schema"); } - let timezone = wsConfig.getTimezone(); + let timezone = wsConfig.getTimezone(); if (timezone && timezone.length > 0) { - await wsSql._wsClient.setOptionConnection(TSDB_OPTION_CONNECTION.TSDB_OPTION_CONNECTION_TIMEZONE, timezone); + await wsSql._wsClient.setOptionConnection( + TSDB_OPTION_CONNECTION.TSDB_OPTION_CONNECTION_TIMEZONE, + timezone + ); } else { - await wsSql._wsClient.setOptionConnection(TSDB_OPTION_CONNECTION.TSDB_OPTION_CONNECTION_TIMEZONE, null); + await wsSql._wsClient.setOptionConnection( + TSDB_OPTION_CONNECTION.TSDB_OPTION_CONNECTION_TIMEZONE, + null + ); } return wsSql; @@ -49,12 +69,11 @@ export class WsSql{ if (wsSql) { await wsSql.close(); } - throw(e); + throw e; } - } - state(){ + state() { return this._wsClient.getState(); } @@ -62,30 +81,39 @@ export class WsSql{ * return client version. */ async version(): Promise { - return await this._wsClient.version() + return await this._wsClient.version(); } - - async close():Promise { + + async close(): Promise { await this._wsClient.close(); } - async schemalessInsert(lines: Array, protocol: SchemalessProto, precision: Precision, ttl: number, reqId?: number): Promise { - let data = ''; + async schemalessInsert( + lines: Array, + protocol: SchemalessProto, + precision: Precision, + ttl: number, + reqId?: number + ): Promise { + let data = ""; if (!lines || lines.length == 0 || !protocol) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, 'WsSchemaless Insert params is error!'); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsSchemaless Insert params is error!" + ); } lines.forEach((element, index) => { data += element; if (index < lines.length - 1) { - data += '\n'; + data += "\n"; } }); let queryMsg = { - action: 'insert', + action: "insert", args: { - req_id : ReqId.getReqID(reqId), + req_id: ReqId.getReqID(reqId), protocol: protocol, precision: precision, data: data, @@ -95,100 +123,153 @@ export class WsSql{ return await this.executeSchemalessInsert(queryMsg); } - async stmtInit(reqId?:number): Promise { - if (this._wsClient) { + async stmtInit(reqId?: number): Promise { + if (this._wsClient) { try { let precision = PrecisionLength["ms"]; if (this.wsConfig.getDb()) { - let sql = "select `precision` from information_schema.ins_databases where name = '" + this.wsConfig.getDb() + "'"; + let sql = + "select `precision` from information_schema.ins_databases where name = '" + + this.wsConfig.getDb() + + "'"; let result = await this.exec(sql); - let data =result.getData() - + let data = result.getData(); + if (data && data[0] && data[0][0]) { - precision = PrecisionLength[data[0][0]] + precision = PrecisionLength[data[0][0]]; } } let version = await this.version(); - let result = compareVersions(version, this.wsConfig.getMinStmt2Version()); + let result = compareVersions( + version, + this.wsConfig.getMinStmt2Version() + ); if (result < 0) { - return await WsStmt1.newStmt(this._wsClient, precision, reqId); + return await WsStmt1.newStmt( + this._wsClient, + precision, + reqId + ); } - return await WsStmt2.newStmt(this._wsClient, precision, reqId); + return await WsStmt2.newStmt(this._wsClient, precision, reqId); } catch (e: any) { - logger.error(`stmtInit failed, code: ${e.code}, message: ${e.message}`); - throw(e); + logger.error( + `stmtInit failed, code: ${e.code}, message: ${e.message}` + ); + throw e; } - } - throw(new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "stmt connect closed")); + throw new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "stmt connect closed" + ); } - async exec(sql: string, reqId?: number, action:string = 'binary_query'): Promise { + async exec( + sql: string, + reqId?: number, + action: string = "binary_query" + ): Promise { try { let bigintReqId = BigInt(ReqId.getReqID(reqId)); - let wsQueryResponse:WSQueryResponse = await this._wsClient.sendBinaryMsg(bigintReqId, - action, getBinarySql(BinaryQueryMessage, bigintReqId, BigInt(0), sql)); + let wsQueryResponse: WSQueryResponse = + await this._wsClient.sendBinaryMsg( + bigintReqId, + action, + getBinarySql( + BinaryQueryMessage, + bigintReqId, + BigInt(0), + sql + ) + ); let taosResult = new TaosResult(wsQueryResponse); if (wsQueryResponse.is_update) { return taosResult; - } else { + } else { if (wsQueryResponse.id) { - try{ + try { while (true) { let bigintReqId = BigInt(ReqId.getReqID(reqId)); - let resp = await this._wsClient.sendBinaryMsg(bigintReqId, - action, getBinarySql(FetchRawBlockMessage, bigintReqId, BigInt(wsQueryResponse.id)), false, true); - - taosResult.addTotalTime(resp.totalTime) + let resp = await this._wsClient.sendBinaryMsg( + bigintReqId, + action, + getBinarySql( + FetchRawBlockMessage, + bigintReqId, + BigInt(wsQueryResponse.id) + ), + false, + true + ); + + taosResult.addTotalTime(resp.totalTime); let wsResponse = new WSFetchBlockResponse(resp.msg); if (wsResponse.code != 0) { - logger.error(`Executing SQL statement returns error: ${wsResponse.code}, ${wsResponse.message}`); - throw new TaosResultError(wsResponse.code, wsResponse.message); + logger.error( + `Executing SQL statement returns error: ${wsResponse.code}, ${wsResponse.message}` + ); + throw new TaosResultError( + wsResponse.code, + wsResponse.message + ); } - + if (wsResponse.finished == 1) { break; } parseBlock(wsResponse, taosResult); } - return taosResult; - } catch(err: any){ + return taosResult; + } catch (err: any) { throw new TaosResultError(err.code, err.message); } finally { - await this._wsClient.freeResult(wsQueryResponse) - } + await this._wsClient.freeResult(wsQueryResponse); + } } - throw new TaosResultError(ErrorCode.ERR_INVALID_FETCH_MESSAGE_DATA, "The result data of the query is incorrect"); - + throw new TaosResultError( + ErrorCode.ERR_INVALID_FETCH_MESSAGE_DATA, + "The result data of the query is incorrect" + ); } - } catch(err: any) { + } catch (err: any) { throw new TaosResultError(err.code, err.message); } } - private async executeSchemalessInsert(queryMsg: SchemalessMessageInfo): Promise { + private async executeSchemalessInsert( + queryMsg: SchemalessMessageInfo + ): Promise { return new Promise(async (resolve, reject) => { try { let reqMsg = JSON.stringify(queryMsg); let result = await this._wsClient.exec(reqMsg); - logger.debug("executeSchemalessInsert:", reqMsg, result) + logger.debug("executeSchemalessInsert:", reqMsg, result); resolve(); - } catch (e:any) { + } catch (e: any) { reject(new TaosResultError(e.code, e.message)); } }); } - async query(sql: string, reqId?:number): Promise { + async query(sql: string, reqId?: number): Promise { try { let bigintReqId = BigInt(ReqId.getReqID(reqId)); - let wsQueryResponse:WSQueryResponse = await this._wsClient.sendBinaryMsg(bigintReqId, - 'binary_query', getBinarySql(BinaryQueryMessage, bigintReqId, BigInt(0), sql)); + let wsQueryResponse: WSQueryResponse = + await this._wsClient.sendBinaryMsg( + bigintReqId, + "binary_query", + getBinarySql( + BinaryQueryMessage, + bigintReqId, + BigInt(0), + sql + ) + ); return new WSRows(this._wsClient, wsQueryResponse); } catch (err: any) { throw new TaosResultError(err.code, err.message); } - } -} \ No newline at end of file +} diff --git a/nodejs/src/stmt/FieldBindParams.ts b/nodejs/src/stmt/FieldBindParams.ts index d1ade040..24be3aa3 100644 --- a/nodejs/src/stmt/FieldBindParams.ts +++ b/nodejs/src/stmt/FieldBindParams.ts @@ -1,15 +1,20 @@ - export class FieldBindParams { params: any[]; dataType: string; typeLen: number; columnType: number; bindType: number; // 0: normal, 1: table name, 2: tag - constructor(params:any[], dataType:string, typeLen:number, columnType:number, bindType:number) { + constructor( + params: any[], + dataType: string, + typeLen: number, + columnType: number, + bindType: number + ) { this.params = [...params]; this.dataType = dataType; this.typeLen = typeLen; this.columnType = columnType; this.bindType = bindType; } -} \ No newline at end of file +} diff --git a/nodejs/src/stmt/wsColumnInfo.ts b/nodejs/src/stmt/wsColumnInfo.ts index c3f6e08d..4db27a98 100644 --- a/nodejs/src/stmt/wsColumnInfo.ts +++ b/nodejs/src/stmt/wsColumnInfo.ts @@ -1,15 +1,21 @@ - export class ColumnInfo { - data:ArrayBuffer; - length:number; - type:number; - typeLen:number; + data: ArrayBuffer; + length: number; + type: number; + typeLen: number; isNull?: number[]; _rows: number; _haveLength: number = 0; _dataLengths?: number[]; - constructor([length,data]:[number, ArrayBuffer], type:number, typeLen:number, rows:number, - isNull?: number[], dataLengths?: number[], haveLength: number = 0) { + constructor( + [length, data]: [number, ArrayBuffer], + type: number, + typeLen: number, + rows: number, + isNull?: number[], + dataLengths?: number[], + haveLength: number = 0 + ) { this.data = data; this.type = type; this.length = length; @@ -19,5 +25,4 @@ export class ColumnInfo { this._dataLengths = dataLengths; this._haveLength = haveLength; } - -} \ No newline at end of file +} diff --git a/nodejs/src/stmt/wsParams1.ts b/nodejs/src/stmt/wsParams1.ts index 7486bf5c..6aa4c4f1 100644 --- a/nodejs/src/stmt/wsParams1.ts +++ b/nodejs/src/stmt/wsParams1.ts @@ -1,12 +1,16 @@ -import { PrecisionLength, TDengineTypeCode, TDengineTypeLength } from "../common/constant"; +import { + PrecisionLength, + TDengineTypeCode, + TDengineTypeLength, +} from "../common/constant"; import { ErrorCode, TaosError } from "../common/wsError"; -import { getCharOffset, setBitmapNull, bitmapLen} from "../common/taosResult" +import { getCharOffset, setBitmapNull, bitmapLen } from "../common/taosResult"; import { isEmpty } from "../common/utils"; import { ColumnInfo } from "./wsColumnInfo"; import { IDataEncoder, StmtBindParams } from "./wsParamsBase"; -export class Stmt1BindParams extends StmtBindParams implements IDataEncoder{ - constructor(precision?:number) { +export class Stmt1BindParams extends StmtBindParams implements IDataEncoder { + constructor(precision?: number) { super(precision); } @@ -18,262 +22,396 @@ export class Stmt1BindParams extends StmtBindParams implements IDataEncoder{ return; } - addParams(params: any[], dataType: string, typeLen: number, columnType: number): void { + addParams( + params: any[], + dataType: string, + typeLen: number, + columnType: number + ): void { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "StmtBindParams params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "StmtBindParams params is invalid!" + ); } - if (dataType === "number" || dataType === "bigint" || dataType === "boolean") { - this._params.push(this.encodeDigitColumns(params, dataType, typeLen, columnType)); + if ( + dataType === "number" || + dataType === "bigint" || + dataType === "boolean" + ) { + this._params.push( + this.encodeDigitColumns(params, dataType, typeLen, columnType) + ); } else { - if (columnType === TDengineTypeCode.NCHAR) { this._params.push(this.encodeNcharColumn(params)); } else { - this._params.push(this.encodeVarLengthColumn(params, columnType)); + this._params.push( + this.encodeVarLengthColumn(params, columnType) + ); } } } - setTimestamp(params :any[]) { + setTimestamp(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SeTimestampColumn params is invalid!"); - } - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SeTimestampColumn params is invalid!" + ); + } + //computing bitmap length - let bitMapLen:number = bitmapLen(params.length) + let bitMapLen: number = bitmapLen(params.length); //Computing the length of data - let arrayBuffer = new ArrayBuffer(bitMapLen + TDengineTypeLength[TDengineTypeCode.TIMESTAMP] * params.length); + let arrayBuffer = new ArrayBuffer( + bitMapLen + + TDengineTypeLength[TDengineTypeCode.TIMESTAMP] * params.length + ); //bitmap get data range - let bitmapBuffer = new DataView(arrayBuffer) - //skip bitmap get data range - let dataBuffer = new DataView(arrayBuffer, bitMapLen) + let bitmapBuffer = new DataView(arrayBuffer); + //skip bitmap get data range + let dataBuffer = new DataView(arrayBuffer, bitMapLen); if (this._rows > 0) { if (this._rows !== params.length) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "wrong row length!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "wrong row length!" + ); } - }else { + } else { this._rows = params.length; } - + for (let i = 0; i < params.length; i++) { if (!isEmpty(params[i])) { if (params[i] instanceof Date) { - let date:Date = params[i] + let date: Date = params[i]; //node only support milliseconds, need fill 0 - if (this.precisionLength == PrecisionLength['us']) { - let ms = date.getTime() * 1000 + if (this.precisionLength == PrecisionLength["us"]) { + let ms = date.getTime() * 1000; dataBuffer.setBigInt64(i * 8, BigInt(ms), true); - }else if (this.precisionLength == PrecisionLength['ns']) { - let ns = date.getTime() * 1000 * 1000 + } else if (this.precisionLength == PrecisionLength["ns"]) { + let ns = date.getTime() * 1000 * 1000; dataBuffer.setBigInt64(i * 8, BigInt(ns), true); - }else { - dataBuffer.setBigInt64(i * 8, BigInt(date.getTime()), true); + } else { + dataBuffer.setBigInt64( + i * 8, + BigInt(date.getTime()), + true + ); } - - } else if (typeof params[i] == 'bigint' || typeof params[i] == 'number') { - - let data:bigint - if (typeof params[i] == 'number') { - data = BigInt(params[i]) - }else { - data = params[i] + } else if ( + typeof params[i] == "bigint" || + typeof params[i] == "number" + ) { + let data: bigint; + if (typeof params[i] == "number") { + data = BigInt(params[i]); + } else { + data = params[i]; } //statistical bits of digit - let digit = this.countBigintDigits(data) - //check digit same table Precision - if (this.precisionLength == PrecisionLength['ns']) { + let digit = this.countBigintDigits(data); + //check digit same table Precision + if (this.precisionLength == PrecisionLength["ns"]) { if (this.precisionLength <= digit) { dataBuffer.setBigInt64(i * 8, data, true); } else { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SeTimestampColumn params precisionLength is invalid! param:=" + params[i]) - } + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SeTimestampColumn params precisionLength is invalid! param:=" + + params[i] + ); + } } else if (this.precisionLength == digit) { dataBuffer.setBigInt64(i * 8, data, true); } else { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SeTimestampColumn params is invalid! param:=" + params[i]) - } + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SeTimestampColumn params is invalid! param:=" + + params[i] + ); + } } - }else{ + } else { //set bitmap bit is null let charOffset = getCharOffset(i); let nullVal = setBitmapNull(dataBuffer.getInt8(charOffset), i); - bitmapBuffer.setInt8(charOffset, nullVal); + bitmapBuffer.setInt8(charOffset, nullVal); } } - this._dataTotalLen += arrayBuffer.byteLength; - this._params.push(new ColumnInfo([TDengineTypeLength[TDengineTypeCode.TIMESTAMP] * params.length, arrayBuffer], TDengineTypeCode.TIMESTAMP, TDengineTypeLength[TDengineTypeCode.TIMESTAMP], this._rows)); + this._dataTotalLen += arrayBuffer.byteLength; + this._params.push( + new ColumnInfo( + [ + TDengineTypeLength[TDengineTypeCode.TIMESTAMP] * + params.length, + arrayBuffer, + ], + TDengineTypeCode.TIMESTAMP, + TDengineTypeLength[TDengineTypeCode.TIMESTAMP], + this._rows + ) + ); } - - private encodeDigitColumns(params:any[], dataType:string = 'number', typeLen:number, columnType:number):ColumnInfo { - let bitMapLen:number = bitmapLen(params.length) + private encodeDigitColumns( + params: any[], + dataType: string = "number", + typeLen: number, + columnType: number + ): ColumnInfo { + let bitMapLen: number = bitmapLen(params.length); let arrayBuffer = new ArrayBuffer(typeLen * params.length + bitMapLen); - let bitmapBuffer = new DataView(arrayBuffer) - let dataBuffer = new DataView(arrayBuffer, bitMapLen) + let bitmapBuffer = new DataView(arrayBuffer); + let dataBuffer = new DataView(arrayBuffer, bitMapLen); if (this._rows > 0) { if (this._rows !== params.length) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "wrong row length!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "wrong row length!" + ); } - }else { + } else { this._rows = params.length; } for (let i = 0; i < params.length; i++) { if (!isEmpty(params[i])) { - this.writeDataToBuffer(dataBuffer, params[i], dataType, typeLen,columnType, i); + this.writeDataToBuffer( + dataBuffer, + params[i], + dataType, + typeLen, + columnType, + i + ); } else { //set bitmap bit is null let charOffset = getCharOffset(i); - let nullVal = setBitmapNull(bitmapBuffer.getUint8(charOffset), i); - bitmapBuffer.setInt8(charOffset, nullVal); + let nullVal = setBitmapNull( + bitmapBuffer.getUint8(charOffset), + i + ); + bitmapBuffer.setInt8(charOffset, nullVal); } } this._dataTotalLen += dataBuffer.buffer.byteLength; - return new ColumnInfo([typeLen * params.length, dataBuffer.buffer], columnType, typeLen, this._rows); + return new ColumnInfo( + [typeLen * params.length, dataBuffer.buffer], + columnType, + typeLen, + this._rows + ); } - private encodeVarLengthColumn(params:any[], columnType:number):ColumnInfo { - let data:ArrayBuffer[] = [] + private encodeVarLengthColumn( + params: any[], + columnType: number + ): ColumnInfo { + let data: ArrayBuffer[] = []; let dataLength = 0; //create params length buffer - let paramsLenBuffer = new ArrayBuffer(TDengineTypeLength[TDengineTypeCode.INT] * params.length) - let paramsLenView = new DataView(paramsLenBuffer) + let paramsLenBuffer = new ArrayBuffer( + TDengineTypeLength[TDengineTypeCode.INT] * params.length + ); + let paramsLenView = new DataView(paramsLenBuffer); if (this._rows > 0) { if (this._rows !== params.length) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "wrong row length!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "wrong row length!" + ); } - }else { + } else { this._rows = params.length; } - for (let i = 0; i < params.length; i++) { + for (let i = 0; i < params.length; i++) { //get param length offset 4byte let offset = TDengineTypeLength[TDengineTypeCode.INT] * i; if (!isEmpty(params[i])) { //save param length offset 4byte paramsLenView.setInt32(offset, dataLength, true); - if (typeof params[i] == 'string' ) { + if (typeof params[i] == "string") { //string TextEncoder let encode = new TextEncoder(); let value = encode.encode(params[i]).buffer; data.push(value); //add offset length - dataLength += value.byteLength + TDengineTypeLength[TDengineTypeCode.SMALLINT]; + dataLength += + value.byteLength + + TDengineTypeLength[TDengineTypeCode.SMALLINT]; } else if (params[i] instanceof ArrayBuffer) { //input arraybuffer, save not need encode - let value:ArrayBuffer = params[i]; - dataLength += value.byteLength + TDengineTypeLength[TDengineTypeCode.SMALLINT]; + let value: ArrayBuffer = params[i]; + dataLength += + value.byteLength + + TDengineTypeLength[TDengineTypeCode.SMALLINT]; data.push(value); } else { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, - "getColumString params is invalid! param_type:=" + typeof params[i]); - } - - }else{ + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "getColumString params is invalid! param_type:=" + + typeof params[i] + ); + } + } else { //set length -1, param is null - for (let j = 0; j < TDengineTypeLength[TDengineTypeCode.INT]; j++) { - paramsLenView.setInt8(offset+j, 255); + for ( + let j = 0; + j < TDengineTypeLength[TDengineTypeCode.INT]; + j++ + ) { + paramsLenView.setInt8(offset + j, 255); } - } } - + this._dataTotalLen += paramsLenBuffer.byteLength + dataLength; - return new ColumnInfo([dataLength, this.getBinaryColumnArrayBuffer(data, paramsLenView.buffer, dataLength)], columnType, 0, this._rows); + return new ColumnInfo( + [ + dataLength, + this.getBinaryColumnArrayBuffer( + data, + paramsLenView.buffer, + dataLength + ), + ], + columnType, + 0, + this._rows + ); } //splicing encode params to arraybuffer - private getBinaryColumnArrayBuffer(data:ArrayBuffer[], paramsLenBuffer: ArrayBuffer, dataLength:number):ArrayBuffer { - //create arraybuffer - let paramsBuffer = new ArrayBuffer(paramsLenBuffer.byteLength + dataLength) + private getBinaryColumnArrayBuffer( + data: ArrayBuffer[], + paramsLenBuffer: ArrayBuffer, + dataLength: number + ): ArrayBuffer { + //create arraybuffer + let paramsBuffer = new ArrayBuffer( + paramsLenBuffer.byteLength + dataLength + ); //get length data range const paramsUint8 = new Uint8Array(paramsBuffer); const paramsLenView = new Uint8Array(paramsLenBuffer); paramsUint8.set(paramsLenView, 0); //get data range - const paramsView = new DataView(paramsBuffer, paramsLenBuffer.byteLength); - + const paramsView = new DataView( + paramsBuffer, + paramsLenBuffer.byteLength + ); + let offset = 0; - for (let i = 0; i < data.length; i++) { + for (let i = 0; i < data.length; i++) { //save param field length - paramsView.setInt16(offset, data[i].byteLength, true) + paramsView.setInt16(offset, data[i].byteLength, true); const dataView = new DataView(data[i]); //save data for (let j = 0; j < data[i].byteLength; j++) { - paramsView.setUint8(offset + 2 + j, dataView.getUint8(j)) + paramsView.setUint8(offset + 2 + j, dataView.getUint8(j)); } offset += data[i].byteLength + 2; } - - return paramsBuffer + + return paramsBuffer; } //encode nchar type params - private encodeNcharColumn(params:any[]):ColumnInfo { - let data:ArrayBuffer[] = [] + private encodeNcharColumn(params: any[]): ColumnInfo { + let data: ArrayBuffer[] = []; let dataLength = 0; - let indexBuffer = new ArrayBuffer(TDengineTypeLength[TDengineTypeCode.INT] * params.length) - let indexView = new DataView(indexBuffer) + let indexBuffer = new ArrayBuffer( + TDengineTypeLength[TDengineTypeCode.INT] * params.length + ); + let indexView = new DataView(indexBuffer); if (this._rows > 0) { if (this._rows !== params.length) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "wrong row length!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "wrong row length!" + ); } - }else { + } else { this._rows = params.length; } - - for (let i = 0; i < params.length; i++) { + + for (let i = 0; i < params.length; i++) { let offset = TDengineTypeLength[TDengineTypeCode.INT] * i; if (!isEmpty(params[i])) { indexView.setInt32(offset, dataLength, true); - if (typeof params[i] == 'string' ) { - let codes:number[] = []; - let strNcharParams:string = params[i]; - for (let j = 0; j < params[i].length; j++) { + if (typeof params[i] == "string") { + let codes: number[] = []; + let strNcharParams: string = params[i]; + for (let j = 0; j < params[i].length; j++) { //get char, cn char need 3~4 byte codes.push(strNcharParams.charCodeAt(j)); } - let ncharBuffer:ArrayBuffer = new ArrayBuffer(codes.length * 4); + let ncharBuffer: ArrayBuffer = new ArrayBuffer( + codes.length * 4 + ); let ncharView = new DataView(ncharBuffer); - for (let j = 0; j < codes.length; j++) { + for (let j = 0; j < codes.length; j++) { //1char, save into uint32 - ncharView.setUint32(j*4, codes[j], true); + ncharView.setUint32(j * 4, codes[j], true); } data.push(ncharBuffer); - dataLength += codes.length * 4 + TDengineTypeLength[TDengineTypeCode.SMALLINT]; - + dataLength += + codes.length * 4 + + TDengineTypeLength[TDengineTypeCode.SMALLINT]; } else if (params[i] instanceof ArrayBuffer) { - let value:ArrayBuffer = params[i] - dataLength += value.byteLength + TDengineTypeLength[TDengineTypeCode.SMALLINT]; + let value: ArrayBuffer = params[i]; + dataLength += + value.byteLength + + TDengineTypeLength[TDengineTypeCode.SMALLINT]; data.push(value); } else { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "getColumString params is invalid! param_type:=" + typeof params[i]) - } - - }else{ + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "getColumString params is invalid! param_type:=" + + typeof params[i] + ); + } + } else { //set length -1, param is null - for (let j = 0; j < TDengineTypeLength[TDengineTypeCode.INT]; j++) { - indexView.setInt8(offset+j, 255) + for ( + let j = 0; + j < TDengineTypeLength[TDengineTypeCode.INT]; + j++ + ) { + indexView.setInt8(offset + j, 255); } - } } - + this._dataTotalLen += indexBuffer.byteLength + dataLength; - return new ColumnInfo([dataLength, this.getBinaryColumnArrayBuffer(data, indexView.buffer, dataLength)], TDengineTypeCode.NCHAR, 0, this._rows); + return new ColumnInfo( + [ + dataLength, + this.getBinaryColumnArrayBuffer( + data, + indexView.buffer, + dataLength + ), + ], + TDengineTypeCode.NCHAR, + 0, + this._rows + ); } - private countBigintDigits(numeral: bigint): number { - if (numeral === 0n) { - return 1; - } - let count = 0; - let temp = numeral; - while (temp !== 0n) { - temp /= 10n; - count++; - } - return count; - } - + private countBigintDigits(numeral: bigint): number { + if (numeral === 0n) { + return 1; + } + let count = 0; + let temp = numeral; + while (temp !== 0n) { + temp /= 10n; + count++; + } + return count; + } } - diff --git a/nodejs/src/stmt/wsParams2.ts b/nodejs/src/stmt/wsParams2.ts index a0a55918..91674ffb 100644 --- a/nodejs/src/stmt/wsParams2.ts +++ b/nodejs/src/stmt/wsParams2.ts @@ -1,73 +1,139 @@ -import { ColumnsBlockType, FieldBindType, PrecisionLength } from "../common/constant"; +import { + ColumnsBlockType, + FieldBindType, + PrecisionLength, +} from "../common/constant"; import { ErrorCode, TaosError } from "../common/wsError"; import { isEmpty } from "../common/utils"; import { ColumnInfo } from "./wsColumnInfo"; import { IDataEncoder, StmtBindParams } from "./wsParamsBase"; import { _isVarType } from "../common/taosResult"; import { FieldBindParams } from "./FieldBindParams"; -import JSONBig from 'json-bigint'; +import JSONBig from "json-bigint"; import { StmtFieldInfo } from "./wsProto"; -export class Stmt2BindParams extends StmtBindParams implements IDataEncoder { +export class Stmt2BindParams extends StmtBindParams implements IDataEncoder { private _fields: Array; - protected paramIndex:number = 0; - constructor(paramsCount?: number, precision?:number, fields?: Array) { + protected paramIndex: number = 0; + constructor( + paramsCount?: number, + precision?: number, + fields?: Array + ) { super(precision, paramsCount); this._fields = fields || []; } - addParams(params: any[], dataType: string, typeLen: number, columnType: number): void { + addParams( + params: any[], + dataType: string, + typeLen: number, + columnType: number + ): void { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "StmtBindParams params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "StmtBindParams params is invalid!" + ); } - if (this._fieldParams) { + if (this._fieldParams) { if (this.paramsCount > 0) { if (this._fieldParams[this.paramIndex]) { - if (this._fieldParams[this.paramIndex].dataType !== dataType || this._fieldParams[this.paramIndex].columnType !== columnType) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, `StmtBindParams params type is not match! ${this.paramIndex} ${this.paramsCount} ${JSONBig.stringify({ dataType, columnType } )} vs ${JSONBig.stringify({ dataType: this._fieldParams[this.paramIndex].dataType, columnType: this._fieldParams[this.paramIndex].columnType})}`); + if ( + this._fieldParams[this.paramIndex].dataType !== + dataType || + this._fieldParams[this.paramIndex].columnType !== + columnType + ) { + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + `StmtBindParams params type is not match! ${ + this.paramIndex + } ${this.paramsCount} ${JSONBig.stringify({ + dataType, + columnType, + })} vs ${JSONBig.stringify({ + dataType: + this._fieldParams[this.paramIndex].dataType, + columnType: + this._fieldParams[this.paramIndex] + .columnType, + })}` + ); } this._fieldParams[this.paramIndex].params.push(...params); - } else { let bindType = this._fields[this.paramIndex].bind_type || 0; - this._fieldParams[this.paramIndex] = new FieldBindParams(params, dataType, typeLen, columnType, bindType); - this._bindCount++ + this._fieldParams[this.paramIndex] = new FieldBindParams( + params, + dataType, + typeLen, + columnType, + bindType + ); + this._bindCount++; } this.paramIndex++; if (this.paramIndex >= this.paramsCount) { this.paramIndex = 0; - } + } } else { - this._fieldParams.push(new FieldBindParams(params, dataType, typeLen, columnType, FieldBindType.TAOS_FIELD_COL)); + this._fieldParams.push( + new FieldBindParams( + params, + dataType, + typeLen, + columnType, + FieldBindType.TAOS_FIELD_COL + ) + ); } } - } mergeParams(bindParams: StmtBindParams): void { - if (!bindParams || !bindParams._fieldParams || bindParams._fieldParams.length === 0 || !this._fieldParams) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "StmtBindParams params is invalid!"); + if ( + !bindParams || + !bindParams._fieldParams || + bindParams._fieldParams.length === 0 || + !this._fieldParams + ) { + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "StmtBindParams params is invalid!" + ); } this.paramIndex = 0; for (let i = 0; i < bindParams._fieldParams.length; i++) { let fieldParam = bindParams._fieldParams[i]; if (fieldParam) { - this.addParams(fieldParam.params, fieldParam.dataType, fieldParam.typeLen, fieldParam.columnType); + this.addParams( + fieldParam.params, + fieldParam.dataType, + fieldParam.typeLen, + fieldParam.columnType + ); } } } - encode(): void{ + encode(): void { this.paramIndex = 0; if (!this._fieldParams || this._fieldParams.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "StmtBindParams params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "StmtBindParams params is invalid!" + ); } - + if (this._rows > 0) { if (this._rows !== this._fieldParams[0].params.length) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "wrong row length!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "wrong row length!" + ); } - }else { + } else { this._rows = this._fieldParams[0].params.length; } for (let i = 0; i < this._fieldParams.length; i++) { @@ -79,27 +145,52 @@ export class Stmt2BindParams extends StmtBindParams implements IDataEncoder { let isVarType = _isVarType(fieldParam.columnType); if (isVarType == ColumnsBlockType.SOLID) { if (fieldParam.dataType === "TIMESTAMP") { - this._params.push(this.encodeTimestampColumn(fieldParam.params, fieldParam.typeLen, fieldParam.columnType)); + this._params.push( + this.encodeTimestampColumn( + fieldParam.params, + fieldParam.typeLen, + fieldParam.columnType + ) + ); } else { - this._params.push(this.encodeDigitColumns(fieldParam.params, fieldParam.dataType, fieldParam.typeLen, fieldParam.columnType)); + this._params.push( + this.encodeDigitColumns( + fieldParam.params, + fieldParam.dataType, + fieldParam.typeLen, + fieldParam.columnType + ) + ); } } else { - this._params.push(this.encodeVarColumns(fieldParam.params, fieldParam.dataType, fieldParam.typeLen, fieldParam.columnType)); + this._params.push( + this.encodeVarColumns( + fieldParam.params, + fieldParam.dataType, + fieldParam.typeLen, + fieldParam.columnType + ) + ); } } } - private encodeVarColumns(params:any[], dataType:string = 'number', typeLen:number, columnType:number):ColumnInfo { - let isNull: number[] = []; + private encodeVarColumns( + params: any[], + dataType: string = "number", + typeLen: number, + columnType: number + ): ColumnInfo { + let isNull: number[] = []; let dataLengths: number[] = []; // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 * v.length + totalLength // 17 + (5 * params.length) + totalLength; - let totalLength = 17 + (5 * params.length); + let totalLength = 17 + 5 * params.length; const bytes: number[] = []; - for (let i = 0; i < params.length; i++) { + for (let i = 0; i < params.length; i++) { if (!isEmpty(params[i])) { isNull.push(0); - if (typeof params[i] == 'string' ) { + if (typeof params[i] == "string") { let encoder = new TextEncoder().encode(params[i]); let length = encoder.length; totalLength += length; @@ -107,80 +198,131 @@ export class Stmt2BindParams extends StmtBindParams implements IDataEncoder { bytes.push(...encoder); } else if (params[i] instanceof ArrayBuffer) { //input arraybuffer, save not need encode - let value:ArrayBuffer = params[i]; + let value: ArrayBuffer = params[i]; totalLength += value.byteLength; dataLengths.push(value.byteLength); bytes.push(...new Uint8Array(value)); } else { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, - "getColumString params is invalid! param_type:=" + typeof params[i]); - } + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "getColumString params is invalid! param_type:=" + + typeof params[i] + ); + } } else { isNull.push(1); } } this._dataTotalLen += totalLength; const dataBuffer = new Uint8Array(bytes).buffer; - return new ColumnInfo([totalLength, dataBuffer], columnType, typeLen, this._rows, isNull, dataLengths, 1); + return new ColumnInfo( + [totalLength, dataBuffer], + columnType, + typeLen, + this._rows, + isNull, + dataLengths, + 1 + ); } - private encodeDigitColumns(params:any[], dataType:string = 'number', typeLen:number, columnType:number):ColumnInfo { + private encodeDigitColumns( + params: any[], + dataType: string = "number", + typeLen: number, + columnType: number + ): ColumnInfo { let isNull: number[] = []; - // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + size * dataLen + // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + size * dataLen let dataLength = 17 + (typeLen + 1) * params.length; let arrayBuffer = new ArrayBuffer(typeLen * params.length); let dataBuffer = new DataView(arrayBuffer); for (let i = 0; i < params.length; i++) { if (!isEmpty(params[i])) { isNull.push(0); - this.writeDataToBuffer(dataBuffer, params[i], dataType, typeLen,columnType, i); + this.writeDataToBuffer( + dataBuffer, + params[i], + dataType, + typeLen, + columnType, + i + ); } else { isNull.push(1); - if (dataType === 'bigint') { - this.writeDataToBuffer(dataBuffer, BigInt(0), dataType, typeLen,columnType, i); - }else { - this.writeDataToBuffer(dataBuffer, 0, dataType, typeLen,columnType, i); + if (dataType === "bigint") { + this.writeDataToBuffer( + dataBuffer, + BigInt(0), + dataType, + typeLen, + columnType, + i + ); + } else { + this.writeDataToBuffer( + dataBuffer, + 0, + dataType, + typeLen, + columnType, + i + ); } } } - + this._dataTotalLen += dataLength; - return new ColumnInfo([dataLength, dataBuffer.buffer], columnType, typeLen, this._rows, isNull); + return new ColumnInfo( + [dataLength, dataBuffer.buffer], + columnType, + typeLen, + this._rows, + isNull + ); } - - private encodeTimestampColumn(params:any[], typeLen:number, columnType:number):ColumnInfo { + private encodeTimestampColumn( + params: any[], + typeLen: number, + columnType: number + ): ColumnInfo { let timeStamps = []; for (let i = 0; i < params.length; i++) { if (!isEmpty(params[i])) { - let timeStamp:bigint = BigInt(0); + let timeStamp: bigint = BigInt(0); if (params[i] instanceof Date) { - let date:Date = params[i] + let date: Date = params[i]; //node only support milliseconds, need fill 0 - - if (this.precisionLength == PrecisionLength['us']) { - timeStamp = BigInt(date.getTime() * 1000); - }else if (this.precisionLength == PrecisionLength['ns']) { - timeStamp = BigInt(date.getTime() * 1000 * 1000); - }else { - timeStamp = BigInt(date.getTime()); + + if (this.precisionLength == PrecisionLength["us"]) { + timeStamp = BigInt(date.getTime() * 1000); + } else if (this.precisionLength == PrecisionLength["ns"]) { + timeStamp = BigInt(date.getTime() * 1000 * 1000); + } else { + timeStamp = BigInt(date.getTime()); } - - } else if (typeof params[i] == 'bigint' || typeof params[i] == 'number') { - if (typeof params[i] == 'number') { - timeStamp = BigInt(params[i]) - }else { - timeStamp = params[i] + } else if ( + typeof params[i] == "bigint" || + typeof params[i] == "number" + ) { + if (typeof params[i] == "number") { + timeStamp = BigInt(params[i]); + } else { + timeStamp = params[i]; } } timeStamps.push(timeStamp); - }else{ + } else { //set bitmap bit is null - timeStamps.push(null); + timeStamps.push(null); } } - return this.encodeDigitColumns(timeStamps, 'bigint', typeLen, columnType); + return this.encodeDigitColumns( + timeStamps, + "bigint", + typeLen, + columnType + ); } } - - diff --git a/nodejs/src/stmt/wsParamsBase.ts b/nodejs/src/stmt/wsParamsBase.ts index 0f8a0f7b..c4f9ad11 100644 --- a/nodejs/src/stmt/wsParamsBase.ts +++ b/nodejs/src/stmt/wsParamsBase.ts @@ -1,28 +1,38 @@ -import { TDengineTypeCode, TDengineTypeLength, TDengineTypeName, PrecisionLength } from "../common/constant"; +import { + TDengineTypeCode, + TDengineTypeLength, + TDengineTypeName, + PrecisionLength, +} from "../common/constant"; import { bitmapLen } from "../common/taosResult"; import { ErrorCode, TaosError } from "../common/wsError"; import { FieldBindParams } from "./FieldBindParams"; import { ColumnInfo } from "./wsColumnInfo"; -import JSONBig from 'json-bigint'; +import JSONBig from "json-bigint"; export interface IDataEncoder { encode(): void; - addParams(params: any[], dataType: string, typeLen: number, columnType: number): void; + addParams( + params: any[], + dataType: string, + typeLen: number, + columnType: number + ): void; mergeParams(bindParams: StmtBindParams): void; } export abstract class StmtBindParams { - protected readonly precisionLength:number = PrecisionLength['ms'] + protected readonly precisionLength: number = PrecisionLength["ms"]; protected readonly _params: ColumnInfo[]; _fieldParams?: FieldBindParams[]; - protected _dataTotalLen:number = 0; + protected _dataTotalLen: number = 0; protected paramsCount: number = 0; protected _rows = 0; protected _bindCount = 0; - constructor(precision?:number, paramsCount?: number) { + constructor(precision?: number, paramsCount?: number) { if (precision) { - this.precisionLength = precision + this.precisionLength = precision; } this._params = []; if (paramsCount && paramsCount > 0) { @@ -36,21 +46,37 @@ export abstract class StmtBindParams { abstract encode(): void; - abstract addParams(params: any[], dataType: string, typeLen: number, columnType: number): void; - + abstract addParams( + params: any[], + dataType: string, + typeLen: number, + columnType: number + ): void; + addBindFieldParams(fieldParams: FieldBindParams): void { - if (!fieldParams || !fieldParams.params || fieldParams.params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "StmtBindParams params is invalid!"); + if ( + !fieldParams || + !fieldParams.params || + fieldParams.params.length == 0 + ) { + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "StmtBindParams params is invalid!" + ); } if (!this._fieldParams) { this._fieldParams = []; } - this.addParams(fieldParams.params, fieldParams.dataType, fieldParams.typeLen, fieldParams.columnType); + this.addParams( + fieldParams.params, + fieldParams.dataType, + fieldParams.typeLen, + fieldParams.columnType + ); } abstract mergeParams(bindParams: StmtBindParams): void; - getBindCount(): number { return this._bindCount; } @@ -58,158 +84,278 @@ export abstract class StmtBindParams { getDataRows(): number { return this._rows; } - + getDataTotalLen(): number { return this._dataTotalLen; } - public getParams(): ColumnInfo[] { return this._params; } - setBoolean(params :any[]) { + setBoolean(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetBooleanColumn params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetBooleanColumn params is invalid!" + ); } - this.addParams(params, "boolean", TDengineTypeLength[TDengineTypeCode.BOOL], TDengineTypeCode.BOOL); + this.addParams( + params, + "boolean", + TDengineTypeLength[TDengineTypeCode.BOOL], + TDengineTypeCode.BOOL + ); } - setTinyInt(params :any[]) { + setTinyInt(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetTinyIntColumn params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetTinyIntColumn params is invalid!" + ); } - this.addParams(params, "number", TDengineTypeLength[TDengineTypeCode.TINYINT], TDengineTypeCode.TINYINT) + this.addParams( + params, + "number", + TDengineTypeLength[TDengineTypeCode.TINYINT], + TDengineTypeCode.TINYINT + ); } - setUTinyInt(params :any[]) { + setUTinyInt(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetUTinyIntColumn params is invalid!"); - } - this.addParams(params, "number", TDengineTypeLength[TDengineTypeCode.TINYINT_UNSIGNED], TDengineTypeCode.TINYINT_UNSIGNED) - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetUTinyIntColumn params is invalid!" + ); + } + this.addParams( + params, + "number", + TDengineTypeLength[TDengineTypeCode.TINYINT_UNSIGNED], + TDengineTypeCode.TINYINT_UNSIGNED + ); } - setSmallInt(params :any[]) { + setSmallInt(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetSmallIntColumn params is invalid!"); - } - this.addParams(params, "number", TDengineTypeLength[TDengineTypeCode.SMALLINT], TDengineTypeCode.SMALLINT) - - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetSmallIntColumn params is invalid!" + ); + } + this.addParams( + params, + "number", + TDengineTypeLength[TDengineTypeCode.SMALLINT], + TDengineTypeCode.SMALLINT + ); } - setUSmallInt(params :any[]) { + setUSmallInt(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetSmallIntColumn params is invalid!"); - } - this.addParams(params, "number", TDengineTypeLength[TDengineTypeCode.SMALLINT_UNSIGNED], TDengineTypeCode.SMALLINT_UNSIGNED) - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetSmallIntColumn params is invalid!" + ); + } + this.addParams( + params, + "number", + TDengineTypeLength[TDengineTypeCode.SMALLINT_UNSIGNED], + TDengineTypeCode.SMALLINT_UNSIGNED + ); } - setInt(params :any[]) { + setInt(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetIntColumn params is invalid!"); - } - this.addParams(params, "number", TDengineTypeLength[TDengineTypeCode.INT], TDengineTypeCode.INT) - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetIntColumn params is invalid!" + ); + } + this.addParams( + params, + "number", + TDengineTypeLength[TDengineTypeCode.INT], + TDengineTypeCode.INT + ); } - setUInt(params :any[]) { + setUInt(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetUIntColumn params is invalid!"); - } - this.addParams(params, "number", TDengineTypeLength[TDengineTypeCode.INT_UNSIGNED], TDengineTypeCode.INT_UNSIGNED) - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetUIntColumn params is invalid!" + ); + } + this.addParams( + params, + "number", + TDengineTypeLength[TDengineTypeCode.INT_UNSIGNED], + TDengineTypeCode.INT_UNSIGNED + ); } - setBigint(params :any[]) { + setBigint(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetBigIntColumn params is invalid!"); - } - this.addParams(params, "bigint", TDengineTypeLength[TDengineTypeCode.BIGINT], TDengineTypeCode.BIGINT) - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetBigIntColumn params is invalid!" + ); + } + this.addParams( + params, + "bigint", + TDengineTypeLength[TDengineTypeCode.BIGINT], + TDengineTypeCode.BIGINT + ); } - setUBigint(params :any[]) { + setUBigint(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetUBigIntColumn params is invalid!"); - } - this.addParams(params, "bigint", TDengineTypeLength[TDengineTypeCode.BIGINT_UNSIGNED], TDengineTypeCode.BIGINT_UNSIGNED) - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetUBigIntColumn params is invalid!" + ); + } + this.addParams( + params, + "bigint", + TDengineTypeLength[TDengineTypeCode.BIGINT_UNSIGNED], + TDengineTypeCode.BIGINT_UNSIGNED + ); } - setFloat(params :any[]) { + setFloat(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetFloatColumn params is invalid!"); - } - this.addParams(params, "number", TDengineTypeLength[TDengineTypeCode.FLOAT], TDengineTypeCode.FLOAT) - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetFloatColumn params is invalid!" + ); + } + this.addParams( + params, + "number", + TDengineTypeLength[TDengineTypeCode.FLOAT], + TDengineTypeCode.FLOAT + ); } - setDouble(params :any[]) { + setDouble(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetDoubleColumn params is invalid!"); - } - this.addParams(params, "number", TDengineTypeLength[TDengineTypeCode.DOUBLE], TDengineTypeCode.DOUBLE) - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetDoubleColumn params is invalid!" + ); + } + this.addParams( + params, + "number", + TDengineTypeLength[TDengineTypeCode.DOUBLE], + TDengineTypeCode.DOUBLE + ); } - setVarchar(params :any[]) { + setVarchar(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetVarcharColumn params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetVarcharColumn params is invalid!" + ); } - this.addParams(params, TDengineTypeName[8], 0, TDengineTypeCode.VARCHAR); - + this.addParams( + params, + TDengineTypeName[8], + 0, + TDengineTypeCode.VARCHAR + ); } - setBinary(params :any[]) { + setBinary(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetBinaryColumn params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetBinaryColumn params is invalid!" + ); } this.addParams(params, TDengineTypeName[8], 0, TDengineTypeCode.BINARY); - } - setNchar(params :any[]) { + setNchar(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetNcharColumn params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetNcharColumn params is invalid!" + ); } this.addParams(params, TDengineTypeName[10], 0, TDengineTypeCode.NCHAR); } - setJson(params :any[]) { + setJson(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetJsonColumn params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetJsonColumn params is invalid!" + ); } this.addParams(params, TDengineTypeName[15], 0, TDengineTypeCode.JSON); - } - setVarBinary(params :any[]) { + setVarBinary(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetVarBinaryColumn params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetVarBinaryColumn params is invalid!" + ); } - this.addParams(params, TDengineTypeName[16], 0, TDengineTypeCode.VARBINARY); + this.addParams( + params, + TDengineTypeName[16], + 0, + TDengineTypeCode.VARBINARY + ); } - setGeometry(params :any[]) { + setGeometry(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetGeometryColumn params is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetGeometryColumn params is invalid!" + ); } - this.addParams(params, TDengineTypeName[20], 0, TDengineTypeCode.GEOMETRY); - + this.addParams( + params, + TDengineTypeName[20], + 0, + TDengineTypeCode.GEOMETRY + ); } - setTimestamp(params :any[]) { + setTimestamp(params: any[]) { if (!params || params.length == 0) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SeTimestampColumn params is invalid!"); - } - this.addParams(params, TDengineTypeName[9], TDengineTypeLength[TDengineTypeCode.TIMESTAMP], TDengineTypeCode.TIMESTAMP); - + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SeTimestampColumn params is invalid!" + ); + } + this.addParams( + params, + TDengineTypeName[9], + TDengineTypeLength[TDengineTypeCode.TIMESTAMP], + TDengineTypeCode.TIMESTAMP + ); } - protected writeDataToBuffer(dataBuffer: DataView, params: any, dataType: string = 'number', typeLen: number, columnType: number, i:number): void { + protected writeDataToBuffer( + dataBuffer: DataView, + params: any, + dataType: string = "number", + typeLen: number, + columnType: number, + i: number + ): void { if (typeof params == dataType) { switch (columnType) { case TDengineTypeCode.BOOL: { @@ -267,13 +413,17 @@ export abstract class StmtBindParams { break; } default: { - throw new TaosError(ErrorCode.ERR_UNSUPPORTED_TDENGINE_TYPE, "unsupported type for column" + columnType) + throw new TaosError( + ErrorCode.ERR_UNSUPPORTED_TDENGINE_TYPE, + "unsupported type for column" + columnType + ); } } - } else { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetTinyIntColumn params is invalid! param:=" + params) + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetTinyIntColumn params is invalid! param:=" + params + ); } } - -} \ No newline at end of file +} diff --git a/nodejs/src/stmt/wsProto.ts b/nodejs/src/stmt/wsProto.ts index bf0a52c0..4c61ac5d 100644 --- a/nodejs/src/stmt/wsProto.ts +++ b/nodejs/src/stmt/wsProto.ts @@ -20,7 +20,6 @@ interface StmtParamsInfo { paramArray?: Array> | undefined | null; } - export interface StmtFieldInfo { name: string | undefined | null; field_type: number | undefined | null; @@ -31,26 +30,31 @@ export interface StmtFieldInfo { } export class WsStmtQueryResponse extends WSQueryResponse { - affected:number | undefined | null; + affected: number | undefined | null; stmt_id?: bigint | undefined | null; is_insert?: boolean | undefined | null; fields?: Array | undefined | null; - constructor(resp:MessageResp) { + constructor(resp: MessageResp) { super(resp); - this.stmt_id = BigInt(resp.msg.stmt_id) - this.affected = resp.msg.affected + this.stmt_id = BigInt(resp.msg.stmt_id); + this.affected = resp.msg.affected; this.is_insert = resp.msg.is_insert; this.fields = resp.msg.fields; } } export const enum StmtBindType { - STMT_TYPE_TAG=1, - STMT_TYPE_BIND=2, + STMT_TYPE_TAG = 1, + STMT_TYPE_BIND = 2, } - -export function binaryBlockEncode(bindParams :StmtBindParams, bindType:StmtBindType, stmtId:bigint, reqId:bigint, row:number): ArrayBuffer { +export function binaryBlockEncode( + bindParams: StmtBindParams, + bindType: StmtBindType, + stmtId: bigint, + reqId: bigint, + row: number +): ArrayBuffer { //Computing the length of data let columns = bindParams.getParams().length; let length = TDengineTypeLength[TDengineTypeCode.BIGINT] * 4; @@ -59,7 +63,7 @@ export function binaryBlockEncode(bindParams :StmtBindParams, bindType:StmtBindT length += bindParams.getDataTotalLen(); let arrayBuffer = new ArrayBuffer(length); - let arrayView = new DataView(arrayBuffer) + let arrayView = new DataView(arrayBuffer); arrayView.setBigUint64(0, reqId, true); arrayView.setBigUint64(8, stmtId, true); @@ -85,30 +89,37 @@ export function binaryBlockEncode(bindParams :StmtBindParams, bindType:StmtBindT //data range offset let dataOffset = offset + columns * 5 + columns * 4; let headOffset = 0; - let columnsData = bindParams.getParams() - for (let i = 0; i< columnsData.length; i++) { + let columnsData = bindParams.getParams(); + for (let i = 0; i < columnsData.length; i++) { //set column data type - typeView.setUint8(headOffset, columnsData[i].type) + typeView.setUint8(headOffset, columnsData[i].type); //set column type length - typeView.setUint32(headOffset+1, columnsData[i].typeLen, true) + typeView.setUint32(headOffset + 1, columnsData[i].typeLen, true); //set column data length - lenView.setUint32(i * 4, columnsData[i].length, true) + lenView.setUint32(i * 4, columnsData[i].length, true); if (columnsData[i].data) { //get encode column data const sourceView = new Uint8Array(columnsData[i].data); - const destView = new Uint8Array(arrayBuffer, dataOffset, columnsData[i].data.byteLength); + const destView = new Uint8Array( + arrayBuffer, + dataOffset, + columnsData[i].data.byteLength + ); //splicing data destView.set(sourceView); dataOffset += columnsData[i].data.byteLength; } - headOffset += 5 + headOffset += 5; } return arrayBuffer; - } -function writeColumnToView(column: ColumnInfo, view: DataView, offset: number): number { +function writeColumnToView( + column: ColumnInfo, + view: DataView, + offset: number +): number { let currentOffset = offset; // length, type, _rows @@ -122,7 +133,9 @@ function writeColumnToView(column: ColumnInfo, view: DataView, offset: number): // isNull bitmap if (column.isNull && column.isNull.length > 0) { const isNullBuffer = new Uint8Array(column.isNull); - new Uint8Array(view.buffer, view.byteOffset + currentOffset).set(isNullBuffer); + new Uint8Array(view.buffer, view.byteOffset + currentOffset).set( + isNullBuffer + ); currentOffset += isNullBuffer.length; } @@ -140,7 +153,9 @@ function writeColumnToView(column: ColumnInfo, view: DataView, offset: number): view.setInt32(currentOffset, column.data.byteLength, true); currentOffset += TDengineTypeLength[TDengineTypeCode.INT]; if (column.data.byteLength > 0) { - new Uint8Array(view.buffer, view.byteOffset + currentOffset).set(new Uint8Array(column.data)); + new Uint8Array(view.buffer, view.byteOffset + currentOffset).set( + new Uint8Array(column.data) + ); currentOffset += column.data.byteLength; } @@ -156,40 +171,54 @@ export function stmt2BinaryBlockEncode( toBeBindColCount: number ): ArrayBuffer { if (!stmt_id) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "stmt_id is invalid"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "stmt_id is invalid" + ); } const listLength = stmtTableInfoList.length; const result = { totalTableNameSize: 0, - totalTagSize: 0, + totalTagSize: 0, totalColSize: 0, tableNameSizeList: new Array(listLength), tagSizeList: new Array(listLength), - colSizeList: new Array(listLength) + colSizeList: new Array(listLength), }; - const hasTableName = toBeBindTableNameIndex != null && toBeBindTableNameIndex >= 0; + const hasTableName = + toBeBindTableNameIndex != null && toBeBindTableNameIndex >= 0; const hasTags = toBeBindTagCount > 0; for (let i = 0; i < listLength; i++) { const tableInfo = stmtTableInfoList[i]; if (hasTableName) { const tableName = tableInfo.getTableName(); - if (!tableName) throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Table name is empty"); - const size = tableInfo.getTableNameLength() + if (!tableName) + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Table name is empty" + ); + const size = tableInfo.getTableNameLength(); if (size > 0) { result.tableNameSizeList[i] = size + 1; result.totalTableNameSize += size + 1; } else { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Table name len is empty"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Table name len is empty" + ); } - } if (hasTags) { const tagParams = tableInfo.getTags(); - if (!tagParams) throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Bind tags is empty!"); - + if (!tagParams) + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Bind tags is empty!" + ); + tagParams.encode(); const size = tagParams.getDataTotalLen(); result.tagSizeList[i] = size; @@ -197,50 +226,63 @@ export function stmt2BinaryBlockEncode( } const params = tableInfo.getParams(); - if (!params) throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Bind params is empty!"); + if (!params) + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Bind params is empty!" + ); params.encode(); const size = params.getDataTotalLen(); result.colSizeList[i] = size; result.totalColSize += size; } - let totalSize = result.totalTableNameSize + result.totalTagSize + result.totalColSize; - let toBeBindTableNameCount = (toBeBindTableNameIndex != null && toBeBindTableNameIndex >= 0) ? 1 : 0; - totalSize += stmtTableInfoList.length * ( - toBeBindTableNameCount * 2 - + (toBeBindTagCount > 0 ? 1 : 0) * 4 - + (toBeBindColCount > 0 ? 1 : 0) * 4); + let totalSize = + result.totalTableNameSize + result.totalTagSize + result.totalColSize; + let toBeBindTableNameCount = + toBeBindTableNameIndex != null && toBeBindTableNameIndex >= 0 ? 1 : 0; + totalSize += + stmtTableInfoList.length * + (toBeBindTableNameCount * 2 + + (toBeBindTagCount > 0 ? 1 : 0) * 4 + + (toBeBindColCount > 0 ? 1 : 0) * 4); let headerSize = 28; // Fixed header size let msgHeaderSize = 30; // Fixed msg header size const buffer = new ArrayBuffer(headerSize + msgHeaderSize + totalSize); const view = new DataView(buffer); let offset = 0; - view.setBigUint64(offset, reqId, true); + view.setBigUint64(offset, reqId, true); offset += TDengineTypeLength[TDengineTypeCode.BIGINT]; - view.setBigUint64(offset, stmt_id, true); + view.setBigUint64(offset, stmt_id, true); offset += TDengineTypeLength[TDengineTypeCode.BIGINT]; - view.setBigUint64(offset, 9n, true); + view.setBigUint64(offset, 9n, true); offset += TDengineTypeLength[TDengineTypeCode.BIGINT]; // action: bind view.setInt16(offset, 1, true); offset += TDengineTypeLength[TDengineTypeCode.SMALLINT]; // version - view.setInt32(offset, -1, true); + view.setInt32(offset, -1, true); offset += TDengineTypeLength[TDengineTypeCode.INT]; view.setInt32(offset, totalSize + headerSize, true); offset += TDengineTypeLength[TDengineTypeCode.INT]; // total length - view.setInt32(offset, stmtTableInfoList.length, true); + view.setInt32(offset, stmtTableInfoList.length, true); offset += TDengineTypeLength[TDengineTypeCode.INT]; - view.setInt32(offset, toBeBindTagCount, true); + view.setInt32(offset, toBeBindTagCount, true); offset += TDengineTypeLength[TDengineTypeCode.INT]; - view.setInt32(offset, toBeBindColCount, true); + view.setInt32(offset, toBeBindColCount, true); offset += TDengineTypeLength[TDengineTypeCode.INT]; - view.setInt32(offset, toBeBindTableNameCount > 0 ? 0x1C : 0, true); + view.setInt32(offset, toBeBindTableNameCount > 0 ? 0x1c : 0, true); offset += TDengineTypeLength[TDengineTypeCode.INT]; if (toBeBindTagCount) { if (toBeBindTableNameCount > 0) { - view.setInt32(offset, headerSize + result.totalTableNameSize + 2 * stmtTableInfoList.length, true); + view.setInt32( + offset, + headerSize + + result.totalTableNameSize + + 2 * stmtTableInfoList.length, + true + ); } else { view.setInt32(offset, headerSize, true); } @@ -252,7 +294,8 @@ export function stmt2BinaryBlockEncode( if (toBeBindColCount > 0) { let skipSize = 0; if (toBeBindTableNameCount > 0) { - skipSize += result.totalTableNameSize + 2 * stmtTableInfoList.length; + skipSize += + result.totalTableNameSize + 2 * stmtTableInfoList.length; } if (toBeBindTagCount > 0) { @@ -266,7 +309,10 @@ export function stmt2BinaryBlockEncode( offset += TDengineTypeLength[TDengineTypeCode.INT]; if (toBeBindTableNameCount > 0) { - let dataOffset = offset + result.tableNameSizeList.length * TDengineTypeLength[TDengineTypeCode.SMALLINT]; + let dataOffset = + offset + + result.tableNameSizeList.length * + TDengineTypeLength[TDengineTypeCode.SMALLINT]; for (let i = 0; i < listLength; i++) { view.setInt16(offset, result.tableNameSizeList[i], true); offset += TDengineTypeLength[TDengineTypeCode.SMALLINT]; @@ -278,14 +324,20 @@ export function stmt2BinaryBlockEncode( view.setUint8(dataOffset, 0); dataOffset += 1; } else { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Table name is empty"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Table name is empty" + ); } } offset = dataOffset; } - + if (toBeBindTagCount > 0) { - let dataOffset = offset + result.tagSizeList.length * TDengineTypeLength[TDengineTypeCode.INT]; + let dataOffset = + offset + + result.tagSizeList.length * + TDengineTypeLength[TDengineTypeCode.INT]; for (let i = 0; i < listLength; i++) { view.setInt32(offset, result.tagSizeList[i], true); offset += TDengineTypeLength[TDengineTypeCode.INT]; @@ -293,31 +345,47 @@ export function stmt2BinaryBlockEncode( if (tags && tags.getParams().length > 0) { for (const col of tags.getParams()) { - dataOffset += writeColumnToView(col, new DataView(buffer, dataOffset), 0); + dataOffset += writeColumnToView( + col, + new DataView(buffer, dataOffset), + 0 + ); } } else { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Tags are empty"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Tags are empty" + ); } } offset = dataOffset; } - + // ColumnDataLength if (toBeBindColCount > 0) { - let dataOffset = offset + result.colSizeList.length * TDengineTypeLength[TDengineTypeCode.INT]; - for (let i = 0; i < listLength; i++) { + let dataOffset = + offset + + result.colSizeList.length * + TDengineTypeLength[TDengineTypeCode.INT]; + for (let i = 0; i < listLength; i++) { view.setInt32(offset, result.colSizeList[i], true); offset += TDengineTypeLength[TDengineTypeCode.INT]; let params = stmtTableInfoList[i].getParams(); if (!params) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Bind params is empty!"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Bind params is empty!" + ); } for (const col of params.getParams()) { - dataOffset += writeColumnToView(col, new DataView(buffer, dataOffset), 0); - } + dataOffset += writeColumnToView( + col, + new DataView(buffer, dataOffset), + 0 + ); + } } } return buffer; - } diff --git a/nodejs/src/stmt/wsStmt.ts b/nodejs/src/stmt/wsStmt.ts index 87000192..4d681043 100644 --- a/nodejs/src/stmt/wsStmt.ts +++ b/nodejs/src/stmt/wsStmt.ts @@ -2,16 +2,15 @@ import { WSRows } from "../sql/wsRows"; import { StmtBindParams } from "./wsParamsBase"; export interface WsStmt { - getStmtId(): bigint | undefined | null + getStmtId(): bigint | undefined | null; prepare(sql: string): Promise; setTableName(tableName: string): Promise; - setTags(paramsArray:StmtBindParams): Promise; - newStmtParam():StmtBindParams - bind(paramsArray:StmtBindParams): Promise; + setTags(paramsArray: StmtBindParams): Promise; + newStmtParam(): StmtBindParams; + bind(paramsArray: StmtBindParams): Promise; batch(): Promise; exec(): Promise; resultSet(): Promise; getLastAffected(): number | null | undefined; - close(): Promise - -} \ No newline at end of file + close(): Promise; +} diff --git a/nodejs/src/stmt/wsStmt1.ts b/nodejs/src/stmt/wsStmt1.ts index 8948ef3e..50e0819d 100644 --- a/nodejs/src/stmt/wsStmt1.ts +++ b/nodejs/src/stmt/wsStmt1.ts @@ -1,42 +1,55 @@ -import JSONBig from 'json-bigint'; -import { WsClient } from '../client/wsClient'; -import { ErrorCode, TDWebSocketClientError, TaosError, TaosResultError } from '../common/wsError'; -import { WsStmtQueryResponse, StmtMessageInfo, binaryBlockEncode, StmtBindType } from './wsProto'; -import { ReqId } from '../common/reqid'; -import { PrecisionLength } from '../common/constant'; -import { StmtBindParams } from './wsParamsBase'; -import { WsStmt } from './wsStmt'; -import logger from '../common/log'; -import { Stmt1BindParams } from './wsParams1'; -import { WSRows } from '../sql/wsRows'; - -export class WsStmt1 implements WsStmt{ +import JSONBig from "json-bigint"; +import { WsClient } from "../client/wsClient"; +import { + ErrorCode, + TDWebSocketClientError, + TaosError, + TaosResultError, +} from "../common/wsError"; +import { + WsStmtQueryResponse, + StmtMessageInfo, + binaryBlockEncode, + StmtBindType, +} from "./wsProto"; +import { ReqId } from "../common/reqid"; +import { PrecisionLength } from "../common/constant"; +import { StmtBindParams } from "./wsParamsBase"; +import { WsStmt } from "./wsStmt"; +import logger from "../common/log"; +import { Stmt1BindParams } from "./wsParams1"; +import { WSRows } from "../sql/wsRows"; + +export class WsStmt1 implements WsStmt { private _wsClient: WsClient; private _stmt_id: bigint | undefined | null; - private _precision:number = PrecisionLength['ms']; + private _precision: number = PrecisionLength["ms"]; private lastAffected: number | undefined | null; - private constructor(wsClient: WsClient, precision?:number) { + private constructor(wsClient: WsClient, precision?: number) { this._wsClient = wsClient; if (precision) { this._precision = precision; } } - static async newStmt(wsClient: WsClient, precision?:number, reqId?:number): Promise { + static async newStmt( + wsClient: WsClient, + precision?: number, + reqId?: number + ): Promise { try { - let wsStmt = new WsStmt1(wsClient, precision) + let wsStmt = new WsStmt1(wsClient, precision); return await wsStmt.init(reqId); - } catch(e: any) { + } catch (e: any) { logger.error(`WsStmt init is failed, ${e.code}, ${e.message}`); - throw(e); + throw e; } - } async prepare(sql: string): Promise { let queryMsg = { - action: 'prepare', + action: "prepare", args: { req_id: ReqId.getReqID(), sql: sql, @@ -48,7 +61,7 @@ export class WsStmt1 implements WsStmt{ async setTableName(tableName: string): Promise { let queryMsg = { - action: 'set_table_name', + action: "set_table_name", args: { req_id: ReqId.getReqID(), name: tableName, @@ -60,7 +73,7 @@ export class WsStmt1 implements WsStmt{ async setJsonTags(tags: Array): Promise { let queryMsg = { - action: 'set_tags', + action: "set_tags", args: { req_id: ReqId.getReqID(), tags: tags, @@ -70,41 +83,65 @@ export class WsStmt1 implements WsStmt{ return await this.execute(queryMsg); } - newStmtParam():Stmt1BindParams { + newStmtParam(): Stmt1BindParams { return new Stmt1BindParams(this._precision); } - async setTags(paramsArray:StmtBindParams): Promise { + async setTags(paramsArray: StmtBindParams): Promise { if (!paramsArray || !this._stmt_id) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetBinaryTags paramArray is invalid!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetBinaryTags paramArray is invalid!" + ); } let columnInfos = paramsArray.getParams(); if (!columnInfos) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "SetBinaryTags paramArray is invalid!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "SetBinaryTags paramArray is invalid!" + ); } - let reqId = BigInt(ReqId.getReqID()) - let dataBlock = binaryBlockEncode(paramsArray, StmtBindType.STMT_TYPE_TAG, this._stmt_id, reqId, paramsArray.getDataRows()) - return await this.sendBinaryMsg(reqId, 'set_tags', dataBlock); + let reqId = BigInt(ReqId.getReqID()); + let dataBlock = binaryBlockEncode( + paramsArray, + StmtBindType.STMT_TYPE_TAG, + this._stmt_id, + reqId, + paramsArray.getDataRows() + ); + return await this.sendBinaryMsg(reqId, "set_tags", dataBlock); } - async bind(paramsArray:StmtBindParams): Promise { + async bind(paramsArray: StmtBindParams): Promise { if (!paramsArray || !this._stmt_id) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "BinaryBind paramArray is invalid!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "BinaryBind paramArray is invalid!" + ); } let columnInfos = paramsArray.getParams(); if (!columnInfos) { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "BinaryBind paramArray is invalid!") + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "BinaryBind paramArray is invalid!" + ); } - let reqId = BigInt(ReqId.getReqID()) - let dataBlock = binaryBlockEncode(paramsArray, StmtBindType.STMT_TYPE_BIND, this._stmt_id, reqId, paramsArray.getDataRows()); - return await this.sendBinaryMsg(reqId, 'bind', dataBlock); + let reqId = BigInt(ReqId.getReqID()); + let dataBlock = binaryBlockEncode( + paramsArray, + StmtBindType.STMT_TYPE_BIND, + this._stmt_id, + reqId, + paramsArray.getDataRows() + ); + return await this.sendBinaryMsg(reqId, "bind", dataBlock); } async jsonBind(paramArray: Array>): Promise { let queryMsg = { - action: 'bind', + action: "bind", args: { req_id: ReqId.getReqID(), columns: paramArray, @@ -116,7 +153,7 @@ export class WsStmt1 implements WsStmt{ async batch(): Promise { let queryMsg = { - action: 'add_batch', + action: "add_batch", args: { req_id: ReqId.getReqID(), stmt_id: this._stmt_id, @@ -127,7 +164,7 @@ export class WsStmt1 implements WsStmt{ async exec(): Promise { let queryMsg = { - action: 'exec', + action: "exec", args: { req_id: ReqId.getReqID(), stmt_id: this._stmt_id, @@ -146,7 +183,7 @@ export class WsStmt1 implements WsStmt{ async close(): Promise { let queryMsg = { - action: 'close', + action: "close", args: { req_id: ReqId.getReqID(), stmt_id: this._stmt_id, @@ -157,72 +194,91 @@ export class WsStmt1 implements WsStmt{ public getStmtId(): bigint | undefined | null { return this._stmt_id; - } - - private async execute(queryMsg: StmtMessageInfo, register: Boolean = true): Promise { + } + + private async execute( + queryMsg: StmtMessageInfo, + register: Boolean = true + ): Promise { try { if (this._wsClient.getState() <= 0) { - throw new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "websocket connect has closed!"); + throw new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "websocket connect has closed!" + ); } let reqMsg = JSONBig.stringify(queryMsg); if (register) { let result = await this._wsClient.exec(reqMsg, false); - let resp = new WsStmtQueryResponse(result) + let resp = new WsStmtQueryResponse(result); if (resp.stmt_id) { this._stmt_id = resp.stmt_id; } if (resp.affected) { - this.lastAffected = resp.affected - } - }else{ + this.lastAffected = resp.affected; + } + } else { await this._wsClient.execNoResp(reqMsg); - this._stmt_id = null - this.lastAffected = null + this._stmt_id = null; + this.lastAffected = null; } - return - } catch (e:any) { + return; + } catch (e: any) { throw new TaosResultError(e.code, e.message); } } - private async sendBinaryMsg(reqId: bigint, action:string, message: ArrayBuffer): Promise { + private async sendBinaryMsg( + reqId: bigint, + action: string, + message: ArrayBuffer + ): Promise { if (this._wsClient.getState() <= 0) { - throw new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "websocket connect has closed!"); + throw new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "websocket connect has closed!" + ); } - let result = await this._wsClient.sendBinaryMsg(reqId, action, message, false); - let resp = new WsStmtQueryResponse(result) + let result = await this._wsClient.sendBinaryMsg( + reqId, + action, + message, + false + ); + let resp = new WsStmtQueryResponse(result); if (resp.stmt_id) { this._stmt_id = resp.stmt_id; } if (resp.affected) { - this.lastAffected = resp.affected - } + this.lastAffected = resp.affected; + } } - private async init(reqId?: number):Promise { - if (this._wsClient) { + private async init(reqId?: number): Promise { + if (this._wsClient) { try { if (this._wsClient.getState() <= 0) { await this._wsClient.connect(); await this._wsClient.checkVersion(); } let queryMsg = { - action: 'init', + action: "init", args: { req_id: ReqId.getReqID(reqId), }, }; await this.execute(queryMsg); - return this; + return this; } catch (e: any) { logger.error(`stmt init filed, ${e.code}, ${e.message}`); - throw(e); - } - + throw e; + } } - throw(new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "stmt connect closed")); + throw new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "stmt connect closed" + ); } - } diff --git a/nodejs/src/stmt/wsStmt2.ts b/nodejs/src/stmt/wsStmt2.ts index 1bfe190d..d54ea69b 100644 --- a/nodejs/src/stmt/wsStmt2.ts +++ b/nodejs/src/stmt/wsStmt2.ts @@ -1,23 +1,32 @@ -import JSONBig from 'json-bigint'; +import JSONBig from "json-bigint"; import { WsClient } from "../client/wsClient"; import { FieldBindType, PrecisionLength } from "../common/constant"; import logger from "../common/log"; import { ReqId } from "../common/reqid"; -import { ErrorCode, TaosResultError, TDWebSocketClientError } from "../common/wsError"; +import { + ErrorCode, + TaosResultError, + TDWebSocketClientError, +} from "../common/wsError"; import { StmtBindParams } from "./wsParamsBase"; -import { stmt2BinaryBlockEncode, StmtFieldInfo, StmtMessageInfo, WsStmtQueryResponse } from "./wsProto"; +import { + stmt2BinaryBlockEncode, + StmtFieldInfo, + StmtMessageInfo, + WsStmtQueryResponse, +} from "./wsProto"; import { WsStmt } from "./wsStmt"; -import { _isVarType } from '../common/taosResult'; -import { Stmt2BindParams } from './wsParams2'; -import { TableInfo } from './wsTableInfo'; -import { WSRows } from '../sql/wsRows'; -import { FieldBindParams } from './FieldBindParams'; +import { _isVarType } from "../common/taosResult"; +import { Stmt2BindParams } from "./wsParams2"; +import { TableInfo } from "./wsTableInfo"; +import { WSRows } from "../sql/wsRows"; +import { FieldBindParams } from "./FieldBindParams"; -export class WsStmt2 implements WsStmt{ +export class WsStmt2 implements WsStmt { private _wsClient: WsClient; private _stmt_id: bigint | undefined | null; private _query_id: bigint | undefined | null; - private _precision:number = PrecisionLength['ms']; + private _precision: number = PrecisionLength["ms"]; private fields?: Array | undefined | null; private lastAffected: number | undefined | null; private _stmtTableInfo: Map; @@ -27,7 +36,7 @@ export class WsStmt2 implements WsStmt{ private _toBeBindColCount: number; private _toBeBindTableNameIndex: number | undefined | null; private _isInsert: boolean = false; - private constructor(wsClient: WsClient, precision?:number) { + private constructor(wsClient: WsClient, precision?: number) { this._wsClient = wsClient; if (precision) { this._precision = precision; @@ -38,51 +47,56 @@ export class WsStmt2 implements WsStmt{ this._toBeBindColCount = 0; this._toBeBindTagCount = 0; } - - static async newStmt(wsClient: WsClient, precision?:number, reqId?:number): Promise { + + static async newStmt( + wsClient: WsClient, + precision?: number, + reqId?: number + ): Promise { try { - let wsStmt = new WsStmt2(wsClient, precision) + let wsStmt = new WsStmt2(wsClient, precision); return await wsStmt.init(reqId); - } catch(e: any) { + } catch (e: any) { logger.error(`WsStmt init is failed, ${e.code}, ${e.message}`); - throw(e); + throw e; } - } private async init(reqId: number | undefined): Promise { - if (this._wsClient) { - try { - if (this._wsClient.getState() <= 0) { - await this._wsClient.connect(); - await this._wsClient.checkVersion(); + if (this._wsClient) { + try { + if (this._wsClient.getState() <= 0) { + await this._wsClient.connect(); + await this._wsClient.checkVersion(); + } + let queryMsg = { + action: "stmt2_init", + args: { + req_id: ReqId.getReqID(reqId), + single_stb_insert: true, + single_table_bind_once: true, + }, + }; + await this.execute(queryMsg); + return this; + } catch (e: any) { + logger.error(`stmt init filed, ${e.code}, ${e.message}`); + throw e; } - let queryMsg = { - action: 'stmt2_init', - args: { - req_id: ReqId.getReqID(reqId), - single_stb_insert: true, - single_table_bind_once: true - }, - }; - await this.execute(queryMsg); - return this; - } catch (e: any) { - logger.error(`stmt init filed, ${e.code}, ${e.message}`); - throw(e); - } - } - throw(new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "stmt connect closed")); + throw new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "stmt connect closed" + ); } getStmtId(): bigint | undefined | null { return this._stmt_id; } - + async prepare(sql: string): Promise { let queryMsg = { - action: 'stmt2_prepare', + action: "stmt2_prepare", args: { req_id: ReqId.getReqID(), sql: sql, @@ -91,8 +105,10 @@ export class WsStmt2 implements WsStmt{ }, }; let resp = await this.execute(queryMsg); - if (this._isInsert && this.fields) { - this._precision = this.fields[0].precision ? this.fields[0].precision : 0; + if (this._isInsert && this.fields) { + this._precision = this.fields[0].precision + ? this.fields[0].precision + : 0; this._toBeBindColCount = 0; this._toBeBindTagCount = 0; this.fields?.forEach((field, index) => { @@ -103,20 +119,26 @@ export class WsStmt2 implements WsStmt{ } else if (field.bind_type == FieldBindType.TAOS_FIELD_COL) { this._toBeBindColCount++; } - }); - } else { + }); + } else { if (resp && resp.fields_count && resp.fields_count > 0) { this._stmtTableInfoList = [this._currentTableInfo]; this._toBeBindColCount = resp.fields_count; } else { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "prepare No columns to bind!"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "prepare No columns to bind!" + ); } } } async setTableName(tableName: string): Promise { if (!tableName || tableName.length === 0) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, 'Table name cannot be empty'); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Table name cannot be empty" + ); } let tableInfo = this._stmtTableInfo.get(tableName); if (!tableInfo) { @@ -131,7 +153,10 @@ export class WsStmt2 implements WsStmt{ async setTags(paramsArray: StmtBindParams): Promise { if (!paramsArray || !this._stmt_id) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "SetBinaryTags paramArray is invalid!"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "SetBinaryTags paramArray is invalid!" + ); } if (!this._currentTableInfo) { @@ -139,58 +164,103 @@ export class WsStmt2 implements WsStmt{ this._stmtTableInfoList.push(this._currentTableInfo); } await this._currentTableInfo.setTags(paramsArray); - + return Promise.resolve(); } newStmtParam(): StmtBindParams { - if (this._isInsert) { + if (this._isInsert) { if (!this.fields || this.fields.length === 0) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "No columns to bind!"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "No columns to bind!" + ); } - return new Stmt2BindParams(this.fields.length, this._precision, this.fields); + return new Stmt2BindParams( + this.fields.length, + this._precision, + this.fields + ); } return new Stmt2BindParams(); } async bind(paramsArray: StmtBindParams): Promise { if (!paramsArray || !this._stmt_id || !paramsArray._fieldParams) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Bind paramArray is invalid!"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Bind paramArray is invalid!" + ); } - if (this._isInsert && this.fields && paramsArray.getBindCount() == this.fields.length) { + if ( + this._isInsert && + this.fields && + paramsArray.getBindCount() == this.fields.length + ) { const tableNameIndex = this._toBeBindTableNameIndex; if (tableNameIndex === null || tableNameIndex === undefined) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Table name index is null or undefined!"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Table name index is null or undefined!" + ); } const paramsCount = paramsArray._fieldParams[0].params.length; for (let i = 0; i < paramsCount; i++) { - let tableName = paramsArray._fieldParams[tableNameIndex].params[i]; + let tableName = + paramsArray._fieldParams[tableNameIndex].params[i]; await this.setTableName(tableName); for (let j = 0; j < paramsArray._fieldParams.length; j++) { if (j == tableNameIndex) { continue; } let fieldParam = paramsArray._fieldParams[j]; - if (this.fields[j].bind_type == FieldBindType.TAOS_FIELD_TAG) { + if ( + this.fields[j].bind_type == FieldBindType.TAOS_FIELD_TAG + ) { if (!this._currentTableInfo.tags) { - this._currentTableInfo.tags = new Stmt2BindParams(this._toBeBindTagCount, this._precision, this.fields); + this._currentTableInfo.tags = new Stmt2BindParams( + this._toBeBindTagCount, + this._precision, + this.fields + ); } - this._currentTableInfo.tags.addBindFieldParams(new FieldBindParams([fieldParam.params[i]], fieldParam.dataType, fieldParam.typeLen, fieldParam.columnType, fieldParam.bindType)); - }else if (this.fields[j].bind_type == FieldBindType.TAOS_FIELD_COL) { + this._currentTableInfo.tags.addBindFieldParams( + new FieldBindParams( + [fieldParam.params[i]], + fieldParam.dataType, + fieldParam.typeLen, + fieldParam.columnType, + fieldParam.bindType + ) + ); + } else if ( + this.fields[j].bind_type == FieldBindType.TAOS_FIELD_COL + ) { if (!this._currentTableInfo.params) { - this._currentTableInfo.params = new Stmt2BindParams(this._toBeBindColCount, this._precision, this.fields); + this._currentTableInfo.params = new Stmt2BindParams( + this._toBeBindColCount, + this._precision, + this.fields + ); } - this._currentTableInfo.params.addBindFieldParams(new FieldBindParams([fieldParam.params[i]], fieldParam.dataType, fieldParam.typeLen, fieldParam.columnType, fieldParam.bindType)); + this._currentTableInfo.params.addBindFieldParams( + new FieldBindParams( + [fieldParam.params[i]], + fieldParam.dataType, + fieldParam.typeLen, + fieldParam.columnType, + fieldParam.bindType + ) + ); } } - } } else { await this._currentTableInfo.setParams(paramsArray); } - + return Promise.resolve(); } @@ -199,26 +269,34 @@ export class WsStmt2 implements WsStmt{ } async exec(): Promise { - if (!this._currentTableInfo ) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "table info is empty!"); + if (!this._currentTableInfo) { + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "table info is empty!" + ); } let params = this._currentTableInfo.getParams(); if (!params) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "Bind params is empty!"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "Bind params is empty!" + ); } let reqId = BigInt(ReqId.getReqID()); - let bytes = stmt2BinaryBlockEncode(reqId, - this._stmtTableInfoList, + let bytes = stmt2BinaryBlockEncode( + reqId, + this._stmtTableInfoList, this._stmt_id, this._toBeBindTableNameIndex, - this._toBeBindTagCount, - this._toBeBindColCount) - await this.sendBinaryMsg(reqId, 'stmt2_bind', new Uint8Array(bytes)); + this._toBeBindTagCount, + this._toBeBindColCount + ); + await this.sendBinaryMsg(reqId, "stmt2_bind", new Uint8Array(bytes)); let execMsg = { - action: 'stmt2_exec', + action: "stmt2_exec", args: { req_id: ReqId.getReqID(), stmt_id: this._stmt_id, @@ -240,7 +318,7 @@ export class WsStmt2 implements WsStmt{ async resultSet(): Promise { let execMsg = { - action: 'stmt2_result', + action: "stmt2_result", args: { req_id: ReqId.getReqID(), stmt_id: this._stmt_id, @@ -248,15 +326,17 @@ export class WsStmt2 implements WsStmt{ }; let resp = await this.execute(execMsg); if (!resp) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, "ResultSet response is empty!"); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "ResultSet response is empty!" + ); } return new WSRows(this._wsClient, resp); - } async close(): Promise { let queryMsg = { - action: 'stmt2_close', + action: "stmt2_close", args: { req_id: ReqId.getReqID(), stmt_id: this._stmt_id, @@ -265,24 +345,30 @@ export class WsStmt2 implements WsStmt{ await this.execute(queryMsg); } - private async execute(stmtMsg: StmtMessageInfo|ArrayBuffer, register: Boolean = true): Promise { + private async execute( + stmtMsg: StmtMessageInfo | ArrayBuffer, + register: Boolean = true + ): Promise { try { if (this._wsClient.getState() <= 0) { - throw new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "websocket connect has closed!"); + throw new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "websocket connect has closed!" + ); } let reqMsg = JSONBig.stringify(stmtMsg); - + if (register) { let result = await this._wsClient.exec(reqMsg, false); - let resp = new WsStmtQueryResponse(result) + let resp = new WsStmtQueryResponse(result); if (resp.stmt_id) { this._stmt_id = resp.stmt_id; } if (resp.affected) { - this.lastAffected = resp.affected - } + this.lastAffected = resp.affected; + } if (resp.fields) { this.fields = resp.fields; @@ -296,27 +382,37 @@ export class WsStmt2 implements WsStmt{ } await this._wsClient.execNoResp(reqMsg); - this._stmt_id = null - this.lastAffected = null - } catch (e:any) { + this._stmt_id = null; + this.lastAffected = null; + } catch (e: any) { throw new TaosResultError(e.code, e.message); } } - private async sendBinaryMsg(reqId: bigint, action:string, message: ArrayBuffer): Promise { + private async sendBinaryMsg( + reqId: bigint, + action: string, + message: ArrayBuffer + ): Promise { if (this._wsClient.getState() <= 0) { - throw new TDWebSocketClientError(ErrorCode.ERR_CONNECTION_CLOSED, "websocket connect has closed!"); + throw new TDWebSocketClientError( + ErrorCode.ERR_CONNECTION_CLOSED, + "websocket connect has closed!" + ); } - let result = await this._wsClient.sendBinaryMsg(reqId, action, message, false); - let resp = new WsStmtQueryResponse(result) + let result = await this._wsClient.sendBinaryMsg( + reqId, + action, + message, + false + ); + let resp = new WsStmtQueryResponse(result); if (resp.stmt_id) { this._stmt_id = resp.stmt_id; } if (resp.affected) { - this.lastAffected = resp.affected - } + this.lastAffected = resp.affected; + } } - - -} \ No newline at end of file +} diff --git a/nodejs/src/stmt/wsTableInfo.ts b/nodejs/src/stmt/wsTableInfo.ts index f7b3cb95..874f8df9 100644 --- a/nodejs/src/stmt/wsTableInfo.ts +++ b/nodejs/src/stmt/wsTableInfo.ts @@ -1,6 +1,6 @@ import { ErrorCode, TaosError } from "../common/wsError"; import { StmtBindParams } from "./wsParamsBase"; -import JSONBig from 'json-bigint'; +import JSONBig from "json-bigint"; export class TableInfo { name: Uint8Array | undefined | null; @@ -11,7 +11,7 @@ export class TableInfo { constructor(name?: string) { if (name && name.length > 0) { this.name = this.textEncoder.encode(name); - this.length = this.name.length; + this.length = this.name.length; } } @@ -34,16 +34,22 @@ export class TableInfo { public setTableName(name: string): void { if (name && name.length > 0) { this.name = this.textEncoder.encode(name); - this.length = this.name.length; + this.length = this.name.length; } else { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "Table name is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "Table name is invalid!" + ); } } - async setTags(paramsArray:StmtBindParams): Promise { + async setTags(paramsArray: StmtBindParams): Promise { if (paramsArray) { this.tags = paramsArray; } else { - throw new TaosError(ErrorCode.ERR_INVALID_PARAMS, "Table tags is invalid!"); + throw new TaosError( + ErrorCode.ERR_INVALID_PARAMS, + "Table tags is invalid!" + ); } } async setParams(bindParams: StmtBindParams): Promise { @@ -55,4 +61,4 @@ export class TableInfo { } } } -} \ No newline at end of file +} diff --git a/nodejs/src/tmq/config.ts b/nodejs/src/tmq/config.ts index 272f8b5d..4e954076 100644 --- a/nodejs/src/tmq/config.ts +++ b/nodejs/src/tmq/config.ts @@ -14,9 +14,8 @@ export class TmqConfig { auto_commit_interval_ms: number = 5 * 1000; timeout: number = 5000; otherConfigs: Map; - - constructor(wsConfig:Map) { + constructor(wsConfig: Map) { this.otherConfigs = new Map(); for (const [key, value] of wsConfig) { switch (key) { @@ -49,28 +48,24 @@ export class TmqConfig { break; default: this.otherConfigs.set(key, value); - } } - + if (this.url) { if (this.user) { this.url.username = this.user; - }else{ + } else { this.user = this.url.username; } if (this.password) { this.url.password = this.password; - - }else{ + } else { this.password = this.url.password; } - + this.sql_url = new URL(this.url); - this.sql_url.pathname = '/ws'; - this.url.pathname = '/rest/tmq' + this.sql_url.pathname = "/ws"; + this.url.pathname = "/rest/tmq"; } - } - -} \ No newline at end of file +} diff --git a/nodejs/src/tmq/constant.ts b/nodejs/src/tmq/constant.ts index 8c440af0..d701ba84 100644 --- a/nodejs/src/tmq/constant.ts +++ b/nodejs/src/tmq/constant.ts @@ -1,102 +1,102 @@ export class TMQConstants { - public static GROUP_ID: string = 'group.id'; + public static GROUP_ID: string = "group.id"; - public static CLIENT_ID: string = 'client.id'; + public static CLIENT_ID: string = "client.id"; /** * auto commit default is true then the commitCallback function will be called after 5 seconds */ - public static ENABLE_AUTO_COMMIT: string = 'enable.auto.commit'; + public static ENABLE_AUTO_COMMIT: string = "enable.auto.commit"; /** * commit interval. unit milliseconds */ - public static AUTO_COMMIT_INTERVAL_MS: string = 'auto.commit.interval.ms'; + public static AUTO_COMMIT_INTERVAL_MS: string = "auto.commit.interval.ms"; /** * only valid in first group id create. */ - public static AUTO_OFFSET_RESET: string = 'auto.offset.reset'; + public static AUTO_OFFSET_RESET: string = "auto.offset.reset"; /** * whether poll result include table name. suggest always true */ - public static MSG_WITH_TABLE_NAME: string = 'msg.with.table.name'; + public static MSG_WITH_TABLE_NAME: string = "msg.with.table.name"; /** * indicate host and port of connection */ - public static BOOTSTRAP_SERVERS: string = 'bootstrap.servers'; + public static BOOTSTRAP_SERVERS: string = "bootstrap.servers"; /** * deserializer Bean */ - public static VALUE_DESERIALIZER: string = 'value.deserializer'; + public static VALUE_DESERIALIZER: string = "value.deserializer"; /** * encode for deserializer String value */ - public static VALUE_DESERIALIZER_ENCODING: string = 'value.deserializer.encoding'; + public static VALUE_DESERIALIZER_ENCODING: string = + "value.deserializer.encoding"; /** * connection ip */ - public static CONNECT_IP: string = 'td.connect.ip'; + public static CONNECT_IP: string = "td.connect.ip"; /** * connection port */ - public static CONNECT_PORT: string = 'td.connect.port'; + public static CONNECT_PORT: string = "td.connect.port"; /** * connection username */ - public static CONNECT_USER: string = 'td.connect.user'; + public static CONNECT_USER: string = "td.connect.user"; /** * connection password */ - public static CONNECT_PASS: string = 'td.connect.pass'; + public static CONNECT_PASS: string = "td.connect.pass"; /** * connect type websocket or jni, default is jni */ - public static CONNECT_TYPE: string = 'td.connect.type'; + public static CONNECT_TYPE: string = "td.connect.type"; /** * Key used to retrieve the token value from the properties instance passed to * the driver. * Just for Cloud Service */ - public static WS_URL: string = 'ws.url'; + public static WS_URL: string = "ws.url"; /** * the timeout in milliseconds until a connection is established. * zero is interpreted as an infinite timeout. * only valid in websocket */ - public static CONNECT_TIMEOUT: string = 'httpConnectTimeout'; + public static CONNECT_TIMEOUT: string = "httpConnectTimeout"; /** * message receive from server timeout. ms. * only valid in websocket */ - public static CONNECT_MESSAGE_TIMEOUT: string = 'messageWaitTimeout'; - + public static CONNECT_MESSAGE_TIMEOUT: string = "messageWaitTimeout"; } export class TMQMessageType { - public static Subscribe: string = 'subscribe'; - public static Poll: string = 'poll'; - public static FetchRaw: string = 'fetch_raw'; - public static FetchJsonMeta: string = 'fetch_json_meta'; - public static Commit: string = 'commit'; - public static Unsubscribe: string = 'unsubscribe'; - public static GetTopicAssignment: string = 'assignment'; - public static Seek: string = 'seek'; - public static CommitOffset: string = 'commit_offset'; - public static Committed: string = 'committed'; - public static Position: string = 'position'; + public static Subscribe: string = "subscribe"; + public static Poll: string = "poll"; + public static FetchRaw: string = "fetch_raw"; + public static FetchJsonMeta: string = "fetch_json_meta"; + public static Commit: string = "commit"; + public static Unsubscribe: string = "unsubscribe"; + public static GetTopicAssignment: string = "assignment"; + public static Seek: string = "seek"; + public static CommitOffset: string = "commit_offset"; + public static Committed: string = "committed"; + public static Position: string = "position"; public static ListTopics: string = "list_topics"; public static ResDataType: number = 1; } @@ -104,19 +104,19 @@ export class TMQMessageType { export class TMQBlockInfo { rawBlock?: ArrayBuffer; precision?: number; - schema: Array; + schema: Array; tableName?: string; constructor() { this.schema = []; } } -export class TMQRawDataSchema { +export class TMQRawDataSchema { colType: number; - flag: number; - bytes: bigint; - colID: number - name: string; + flag: number; + bytes: bigint; + colID: number; + name: string; precision: number; scale: number; constructor() { @@ -127,7 +127,5 @@ export class TMQRawDataSchema { this.name = ""; this.scale = 0; this.precision = 0; - } } - diff --git a/nodejs/src/tmq/tmqResponse.ts b/nodejs/src/tmq/tmqResponse.ts index 913e85ff..6cf95dc3 100644 --- a/nodejs/src/tmq/tmqResponse.ts +++ b/nodejs/src/tmq/tmqResponse.ts @@ -1,7 +1,24 @@ import { WSQueryResponse } from "../client/wsResponse"; -import { ColumnsBlockType, TDengineTypeCode, TDengineTypeLength } from "../common/constant"; -import { MessageResp, TaosResult, _isVarType, getString, readBinary, readNchar, readSolidDataToArray, readVarchar } from "../common/taosResult"; -import { WebSocketInterfaceError, ErrorCode, TDWebSocketClientError } from "../common/wsError"; +import { + ColumnsBlockType, + TDengineTypeCode, + TDengineTypeLength, +} from "../common/constant"; +import { + MessageResp, + TaosResult, + _isVarType, + getString, + readBinary, + readNchar, + readSolidDataToArray, + readVarchar, +} from "../common/taosResult"; +import { + WebSocketInterfaceError, + ErrorCode, + TDWebSocketClientError, +} from "../common/wsError"; import { TMQBlockInfo, TMQRawDataSchema } from "./constant"; import { zigzagDecode } from "../common/utils"; import logger from "../common/log"; @@ -14,13 +31,13 @@ export class WsPollResponse { have_message: boolean; topic: string; database: string; - vgroup_id:number; + vgroup_id: number; message_id: bigint; id: bigint; - message_type:number; - totalTime:number; - constructor(resp:MessageResp) { - this.totalTime = resp.totalTime + message_type: number; + totalTime: number; + constructor(resp: MessageResp) { + this.totalTime = resp.totalTime; this.code = resp.msg.code; this.message = resp.msg.message; this.action = resp.msg.action; @@ -33,21 +50,20 @@ export class WsPollResponse { this.message_type = resp.msg.message_type; if (resp.msg.id) { this.id = BigInt(resp.msg.id); - }else{ - this.id = BigInt(0) + } else { + this.id = BigInt(0); } } } // resp: {"code":0,"message":"","action":"fetch","req_id":4,"message_id":1,"completed":false,"table_name":"ct2","rows":1,"fields_count":4,"fields_names":["ts","c1","c2","c3"],"fields_types":[9,4,6,8],"fields_lengths":[8,4,4,10],"precision":0} -export class WsTmqQueryResponse extends WSQueryResponse{ +export class WsTmqQueryResponse extends WSQueryResponse { completed: boolean; table_name: string; - rows:number; - message_id:number; - + rows: number; + message_id: number; - constructor(resp:MessageResp) { + constructor(resp: MessageResp) { super(resp); this.completed = resp.msg.completed; this.table_name = resp.msg.table_name; @@ -58,8 +74,8 @@ export class WsTmqQueryResponse extends WSQueryResponse{ export class TaosTmqResult extends TaosResult { database: string; - vgroup_id:number; - constructor(pollResp:WsPollResponse) { + vgroup_id: number; + constructor(pollResp: WsPollResponse) { super(); this.setTopic(pollResp.topic); this.database = pollResp.database; @@ -87,31 +103,40 @@ export class WSTmqFetchBlockInfo { let blockDataView: DataView = this.skipHead(dataView); this.rows = this.parseBlockInfos(blockDataView); } - public getRows(): number{ + public getRows(): number { return this.rows; } - private skipHead(dataView: DataView): DataView{ + private skipHead(dataView: DataView): DataView { let v = dataView.getUint8(0); if (v >= 100) { - let skip = dataView.getUint32(1, true); - return new DataView(dataView.buffer, dataView.byteOffset + skip + 5); - } + let skip = dataView.getUint32(1, true); + return new DataView( + dataView.buffer, + dataView.byteOffset + skip + 5 + ); + } let skip1 = this.getTypeSkip(v); v = dataView.getUint8(1 + skip1); let skip2 = this.getTypeSkip(v); - return new DataView(dataView.buffer, dataView.byteOffset + skip1 + 2 + skip2); + return new DataView( + dataView.buffer, + dataView.byteOffset + skip1 + 2 + skip2 + ); } private getTypeSkip(v: number) { switch (v) { - case 1: - return 8; - case 2: - case 3: - return 16; - default: - throw(new TDWebSocketClientError(ErrorCode.ERR_INVALID_FETCH_MESSAGE_DATA, `FetchBlockRawResp getTypeSkip error, type: ${v}`)); - } + case 1: + return 8; + case 2: + case 3: + return 16; + default: + throw new TDWebSocketClientError( + ErrorCode.ERR_INVALID_FETCH_MESSAGE_DATA, + `FetchBlockRawResp getTypeSkip error, type: ${v}` + ); + } } private parseBlockInfos(dataView: DataView): number { @@ -119,37 +144,51 @@ export class WSTmqFetchBlockInfo { if (blockNum == 0) { return 0; } - this.withTableName = dataView.getUint8(4) == 1? true : false; - this.withSchema = dataView.getUint8(5) == 1? true : false; - + this.withTableName = dataView.getUint8(4) == 1 ? true : false; + this.withSchema = dataView.getUint8(5) == 1 ? true : false; + // let dataBuffer = dataView.buffer.slice(6) let dataBuffer = new DataView(dataView.buffer, dataView.byteOffset + 6); - let rows = 0; + let rows = 0; // const parseStartTime = new Date().getTime(); // console.log("parseBlockInfos blockNum="+ blockNum) for (let i = 0; i < blockNum; i++) { let variableInfo = this.parseVariableByteInteger(dataBuffer); this.taosResult.setPrecision(variableInfo[1].getUint8(17)); - dataView = new DataView(variableInfo[1].buffer, variableInfo[1].byteOffset + 17); + dataView = new DataView( + variableInfo[1].buffer, + variableInfo[1].byteOffset + 17 + ); let offset = variableInfo[0] - 17; - dataBuffer = this.parseSchemaInfo(dataView, offset); - rows += this.parseTmqBlock(dataView, 1); + dataBuffer = this.parseSchemaInfo(dataView, offset); + rows += this.parseTmqBlock(dataView, 1); } // const parseEndTime = new Date().getTime(); // console.log("------------->", parseEndTime- parseStartTime, rows); - logger.info("parseBlockInfos blockNum="+ blockNum + ", withTableName=" + this.withTableName + ", withSchema=" + this.withSchema + ", rows=" + rows) + logger.info( + "parseBlockInfos blockNum=" + + blockNum + + ", withTableName=" + + this.withTableName + + ", withSchema=" + + this.withSchema + + ", rows=" + + rows + ); return rows; - } private parseSchemaInfo(dataBuffer: DataView, offset: number) { if (this.withSchema) { - let isSkip = this.schema.length > 0 - if (!isSkip) { - dataBuffer = new DataView(dataBuffer.buffer, dataBuffer.byteOffset + offset); + let isSkip = this.schema.length > 0; + if (!isSkip) { + dataBuffer = new DataView( + dataBuffer.buffer, + dataBuffer.byteOffset + offset + ); let variableInfo = this.parseVariableByteInteger(dataBuffer); this.schemaLen = variableInfo[2]; - let cols = zigzagDecode(variableInfo[0]); + let cols = zigzagDecode(variableInfo[0]); variableInfo = this.parseVariableByteInteger(variableInfo[1]); this.schemaLen += variableInfo[2]; let dataView = variableInfo[1]; @@ -160,155 +199,216 @@ export class WSTmqFetchBlockInfo { variableInfo = this.parseVariableByteInteger(dataView, 2); this.schemaLen += 2 + variableInfo[2]; schema.bytes = BigInt(zigzagDecode(variableInfo[0])); - variableInfo = this.parseVariableByteInteger(variableInfo[1]); + variableInfo = this.parseVariableByteInteger( + variableInfo[1] + ); this.schemaLen += variableInfo[2]; schema.colID = zigzagDecode(variableInfo[0]); - variableInfo = this.parseVariableByteInteger(variableInfo[1]); + variableInfo = this.parseVariableByteInteger( + variableInfo[1] + ); this.schemaLen += variableInfo[2]; - schema.name = getString(variableInfo[1], 0, variableInfo[0], this.textDecoder); - + schema.name = getString( + variableInfo[1], + 0, + variableInfo[0], + this.textDecoder + ); + if (!isSkip) { this.taosResult.setMeta({ name: schema.name, type: schema.colType, - length: Number(schema.bytes) - } ); + length: Number(schema.bytes), + }); this.schema.push(schema); } - dataView = new DataView(variableInfo[1].buffer, variableInfo[1].byteOffset + variableInfo[0]); + dataView = new DataView( + variableInfo[1].buffer, + variableInfo[1].byteOffset + variableInfo[0] + ); this.schemaLen += variableInfo[0]; } - if(this.withTableName) { + if (this.withTableName) { variableInfo = this.parseVariableByteInteger(dataView); this.schemaLen += variableInfo[2]; - this.tableName = readVarchar(variableInfo[1].buffer, variableInfo[1].byteOffset, variableInfo[0], this.textDecoder); - dataView = new DataView(variableInfo[1].buffer, variableInfo[1].byteOffset + variableInfo[0]); + this.tableName = readVarchar( + variableInfo[1].buffer, + variableInfo[1].byteOffset, + variableInfo[0], + this.textDecoder + ); + dataView = new DataView( + variableInfo[1].buffer, + variableInfo[1].byteOffset + variableInfo[0] + ); this.schemaLen += variableInfo[0]; } - + return dataView; } else { - return new DataView(dataBuffer.buffer, dataBuffer.byteOffset + this.schemaLen + offset); - + return new DataView( + dataBuffer.buffer, + dataBuffer.byteOffset + this.schemaLen + offset + ); } } return dataBuffer; } - private parseVariableByteInteger(dataView: DataView, offset: number = 0): [number, DataView, number] { + private parseVariableByteInteger( + dataView: DataView, + offset: number = 0 + ): [number, DataView, number] { let value = 0; let multiplier = 1; let count = 0; while (true) { let encodedByte = dataView.getUint8(count + offset); - value += (encodedByte&127) * multiplier; + value += (encodedByte & 127) * multiplier; if ((encodedByte & 128) == 0) { break; } multiplier *= 128; count++; } - - return [value, new DataView(dataView.buffer, dataView.byteOffset + count + 1 + offset), count+1] + + return [ + value, + new DataView( + dataView.buffer, + dataView.byteOffset + count + 1 + offset + ), + count + 1, + ]; } private parseTmqBlock(dataView: DataView, startOffset: number): number { // let dataView = new DataView(dataBuffer) let rows = dataView.getInt32(8 + startOffset, true); if (rows == 0) { - return rows; + return rows; } - - let taosData = this.taosResult.getData() - let metaData = this.taosResult.getMeta() + + let taosData = this.taosResult.getData(); + let metaData = this.taosResult.getMeta(); if (metaData && rows && taosData) { - let dataList:any[][] = new Array(rows); + let dataList: any[][] = new Array(rows); //get bitmap length - let bitMapOffset:number = getBitmapLen(rows); + let bitMapOffset: number = getBitmapLen(rows); //skip data head let bufferOffset = 28 + 5 * this.schema.length + startOffset; - let metaLens:number[]= [] - for (let i = 0; i< this.schema.length; i++) { + let metaLens: number[] = []; + for (let i = 0; i < this.schema.length; i++) { //get data len - metaLens.push(dataView.getInt32(bufferOffset + i*4, true)); + metaLens.push(dataView.getInt32(bufferOffset + i * 4, true)); } - + bufferOffset += this.schema.length * 4; for (let i = 0; i < this.schema.length; i++) { - let data:any[] = []; - //get type code - let isVarType = _isVarType(this.schema[i].colType) - //fixed length type + let data: any[] = []; + //get type code + let isVarType = _isVarType(this.schema[i].colType); + //fixed length type if (isVarType == ColumnsBlockType.SOLID) { // let bitMapArr = dataBuffer.slice(bufferOffset, bufferOffset + bitMapOffset); - let bitMapArr = new Uint8Array(dataView.buffer, dataView.byteOffset + bufferOffset, bitMapOffset) + let bitMapArr = new Uint8Array( + dataView.buffer, + dataView.byteOffset + bufferOffset, + bitMapOffset + ); bufferOffset += bitMapOffset; //decode column data, data is array - data = readSolidDataToArray(dataView, bufferOffset, rows, this.schema[i].colType, bitMapArr, startOffset, i); - - } else { - //Variable length type + data = readSolidDataToArray( + dataView, + bufferOffset, + rows, + this.schema[i].colType, + bitMapArr, + startOffset, + i + ); + } else { + //Variable length type let start = bufferOffset; - let offsets:number[]= []; - for (let i = 0; i< rows; i++, start += TDengineTypeLength[TDengineTypeCode.INT]) { + let offsets: number[] = []; + for ( + let i = 0; + i < rows; + i++, start += TDengineTypeLength[TDengineTypeCode.INT] + ) { //get data length, -1 is null - offsets.push(dataView.getInt32(start, true)) + offsets.push(dataView.getInt32(start, true)); } - for (let i = 0; i< rows; i++) { - let value:any = '' + for (let i = 0; i < rows; i++) { + let value: any = ""; if (-1 == offsets[i]) { - value = null - }else{ + value = null; + } else { let header = start + offsets[i]; - let dataLength = dataView.getInt16(header, true) & 0xFFFF; + let dataLength = + dataView.getInt16(header, true) & 0xffff; if (isVarType == ColumnsBlockType.VARCHAR) { //decode var char - - value = readVarchar(dataView.buffer, dataView.byteOffset + header + 2, dataLength, this.textDecoder) - } else if(isVarType == ColumnsBlockType.GEOMETRY || isVarType == ColumnsBlockType.VARBINARY) { + + value = readVarchar( + dataView.buffer, + dataView.byteOffset + header + 2, + dataLength, + this.textDecoder + ); + } else if ( + isVarType == ColumnsBlockType.GEOMETRY || + isVarType == ColumnsBlockType.VARBINARY + ) { //decode binary - value = readBinary(dataView.buffer, dataView.byteOffset + header + 2, dataLength) + value = readBinary( + dataView.buffer, + dataView.byteOffset + header + 2, + dataLength + ); } else { //decode nchar - value = readNchar(dataView.buffer, dataView.byteOffset + header + 2, dataLength) + value = readNchar( + dataView.buffer, + dataView.byteOffset + header + 2, + dataLength + ); } - } - + data.push(value); } - bufferOffset += rows * 4 + bufferOffset += rows * 4; } - bufferOffset += metaLens[i] + bufferOffset += metaLens[i]; //column data to row data for (let row = 0; row < data.length; row++) { if (dataList[row] == null) { - dataList[row] = [] + dataList[row] = []; } - dataList[row].push(data[row]) + dataList[row].push(data[row]); } } taosData.push(...dataList); - } - return rows; + return rows; } - } -export class AssignmentResp{ +export class AssignmentResp { req_id: number; code: number; message: string; action: string; totalTime: number; - timing:bigint; - topicPartition:TopicPartition[]; - constructor(resp:MessageResp, topic:string) { + timing: bigint; + topicPartition: TopicPartition[]; + constructor(resp: MessageResp, topic: string) { this.timing = BigInt(resp.msg.timing); this.code = resp.msg.code; this.message = resp.msg.message; @@ -319,17 +419,17 @@ export class AssignmentResp{ for (let i in this.topicPartition) { this.topicPartition[i].topic = topic; } - } + } } -export class SubscriptionResp{ +export class SubscriptionResp { req_id: number; code: number; message: string; action: string; totalTime: number; - timing:bigint; - topics:string[]; - constructor(resp:MessageResp) { + timing: bigint; + topics: string[]; + constructor(resp: MessageResp) { this.timing = BigInt(resp.msg.timing); this.code = resp.msg.code; this.message = resp.msg.message; @@ -337,61 +437,67 @@ export class SubscriptionResp{ this.action = resp.msg.action; this.totalTime = resp.totalTime; this.topics = resp.msg.topics; - } + } } -export class PartitionsResp{ +export class PartitionsResp { req_id: number; code: number; message: string; action: string; totalTime: number; - timing:bigint; - positions:bigint[]; - constructor(resp:MessageResp) { + timing: bigint; + positions: bigint[]; + constructor(resp: MessageResp) { this.timing = BigInt(resp.msg.timing); this.code = resp.msg.code; this.message = resp.msg.message; this.req_id = resp.msg.req_id; this.action = resp.msg.action; this.totalTime = resp.totalTime; - this.positions = resp.msg.position ? resp.msg.position.map((pos: number) => BigInt(pos)) : []; + this.positions = resp.msg.position + ? resp.msg.position.map((pos: number) => BigInt(pos)) + : []; } - setTopicPartitions(topicPartitions:TopicPartition[]):TopicPartition[] { + setTopicPartitions(topicPartitions: TopicPartition[]): TopicPartition[] { if (topicPartitions.length != this.positions.length) { - throw new WebSocketInterfaceError(ErrorCode.ERR_PARTITIONS_TOPIC_VGROUP_LENGTH_NOT_EQUAL, 'TopicPartitions and positions are not equal in length'); + throw new WebSocketInterfaceError( + ErrorCode.ERR_PARTITIONS_TOPIC_VGROUP_LENGTH_NOT_EQUAL, + "TopicPartitions and positions are not equal in length" + ); } for (let i in this.positions) { - topicPartitions[i].offset = this.positions[i] + topicPartitions[i].offset = this.positions[i]; } return topicPartitions; - } - + } } export class CommittedResp extends PartitionsResp { - constructor(resp:MessageResp) { + constructor(resp: MessageResp) { super(resp); - this.positions = resp.msg.committed ? resp.msg.committed.map((pos: number) => BigInt(pos)) : []; + this.positions = resp.msg.committed + ? resp.msg.committed.map((pos: number) => BigInt(pos)) + : []; } } export class TopicPartition { - topic :string; - vgroup_id :number; - offset ?:bigint; - begin ?:bigint; - end ?:bigint; - constructor(msg:any) { + topic: string; + vgroup_id: number; + offset?: bigint; + begin?: bigint; + end?: bigint; + constructor(msg: any) { this.vgroup_id = msg.vgroup_id; this.offset = BigInt(msg.offset); this.begin = BigInt(msg.begin); this.end = BigInt(msg.end); - this.topic = '' + this.topic = ""; } } -function getBitmapLen(n:number) { +function getBitmapLen(n: number) { return (n + 0x7) >> 3; } diff --git a/nodejs/src/tmq/wsTmq.ts b/nodejs/src/tmq/wsTmq.ts index ca0c2052..19ad079f 100644 --- a/nodejs/src/tmq/wsTmq.ts +++ b/nodejs/src/tmq/wsTmq.ts @@ -1,90 +1,118 @@ -import JSONBig from 'json-bigint'; -import { TmqConfig } from './config'; -import { TMQConstants, TMQMessageType } from './constant'; -import { WsClient } from '../client/wsClient'; -import { TaosResult } from '../common/taosResult'; -import { ErrorCode, TaosResultError, TDWebSocketClientError, WebSocketInterfaceError } from '../common/wsError'; -import { AssignmentResp, CommittedResp, PartitionsResp, SubscriptionResp, TaosTmqResult, TopicPartition, WSTmqFetchBlockInfo, WsPollResponse, WsTmqQueryResponse} from './tmqResponse'; -import { ReqId } from '../common/reqid'; +import JSONBig from "json-bigint"; +import { TmqConfig } from "./config"; +import { TMQConstants, TMQMessageType } from "./constant"; +import { WsClient } from "../client/wsClient"; +import { TaosResult } from "../common/taosResult"; +import { + ErrorCode, + TaosResultError, + TDWebSocketClientError, + WebSocketInterfaceError, +} from "../common/wsError"; +import { + AssignmentResp, + CommittedResp, + PartitionsResp, + SubscriptionResp, + TaosTmqResult, + TopicPartition, + WSTmqFetchBlockInfo, + WsPollResponse, + WsTmqQueryResponse, +} from "./tmqResponse"; +import { ReqId } from "../common/reqid"; import logger from "../common/log"; -import { WSFetchBlockResponse } from '../client/wsResponse'; +import { WSFetchBlockResponse } from "../client/wsResponse"; export class WsConsumer { private _wsClient: WsClient; - private _wsConfig:TmqConfig; - private _topics?:string[]; - private _commitTime?:number; - private _lastMessageID?:bigint; - private constructor(wsConfig:Map) { - this._wsConfig = new TmqConfig(wsConfig) - logger.debug(this._wsConfig) + private _wsConfig: TmqConfig; + private _topics?: string[]; + private _commitTime?: number; + private _lastMessageID?: bigint; + private constructor(wsConfig: Map) { + this._wsConfig = new TmqConfig(wsConfig); + logger.debug(this._wsConfig); if (wsConfig.size == 0 || !this._wsConfig.url) { - throw new WebSocketInterfaceError(ErrorCode.ERR_INVALID_URL, - 'invalid url, password or username needed.'); + throw new WebSocketInterfaceError( + ErrorCode.ERR_INVALID_URL, + "invalid url, password or username needed." + ); } - this._wsClient = new WsClient(this._wsConfig.url, this._wsConfig.timeout); + this._wsClient = new WsClient( + this._wsConfig.url, + this._wsConfig.timeout + ); this._lastMessageID = BigInt(0); } - private async init():Promise { - let wsSql = null + private async init(): Promise { + let wsSql = null; try { if (this._wsConfig.sql_url) { - wsSql = new WsClient(this._wsConfig.sql_url, this._wsConfig.timeout); + wsSql = new WsClient( + this._wsConfig.sql_url, + this._wsConfig.timeout + ); await wsSql.connect(); await wsSql.checkVersion(); await this._wsClient.ready(); } else { - throw(new TDWebSocketClientError(ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, `connection creation failed, url: ${this._wsConfig.url}`)); + throw new TDWebSocketClientError( + ErrorCode.ERR_WEBSOCKET_CONNECTION_FAIL, + `connection creation failed, url: ${this._wsConfig.url}` + ); } - }catch (e: any) { + } catch (e: any) { await this._wsClient.close(); - throw(e); - }finally { + throw e; + } finally { if (wsSql) { await wsSql.close(); } } - return this; - + return this; } - static async newConsumer(wsConfig:Map):Promise { + static async newConsumer(wsConfig: Map): Promise { if (wsConfig.size == 0 || !wsConfig.get(TMQConstants.WS_URL)) { - throw new WebSocketInterfaceError(ErrorCode.ERR_INVALID_URL, - 'invalid url, password or username needed.'); + throw new WebSocketInterfaceError( + ErrorCode.ERR_INVALID_URL, + "invalid url, password or username needed." + ); } let wsConsumer = new WsConsumer(wsConfig); - return await wsConsumer.init() - + return await wsConsumer.init(); } - async subscribe(topics: Array, reqId?:number): Promise { - if (!topics || topics.length == 0 ) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, - 'WsTmq Subscribe params is error!'); + async subscribe(topics: Array, reqId?: number): Promise { + if (!topics || topics.length == 0) { + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsTmq Subscribe params is error!" + ); } let queryMsg = { action: TMQMessageType.Subscribe, args: { - req_id :ReqId.getReqID(reqId), - user :this._wsConfig.user, - password :this._wsConfig.password, - group_id :this._wsConfig.group_id, - client_id :this._wsConfig.client_id, - topics :topics, - offset_rest:this._wsConfig.offset_rest, - auto_commit:this._wsConfig.auto_commit, + req_id: ReqId.getReqID(reqId), + user: this._wsConfig.user, + password: this._wsConfig.password, + group_id: this._wsConfig.group_id, + client_id: this._wsConfig.client_id, + topics: topics, + offset_rest: this._wsConfig.offset_rest, + auto_commit: this._wsConfig.auto_commit, auto_commit_interval_ms: this._wsConfig.auto_commit_interval_ms, - config: this._wsConfig.otherConfigs + config: this._wsConfig.otherConfigs, }, }; - this._topics = topics + this._topics = topics; return await this._wsClient.exec(JSON.stringify(queryMsg)); } - async unsubscribe(reqId?:number): Promise { + async unsubscribe(reqId?: number): Promise { let queryMsg = { action: TMQMessageType.Unsubscribe, args: { @@ -94,287 +122,344 @@ export class WsConsumer { return await this._wsClient.exec(JSON.stringify(queryMsg)); } - async poll(timeoutMs: number, reqId?:number):Promise> { + async poll( + timeoutMs: number, + reqId?: number + ): Promise> { if (this._wsConfig.auto_commit) { if (this._commitTime) { let currTime = new Date().getTime(); let diff = Math.abs(currTime - this._commitTime); if (diff >= this._wsConfig.auto_commit_interval_ms) { - await this.doCommit() + await this.doCommit(); this._commitTime = new Date().getTime(); } } else { this._commitTime = new Date().getTime(); } } - return await this.pollData(timeoutMs,reqId) + return await this.pollData(timeoutMs, reqId); } - async subscription(reqId?:number):Promise> { + async subscription(reqId?: number): Promise> { let queryMsg = { action: TMQMessageType.ListTopics, args: { req_id: ReqId.getReqID(reqId), }, }; - + let resp = await this._wsClient.exec(JSON.stringify(queryMsg), false); - return new SubscriptionResp(resp).topics; + return new SubscriptionResp(resp).topics; } - async commit(reqId?:number):Promise> { - await this.doCommit(reqId) - return await this.assignment() + async commit(reqId?: number): Promise> { + await this.doCommit(reqId); + return await this.assignment(); } - private async doCommit(reqId?:number):Promise { + private async doCommit(reqId?: number): Promise { let queryMsg = { action: TMQMessageType.Commit, args: { - req_id : ReqId.getReqID(reqId), - message_id: 0 + req_id: ReqId.getReqID(reqId), + message_id: 0, }, - }; - + }; + await this._wsClient.exec(JSON.stringify(queryMsg)); } - async committed(partitions:Array, reqId?:number):Promise> { - if (!partitions || partitions.length == 0 ) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, 'WsTmq Positions params is error!'); + async committed( + partitions: Array, + reqId?: number + ): Promise> { + if (!partitions || partitions.length == 0) { + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsTmq Positions params is error!" + ); } let offsets: TopicPartition[] = new Array(partitions.length); for (let i = 0; i < partitions.length; i++) { offsets[i] = { topic: partitions[i].topic, - vgroup_id: partitions[i].vgroup_id + vgroup_id: partitions[i].vgroup_id, }; offsets[i].vgroup_id = partitions[i].vgroup_id; } - + let queryMsg = { action: TMQMessageType.Committed, args: { - req_id : ReqId.getReqID(reqId), - topic_vgroup_ids:offsets + req_id: ReqId.getReqID(reqId), + topic_vgroup_ids: offsets, }, }; - let resp = await this._wsClient.exec(JSONBig.stringify(queryMsg), false); + let resp = await this._wsClient.exec( + JSONBig.stringify(queryMsg), + false + ); return new CommittedResp(resp).setTopicPartitions(offsets); } - async commitOffsets(partitions:Array):Promise> { + async commitOffsets( + partitions: Array + ): Promise> { if (!partitions || partitions.length == 0) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, - 'WsTmq CommitOffsets params is error!'); - } - const allp:any[] = []; - partitions.forEach(e => { - allp.push(this.commitOffset(e)); - }) + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsTmq CommitOffsets params is error!" + ); + } + const allp: any[] = []; + partitions.forEach((e) => { + allp.push(this.commitOffset(e)); + }); await Promise.all(allp); return await this.committed(partitions); } - - async commitOffset(partition:TopicPartition, reqId?:number):Promise { + async commitOffset( + partition: TopicPartition, + reqId?: number + ): Promise { if (!partition) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, - 'WsTmq CommitOffsets params is error!'); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsTmq CommitOffsets params is error!" + ); } let queryMsg = { - action: TMQMessageType.CommitOffset, + action: TMQMessageType.CommitOffset, args: { - req_id : ReqId.getReqID(reqId), - vgroup_id :partition.vgroup_id, - topic :partition.topic, - offset :partition.offset, + req_id: ReqId.getReqID(reqId), + vgroup_id: partition.vgroup_id, + topic: partition.topic, + offset: partition.offset, }, }; return await this._wsClient.exec(JSONBig.stringify(queryMsg)); } - async positions(partitions:Array, reqId?:number):Promise> { - if (!partitions || partitions.length == 0 ) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, - 'WsTmq Positions params is error!'); + async positions( + partitions: Array, + reqId?: number + ): Promise> { + if (!partitions || partitions.length == 0) { + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsTmq Positions params is error!" + ); } let offsets: TopicPartition[] = new Array(partitions.length); for (let i = 0; i < partitions.length; i++) { offsets[i] = { topic: partitions[i].topic, - vgroup_id: partitions[i].vgroup_id + vgroup_id: partitions[i].vgroup_id, }; - offsets[i].vgroup_id = partitions[i].vgroup_id + offsets[i].vgroup_id = partitions[i].vgroup_id; } let queryMsg = { action: TMQMessageType.Position, args: { - req_id : ReqId.getReqID(reqId), - topic_vgroup_ids:offsets + req_id: ReqId.getReqID(reqId), + topic_vgroup_ids: offsets, }, }; - + let resp = await this._wsClient.exec(JSON.stringify(queryMsg), false); - return new PartitionsResp(resp).setTopicPartitions(offsets); + return new PartitionsResp(resp).setTopicPartitions(offsets); } - async seek(partition:TopicPartition, reqId?:number):Promise { + async seek(partition: TopicPartition, reqId?: number): Promise { if (!partition) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, - 'WsTmq Seek params is error!'); + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsTmq Seek params is error!" + ); } let queryMsg = { action: TMQMessageType.Seek, args: { - req_id : ReqId.getReqID(reqId), - vgroup_id :partition.vgroup_id, - topic :partition.topic, - offset :partition.offset, + req_id: ReqId.getReqID(reqId), + vgroup_id: partition.vgroup_id, + topic: partition.topic, + offset: partition.offset, }, }; return await this._wsClient.exec(JSON.stringify(queryMsg)); } - async seekToBeginning(partitions:Array):Promise { + async seekToBeginning(partitions: Array): Promise { if (!partitions || partitions.length == 0) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, - 'WsTmq SeekToBeginning params is error!'); - } - return await this.seekToBeginOrEnd(partitions) + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsTmq SeekToBeginning params is error!" + ); + } + return await this.seekToBeginOrEnd(partitions); } - async seekToEnd(partitions:Array):Promise { + async seekToEnd(partitions: Array): Promise { if (!partitions || partitions.length == 0) { - throw new TaosResultError(ErrorCode.ERR_INVALID_PARAMS, - 'WsTmq SeekToEnd params is error!'); - } + throw new TaosResultError( + ErrorCode.ERR_INVALID_PARAMS, + "WsTmq SeekToEnd params is error!" + ); + } - return await this.seekToBeginOrEnd(partitions, false) + return await this.seekToBeginOrEnd(partitions, false); } - async close():Promise { + async close(): Promise { await this._wsClient.close(); } - private async fetchBlockData(pollResp: WsPollResponse, taosResult: TaosTmqResult):Promise { + private async fetchBlockData( + pollResp: WsPollResponse, + taosResult: TaosTmqResult + ): Promise { let fetchMsg = { - action: 'fetch_raw_data', + action: "fetch_raw_data", args: { req_id: ReqId.getReqID(), message_id: pollResp.message_id, }, - }; + }; let jsonStr = JSONBig.stringify(fetchMsg); - logger.debug('[wsQueryInterface.fetch.fetchMsg]===>' + jsonStr); - let result = await this._wsClient.sendMsg(jsonStr) - let wsResponse = new WSFetchBlockResponse(result.msg) + logger.debug("[wsQueryInterface.fetch.fetchMsg]===>" + jsonStr); + let result = await this._wsClient.sendMsg(jsonStr); + let wsResponse = new WSFetchBlockResponse(result.msg); if (wsResponse && wsResponse.data && wsResponse.blockLen > 0) { - let wsTmqResponse = new WSTmqFetchBlockInfo(wsResponse.data, taosResult); - logger.debug('[WSTmqFetchBlockInfo.fetchBlockData]===>' + wsTmqResponse.taosResult); + let wsTmqResponse = new WSTmqFetchBlockInfo( + wsResponse.data, + taosResult + ); + logger.debug( + "[WSTmqFetchBlockInfo.fetchBlockData]===>" + + wsTmqResponse.taosResult + ); if (wsTmqResponse.rows > 0) { return true; } } - + return false; } - private async pollData(timeoutMs: number, reqId?:number): Promise> { + private async pollData( + timeoutMs: number, + reqId?: number + ): Promise> { let queryMsg = { action: TMQMessageType.Poll, args: { - req_id : ReqId.getReqID(reqId), - blocking_time :timeoutMs, + req_id: ReqId.getReqID(reqId), + blocking_time: timeoutMs, message_id: this._lastMessageID, }, }; - let resp = await this._wsClient.exec(JSONBig.stringify(queryMsg), false); - let pollResp = new WsPollResponse(resp) - let taosResult = new TaosTmqResult(pollResp) + let resp = await this._wsClient.exec( + JSONBig.stringify(queryMsg), + false + ); + let pollResp = new WsPollResponse(resp); + let taosResult = new TaosTmqResult(pollResp); var taosResults: Map = new Map(); taosResults.set(pollResp.topic, taosResult); - if (!pollResp.have_message || pollResp.message_type != TMQMessageType.ResDataType) { + if ( + !pollResp.have_message || + pollResp.message_type != TMQMessageType.ResDataType + ) { return taosResults; - } + } this._lastMessageID = pollResp.message_id; let finish = false; while (!finish) { - finish = await this.fetchBlockData(pollResp, taosResult) + finish = await this.fetchBlockData(pollResp, taosResult); } - - return taosResults; + + return taosResults; } - private async sendAssignmentReq(topic:string):Promise> { + private async sendAssignmentReq( + topic: string + ): Promise> { let queryMsg = { action: TMQMessageType.GetTopicAssignment, args: { req_id: ReqId.getReqID(), - topic: topic - } + topic: topic, + }, }; - + let resp = await this._wsClient.exec(JSON.stringify(queryMsg), false); let assignmentInfo = new AssignmentResp(resp, queryMsg.args.topic); - return assignmentInfo.topicPartition; + return assignmentInfo.topicPartition; } - async assignment(topics?:string[]):Promise> { + async assignment(topics?: string[]): Promise> { if (!topics || topics.length == 0) { - topics = this._topics + topics = this._topics; } - let topicPartitions:TopicPartition[] = []; - + let topicPartitions: TopicPartition[] = []; + if (topics && topics.length > 0) { - const allp:any[] = []; + const allp: any[] = []; for (let i in topics) { allp.push(this.sendAssignmentReq(topics[i])); } - let result = await Promise.all(allp) - result.forEach(e => { - topicPartitions.push(...e); - }) + let result = await Promise.all(allp); + result.forEach((e) => { + topicPartitions.push(...e); + }); } - return topicPartitions; + return topicPartitions; } - private async seekToBeginOrEnd(partitions:Array, bBegin:boolean = true):Promise { + private async seekToBeginOrEnd( + partitions: Array, + bBegin: boolean = true + ): Promise { let topics: string[] = []; - partitions.forEach(e => { - topics.push(e.topic) - }) - - let topicPartitions = await this.assignment(topics) - let itemMap = topicPartitions.reduce((map, obj)=> { - map.set(obj.topic+'_'+obj.vgroup_id, obj) - return map + partitions.forEach((e) => { + topics.push(e.topic); + }); + + let topicPartitions = await this.assignment(topics); + let itemMap = topicPartitions.reduce((map, obj) => { + map.set(obj.topic + "_" + obj.vgroup_id, obj); + return map; }, new Map()); - const allp:any[] = [] - for(let i in partitions) { - if(itemMap.has(partitions[i].topic + '_' +partitions[i].vgroup_id)) { - let topicPartition = itemMap.get(partitions[i].topic + '_' +partitions[i].vgroup_id) + const allp: any[] = []; + for (let i in partitions) { + if ( + itemMap.has(partitions[i].topic + "_" + partitions[i].vgroup_id) + ) { + let topicPartition = itemMap.get( + partitions[i].topic + "_" + partitions[i].vgroup_id + ); if (topicPartition) { - if(bBegin) { - topicPartition.offset = topicPartition.begin - }else{ - topicPartition.offset = topicPartition.end + if (bBegin) { + topicPartition.offset = topicPartition.begin; + } else { + topicPartition.offset = topicPartition.end; } - allp.push(this.seek(topicPartition)) + allp.push(this.seek(topicPartition)); } } } - await Promise.all(allp) + await Promise.all(allp); } - } diff --git a/nodejs/test/bulkPulling/cloud.tmq.test.ts b/nodejs/test/bulkPulling/cloud.tmq.test.ts index 09906424..6f5f031b 100644 --- a/nodejs/test/bulkPulling/cloud.tmq.test.ts +++ b/nodejs/test/bulkPulling/cloud.tmq.test.ts @@ -1,23 +1,22 @@ - import { TMQConstants } from "../../src/tmq/constant"; import { WsConsumer } from "../../src/tmq/wsTmq"; import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; -import logger, { setLevel } from "../../src/common/log" +import logger, { setLevel } from "../../src/common/log"; import { WSConfig } from "../../src/common/config"; import { WsSql } from "../../src/sql/wsSql"; beforeAll(async () => { -const url = `wss://${process.env.TDENGINE_CLOUD_URL}?token=${process.env.TDENGINE_CLOUD_TOKEN}`; -let wsSql = null; + const url = `wss://${process.env.TDENGINE_CLOUD_URL}?token=${process.env.TDENGINE_CLOUD_TOKEN}`; + let wsSql = null; try { const conf = new WSConfig(url); - conf.setUser('root') - conf.setPwd('taosdata') - wsSql = await WsSql.open(conf) + conf.setUser("root"); + conf.setPwd("taosdata"); + wsSql = await WsSql.open(conf); let sql = `INSERT INTO dmeters.d1001 USING dmeters.meters (groupid, location) TAGS(2, 'SanFrancisco') VALUES (NOW + 1a, 10.30000, 219, 0.31000) (NOW + 2a, 12.60000, 218, 0.33000) (NOW + 3a, 12.30000, 221, 0.31000) dmeters.d1002 USING dmeters.meters (groupid, location) TAGS(3, 'SanFrancisco') - VALUES (NOW + 1a, 10.30000, 218, 0.25000)` + VALUES (NOW + 1a, 10.30000, 218, 0.25000)`; let res = await wsSql.exec(sql); console.log(res); expect(res.getAffectRows()).toBeGreaterThanOrEqual(3); @@ -25,62 +24,61 @@ let wsSql = null; throw err; } finally { if (wsSql) { - await wsSql.close(); + await wsSql.close(); } } -}) +}); + +describe("TDWebSocket.Tmq()", () => { + jest.setTimeout(20 * 1000); -describe('TDWebSocket.Tmq()', () => { - jest.setTimeout(20 * 1000) - - test('normal connect', async() => { + test("normal connect", async () => { const url = `wss://${process.env.TDENGINE_CLOUD_URL}?token=${process.env.TDENGINE_CLOUD_TOKEN}`; - const topic = 'topic_meters'; + const topic = "topic_meters"; const topics = [topic]; - const groupId = 'group1'; - const clientId = 'client1'; + const groupId = "group1"; + const clientId = "client1"; let configMap = new Map([ - [TMQConstants.GROUP_ID, groupId], - [TMQConstants.CLIENT_ID, clientId], - [TMQConstants.AUTO_OFFSET_RESET, 'earliest'], - [TMQConstants.WS_URL, url], - [TMQConstants.ENABLE_AUTO_COMMIT, 'true'], - [TMQConstants.AUTO_COMMIT_INTERVAL_MS, '1000'], - ]) - + [TMQConstants.GROUP_ID, groupId], + [TMQConstants.CLIENT_ID, clientId], + [TMQConstants.AUTO_OFFSET_RESET, "earliest"], + [TMQConstants.WS_URL, url], + [TMQConstants.ENABLE_AUTO_COMMIT, "true"], + [TMQConstants.AUTO_COMMIT_INTERVAL_MS, "1000"], + ]); + setLevel("debug"); // create consumer let consumer = await WsConsumer.newConsumer(configMap); console.log( - `Create consumer successfully, host: ${url}, groupId: ${groupId}, clientId: ${clientId}` + `Create consumer successfully, host: ${url}, groupId: ${groupId}, clientId: ${clientId}` ); // subscribe await consumer.subscribe(topics); console.log(`Subscribe topics successfully, topics: ${topics}`); let res = new Map(); while (res.size == 0) { - // poll - res = await consumer.poll(1000); - for (let [key, value] of res) { - // Add your data processing logic here - console.log(`data: ${key} ${value}`); - } - // commit - await consumer.commit(); + // poll + res = await consumer.poll(1000); + for (let [key, value] of res) { + // Add your data processing logic here + console.log(`data: ${key} ${value}`); + } + // commit + await consumer.commit(); } // seek let assignment = await consumer.assignment(); await consumer.seekToBeginning(assignment); - console.log('Assignment seek to beginning successfully'); + console.log("Assignment seek to beginning successfully"); // clean await consumer.unsubscribe(); await consumer.close(); - }); -}) +}); afterAll(async () => { - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/decimal.test.ts b/nodejs/test/bulkPulling/decimal.test.ts index 39c041e6..e52f4efa 100644 --- a/nodejs/test/bulkPulling/decimal.test.ts +++ b/nodejs/test/bulkPulling/decimal.test.ts @@ -2,58 +2,88 @@ import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; import { WSConfig } from "../../src/common/config"; import { WsSql } from "../../src/sql/wsSql"; import { Sleep } from "../utils"; -import logger, { setLevel } from "../../src/common/log" +import logger, { setLevel } from "../../src/common/log"; import { TMQConstants } from "../../src/tmq/constant"; import { WsConsumer } from "../../src/tmq/wsTmq"; -let dns = 'ws://localhost:6041' -let createTopic = `create topic if not exists topic_decimal_test as select * from power.decimal_test` -let dropTopic = `DROP TOPIC IF EXISTS topic_decimal_test;` -setLevel("debug") +let dns = "ws://localhost:6041"; +let createTopic = `create topic if not exists topic_decimal_test as select * from power.decimal_test`; +let dropTopic = `DROP TOPIC IF EXISTS topic_decimal_test;`; +setLevel("debug"); beforeAll(async () => { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); await wsSql.exec(dropTopic); - await wsSql.exec('drop database if exists power'); - await wsSql.exec('create database if not exists power KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;'); - await Sleep(100) - await wsSql.exec('use power') - await wsSql.exec('CREATE STABLE if not exists decimal_test (ts timestamp, dec64 decimal(10,6), dec128 decimal(24,10), int1 int) TAGS (location binary(64), groupId int);'); - await wsSql.exec(createTopic) - await wsSql.close() -}) + await wsSql.exec("drop database if exists power"); + await wsSql.exec( + "create database if not exists power KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;" + ); + await Sleep(100); + await wsSql.exec("use power"); + await wsSql.exec( + "CREATE STABLE if not exists decimal_test (ts timestamp, dec64 decimal(10,6), dec128 decimal(24,10), int1 int) TAGS (location binary(64), groupId int);" + ); + await wsSql.exec(createTopic); + await wsSql.close(); +}); const expectedResultsMap = new Map([ - ['-1234.654321', { dec128: '-123456789012.0987654321', int1: 3, location: 'California', groupId: 3 }], - ['-0.000654', { dec128: '-0.0009876543', int1: 2, location: 'California', groupId: 3 }], - ['9876.123456', { dec128: '1234567890.0987654321', int1: 1, location: 'California', groupId: 3 }] + [ + "-1234.654321", + { + dec128: "-123456789012.0987654321", + int1: 3, + location: "California", + groupId: 3, + }, + ], + [ + "-0.000654", + { + dec128: "-0.0009876543", + int1: 2, + location: "California", + groupId: 3, + }, + ], + [ + "9876.123456", + { + dec128: "1234567890.0987654321", + int1: 1, + location: "California", + groupId: 3, + }, + ], ]); -describe('TDWebSocket.WsSql()', () => { - jest.setTimeout(20 * 1000) +describe("TDWebSocket.WsSql()", () => { + jest.setTimeout(20 * 1000); - test('insert recoder', async()=>{ - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - let taosResult = await wsSql.exec('use power') + test("insert recoder", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + let taosResult = await wsSql.exec("use power"); console.log(taosResult); - expect(taosResult).toBeTruthy() + expect(taosResult).toBeTruthy(); - taosResult = await wsSql.exec('describe decimal_test') + taosResult = await wsSql.exec("describe decimal_test"); console.log(taosResult); - taosResult = await wsSql.exec('INSERT INTO d1001 USING decimal_test (location, groupid) TAGS ("California", 3) VALUES (NOW, "9876.123456", "1234567890.0987654321", 1) (NOW + 1a, "-0.000654", "-0.0009876543", 2) (NOW + 2a, "-1234.654321", "-123456789012.0987654321", 3)') + taosResult = await wsSql.exec( + 'INSERT INTO d1001 USING decimal_test (location, groupid) TAGS ("California", 3) VALUES (NOW, "9876.123456", "1234567890.0987654321", 1) (NOW + 1a, "-0.000654", "-0.0009876543", 2) (NOW + 2a, "-1234.654321", "-123456789012.0987654321", 3)' + ); console.log(taosResult); - expect(taosResult.getAffectRows()).toBeGreaterThanOrEqual(3) - let wsRows = await wsSql.query('select * from decimal_test'); - expect(wsRows).toBeTruthy() - let meta = wsRows.getMeta() - expect(meta).toBeTruthy() + expect(taosResult.getAffectRows()).toBeGreaterThanOrEqual(3); + let wsRows = await wsSql.query("select * from decimal_test"); + expect(wsRows).toBeTruthy(); + let meta = wsRows.getMeta(); + expect(meta).toBeTruthy(); console.log("wsRow:meta:=>", meta); let count = 0; while (await wsRows.next()) { @@ -65,38 +95,38 @@ describe('TDWebSocket.WsSql()', () => { expect(result[2]).toBe(expected?.dec128); expect(result[3]).toBe(expected?.int1); expect(result[4]).toBe(expected?.location); - expect(result[5]).toBe(expected?.groupId); - count++; - } + expect(result[5]).toBe(expected?.groupId); + count++; + } } } - await wsSql.close() - expect(count).toBe(3) - }) -}) + await wsSql.close(); + expect(count).toBe(3); + }); +}); -test('normal Subscribe', async() => { +test("normal Subscribe", async () => { let configMap = new Map([ [TMQConstants.GROUP_ID, "gId"], [TMQConstants.CONNECT_USER, "root"], [TMQConstants.CONNECT_PASS, "taosdata"], [TMQConstants.AUTO_OFFSET_RESET, "earliest"], - [TMQConstants.CLIENT_ID, 'test_tmq_client'], + [TMQConstants.CLIENT_ID, "test_tmq_client"], [TMQConstants.WS_URL, dns], - [TMQConstants.ENABLE_AUTO_COMMIT, 'true'], - [TMQConstants.AUTO_COMMIT_INTERVAL_MS, '1000'], + [TMQConstants.ENABLE_AUTO_COMMIT, "true"], + [TMQConstants.AUTO_COMMIT_INTERVAL_MS, "1000"], ["session.timeout.ms", "10000"], ["max.poll.interval.ms", "30000"], - ["msg.with.table.name", "true"] - ]); + ["msg.with.table.name", "true"], + ]); let consumer = await WsConsumer.newConsumer(configMap); - await consumer.subscribe(['topic_decimal_test']); + await consumer.subscribe(["topic_decimal_test"]); - let assignment = await consumer.assignment() - console.log(assignment) - let useTime:number[] = []; + let assignment = await consumer.assignment(); + console.log(assignment); + let useTime: number[] = []; let count = 0; - for (let i = 0; i < 5; i++) { + for (let i = 0; i < 5; i++) { let startTime = new Date().getTime(); let res = await consumer.poll(500); let currTime = new Date().getTime(); @@ -108,34 +138,32 @@ test('normal Subscribe', async() => { if (data == null || data.length == 0) { break; } - - for (let record of data ) { + + for (let record of data) { console.log("record:=----------->", record); if (expectedResultsMap.has(record[1])) { const expected = expectedResultsMap.get(record[1]); expect(record[2]).toBe(expected?.dec128); expect(record[3]).toBe(expected?.int1); expect(record[4]).toBe(expected?.location); - expect(record[5]).toBe(expected?.groupId); - count++; + expect(record[5]).toBe(expected?.groupId); + count++; } - } - + } } } - await consumer.unsubscribe() - await consumer.close() - expect(count).toBe(3) -}) - + await consumer.unsubscribe(); + await consumer.close(); + expect(count).toBe(3); +}); afterAll(async () => { - let conf :WSConfig = new WSConfig(dns); - conf.setUser('root'); - conf.setPwd('taosdata'); + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); let wsSql = await WsSql.open(conf); await wsSql.exec(dropTopic); - await wsSql.exec('drop database power'); + await wsSql.exec("drop database power"); await wsSql.close(); - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/log.test.ts b/nodejs/test/bulkPulling/log.test.ts index 678f586d..919376ca 100644 --- a/nodejs/test/bulkPulling/log.test.ts +++ b/nodejs/test/bulkPulling/log.test.ts @@ -1,24 +1,23 @@ -import logger, { setLevel } from "../../src/common/log" +import logger, { setLevel } from "../../src/common/log"; -describe('log level print', () => { - test('normal connect', async() => { - logger.info('log level is info'); - logger.debug('log level is debug'); - logger.error('log level is error'); +describe("log level print", () => { + test("normal connect", async () => { + logger.info("log level is info"); + logger.debug("log level is debug"); + logger.error("log level is error"); - let isLevel = logger.isLevelEnabled("info") - expect(isLevel).toEqual(true) + let isLevel = logger.isLevelEnabled("info"); + expect(isLevel).toEqual(true); - setLevel("debug") - logger.debug('log level is debug'); - isLevel = logger.isLevelEnabled("debug") - expect(isLevel).toEqual(true) - - setLevel("error") - logger.error('log level is error'); - logger.debug('log level is debug'); - isLevel = logger.isLevelEnabled("error") - expect(isLevel).toEqual(true) + setLevel("debug"); + logger.debug("log level is debug"); + isLevel = logger.isLevelEnabled("debug"); + expect(isLevel).toEqual(true); + setLevel("error"); + logger.error("log level is error"); + logger.debug("log level is debug"); + isLevel = logger.isLevelEnabled("error"); + expect(isLevel).toEqual(true); }); -}) \ No newline at end of file +}); diff --git a/nodejs/test/bulkPulling/queryTables.test.ts b/nodejs/test/bulkPulling/queryTables.test.ts index 02fe90ad..49fd6269 100644 --- a/nodejs/test/bulkPulling/queryTables.test.ts +++ b/nodejs/test/bulkPulling/queryTables.test.ts @@ -1,67 +1,307 @@ - import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; import { WSConfig } from "../../src/common/config"; import { WsSql } from "../../src/sql/wsSql"; -import { compareUint8Arrays, createSTable, createSTableJSON, createTable, expectStableData, hexToBytes, insertNTable, insertStable, jsonMeta, tableMeta, tagMeta } from "../utils"; +import { + compareUint8Arrays, + createSTable, + createSTableJSON, + createTable, + expectStableData, + hexToBytes, + insertNTable, + insertStable, + jsonMeta, + tableMeta, + tagMeta, +} from "../utils"; // const DSN = 'ws://root:taosdata@127.0.0.1:6041' -let dsn = 'ws://root:taosdata@localhost:6041'; -let conf :WSConfig = new WSConfig(dsn) -const resultMap:Map = new Map(); -resultMap.set("POINT (4.0 8.0)", hexToBytes("010100000000000000000010400000000000002040")); -resultMap.set("POINT (3.0 5.0)", hexToBytes("010100000000000000000008400000000000001440")); -resultMap.set("LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)", - hexToBytes("010200000003000000000000000000f03f000000000000f03f0000000000000040000000000000004000000000000014400000000000001440")); -resultMap.set("POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))", - hexToBytes("010300000001000000050000000000000000000840000000000000184000000000000014400000000000001840000000000000144000000000000020400000000000000840000000000000204000000000000008400000000000001840")); -resultMap.set("POINT (7.0 9.0)", hexToBytes("01010000000000000000001c400000000000002240")); +let dsn = "ws://root:taosdata@localhost:6041"; +let conf: WSConfig = new WSConfig(dsn); +const resultMap: Map = new Map(); +resultMap.set( + "POINT (4.0 8.0)", + hexToBytes("010100000000000000000010400000000000002040") +); +resultMap.set( + "POINT (3.0 5.0)", + hexToBytes("010100000000000000000008400000000000001440") +); +resultMap.set( + "LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)", + hexToBytes( + "010200000003000000000000000000f03f000000000000f03f0000000000000040000000000000004000000000000014400000000000001440" + ) +); +resultMap.set( + "POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))", + hexToBytes( + "010300000001000000050000000000000000000840000000000000184000000000000014400000000000001840000000000000144000000000000020400000000000000840000000000000204000000000000008400000000000001840" + ) +); +resultMap.set( + "POINT (7.0 9.0)", + hexToBytes("01010000000000000000001c400000000000002240") +); resultMap.set("0x7661726332", hexToBytes("307837363631373236333332")); resultMap.set("0x7661726333", hexToBytes("307837363631373236333333")); resultMap.set("0x7661726334", hexToBytes("307837363631373236333334")); resultMap.set("0x7661726335", hexToBytes("307837363631373236333335")); -const table = 'ws_q_n'; -const stable = 'ws_q_s'; -const tableCN = 'ws_q_n_cn'; -const stableCN = 'ws_q_s_cn'; -const db = 'ws_q_db' -const jsonTable = 'ws_q_j'; -const jsonTableCN = 'ws_q_j_cn'; - -const createDB = `create database if not exists ${db} keep 3650` -const dropDB = `drop database if exists ${db}` -const useDB = `use ${db}` - -const stableTags = [true, -1, -2, -3, BigInt(-4), 1, 2, 3, BigInt(4), parseFloat(3.1415.toFixed(5)), parseFloat(3.14159265.toFixed(15)), 'varchar_tag_1', 'nchar_tag_1'] -const stableCNTags = [false, -1 * 2, -2 * 2, -3 * 2, BigInt(-4 * 2), 1 * 2, 2 * 2, 3 * 2, BigInt(4 * 2), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.14159265 * 2).toFixed(15)), 'varchar_标签_壹', 'nchar_标签_贰'] +const table = "ws_q_n"; +const stable = "ws_q_s"; +const tableCN = "ws_q_n_cn"; +const stableCN = "ws_q_s_cn"; +const db = "ws_q_db"; +const jsonTable = "ws_q_j"; +const jsonTableCN = "ws_q_j_cn"; + +const createDB = `create database if not exists ${db} keep 3650`; +const dropDB = `drop database if exists ${db}`; +const useDB = `use ${db}`; + +const stableTags = [ + true, + -1, + -2, + -3, + BigInt(-4), + 1, + 2, + 3, + BigInt(4), + parseFloat((3.1415).toFixed(5)), + parseFloat((3.14159265).toFixed(15)), + "varchar_tag_1", + "nchar_tag_1", +]; +const stableCNTags = [ + false, + -1 * 2, + -2 * 2, + -3 * 2, + BigInt(-4 * 2), + 1 * 2, + 2 * 2, + 3 * 2, + BigInt(4 * 2), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.14159265 * 2).toFixed(15)), + "varchar_标签_壹", + "nchar_标签_贰", +]; const tableValues = [ - [BigInt(1656677710000), 0, -1, -2, BigInt(-3), 0, 1, 2, BigInt(3), parseFloat(3.1415.toFixed(5)), parseFloat(3.14159265.toFixed(15)), 'varchar_col_1', 'nchar_col_1', true, 'NULL' , 'POINT (4.0 8.0)', '0x7661726332'], - [BigInt(1656677720000), -1, -2, -3, BigInt(-4), 1, 2, 3, BigInt(4), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.14159265 * 2).toFixed(15)), 'varchar_col_2', 'nchar_col_2', false, 'NULL', 'POINT (3.0 5.0)', '0x7661726333'], - [BigInt(1656677730000), -2, -3, -4, BigInt(-5), 2, 3, 4, BigInt(5), parseFloat((3.1415 * 3).toFixed(5)), parseFloat((3.14159265 * 3).toFixed(15)), 'varchar_col_3', 'nchar_col_3', true, 'NULL', 'LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)', '0x7661726334'], - [BigInt(1656677740000), -3, -4, -5, BigInt(-6), 3, 4, 5, BigInt(6), parseFloat((3.1415 * 4).toFixed(5)), parseFloat((3.14159265 * 4).toFixed(15)), 'varchar_col_4', 'nchar_col_4', false, 'NULL', 'POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))', '0x7661726335'], - [BigInt(1656677750000), -4, -5, -6, BigInt(-7), 4, 5, 6, BigInt(7), parseFloat((3.1415 * 5).toFixed(5)), parseFloat((3.14159265 * 5).toFixed(15)), 'varchar_col_5', 'nchar_col_5', true, 'NULL', 'POINT (7.0 9.0)', '0x7661726335'], -] + [ + BigInt(1656677710000), + 0, + -1, + -2, + BigInt(-3), + 0, + 1, + 2, + BigInt(3), + parseFloat((3.1415).toFixed(5)), + parseFloat((3.14159265).toFixed(15)), + "varchar_col_1", + "nchar_col_1", + true, + "NULL", + "POINT (4.0 8.0)", + "0x7661726332", + ], + [ + BigInt(1656677720000), + -1, + -2, + -3, + BigInt(-4), + 1, + 2, + 3, + BigInt(4), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.14159265 * 2).toFixed(15)), + "varchar_col_2", + "nchar_col_2", + false, + "NULL", + "POINT (3.0 5.0)", + "0x7661726333", + ], + [ + BigInt(1656677730000), + -2, + -3, + -4, + BigInt(-5), + 2, + 3, + 4, + BigInt(5), + parseFloat((3.1415 * 3).toFixed(5)), + parseFloat((3.14159265 * 3).toFixed(15)), + "varchar_col_3", + "nchar_col_3", + true, + "NULL", + "LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)", + "0x7661726334", + ], + [ + BigInt(1656677740000), + -3, + -4, + -5, + BigInt(-6), + 3, + 4, + 5, + BigInt(6), + parseFloat((3.1415 * 4).toFixed(5)), + parseFloat((3.14159265 * 4).toFixed(15)), + "varchar_col_4", + "nchar_col_4", + false, + "NULL", + "POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))", + "0x7661726335", + ], + [ + BigInt(1656677750000), + -4, + -5, + -6, + BigInt(-7), + 4, + 5, + 6, + BigInt(7), + parseFloat((3.1415 * 5).toFixed(5)), + parseFloat((3.14159265 * 5).toFixed(15)), + "varchar_col_5", + "nchar_col_5", + true, + "NULL", + "POINT (7.0 9.0)", + "0x7661726335", + ], +]; const tableCNValues = [ - [BigInt(1656677760000), 0, -1, -2, BigInt(-3), 0, 1, 2, BigInt(3), parseFloat(3.1415.toFixed(5)), parseFloat(3.14159265.toFixed(15)), 'varchar_列_壹', 'nchar_列_甲', true, 'NULL', 'POINT (4.0 8.0)', '0x7661726332'], - [BigInt(1656677770000), -1, -2, -3, BigInt(-4), 1, 2, 3, BigInt(4), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.14159265 * 2).toFixed(15)), 'varchar_列_贰', 'nchar_列_乙', false, 'NULL', 'POINT (3.0 5.0)', '0x7661726333'], - [BigInt(1656677780000), -2, -3, -4, BigInt(-5), 2, 3, 4, BigInt(5), parseFloat((3.1415 * 3).toFixed(5)), parseFloat((3.14159265 * 3).toFixed(15)), 'varchar_列_叁', 'nchar_列_丙', true, 'NULL', 'LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)', '0x7661726334'], - [BigInt(1656677790000), -3, -4, -5, BigInt(-6), 3, 4, 5, BigInt(6), parseFloat((3.1415 * 4).toFixed(5)), parseFloat((3.14159265 * 4).toFixed(15)), 'varchar_列_肆', 'nchar_列_丁', false, 'NULL', 'POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))', '0x7661726335'], - [BigInt(1656677800000), -4, -5, -6, BigInt(-7), 4, 5, 6, BigInt(7), parseFloat((3.1415 * 5).toFixed(5)), parseFloat((3.14159265 * 5).toFixed(15)), 'varchar_列_伍', 'nchar_列_戊', true, 'NULL', 'POINT (7.0 9.0)', '0x7661726335'], -] -const jsonTags = ["{\"key1\":\"taos\",\"key2\":null,\"key3\":\"TDengine\",\"key4\":0,\"key5\":false}"] -const jsonTagsCN = ["{\"key1\":\"taosdata\",\"key2\":null,\"key3\":\"TDengine涛思数据\",\"key4\":1,\"key5\":true}"] - -const selectStable = `select * from ${stable}` -const selectStableCN = `select * from ${stableCN}` -const selectTable = `select * from ${table}` -const selectTableCN = `select * from ${tableCN}` -const selectJsonTable = `select * from ${jsonTable}` -const selectJsonTableCN = `select * from ${jsonTableCN}` + [ + BigInt(1656677760000), + 0, + -1, + -2, + BigInt(-3), + 0, + 1, + 2, + BigInt(3), + parseFloat((3.1415).toFixed(5)), + parseFloat((3.14159265).toFixed(15)), + "varchar_列_壹", + "nchar_列_甲", + true, + "NULL", + "POINT (4.0 8.0)", + "0x7661726332", + ], + [ + BigInt(1656677770000), + -1, + -2, + -3, + BigInt(-4), + 1, + 2, + 3, + BigInt(4), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.14159265 * 2).toFixed(15)), + "varchar_列_贰", + "nchar_列_乙", + false, + "NULL", + "POINT (3.0 5.0)", + "0x7661726333", + ], + [ + BigInt(1656677780000), + -2, + -3, + -4, + BigInt(-5), + 2, + 3, + 4, + BigInt(5), + parseFloat((3.1415 * 3).toFixed(5)), + parseFloat((3.14159265 * 3).toFixed(15)), + "varchar_列_叁", + "nchar_列_丙", + true, + "NULL", + "LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)", + "0x7661726334", + ], + [ + BigInt(1656677790000), + -3, + -4, + -5, + BigInt(-6), + 3, + 4, + 5, + BigInt(6), + parseFloat((3.1415 * 4).toFixed(5)), + parseFloat((3.14159265 * 4).toFixed(15)), + "varchar_列_肆", + "nchar_列_丁", + false, + "NULL", + "POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))", + "0x7661726335", + ], + [ + BigInt(1656677800000), + -4, + -5, + -6, + BigInt(-7), + 4, + 5, + 6, + BigInt(7), + parseFloat((3.1415 * 5).toFixed(5)), + parseFloat((3.14159265 * 5).toFixed(15)), + "varchar_列_伍", + "nchar_列_戊", + true, + "NULL", + "POINT (7.0 9.0)", + "0x7661726335", + ], +]; +const jsonTags = [ + '{"key1":"taos","key2":null,"key3":"TDengine","key4":0,"key5":false}', +]; +const jsonTagsCN = [ + '{"key1":"taosdata","key2":null,"key3":"TDengine涛思数据","key4":1,"key5":true}', +]; + +const selectStable = `select * from ${stable}`; +const selectStableCN = `select * from ${stableCN}`; +const selectTable = `select * from ${table}`; +const selectTableCN = `select * from ${tableCN}`; +const selectJsonTable = `select * from ${jsonTable}`; +const selectJsonTableCN = `select * from ${jsonTableCN}`; beforeAll(async () => { let ws = await WsSql.open(conf); - await ws.exec(dropDB) + await ws.exec(dropDB); await ws.exec(createDB); await ws.exec(useDB); await ws.exec(createSTable(stable)); @@ -71,261 +311,304 @@ beforeAll(async () => { await ws.exec(createSTableJSON(jsonTable)); await ws.exec(createSTableJSON(jsonTableCN)); await ws.close(); -}) +}); -describe('ws.query(stable)', () => { - jest.setTimeout(20 * 1000) - test('Insert query stable without CN character', async () => { +describe("ws.query(stable)", () => { + jest.setTimeout(20 * 1000); + test("Insert query stable without CN character", async () => { let ws = await WsSql.open(conf); await ws.exec(useDB); - let insert = insertStable(tableValues, stableTags, stable) - let insertRes = await ws.exec(insert) - expect(insertRes.getAffectRows()).toBe(5) - - let queryRes = await ws.exec(selectStable) - let expectMeta = tableMeta.concat(tagMeta) - let expectData = expectStableData(tableValues, stableTags) - let actualMeta = queryRes.getMeta() - let actualData = queryRes.getData() - await ws.close() + let insert = insertStable(tableValues, stableTags, stable); + let insertRes = await ws.exec(insert); + expect(insertRes.getAffectRows()).toBe(5); + + let queryRes = await ws.exec(selectStable); + let expectMeta = tableMeta.concat(tagMeta); + let expectData = expectStableData(tableValues, stableTags); + let actualMeta = queryRes.getMeta(); + let actualData = queryRes.getData(); + await ws.close(); if (actualData && actualMeta) { actualMeta.forEach((meta, index) => { - expect(meta.name).toBe(expectMeta[index].name) - expect(meta.type).toBe(expectMeta[index].type) - expect(meta.length).toBe(expectMeta[index].length) - }) + expect(meta.name).toBe(expectMeta[index].name); + expect(meta.type).toBe(expectMeta[index].type); + expect(meta.length).toBe(expectMeta[index].length); + }); for (let i = 0; i < actualData.length; i++) { actualData[i].forEach((d, index) => { // // console.log(i, index, d, expectData[i][index]) - if (expectMeta[index].name == 'geo' || expectMeta[index].name == 'vbinary') { - let buffer:ArrayBuffer = resultMap.get(expectData[i][index]) + if ( + expectMeta[index].name == "geo" || + expectMeta[index].name == "vbinary" + ) { + let buffer: ArrayBuffer = resultMap.get( + expectData[i][index] + ); if (buffer) { - let dbData :ArrayBuffer = d - console.log(i, index, dbData, expectData[i][index], buffer, compareUint8Arrays(new Uint8Array(dbData), new Uint8Array(buffer))) - expect(compareUint8Arrays(new Uint8Array(dbData), new Uint8Array(buffer))).toBe(true) + let dbData: ArrayBuffer = d; + console.log( + i, + index, + dbData, + expectData[i][index], + buffer, + compareUint8Arrays( + new Uint8Array(dbData), + new Uint8Array(buffer) + ) + ); + expect( + compareUint8Arrays( + new Uint8Array(dbData), + new Uint8Array(buffer) + ) + ).toBe(true); } - } else { - expect(d).toBe(expectData[i][index]) + expect(d).toBe(expectData[i][index]); } - - }) + }); } } else { - throw new Error("retrieve empty result") + throw new Error("retrieve empty result"); } + }); - }) - - test('query stable with CN character', async () => { + test("query stable with CN character", async () => { let ws = await WsSql.open(conf); await ws.exec(useDB); - let insertCN = insertStable(tableCNValues, stableCNTags, stableCN) + let insertCN = insertStable(tableCNValues, stableCNTags, stableCN); // console.log(insertCN) - let insertRes = await ws.exec(insertCN) + let insertRes = await ws.exec(insertCN); // console.log(insertRes) - expect(insertRes.getAffectRows()).toBe(5) + expect(insertRes.getAffectRows()).toBe(5); - let queryRes = await ws.exec(selectStableCN) + let queryRes = await ws.exec(selectStableCN); - let expectMeta = tableMeta.concat(tagMeta) - let expectData = expectStableData(tableCNValues, stableCNTags) - let actualMeta = queryRes.getMeta() - let actualData = queryRes.getData() - await ws.close() + let expectMeta = tableMeta.concat(tagMeta); + let expectData = expectStableData(tableCNValues, stableCNTags); + let actualMeta = queryRes.getMeta(); + let actualData = queryRes.getData(); + await ws.close(); if (actualData && actualMeta) { actualMeta.forEach((meta, index) => { - expect(meta.name).toBe(expectMeta[index].name) - expect(meta.type).toBe(expectMeta[index].type) - expect(meta.length).toBe(expectMeta[index].length) - }) + expect(meta.name).toBe(expectMeta[index].name); + expect(meta.type).toBe(expectMeta[index].type); + expect(meta.length).toBe(expectMeta[index].length); + }); for (let i = 0; i < actualData.length; i++) { actualData[i].forEach((d, index) => { - if (expectMeta[index].name == 'geo' || expectMeta[index].name == 'vbinary') { - let buffer:ArrayBuffer = resultMap.get(expectData[i][index]) + if ( + expectMeta[index].name == "geo" || + expectMeta[index].name == "vbinary" + ) { + let buffer: ArrayBuffer = resultMap.get( + expectData[i][index] + ); if (buffer) { - let dbData :ArrayBuffer = d - console.log(i, index, dbData, expectData[i][index], buffer, compareUint8Arrays(new Uint8Array(dbData), new Uint8Array(buffer))) - expect(compareUint8Arrays(new Uint8Array(dbData), new Uint8Array(buffer))).toBe(true) + let dbData: ArrayBuffer = d; + console.log( + i, + index, + dbData, + expectData[i][index], + buffer, + compareUint8Arrays( + new Uint8Array(dbData), + new Uint8Array(buffer) + ) + ); + expect( + compareUint8Arrays( + new Uint8Array(dbData), + new Uint8Array(buffer) + ) + ).toBe(true); } - } else { - expect(d).toBe(expectData[i][index]) + expect(d).toBe(expectData[i][index]); } - }) + }); } } else { - throw new Error("retrieve empty result") + throw new Error("retrieve empty result"); } - }) -}) + }); +}); -describe('ws.query(table)', () => { - test('Insert query normal table without CN character', async () => { +describe("ws.query(table)", () => { + test("Insert query normal table without CN character", async () => { let ws = await WsSql.open(conf); await ws.exec(useDB); - let insert = insertNTable(tableValues, table) + let insert = insertNTable(tableValues, table); // console.log(insert) - let insertRes = await ws.exec(insert) - expect(insertRes.getAffectRows()).toBe(5) + let insertRes = await ws.exec(insert); + expect(insertRes.getAffectRows()).toBe(5); - let queryRes = await ws.exec(selectTable) + let queryRes = await ws.exec(selectTable); - let expectMeta = tableMeta - let expectData = tableValues - let actualMeta = queryRes.getMeta() - let actualData = queryRes.getData() - await ws.close() + let expectMeta = tableMeta; + let expectData = tableValues; + let actualMeta = queryRes.getMeta(); + let actualData = queryRes.getData(); + await ws.close(); if (actualData && actualMeta) { actualMeta.forEach((meta, index) => { // console.log(meta,expectMeta[index]); - expect(meta.name).toBe(expectMeta[index].name) - expect(meta.type).toBe(expectMeta[index].type) - expect(meta.length).toBe(expectMeta[index].length) - }) + expect(meta.name).toBe(expectMeta[index].name); + expect(meta.type).toBe(expectMeta[index].type); + expect(meta.length).toBe(expectMeta[index].length); + }); for (let i = 0; i < actualData.length; i++) { actualData[i].forEach((d, index) => { - if (expectMeta[index].name == 'geo' || expectMeta[index].name == 'vbinary') { - expect(d).toBeTruthy() + if ( + expectMeta[index].name == "geo" || + expectMeta[index].name == "vbinary" + ) { + expect(d).toBeTruthy(); } else { - expect(d).toBe(expectData[i][index]) + expect(d).toBe(expectData[i][index]); } - }) + }); } } else { - throw new Error("retrieve empty result") + throw new Error("retrieve empty result"); } - }) + }); - test('Insert query normal table with CN character', async () => { + test("Insert query normal table with CN character", async () => { let ws = await WsSql.open(conf); await ws.exec(useDB); - let insertCN = insertNTable(tableCNValues, tableCN) + let insertCN = insertNTable(tableCNValues, tableCN); // console.log(insertCN) - let insertRes = await ws.exec(insertCN) + let insertRes = await ws.exec(insertCN); // console.log(insertRes) - expect(insertRes.getAffectRows()).toBe(5) + expect(insertRes.getAffectRows()).toBe(5); - let queryRes = await ws.exec(selectTableCN) + let queryRes = await ws.exec(selectTableCN); - let expectMeta = tableMeta - let expectData = tableCNValues - let actualMeta = queryRes.getMeta() - let actualData = queryRes.getData() - await ws.close() + let expectMeta = tableMeta; + let expectData = tableCNValues; + let actualMeta = queryRes.getMeta(); + let actualData = queryRes.getData(); + await ws.close(); if (actualData && actualMeta) { actualMeta.forEach((meta, index) => { // console.log(meta, expectMeta[index]); - expect(meta.name).toBe(expectMeta[index].name) - expect(meta.type).toBe(expectMeta[index].type) - expect(meta.length).toBe(expectMeta[index].length) - }) + expect(meta.name).toBe(expectMeta[index].name); + expect(meta.type).toBe(expectMeta[index].type); + expect(meta.length).toBe(expectMeta[index].length); + }); for (let i = 0; i < actualData.length; i++) { actualData[i].forEach((d, index) => { - if (expectMeta[index].name == 'geo' || expectMeta[index].name == 'vbinary') { - expect(d).toBeTruthy() + if ( + expectMeta[index].name == "geo" || + expectMeta[index].name == "vbinary" + ) { + expect(d).toBeTruthy(); } else { - expect(d).toBe(expectData[i][index]) + expect(d).toBe(expectData[i][index]); } - - }) + }); } } else { - throw new Error("retrieve empty result") + throw new Error("retrieve empty result"); } - }) -}) + }); +}); -describe('ws.query(jsonTable)', () => { - test('Insert and query json data from table without CN', async () => { +describe("ws.query(jsonTable)", () => { + test("Insert and query json data from table without CN", async () => { let ws = await WsSql.open(conf); await ws.exec(useDB); - let insert = insertStable(tableValues, jsonTags, jsonTable) + let insert = insertStable(tableValues, jsonTags, jsonTable); // console.log(insert) let insertRes = await ws.exec(insert); - expect(insertRes.getAffectRows()).toBe(5) - - let queryRes = await ws.exec(selectJsonTable) - let expectMeta = tableMeta.concat(jsonMeta) - let expectData = expectStableData(tableValues, jsonTags) - let actualMeta = queryRes.getMeta() - let actualData = queryRes.getData() - await ws.close() + expect(insertRes.getAffectRows()).toBe(5); + + let queryRes = await ws.exec(selectJsonTable); + let expectMeta = tableMeta.concat(jsonMeta); + let expectData = expectStableData(tableValues, jsonTags); + let actualMeta = queryRes.getMeta(); + let actualData = queryRes.getData(); + await ws.close(); if (actualData && actualMeta) { actualMeta.forEach((meta, index) => { // console.log(meta); - expect(meta.name).toBe(expectMeta[index].name) - expect(meta.type).toBe(expectMeta[index].type) - expect(meta.length).toBe(expectMeta[index].length) - }) + expect(meta.name).toBe(expectMeta[index].name); + expect(meta.type).toBe(expectMeta[index].type); + expect(meta.length).toBe(expectMeta[index].length); + }); for (let i = 0; i < actualData.length; i++) { actualData[i].forEach((d, index) => { - if (expectMeta[index].name == 'geo' || expectMeta[index].name == 'vbinary') { - expect(d).toBeTruthy() + if ( + expectMeta[index].name == "geo" || + expectMeta[index].name == "vbinary" + ) { + expect(d).toBeTruthy(); } else { - expect(d).toBe(expectData[i][index]) + expect(d).toBe(expectData[i][index]); } - }) + }); } } else { - throw new Error("retrieve empty result") + throw new Error("retrieve empty result"); } + }); - }) - - - test('Insert and query json data from table with CN', async () => { + test("Insert and query json data from table with CN", async () => { let ws = await WsSql.open(conf); await ws.exec(useDB); - let insert = insertStable(tableCNValues, jsonTagsCN, jsonTableCN) + let insert = insertStable(tableCNValues, jsonTagsCN, jsonTableCN); // console.log(insert) let insertRes = await ws.exec(insert); - expect(insertRes.getAffectRows()).toBe(5) - - let queryRes = await ws.exec(selectJsonTableCN) - let expectMeta = tableMeta.concat(jsonMeta) - let expectData = expectStableData(tableCNValues, jsonTagsCN) - let actualMeta = queryRes.getMeta() - let actualData = queryRes.getData() - await ws.close() + expect(insertRes.getAffectRows()).toBe(5); + + let queryRes = await ws.exec(selectJsonTableCN); + let expectMeta = tableMeta.concat(jsonMeta); + let expectData = expectStableData(tableCNValues, jsonTagsCN); + let actualMeta = queryRes.getMeta(); + let actualData = queryRes.getData(); + await ws.close(); if (actualData && actualMeta) { actualMeta.forEach((meta, index) => { // console.log(meta); - expect(meta.name).toBe(expectMeta[index].name) - expect(meta.type).toBe(expectMeta[index].type) - expect(meta.length).toBe(expectMeta[index].length) - }) + expect(meta.name).toBe(expectMeta[index].name); + expect(meta.type).toBe(expectMeta[index].type); + expect(meta.length).toBe(expectMeta[index].length); + }); for (let i = 0; i < actualData.length; i++) { actualData[i].forEach((d, index) => { - if (expectMeta[index].name == 'geo' || expectMeta[index].name == 'vbinary') { - expect(d).toBeTruthy() + if ( + expectMeta[index].name == "geo" || + expectMeta[index].name == "vbinary" + ) { + expect(d).toBeTruthy(); } else { - expect(d).toBe(expectData[i][index]) + expect(d).toBe(expectData[i][index]); } - }) + }); } } else { - throw new Error("retrieve empty result") + throw new Error("retrieve empty result"); } - }) - -}) + }); +}); afterAll(async () => { let ws = await WsSql.open(conf); await ws.exec(dropDB); await ws.close(); - WebSocketConnectionPool.instance().destroyed() -}) - + WebSocketConnectionPool.instance().destroyed(); +}); -//--detectOpenHandles --maxConcurrency=1 --forceExit \ No newline at end of file +//--detectOpenHandles --maxConcurrency=1 --forceExit diff --git a/nodejs/test/bulkPulling/schemaless.test.ts b/nodejs/test/bulkPulling/schemaless.test.ts index 3f25c51d..ff280479 100644 --- a/nodejs/test/bulkPulling/schemaless.test.ts +++ b/nodejs/test/bulkPulling/schemaless.test.ts @@ -2,110 +2,153 @@ import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; import { WSConfig } from "../../src/common/config"; import { Precision, SchemalessProto } from "../../src/sql/wsProto"; import { WsSql } from "../../src/sql/wsSql"; -let dns = 'ws://localhost:6041' +let dns = "ws://localhost:6041"; beforeAll(async () => { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); - let wsSql = await WsSql.open(conf) - await wsSql.exec('drop database if exists power_schemaless;') - await wsSql.exec('create database if not exists power_schemaless KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;'); - await wsSql.exec('CREATE STABLE if not exists power_schemaless.meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);'); - await wsSql.close() -}) + let wsSql = await WsSql.open(conf); + await wsSql.exec("drop database if exists power_schemaless;"); + await wsSql.exec( + "create database if not exists power_schemaless KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;" + ); + await wsSql.exec( + "CREATE STABLE if not exists power_schemaless.meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);" + ); + await wsSql.close(); +}); +describe("TDWebSocket.WsSchemaless()", () => { + jest.setTimeout(20 * 1000); + let influxdbData = + 'st,t1=3i64,t2=4f64,t3="t3" c1=3i64,c3=L"passit",c2=false,c4=4f64 1626006833639000000'; + let telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0"; + let jsonData = + '{"metric": "meter_current","timestamp": 1626846400,"value": 10.3, "tags": {"groupid": 2, "location": "California.SanFrancisco", "id": "d1001"}}'; -describe('TDWebSocket.WsSchemaless()', () => { - jest.setTimeout(20 * 1000) - let influxdbData = "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000" - let telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0" - let jsonData = "{\"metric\": \"meter_current\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}" - - test('normal connect', async() => { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_schemaless') - let wsSchemaless = await WsSql.open(conf) - expect(wsSchemaless.state()).toBeGreaterThan(0) + test("normal connect", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_schemaless"); + let wsSchemaless = await WsSql.open(conf); + expect(wsSchemaless.state()).toBeGreaterThan(0); await wsSchemaless.close(); }); - test('connect db with error', async() => { - expect.assertions(1) + test("connect db with error", async () => { + expect.assertions(1); let wsSchemaless = null; try { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('jest') - wsSchemaless = await WsSql.open(conf) - }catch(e :any){ - console.log(e) - expect(e.message).toMatch('Database not exist') - }finally{ - if(wsSchemaless) { - await wsSchemaless.close() + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("jest"); + wsSchemaless = await WsSql.open(conf); + } catch (e: any) { + console.log(e); + expect(e.message).toMatch("Database not exist"); + } finally { + if (wsSchemaless) { + await wsSchemaless.close(); } } - }) + }); - test('normal insert', async() => { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_schemaless') - let wsSchemaless = await WsSql.open(conf) - expect(wsSchemaless.state()).toBeGreaterThan(0) - await wsSchemaless.schemalessInsert([influxdbData], SchemalessProto.InfluxDBLineProtocol, Precision.NANO_SECONDS, 0); - await wsSchemaless.schemalessInsert([telnetData], SchemalessProto.OpenTSDBTelnetLineProtocol, Precision.SECONDS, 0); - await wsSchemaless.schemalessInsert([jsonData], SchemalessProto.OpenTSDBJsonFormatProtocol, Precision.SECONDS, 0); + test("normal insert", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_schemaless"); + let wsSchemaless = await WsSql.open(conf); + expect(wsSchemaless.state()).toBeGreaterThan(0); + await wsSchemaless.schemalessInsert( + [influxdbData], + SchemalessProto.InfluxDBLineProtocol, + Precision.NANO_SECONDS, + 0 + ); + await wsSchemaless.schemalessInsert( + [telnetData], + SchemalessProto.OpenTSDBTelnetLineProtocol, + Precision.SECONDS, + 0 + ); + await wsSchemaless.schemalessInsert( + [jsonData], + SchemalessProto.OpenTSDBJsonFormatProtocol, + Precision.SECONDS, + 0 + ); await wsSchemaless.close(); }); - test('normal wsSql insert', async() => { - - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_schemaless') - let wsSchemaless = await WsSql.open(conf) - expect(wsSchemaless.state()).toBeGreaterThan(0) - await wsSchemaless.schemalessInsert([influxdbData], SchemalessProto.InfluxDBLineProtocol, Precision.NOT_CONFIGURED, 0); - await wsSchemaless.schemalessInsert([influxdbData], SchemalessProto.InfluxDBLineProtocol, Precision.NANO_SECONDS, 0); - await wsSchemaless.schemalessInsert([telnetData], SchemalessProto.OpenTSDBTelnetLineProtocol, Precision.SECONDS, 0); - await wsSchemaless.schemalessInsert([jsonData], SchemalessProto.OpenTSDBJsonFormatProtocol, Precision.SECONDS, 0); - + test("normal wsSql insert", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_schemaless"); + let wsSchemaless = await WsSql.open(conf); + expect(wsSchemaless.state()).toBeGreaterThan(0); + await wsSchemaless.schemalessInsert( + [influxdbData], + SchemalessProto.InfluxDBLineProtocol, + Precision.NOT_CONFIGURED, + 0 + ); + await wsSchemaless.schemalessInsert( + [influxdbData], + SchemalessProto.InfluxDBLineProtocol, + Precision.NANO_SECONDS, + 0 + ); + await wsSchemaless.schemalessInsert( + [telnetData], + SchemalessProto.OpenTSDBTelnetLineProtocol, + Precision.SECONDS, + 0 + ); + await wsSchemaless.schemalessInsert( + [jsonData], + SchemalessProto.OpenTSDBJsonFormatProtocol, + Precision.SECONDS, + 0 + ); + await wsSchemaless.close(); }); - test('SchemalessProto error', async() => { - - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_schemaless') - let wsSchemaless = await WsSql.open(conf) - expect(wsSchemaless.state()).toBeGreaterThan(0) + test("SchemalessProto error", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_schemaless"); + let wsSchemaless = await WsSql.open(conf); + expect(wsSchemaless.state()).toBeGreaterThan(0); try { - await wsSchemaless.schemalessInsert([influxdbData], SchemalessProto.OpenTSDBTelnetLineProtocol, Precision.NANO_SECONDS, 0); - }catch (e:any) { - expect(e.message).toMatch('parse timestamp failed') + await wsSchemaless.schemalessInsert( + [influxdbData], + SchemalessProto.OpenTSDBTelnetLineProtocol, + Precision.NANO_SECONDS, + 0 + ); + } catch (e: any) { + expect(e.message).toMatch("parse timestamp failed"); } await wsSchemaless.close(); }); -}) +}); afterAll(async () => { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); - let wsSql = await WsSql.open(conf) - await wsSql.exec('drop database if exists power_schemaless;') - await wsSql.close() - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + let wsSql = await WsSql.open(conf); + await wsSql.exec("drop database if exists power_schemaless;"); + await wsSql.close(); + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/sql.test.ts b/nodejs/test/bulkPulling/sql.test.ts index 3b10b79e..a7474205 100644 --- a/nodejs/test/bulkPulling/sql.test.ts +++ b/nodejs/test/bulkPulling/sql.test.ts @@ -2,226 +2,236 @@ import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; import { WSConfig } from "../../src/common/config"; import { WsSql } from "../../src/sql/wsSql"; import { Sleep } from "../utils"; -import logger, { setLevel } from "../../src/common/log" +import logger, { setLevel } from "../../src/common/log"; -let dns = 'ws://localhost:6041' -let password1 = 'Ab1!@#$%,.:?<>;~' -let password2 = 'Bc%^&*()-_+=[]{}' -setLevel("debug") +let dns = "ws://localhost:6041"; +let password1 = "Ab1!@#$%,.:?<>;~"; +let password2 = "Bc%^&*()-_+=[]{}"; +setLevel("debug"); beforeAll(async () => { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - await wsSql.exec('drop database if exists sql_test'); - await wsSql.exec('drop database if exists sql_create') + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + await wsSql.exec("drop database if exists sql_test"); + await wsSql.exec("drop database if exists sql_create"); await wsSql.exec(`CREATE USER user1 PASS '${password1}'`); await wsSql.exec(`CREATE USER user2 PASS '${password2}'`); - await wsSql.exec('create database if not exists sql_test KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;'); - await Sleep(100) - await wsSql.exec('use sql_test') - await wsSql.exec('CREATE STABLE if not exists meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);'); - await wsSql.close() -}) - -describe('TDWebSocket.WsSql()', () => { - jest.setTimeout(20 * 1000) - test('normal connect', async() => { + await wsSql.exec( + "create database if not exists sql_test KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;" + ); + await Sleep(100); + await wsSql.exec("use sql_test"); + await wsSql.exec( + "CREATE STABLE if not exists meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);" + ); + await wsSql.close(); +}); + +describe("TDWebSocket.WsSql()", () => { + jest.setTimeout(20 * 1000); + test("normal connect", async () => { let wsSql = null; - let conf :WSConfig = new WSConfig(''); + let conf: WSConfig = new WSConfig(""); conf.setUrl(dns); - conf.setUser('root'); - conf.setPwd('taosdata'); - conf.setDb('sql_test'); - conf.setTimezone('America/New_York'); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("sql_test"); + conf.setTimezone("America/New_York"); conf.setTimeOut(6000); - wsSql = await WsSql.open(conf) - expect(wsSql.state()).toBeGreaterThan(0) - let wsRows = await wsSql.query('select timezone()') + wsSql = await WsSql.open(conf); + expect(wsSql.state()).toBeGreaterThan(0); + let wsRows = await wsSql.query("select timezone()"); while (await wsRows.next()) { - let result = wsRows.getData() + let result = wsRows.getData(); console.log(result); - expect(result).toBeTruthy() - expect(JSON.stringify(result)).toContain('America/New_York') + expect(result).toBeTruthy(); + expect(JSON.stringify(result)).toContain("America/New_York"); } await wsSql.close(); }); - test('special characters connect1', async() => { + test("special characters connect1", async () => { let wsSql = null; - let conf :WSConfig = new WSConfig(dns) - conf.setUser('user1') - conf.setPwd(password1) - wsSql = await WsSql.open(conf) - expect(wsSql.state()).toBeGreaterThan(0) + let conf: WSConfig = new WSConfig(dns); + conf.setUser("user1"); + conf.setPwd(password1); + wsSql = await WsSql.open(conf); + expect(wsSql.state()).toBeGreaterThan(0); let version = await wsSql.version(); expect(version).not.toBeNull(); expect(version).not.toBeUndefined(); await wsSql.close(); }); - test('special characters connect2', async() => { + test("special characters connect2", async () => { let wsSql = null; - let conf :WSConfig = new WSConfig(dns) - conf.setUser('user2') - conf.setPwd(password2) - wsSql = await WsSql.open(conf) - expect(wsSql.state()).toBeGreaterThan(0) + let conf: WSConfig = new WSConfig(dns); + conf.setUser("user2"); + conf.setPwd(password2); + wsSql = await WsSql.open(conf); + expect(wsSql.state()).toBeGreaterThan(0); let version = await wsSql.version(); expect(version).not.toBeNull(); expect(version).not.toBeUndefined(); await wsSql.close(); }); - test('connect db with error', async() => { - expect.assertions(1) + test("connect db with error", async () => { + expect.assertions(1); let wsSql = null; try { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('jest') - wsSql = await WsSql.open(conf) - }catch(e){ - let err:any = e - expect(err.message).toMatch('Database not exist') - }finally{ - if(wsSql) { - await wsSql.close() + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("jest"); + wsSql = await WsSql.open(conf); + } catch (e) { + let err: any = e; + expect(err.message).toMatch("Database not exist"); + } finally { + if (wsSql) { + await wsSql.close(); } } - }) + }); - test('connect url', async() => { - let url = 'ws://root:taosdata@localhost:6041/information_schema?timezone=Asia/Shanghai' - let conf :WSConfig = new WSConfig(url) - let wsSql = await WsSql.open(conf) - let version = await wsSql.version() + test("connect url", async () => { + let url = + "ws://root:taosdata@localhost:6041/information_schema?timezone=Asia/Shanghai"; + let conf: WSConfig = new WSConfig(url); + let wsSql = await WsSql.open(conf); + let version = await wsSql.version(); console.log(version); - expect(version).toBeTruthy() - let wsRows = await wsSql.query('select timezone()') + expect(version).toBeTruthy(); + let wsRows = await wsSql.query("select timezone()"); while (await wsRows.next()) { - let result = wsRows.getData() + let result = wsRows.getData(); console.log(result); - expect(result).toBeTruthy() - expect(JSON.stringify(result)).toContain('Asia/Shanghai') + expect(result).toBeTruthy(); + expect(JSON.stringify(result)).toContain("Asia/Shanghai"); } await wsSql.close(); - }) - - test('get taosc version', async() => { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - let version = await wsSql.version() - await wsSql.close() + }); + + test("get taosc version", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + let version = await wsSql.version(); + await wsSql.close(); console.log(version); - expect(version).toBeTruthy() - }) - - test('show databases', async()=>{ - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - let taosResult = await wsSql.exec('show databases') - await wsSql.close() + expect(version).toBeTruthy(); + }); + + test("show databases", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + let taosResult = await wsSql.exec("show databases"); + await wsSql.close(); console.log(taosResult); - expect(taosResult).toBeTruthy() - }) - - test('create databases', async()=>{ - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - let taosResult = await wsSql.exec('create database if not exists sql_create KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;') - await wsSql.close() + expect(taosResult).toBeTruthy(); + }); + + test("create databases", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + let taosResult = await wsSql.exec( + "create database if not exists sql_create KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;" + ); + await wsSql.close(); console.log(taosResult); - expect(taosResult).toBeTruthy() - }) - - test('create stable', async()=>{ - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - let taosResult = await wsSql.exec('use sql_test') + expect(taosResult).toBeTruthy(); + }); + + test("create stable", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + let taosResult = await wsSql.exec("use sql_test"); console.log(taosResult); - expect(taosResult).toBeTruthy() + expect(taosResult).toBeTruthy(); - taosResult = await wsSql.exec('CREATE STABLE if not exists meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);'); - await wsSql.close() + taosResult = await wsSql.exec( + "CREATE STABLE if not exists meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);" + ); + await wsSql.close(); console.log(taosResult); - expect(taosResult).toBeTruthy() - }) - - test('insert recoder', async()=>{ - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - let taosResult = await wsSql.exec('use sql_test') + expect(taosResult).toBeTruthy(); + }); + + test("insert recoder", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + let taosResult = await wsSql.exec("use sql_test"); console.log(taosResult); - expect(taosResult).toBeTruthy() + expect(taosResult).toBeTruthy(); - taosResult = await wsSql.exec('describe meters') + taosResult = await wsSql.exec("describe meters"); console.log(taosResult); - - taosResult = await wsSql.exec('INSERT INTO d1001 USING meters (location, groupid) TAGS ("California", 3) VALUES (NOW, 10.2, 219, 0.32)') + + taosResult = await wsSql.exec( + 'INSERT INTO d1001 USING meters (location, groupid) TAGS ("California", 3) VALUES (NOW, 10.2, 219, 0.32)' + ); console.log(taosResult); - expect(taosResult.getAffectRows()).toBeGreaterThanOrEqual(1) - await wsSql.close() - - }) - - test('query sql', async()=>{ - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - let taosResult = await wsSql.exec('use sql_test') + expect(taosResult.getAffectRows()).toBeGreaterThanOrEqual(1); + await wsSql.close(); + }); + + test("query sql", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + let taosResult = await wsSql.exec("use sql_test"); console.log(taosResult); - expect(taosResult).toBeTruthy() + expect(taosResult).toBeTruthy(); for (let i = 0; i < 10; i++) { - let wsRows = await wsSql.query('select * from meters limit 3'); - expect(wsRows).toBeTruthy() - let meta = wsRows.getMeta() - expect(meta).toBeTruthy() + let wsRows = await wsSql.query("select * from meters limit 3"); + expect(wsRows).toBeTruthy(); + let meta = wsRows.getMeta(); + expect(meta).toBeTruthy(); console.log("wsRow:meta:=>", meta); while (await wsRows.next()) { let result = await wsRows.getData(); - expect(result).toBeTruthy() + expect(result).toBeTruthy(); } - await wsRows.close() + await wsRows.close(); } - await wsSql.close() - }) + await wsSql.close(); + }); - test('query sql no getdata', async()=>{ - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - let wsSql = await WsSql.open(conf) - let taosResult = await wsSql.exec('use sql_test') + test("query sql no getdata", async () => { + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + let wsSql = await WsSql.open(conf); + let taosResult = await wsSql.exec("use sql_test"); console.log(taosResult); - expect(taosResult).toBeTruthy() - let wsRows = await wsSql.query('select * from meters'); - await wsRows.close() - await wsSql.close() - }) -}) + expect(taosResult).toBeTruthy(); + let wsRows = await wsSql.query("select * from meters"); + await wsRows.close(); + await wsSql.close(); + }); +}); afterAll(async () => { - let conf :WSConfig = new WSConfig(dns); - conf.setUser('root'); - conf.setPwd('taosdata'); + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); let wsSql = await WsSql.open(conf); - await wsSql.exec('drop database sql_test'); - await wsSql.exec('drop database sql_create'); - await wsSql.exec('DROP USER user1;') - await wsSql.exec('DROP USER user2;') + await wsSql.exec("drop database sql_test"); + await wsSql.exec("drop database sql_create"); + await wsSql.exec("DROP USER user1;"); + await wsSql.exec("DROP USER user2;"); await wsSql.close(); - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/stmt1.func.test.ts b/nodejs/test/bulkPulling/stmt1.func.test.ts index ee826dd4..8e94d313 100644 --- a/nodejs/test/bulkPulling/stmt1.func.test.ts +++ b/nodejs/test/bulkPulling/stmt1.func.test.ts @@ -1,433 +1,463 @@ - import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; import { WSConfig } from "../../src/common/config"; import { setLevel } from "../../src/common/log"; import { WsSql } from "../../src/sql/wsSql"; import { WsStmt1 } from "../../src/stmt/wsStmt1"; -let dns = 'ws://localhost:6041' -setLevel("debug") +let dns = "ws://localhost:6041"; +setLevel("debug"); beforeAll(async () => { - let conf :WSConfig = new WSConfig(dns); - conf.setUser('root'); - conf.setPwd('taosdata'); + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); let wsSql = await WsSql.open(conf); - await wsSql.exec('drop database if exists power_func_stmt1;'); - await wsSql.exec('create database if not exists power_func_stmt1 KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;'); - await wsSql.exec('CREATE STABLE if not exists power_func_stmt1.meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);'); + await wsSql.exec("drop database if exists power_func_stmt1;"); + await wsSql.exec( + "create database if not exists power_func_stmt1 KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;" + ); + await wsSql.exec( + "CREATE STABLE if not exists power_func_stmt1.meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);" + ); await wsSql.close(); -}) -describe('TDWebSocket.Stmt()', () => { - jest.setTimeout(20 * 1000) - let tags = ['California', 3]; +}); +describe("TDWebSocket.Stmt()", () => { + jest.setTimeout(20 * 1000); + let tags = ["California", 3]; let multi = [ - // [1709183268567], - // [10.2], - // [292], - // [0.32], - [1709183268567, 1709183268568, 1709183268569], - [10.2, 10.3, 10.4], - [292, 293, 294], - [0.32, 0.33, 0.34], + // [1709183268567], + // [10.2], + // [292], + // [0.32], + [1709183268567, 1709183268568, 1709183268569], + [10.2, 10.3, 10.4], + [292, 293, 294], + [0.32, 0.33, 0.34], ]; - test('normal connect', async() => { + test("normal connect", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.close() + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.close(); await connector.close(); }); - test('connect db with error', async() => { - expect.assertions(1) + test("connect db with error", async () => { + expect.assertions(1); let connector = null; try { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('jest') - connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - await stmt.close() - }catch(e){ - let err:any = e - expect(err.message).toMatch('Database not exist') - }finally{ - if(connector) { - await connector.close() + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("jest"); + connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + await stmt.close(); + } catch (e) { + let err: any = e; + expect(err.message).toMatch("Database not exist"); + } finally { + if (connector) { + await connector.close(); } } - }) + }); - test('normal Prepare', async() => { + test("normal Prepare", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); params.setVarchar([tags[0]]); - params.setInt([tags[1]]); + params.setInt([tags[1]]); await stmt.setTags(params); - await stmt.close() + await stmt.close(); await connector.close(); - }); + }); - test('set tag error', async() => { + test("set tag error", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); params.setVarchar([tags[0]]); try { - await stmt.setTags(params) - } catch(err:any) { - expect(err.message).toMatch('stmt tags count not match') - } - await stmt.close() + await stmt.setTags(params); + } catch (err: any) { + expect(err.message).toMatch("stmt tags count not match"); + } + await stmt.close(); await connector.close(); - }); - - test('error Prepare table', async() => { + }); + + test("error Prepare table", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - try{ - await stmt.prepare('INSERT ? INTO ? USING meters TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - }catch(e) { - let err:any = e - expect(err.message).toMatch(/keyword INTO is expected|Syntax error in SQL/) + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + try { + await stmt.prepare( + "INSERT ? INTO ? USING meters TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + } catch (e) { + let err: any = e; + expect(err.message).toMatch( + /keyword INTO is expected|Syntax error in SQL/ + ); } - await stmt.close() + await stmt.close(); await connector.close(); - }); + }); - test('error Prepare tag', async() => { + test("error Prepare tag", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - try{ - await stmt.prepare('INSERT INTO ? USING meters TAGS (?, ?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - }catch(e) { - let err:any = e - expect(err.message).toMatch("Tags number not matched") + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + try { + await stmt.prepare( + "INSERT INTO ? USING meters TAGS (?, ?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + } catch (e) { + let err: any = e; + expect(err.message).toMatch("Tags number not matched"); } - await stmt.close() + await stmt.close(); await connector.close(); }); - test('Bind a single table', async() => { + test("Bind a single table", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) (ts, current, voltage, phase) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('power_func_stmt1.d1001'); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) (ts, current, voltage, phase) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("power_func_stmt1.d1001"); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([1]); - await stmt.setTags(params) + await stmt.setTags(params); - let lastTs = 0 + let lastTs = 0; for (let i = 0; i < 10; i++) { for (let j = 0; j < multi[0].length; j++) { multi[0][j] = multi[0][0] + j; - lastTs = multi[0][j] + lastTs = multi[0][j]; } - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); multi[0][0] = lastTs + 1; } - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(30) - await stmt.close() + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(30); + await stmt.close(); await connector.close(); }); - test('error BindParam', async() => { + test("error BindParam", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) + await stmt.setTags(params); let multi = [ [1709183268567, 1709183268568], [10.2, 10.3, 10.4, 10.5], [292, 293, 294], [0.32, 0.33, 0.31], - ]; - try{ - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) - await stmt.batch() - await stmt.exec() - }catch(e) { - let err:any = e - expect(err.message).toMatch(/wrong row length|bind data length error/) + ]; + try { + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); + await stmt.batch(); + await stmt.exec(); + } catch (e) { + let err: any = e; + expect(err.message).toMatch( + /wrong row length|bind data length error/ + ); } - await stmt.close() + await stmt.close(); await connector.close(); }); - test('no Batch', async() => { + test("no Batch", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) + await stmt.setTags(params); let multi = [ [1709183268567, 1709183268568], [10.2, 10.3], [292, 293], [0.32, 0.33], - ]; - try{ - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) - await stmt.exec() - }catch(e) { - let err:any = e - expect(err.message).toMatch("Stmt API usage error") + ]; + try { + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); + await stmt.exec(); + } catch (e) { + let err: any = e; + expect(err.message).toMatch("Stmt API usage error"); } - await stmt.close() + await stmt.close(); await connector.close(); }); - test('Batch after BindParam', async() => { + test("Batch after BindParam", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) + await stmt.setTags(params); let multi1 = [ [1709188881548, 1709188881549], [10.2, 10.3], [292, 293], [0.32, 0.33], - ]; + ]; let multi2 = [ [1709188881550, 1709188881551], [10.2, 10.3], [292, 293], [0.32, 0.33], - ]; - - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi1[0]) - dataParams.setFloat(multi1[1]) - dataParams.setInt(multi1[2]) - dataParams.setFloat(multi1[3]) - await stmt.bind(dataParams) - await stmt.batch() + ]; - await stmt.setTableName('d1002'); - params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi1[0]); + dataParams.setFloat(multi1[1]); + dataParams.setInt(multi1[2]); + dataParams.setFloat(multi1[3]); + await stmt.bind(dataParams); + await stmt.batch(); + + await stmt.setTableName("d1002"); + params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([5]); - await stmt.setTags(params) - - dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi2[0]) - dataParams.setFloat(multi2[1]) - dataParams.setInt(multi2[2]) - dataParams.setFloat(multi2[3]) - await stmt.bind(dataParams) - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(4) - await stmt.close() + await stmt.setTags(params); + + dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi2[0]); + dataParams.setFloat(multi2[1]); + dataParams.setInt(multi2[2]); + dataParams.setFloat(multi2[3]); + await stmt.bind(dataParams); + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(4); + await stmt.close(); await connector.close(); }); - test('no set tag', async() => { + test("no set tag", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); // await stmt.SetTags(tags) - try{ - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) - await stmt.batch() - await stmt.exec() - }catch(e) { - let err:any = e + try { + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); + await stmt.batch(); + await stmt.exec(); + } catch (e) { + let err: any = e; expect(err.message).toMatch(/Retry needed|Tags are empty/); } - await stmt.close() + await stmt.close(); await connector.close(); }); - test('normal binary BindParam', async() => { + test("normal binary BindParam", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1002'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1002"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) - - await stmt.batch() - await stmt.exec() + await stmt.setTags(params); + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); - let result = await connector.exec("select * from power_func_stmt1.meters") - console.log(result) - await stmt.close() - await connector.close(); + await stmt.batch(); + await stmt.exec(); + let result = await connector.exec( + "select * from power_func_stmt1.meters" + ); + console.log(result); + await stmt.close(); + await connector.close(); }); - test('normal json BindParam', async() => { + test("normal json BindParam", async () => { let conf = new WSConfig(dns, "100.100.100.100"); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt1') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt1"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) + await stmt.setTags(params); let multi1 = [ [1709188881548, 1709188881549], [10.2, 10.3], [292, 293], [0.32, 0.33], - ]; - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi1[0]) - dataParams.setFloat(multi1[1]) - dataParams.setInt(multi1[2]) - dataParams.setFloat(multi1[3]) - await stmt.bind(dataParams) - await stmt.batch() - await stmt.exec() - await stmt.close() + ]; + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi1[0]); + dataParams.setFloat(multi1[1]); + dataParams.setInt(multi1[2]); + dataParams.setFloat(multi1[3]); + await stmt.bind(dataParams); + await stmt.batch(); + await stmt.exec(); + await stmt.close(); await connector.close(); }); -}) +}); afterAll(async () => { - let conf :WSConfig = new WSConfig(dns); - conf.setUser('root'); - conf.setPwd('taosdata'); + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); let wsSql = await WsSql.open(conf); - await wsSql.exec('drop database power_func_stmt1'); + await wsSql.exec("drop database power_func_stmt1"); await wsSql.close(); - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/stmt1.type.test.ts b/nodejs/test/bulkPulling/stmt1.type.test.ts index a15111fb..fbd10b72 100644 --- a/nodejs/test/bulkPulling/stmt1.type.test.ts +++ b/nodejs/test/bulkPulling/stmt1.type.test.ts @@ -3,91 +3,171 @@ import { WSConfig } from "../../src/common/config"; import { setLevel } from "../../src/common/log"; import { WsSql } from "../../src/sql/wsSql"; import { WsStmt1 } from "../../src/stmt/wsStmt1"; -import { createBaseSTable, createBaseSTableJSON, createSTableJSON, getInsertBind } from "../utils"; +import { + createBaseSTable, + createBaseSTableJSON, + createSTableJSON, + getInsertBind, +} from "../utils"; -const stable = 'ws_stmt_stb'; -const table = 'stmt_001'; -const db = 'ws_stmt1' -const createDB = `create database if not exists ${db} keep 3650` -const useDB = `use ${db}` -const dropDB = `drop database if exists ${db}` +const stable = "ws_stmt_stb"; +const table = "stmt_001"; +const db = "ws_stmt1"; +const createDB = `create database if not exists ${db} keep 3650`; +const useDB = `use ${db}`; +const dropDB = `drop database if exists ${db}`; -const tableCN = 'stmt_cn'; -const stableCN = 'ws_stmt_stb_cn'; -const jsonTable = 'stmt_json'; -const jsonTableCN = 'stmt_json_cn'; +const tableCN = "stmt_cn"; +const stableCN = "ws_stmt_stb_cn"; +const jsonTable = "stmt_json"; +const jsonTableCN = "stmt_json_cn"; - -const stableTags = [true, -1, -2, -3, -4, 1, 2, 3, 4, parseFloat(3.1415.toFixed(5)), parseFloat(3.14159265.toFixed(15)), 'varchar_tag_1', 'nchar_tag_1'] -const stableCNTags = [false, -1 * 2, -2 * 2, -3 * 2, -4 * 2, 1 * 2, 2 * 2, 3 * 2, 4 * 2, parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.14159265 * 2).toFixed(15)), 'varchar_标签_壹', 'nchar_标签_贰'] +const stableTags = [ + true, + -1, + -2, + -3, + -4, + 1, + 2, + 3, + 4, + parseFloat((3.1415).toFixed(5)), + parseFloat((3.14159265).toFixed(15)), + "varchar_tag_1", + "nchar_tag_1", +]; +const stableCNTags = [ + false, + -1 * 2, + -2 * 2, + -3 * 2, + -4 * 2, + 1 * 2, + 2 * 2, + 3 * 2, + 4 * 2, + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.14159265 * 2).toFixed(15)), + "varchar_标签_壹", + "nchar_标签_贰", +]; const tableValues = [ - [1656677710000, 1656677720000, 1656677730000, 1656677740000, 1656677750000], - [0, -1, -2, -3, -4], - [-1, -2,-3, -4, -5], - [-3, -4,-5, -6, -7], + [1656677710000, 1656677720000, 1656677730000, 1656677740000, 1656677750000], + [0, -1, -2, -3, -4], + [-1, -2, -3, -4, -5], + [-3, -4, -5, -6, -7], // [0, 1, 2, 3, 4], - [BigInt(-2), BigInt(-3), BigInt(-4), BigInt(-5), BigInt(-6)], + [BigInt(-2), BigInt(-3), BigInt(-4), BigInt(-5), BigInt(-6)], - [0, 1, 2, 3, 4], - [1, 2, 3, 4,5], - [2, 3, 4,5, 6], + [0, 1, 2, 3, 4], + [1, 2, 3, 4, 5], + [2, 3, 4, 5, 6], // [0, 1, 2, 3, 4], - [BigInt(3), BigInt(4), BigInt(5), BigInt(6), BigInt(7)], + [BigInt(3), BigInt(4), BigInt(5), BigInt(6), BigInt(7)], - [parseFloat(3.1415.toFixed(5)), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.1415 * 3).toFixed(5)), parseFloat((3.1415 * 4).toFixed(5)), parseFloat((3.1415 * 5).toFixed(5))], - [parseFloat(3.14159265.toFixed(15)), parseFloat((3.14159265 * 2).toFixed(15)), parseFloat((3.14159265 * 3).toFixed(15)), parseFloat((3.14159265 * 4).toFixed(15)), parseFloat((3.14159265 * 5).toFixed(15))], - ['varchar_col_1', 'varchar_col_2', 'varchar_col_3', 'varchar_col_4', 'varchar_col_5' ], - ['nchar_col_1', 'nchar_col_2', '', 'nchar_col_4', 'nchar_col_5'], - [true, false, true, false, true], - [null, null, null, null, null] -] + [ + parseFloat((3.1415).toFixed(5)), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.1415 * 3).toFixed(5)), + parseFloat((3.1415 * 4).toFixed(5)), + parseFloat((3.1415 * 5).toFixed(5)), + ], + [ + parseFloat((3.14159265).toFixed(15)), + parseFloat((3.14159265 * 2).toFixed(15)), + parseFloat((3.14159265 * 3).toFixed(15)), + parseFloat((3.14159265 * 4).toFixed(15)), + parseFloat((3.14159265 * 5).toFixed(15)), + ], + [ + "varchar_col_1", + "varchar_col_2", + "varchar_col_3", + "varchar_col_4", + "varchar_col_5", + ], + ["nchar_col_1", "nchar_col_2", "", "nchar_col_4", "nchar_col_5"], + [true, false, true, false, true], + [null, null, null, null, null], +]; const tableCNValues = [ - [BigInt(1656677760000), BigInt(1656677770000), BigInt(1656677780000), BigInt(1656677790000), BigInt(1656677100000)], - [0, -1, -2, -3, -4], - [-1, -2,-3, -4, -5], - [ -2, -3, -4,-5, -6], - [BigInt(-3), BigInt(-4),BigInt(-5), BigInt(-6), BigInt(-7)], - [0, 1, 2, 3, 4], - [1, 2, 3, 4,5], - [2, 3, 4,5, 6], - [BigInt(3), BigInt(4), BigInt(5), BigInt(6), BigInt(7)], - [parseFloat(3.1415.toFixed(5)), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.1415 * 3).toFixed(5)), parseFloat((3.1415 * 4).toFixed(5)), parseFloat((3.1415 * 5).toFixed(5))], - [parseFloat(3.14159265.toFixed(15)), parseFloat((3.14159265 * 2).toFixed(15)), parseFloat((3.14159265 * 3).toFixed(15)), parseFloat((3.14159265 * 4).toFixed(15)), parseFloat((3.14159265 * 5).toFixed(15))], - ['varchar_列_壹','varchar_列_贰','varchar_列_叁','varchar_列_肆','varchar_列_伍'], - ['nchar_列_甲','nchar_列_乙','nchar_列_丙','nchar_列_丁','nchar_列_戊'], - [true, false, true, false, true], - [null, null, null, null, null], -] - -let geoDataArray:any[] = []; -let varbinary:any[] = []; + [ + BigInt(1656677760000), + BigInt(1656677770000), + BigInt(1656677780000), + BigInt(1656677790000), + BigInt(1656677100000), + ], + [0, -1, -2, -3, -4], + [-1, -2, -3, -4, -5], + [-2, -3, -4, -5, -6], + [BigInt(-3), BigInt(-4), BigInt(-5), BigInt(-6), BigInt(-7)], + [0, 1, 2, 3, 4], + [1, 2, 3, 4, 5], + [2, 3, 4, 5, 6], + [BigInt(3), BigInt(4), BigInt(5), BigInt(6), BigInt(7)], + [ + parseFloat((3.1415).toFixed(5)), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.1415 * 3).toFixed(5)), + parseFloat((3.1415 * 4).toFixed(5)), + parseFloat((3.1415 * 5).toFixed(5)), + ], + [ + parseFloat((3.14159265).toFixed(15)), + parseFloat((3.14159265 * 2).toFixed(15)), + parseFloat((3.14159265 * 3).toFixed(15)), + parseFloat((3.14159265 * 4).toFixed(15)), + parseFloat((3.14159265 * 5).toFixed(15)), + ], + [ + "varchar_列_壹", + "varchar_列_贰", + "varchar_列_叁", + "varchar_列_肆", + "varchar_列_伍", + ], + ["nchar_列_甲", "nchar_列_乙", "nchar_列_丙", "nchar_列_丁", "nchar_列_戊"], + [true, false, true, false, true], + [null, null, null, null, null], +]; + +let geoDataArray: any[] = []; +let varbinary: any[] = []; const encoder = new TextEncoder(); -for (let i = 0; i< 5; i++) { - let data = new Uint8Array([0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x59,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x40,]) - geoDataArray.push(data.buffer) ; - let vdata = encoder.encode(`varchar_col_${i+1}`) - varbinary.push(vdata.buffer) +for (let i = 0; i < 5; i++) { + let data = new Uint8Array([ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40, + ]); + geoDataArray.push(data.buffer); + let vdata = encoder.encode(`varchar_col_${i + 1}`); + varbinary.push(vdata.buffer); } -const jsonTags = ["{\"key1\":\"taos\",\"key2\":null,\"key3\":\"TDengine\",\"key4\":0,\"key5\":false}"] -const jsonTagsCN = ["{\"key1\":\"taosdata\",\"key2\":null,\"key3\":\"TDengine涛思数据\",\"key4\":1,\"key5\":true}"] +const jsonTags = [ + '{"key1":"taos","key2":null,"key3":"TDengine","key4":0,"key5":false}', +]; +const jsonTagsCN = [ + '{"key1":"taosdata","key2":null,"key3":"TDengine涛思数据","key4":1,"key5":true}', +]; -const selectStable = `select * from ${stable}` -const selectStableCN = `select * from ${stableCN}` -const selectTable = `select * from ${table}` -const selectTableCN = `select * from ${tableCN}` -const selectJsonTable = `select * from ${jsonTable}` -const selectJsonTableCN = `select * from ${jsonTableCN}` +const selectStable = `select * from ${stable}`; +const selectStableCN = `select * from ${stableCN}`; +const selectTable = `select * from ${table}`; +const selectTableCN = `select * from ${tableCN}`; +const selectJsonTable = `select * from ${jsonTable}`; +const selectJsonTableCN = `select * from ${jsonTableCN}`; -let dsn = 'ws://root:taosdata@localhost:6041'; -setLevel("debug") +let dsn = "ws://root:taosdata@localhost:6041"; +setLevel("debug"); beforeAll(async () => { - let conf :WSConfig = new WSConfig(dsn) + let conf: WSConfig = new WSConfig(dsn); let ws = await WsSql.open(conf); await ws.exec(dropDB); await ws.exec(createDB); @@ -95,270 +175,288 @@ beforeAll(async () => { await ws.exec(createBaseSTable(stable)); await ws.exec(createSTableJSON(jsonTable)); await ws.close(); -}) +}); -describe('TDWebSocket.Stmt()', () => { - jest.setTimeout(20 * 1000) - test('normal BindParam', async() => { +describe("TDWebSocket.Stmt()", () => { + jest.setTimeout(20 * 1000); + test("normal BindParam", async () => { let wsConf = new WSConfig(dsn, "100.100.100.100"); - wsConf.setDb(db) - let connector = await WsSql.open(wsConf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); + wsConf.setDb(db); + let connector = await WsSql.open(wsConf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare(getInsertBind(tableValues.length + 2, stableTags.length, db, stable)); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + getInsertBind(tableValues.length + 2, stableTags.length, db, stable) + ); await stmt.setTableName(table); let tagParams = stmt.newStmtParam(); - tagParams.setBoolean([stableTags[0]]) - tagParams.setTinyInt([stableTags[1]]) - tagParams.setSmallInt([stableTags[2]]) - tagParams.setInt([stableTags[3]]) - tagParams.setBigint([BigInt(stableTags[4])]) - tagParams.setUTinyInt([stableTags[5]]) - - tagParams.setUSmallInt([stableTags[6]]) - tagParams.setUInt([stableTags[7]]) - tagParams.setUBigint([BigInt(stableTags[8])]) - tagParams.setFloat([stableTags[9]]) - tagParams.setDouble([stableTags[10]]) - tagParams.setBinary([stableTags[11]]) - tagParams.setNchar([stableTags[12]]) + tagParams.setBoolean([stableTags[0]]); + tagParams.setTinyInt([stableTags[1]]); + tagParams.setSmallInt([stableTags[2]]); + tagParams.setInt([stableTags[3]]); + tagParams.setBigint([BigInt(stableTags[4])]); + tagParams.setUTinyInt([stableTags[5]]); + + tagParams.setUSmallInt([stableTags[6]]); + tagParams.setUInt([stableTags[7]]); + tagParams.setUBigint([BigInt(stableTags[8])]); + tagParams.setFloat([stableTags[9]]); + tagParams.setDouble([stableTags[10]]); + tagParams.setBinary([stableTags[11]]); + tagParams.setNchar([stableTags[12]]); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); - bindParams.setTimestamp(tableValues[0]) - bindParams.setTinyInt(tableValues[1]) - bindParams.setSmallInt(tableValues[2]) - bindParams.setInt(tableValues[3]) - bindParams.setBigint(tableValues[4]) - bindParams.setUTinyInt(tableValues[5]) - bindParams.setUSmallInt(tableValues[6]) - bindParams.setUInt(tableValues[7]) - bindParams.setUBigint(tableValues[8]) - bindParams.setFloat(tableValues[9]) - bindParams.setDouble(tableValues[10]) - - bindParams.setBinary(tableValues[11]) - bindParams.setNchar(tableValues[12]) - bindParams.setBoolean(tableValues[13]) - bindParams.setInt(tableValues[14]) - bindParams.setGeometry(geoDataArray) - bindParams.setVarBinary(varbinary) - + bindParams.setTimestamp(tableValues[0]); + bindParams.setTinyInt(tableValues[1]); + bindParams.setSmallInt(tableValues[2]); + bindParams.setInt(tableValues[3]); + bindParams.setBigint(tableValues[4]); + bindParams.setUTinyInt(tableValues[5]); + bindParams.setUSmallInt(tableValues[6]); + bindParams.setUInt(tableValues[7]); + bindParams.setUBigint(tableValues[8]); + bindParams.setFloat(tableValues[9]); + bindParams.setDouble(tableValues[10]); + + bindParams.setBinary(tableValues[11]); + bindParams.setNchar(tableValues[12]); + bindParams.setBoolean(tableValues[13]); + bindParams.setInt(tableValues[14]); + bindParams.setGeometry(geoDataArray); + bindParams.setVarBinary(varbinary); + await stmt.bind(bindParams); - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(5) - await stmt.close() - let result = await connector.exec(`select * from ${db}.${stable}`) - console.log(result) + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(5); + await stmt.close(); + let result = await connector.exec(`select * from ${db}.${stable}`); + console.log(result); await connector.close(); }); - test('normal CN BindParam', async() => { + test("normal CN BindParam", async () => { let wsConf = new WSConfig(dsn, "100.100.100.100"); - wsConf.setDb(db) - let connector = await WsSql.open(wsConf) - let stmt = await (await connector).stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare(getInsertBind(tableValues.length + 2, stableTags.length, db, stable)); + wsConf.setDb(db); + let connector = await WsSql.open(wsConf); + let stmt = await (await connector).stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + getInsertBind(tableValues.length + 2, stableTags.length, db, stable) + ); await stmt.setTableName(table); let tagParams = stmt.newStmtParam(); - tagParams.setBoolean([stableCNTags[0]]) - tagParams.setTinyInt([stableCNTags[1]]) - tagParams.setSmallInt([stableCNTags[2]]) - tagParams.setInt([stableCNTags[3]]) - tagParams.setBigint([BigInt(stableCNTags[4])]) - tagParams.setUTinyInt([stableCNTags[5]]) - - tagParams.setUSmallInt([stableCNTags[6]]) - tagParams.setUInt([stableCNTags[7]]) - tagParams.setUBigint([BigInt(stableCNTags[8])]) - tagParams.setFloat([stableCNTags[9]]) - tagParams.setDouble([stableCNTags[10]]) - tagParams.setBinary([stableCNTags[11]]) - tagParams.setNchar([stableCNTags[12]]) + tagParams.setBoolean([stableCNTags[0]]); + tagParams.setTinyInt([stableCNTags[1]]); + tagParams.setSmallInt([stableCNTags[2]]); + tagParams.setInt([stableCNTags[3]]); + tagParams.setBigint([BigInt(stableCNTags[4])]); + tagParams.setUTinyInt([stableCNTags[5]]); + + tagParams.setUSmallInt([stableCNTags[6]]); + tagParams.setUInt([stableCNTags[7]]); + tagParams.setUBigint([BigInt(stableCNTags[8])]); + tagParams.setFloat([stableCNTags[9]]); + tagParams.setDouble([stableCNTags[10]]); + tagParams.setBinary([stableCNTags[11]]); + tagParams.setNchar([stableCNTags[12]]); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); - bindParams.setTimestamp(tableCNValues[0]) - bindParams.setTinyInt(tableCNValues[1]) - bindParams.setSmallInt(tableCNValues[2]) - bindParams.setInt(tableCNValues[3]) - bindParams.setBigint(tableCNValues[4]) - bindParams.setUTinyInt(tableCNValues[5]) - bindParams.setUSmallInt(tableCNValues[6]) - bindParams.setUInt(tableCNValues[7]) - bindParams.setUBigint(tableCNValues[8]) - bindParams.setFloat(tableCNValues[9]) - bindParams.setDouble(tableCNValues[10]) - - bindParams.setBinary(tableCNValues[11]) - bindParams.setNchar(tableCNValues[12]) - bindParams.setBoolean(tableCNValues[13]) - bindParams.setInt(tableCNValues[14]) - bindParams.setGeometry(geoDataArray) - bindParams.setVarBinary(varbinary) - + bindParams.setTimestamp(tableCNValues[0]); + bindParams.setTinyInt(tableCNValues[1]); + bindParams.setSmallInt(tableCNValues[2]); + bindParams.setInt(tableCNValues[3]); + bindParams.setBigint(tableCNValues[4]); + bindParams.setUTinyInt(tableCNValues[5]); + bindParams.setUSmallInt(tableCNValues[6]); + bindParams.setUInt(tableCNValues[7]); + bindParams.setUBigint(tableCNValues[8]); + bindParams.setFloat(tableCNValues[9]); + bindParams.setDouble(tableCNValues[10]); + + bindParams.setBinary(tableCNValues[11]); + bindParams.setNchar(tableCNValues[12]); + bindParams.setBoolean(tableCNValues[13]); + bindParams.setInt(tableCNValues[14]); + bindParams.setGeometry(geoDataArray); + bindParams.setVarBinary(varbinary); + await stmt.bind(bindParams); - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(5) - await stmt.close() - let result = await connector.exec(`select count(*) from ${db}.${stable}`) - console.log(result) + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(5); + await stmt.close(); + let result = await connector.exec( + `select count(*) from ${db}.${stable}` + ); + console.log(result); await connector.close(); }); - test('normal json tag BindParam', async() => { + test("normal json tag BindParam", async () => { let wsConf = new WSConfig(dsn, "100.100.100.100"); - wsConf.setDb(db) - let connector = await WsSql.open(wsConf) - let stmt = await (await connector).stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare(getInsertBind(tableValues.length + 2, jsonTags.length, db, jsonTable)); + wsConf.setDb(db); + let connector = await WsSql.open(wsConf); + let stmt = await (await connector).stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + getInsertBind( + tableValues.length + 2, + jsonTags.length, + db, + jsonTable + ) + ); await stmt.setTableName(`${jsonTable}_001`); let tagParams = stmt.newStmtParam(); tagParams.setJson(jsonTags); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); - bindParams.setTimestamp(tableCNValues[0]) - bindParams.setTinyInt(tableCNValues[1]) - bindParams.setSmallInt(tableCNValues[2]) - bindParams.setInt(tableCNValues[3]) - bindParams.setBigint(tableCNValues[4]) - bindParams.setUTinyInt(tableCNValues[5]) - bindParams.setUSmallInt(tableCNValues[6]) - bindParams.setUInt(tableCNValues[7]) - bindParams.setUBigint(tableCNValues[8]) - bindParams.setFloat(tableCNValues[9]) - bindParams.setDouble(tableCNValues[10]) - - bindParams.setBinary(tableCNValues[11]) - bindParams.setNchar(tableCNValues[12]) - bindParams.setBoolean(tableCNValues[13]) - bindParams.setInt(tableCNValues[14]) - bindParams.setGeometry(geoDataArray) - bindParams.setVarBinary(varbinary) - + bindParams.setTimestamp(tableCNValues[0]); + bindParams.setTinyInt(tableCNValues[1]); + bindParams.setSmallInt(tableCNValues[2]); + bindParams.setInt(tableCNValues[3]); + bindParams.setBigint(tableCNValues[4]); + bindParams.setUTinyInt(tableCNValues[5]); + bindParams.setUSmallInt(tableCNValues[6]); + bindParams.setUInt(tableCNValues[7]); + bindParams.setUBigint(tableCNValues[8]); + bindParams.setFloat(tableCNValues[9]); + bindParams.setDouble(tableCNValues[10]); + + bindParams.setBinary(tableCNValues[11]); + bindParams.setNchar(tableCNValues[12]); + bindParams.setBoolean(tableCNValues[13]); + bindParams.setInt(tableCNValues[14]); + bindParams.setGeometry(geoDataArray); + bindParams.setVarBinary(varbinary); + await stmt.bind(bindParams); - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(5) - await stmt.close() - let result = await connector.exec(`select * from ${db}.${jsonTable}`) - console.log(result) + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(5); + await stmt.close(); + let result = await connector.exec(`select * from ${db}.${jsonTable}`); + console.log(result); await connector.close(); }); - test('normal json cn tag BindParam', async() => { + test("normal json cn tag BindParam", async () => { let wsConf = new WSConfig(dsn, "100.100.100.100"); - wsConf.setDb(db) - let connector = await WsSql.open(wsConf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt1); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare(getInsertBind(tableValues.length + 2, jsonTags.length, db, jsonTable)); + wsConf.setDb(db); + let connector = await WsSql.open(wsConf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt1); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + getInsertBind( + tableValues.length + 2, + jsonTags.length, + db, + jsonTable + ) + ); await stmt.setTableName(`${jsonTable}_001`); let tagParams = stmt.newStmtParam(); tagParams.setJson(jsonTagsCN); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); - bindParams.setTimestamp(tableCNValues[0]) - bindParams.setTinyInt(tableCNValues[1]) - bindParams.setSmallInt(tableCNValues[2]) - bindParams.setInt(tableCNValues[3]) - bindParams.setBigint(tableCNValues[4]) - bindParams.setUTinyInt(tableCNValues[5]) - bindParams.setUSmallInt(tableCNValues[6]) - bindParams.setUInt(tableCNValues[7]) - bindParams.setUBigint(tableCNValues[8]) - bindParams.setFloat(tableCNValues[9]) - bindParams.setDouble(tableCNValues[10]) - - bindParams.setBinary(tableCNValues[11]) - bindParams.setNchar(tableCNValues[12]) - bindParams.setBoolean(tableCNValues[13]) - bindParams.setInt(tableCNValues[14]) - bindParams.setGeometry(geoDataArray) - bindParams.setVarBinary(varbinary) - + bindParams.setTimestamp(tableCNValues[0]); + bindParams.setTinyInt(tableCNValues[1]); + bindParams.setSmallInt(tableCNValues[2]); + bindParams.setInt(tableCNValues[3]); + bindParams.setBigint(tableCNValues[4]); + bindParams.setUTinyInt(tableCNValues[5]); + bindParams.setUSmallInt(tableCNValues[6]); + bindParams.setUInt(tableCNValues[7]); + bindParams.setUBigint(tableCNValues[8]); + bindParams.setFloat(tableCNValues[9]); + bindParams.setDouble(tableCNValues[10]); + + bindParams.setBinary(tableCNValues[11]); + bindParams.setNchar(tableCNValues[12]); + bindParams.setBoolean(tableCNValues[13]); + bindParams.setInt(tableCNValues[14]); + bindParams.setGeometry(geoDataArray); + bindParams.setVarBinary(varbinary); + await stmt.bind(bindParams); - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(5) - await stmt.close() - let result = await connector.exec(`select * from ${db}.${jsonTable}`) - console.log(result) + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(5); + await stmt.close(); + let result = await connector.exec(`select * from ${db}.${jsonTable}`); + console.log(result); await connector.close(); }); +}); -}) - -test('test bind exception cases', async() => { +test("test bind exception cases", async () => { let wsConf = new WSConfig(dsn, "100.100.100.100"); - let connector = await WsSql.open(wsConf) - let stmt = await connector.stmtInit() + let connector = await WsSql.open(wsConf); + let stmt = await connector.stmtInit(); expect(stmt).toBeInstanceOf(WsStmt1); const params = stmt.newStmtParam(); - + const emptyArrayMethods = [ - { method: 'setBoolean', name: 'SetBooleanColumn' }, - { method: 'setTinyInt', name: 'SetTinyIntColumn' }, - { method: 'setUTinyInt', name: 'SetUTinyIntColumn' }, - { method: 'setSmallInt', name: 'SetSmallIntColumn' }, - { method: 'setUSmallInt', name: 'SetSmallIntColumn' }, - { method: 'setInt', name: 'SetIntColumn' }, - { method: 'setUInt', name: 'SetUIntColumn' }, - { method: 'setBigint', name: 'SetBigIntColumn' }, - { method: 'setUBigint', name: 'SetUBigIntColumn' }, - { method: 'setFloat', name: 'SetFloatColumn' }, - { method: 'setDouble', name: 'SetDoubleColumn' }, - { method: 'setTimestamp', name: 'SeTimestampColumn' } + { method: "setBoolean", name: "SetBooleanColumn" }, + { method: "setTinyInt", name: "SetTinyIntColumn" }, + { method: "setUTinyInt", name: "SetUTinyIntColumn" }, + { method: "setSmallInt", name: "SetSmallIntColumn" }, + { method: "setUSmallInt", name: "SetSmallIntColumn" }, + { method: "setInt", name: "SetIntColumn" }, + { method: "setUInt", name: "SetUIntColumn" }, + { method: "setBigint", name: "SetBigIntColumn" }, + { method: "setUBigint", name: "SetUBigIntColumn" }, + { method: "setFloat", name: "SetFloatColumn" }, + { method: "setDouble", name: "SetDoubleColumn" }, + { method: "setTimestamp", name: "SeTimestampColumn" }, ]; - + emptyArrayMethods.forEach(({ method, name }) => { expect(() => { (params as any)[method]([]); }).toThrow(`${name} params is invalid!`); - + expect(() => { (params as any)[method](null); }).toThrow(`${name} params is invalid!`); - + expect(() => { (params as any)[method](undefined); }).toThrow(`${name} params is invalid!`); }); - + expect(() => { - params.setBoolean(['not boolean']); - }).toThrow('SetTinyIntColumn params is invalid!'); - + params.setBoolean(["not boolean"]); + }).toThrow("SetTinyIntColumn params is invalid!"); + expect(() => { - params.setTinyInt(['not number']); - }).toThrow('SetTinyIntColumn params is invalid!'); - + params.setTinyInt(["not number"]); + }).toThrow("SetTinyIntColumn params is invalid!"); + expect(() => { - params.setBigint(['not bigint']); - }).toThrow('SetTinyIntColumn params is invalid!'); + params.setBigint(["not bigint"]); + }).toThrow("SetTinyIntColumn params is invalid!"); await connector.close(); }); - afterAll(async () => { - let conf :WSConfig = new WSConfig(dsn) + let conf: WSConfig = new WSConfig(dsn); let ws = await WsSql.open(conf); await ws.exec(dropDB); await ws.close(); - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/stmt2.func.test.ts b/nodejs/test/bulkPulling/stmt2.func.test.ts index 83646e14..f8625209 100644 --- a/nodejs/test/bulkPulling/stmt2.func.test.ts +++ b/nodejs/test/bulkPulling/stmt2.func.test.ts @@ -4,566 +4,607 @@ import { setLevel } from "../../src/common/log"; import { WsSql } from "../../src/sql/wsSql"; import { WsStmt2 } from "../../src/stmt/wsStmt2"; -let dns = 'ws://localhost:6041' -setLevel("debug") +let dns = "ws://localhost:6041"; +setLevel("debug"); beforeAll(async () => { - let conf :WSConfig = new WSConfig(dns); - conf.setUser('root'); - conf.setPwd('taosdata'); + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); let wsSql = await WsSql.open(conf); - await wsSql.exec('create database if not exists power_func_stmt2 KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;'); - await wsSql.exec('CREATE STABLE if not exists power_func_stmt2.meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);'); + await wsSql.exec( + "create database if not exists power_func_stmt2 KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;" + ); + await wsSql.exec( + "CREATE STABLE if not exists power_func_stmt2.meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);" + ); await wsSql.close(); -}) -describe('TDWebSocket.Stmt()', () => { - jest.setTimeout(20 * 1000) - let tags = ['California', 3]; +}); +describe("TDWebSocket.Stmt()", () => { + jest.setTimeout(20 * 1000); + let tags = ["California", 3]; let multi = [ - // [1709183268567], - // [10.2], - // [292], - // [0.32], - [1709183268567, 1709183268568, 1709183268569], - [10.2, 10.3, 10.4], - [292, 293, 294], - [0.32, 0.33, 0.34], + // [1709183268567], + // [10.2], + // [292], + // [0.32], + [1709183268567, 1709183268568, 1709183268569], + [10.2, 10.3, 10.4], + [292, 293, 294], + [0.32, 0.33, 0.34], ]; - test('normal connect', async() => { + test("normal connect", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.close() + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.close(); await connector.close(); }); - test('connect db with error', async() => { - expect.assertions(1) + test("connect db with error", async () => { + expect.assertions(1); let connector = null; try { - let conf :WSConfig = new WSConfig(dns) - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('jest') - connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - await stmt.close() - }catch(e){ - let err:any = e - expect(err.message).toMatch('Database not exist') - }finally{ - if(connector) { - await connector.close() + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("jest"); + connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + await stmt.close(); + } catch (e) { + let err: any = e; + expect(err.message).toMatch("Database not exist"); + } finally { + if (connector) { + await connector.close(); } } - }) + }); - test('normal Prepare', async() => { + test("normal Prepare", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); params.setVarchar([tags[0]]); - params.setInt([tags[1]]); + params.setInt([tags[1]]); await stmt.setTags(params); - await stmt.close() + await stmt.close(); await connector.close(); - }); + }); - test('set tag error', async() => { + test("set tag error", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); params.setVarchar([tags[0]]); try { - await stmt.setTags(params) - } catch(err:any) { - expect(err.message).toMatch('stmt tags count not match') - } - await stmt.close() + await stmt.setTags(params); + } catch (err: any) { + expect(err.message).toMatch("stmt tags count not match"); + } + await stmt.close(); await connector.close(); - }); - - test('error Prepare table', async() => { + }); + + test("error Prepare table", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - try{ - await stmt.prepare('INSERT ? INTO ? USING meters TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - }catch(e) { - let err:any = e - expect(err.message).toMatch(/keyword INTO is expected|Syntax error in SQL/) + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + try { + await stmt.prepare( + "INSERT ? INTO ? USING meters TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + } catch (e) { + let err: any = e; + expect(err.message).toMatch( + /keyword INTO is expected|Syntax error in SQL/ + ); } - await stmt.close() + await stmt.close(); await connector.close(); - }); + }); - test('error Prepare tag', async() => { + test("error Prepare tag", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - try{ - await stmt.prepare('INSERT INTO ? USING meters TAGS (?, ?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - }catch(e) { - let err:any = e - expect(err.message).toMatch("Tags number not matched") + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + try { + await stmt.prepare( + "INSERT INTO ? USING meters TAGS (?, ?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + } catch (e) { + let err: any = e; + expect(err.message).toMatch("Tags number not matched"); } - await stmt.close() + await stmt.close(); await connector.close(); }); - test('Bind supper table', async() => { + test("Bind supper table", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - await stmt.prepare('INSERT INTO meters (ts, tbname, current, voltage, phase, location, groupId) VALUES (?, ?, ?, ?, ?, ?, ?)'); - let lastTs = 0 + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + await stmt.prepare( + "INSERT INTO meters (ts, tbname, current, voltage, phase, location, groupId) VALUES (?, ?, ?, ?, ?, ?, ?)" + ); + let lastTs = 0; for (let i = 0; i < 10; i++) { for (let j = 0; j < multi[0].length; j++) { multi[0][j] = multi[0][0] + j; - lastTs = multi[0][j] + lastTs = multi[0][j]; } - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setVarchar([`d1001`, `d1002`, `d1003`]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - dataParams.setVarchar(['SanFrancisco_1', 'SanFrancisco_2','SanFrancisco_3']); + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setVarchar([`d1001`, `d1002`, `d1003`]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + dataParams.setVarchar([ + "SanFrancisco_1", + "SanFrancisco_2", + "SanFrancisco_3", + ]); dataParams.setInt([1, 2, 3]); - await stmt.bind(dataParams) + await stmt.bind(dataParams); multi[0][0] = lastTs + 1; - } - - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(30) - await stmt.close() + + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(30); + await stmt.close(); await connector.close(); }); - test('Bind a single table', async() => { + test("Bind a single table", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) (ts, current, voltage, phase) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('power_func_stmt2.d1001'); - - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) (ts, current, voltage, phase) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("power_func_stmt2.d1001"); + + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([1]); - await stmt.setTags(params) + await stmt.setTags(params); - let lastTs = 0 + let lastTs = 0; for (let i = 0; i < 10; i++) { for (let j = 0; j < multi[0].length; j++) { multi[0][j] = multi[0][0] + j; - lastTs = multi[0][j] + lastTs = multi[0][j]; } - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); multi[0][0] = lastTs + 1; } - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(30) - await stmt.close() + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(30); + await stmt.close(); await connector.close(); }); - test('Bind multiple tables', async() => { + test("Bind multiple tables", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) (ts, current, voltage, phase) VALUES (?, ?, ?, ?)'); - let lastTs = 0 + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) (ts, current, voltage, phase) VALUES (?, ?, ?, ?)" + ); + let lastTs = 0; for (let i = 0; i < 10; i++) { for (let j = 0; j < multi[0].length; j++) { multi[0][j] = multi[0][0] + j; - lastTs = multi[0][j] + lastTs = multi[0][j]; } - await stmt.setTableName(`power_func_stmt2.d100${i+1}`); + await stmt.setTableName(`power_func_stmt2.d100${i + 1}`); - let params = stmt.newStmtParam() - params.setVarchar([`SanFrancisco${i+1}`]); - params.setInt([i+1]); - await stmt.setTags(params) + let params = stmt.newStmtParam(); + params.setVarchar([`SanFrancisco${i + 1}`]); + params.setInt([i + 1]); + await stmt.setTags(params); - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); multi[0][0] = lastTs + 1; - } - - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(30) - await stmt.close() + + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(30); + await stmt.close(); await connector.close(); }); - test('query bind', async() => { + test("query bind", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let wsSql = await WsSql.open(conf) - - await wsSql.exec('CREATE STABLE if not exists power_func_stmt2.query_meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);'); - let insertQuery = "INSERT INTO " + - "power_func_stmt2.q1001 USING power_func_stmt2.query_meters TAGS('California.SanFrancisco', 1) " + - "VALUES " + - "('2024-12-19 19:12:45.642', 50.30000, 201, 0.31000) " + - "('2024-12-19 19:12:46.642', 82.60000, 202, 0.33000) " + - "('2024-12-19 19:12:47.642', 92.30000, 203, 0.31000) " + - "('2024-12-19 18:12:45.642', 50.30000, 201, 0.31000) " + - "('2024-12-19 18:12:46.642', 82.60000, 202, 0.33000) " + - "('2024-12-19 18:12:47.642', 92.30000, 203, 0.31000) " + - "('2024-12-19 17:12:45.642', 50.30000, 201, 0.31000) " + - "('2024-12-19 17:12:46.642', 82.60000, 202, 0.33000) " + - "('2024-12-19 17:12:47.642', 92.30000, 203, 0.31000) " + - "power_func_stmt2.q1002 USING power_func_stmt2.query_meters TAGS('Alabama.Montgomery', 2) " + - "VALUES " + - "('2024-12-19 19:12:45.642', 50.30000, 204, 0.25000) " + - "('2024-12-19 19:12:46.642', 62.60000, 205, 0.33000) " + - "('2024-12-19 19:12:47.642', 72.30000, 206, 0.31000) " + - "('2024-12-19 18:12:45.642', 50.30000, 204, 0.25000) " + - "('2024-12-19 18:12:46.642', 62.60000, 205, 0.33000) " + - "('2024-12-19 18:12:47.642', 72.30000, 206, 0.31000) " + - "('2024-12-19 17:12:45.642', 50.30000, 204, 0.25000) " + - "('2024-12-19 17:12:46.642', 62.60000, 205, 0.33000) " + - "('2024-12-19 17:12:47.642', 72.30000, 206, 0.31000) "; + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let wsSql = await WsSql.open(conf); + + await wsSql.exec( + "CREATE STABLE if not exists power_func_stmt2.query_meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);" + ); + let insertQuery = + "INSERT INTO " + + "power_func_stmt2.q1001 USING power_func_stmt2.query_meters TAGS('California.SanFrancisco', 1) " + + "VALUES " + + "('2024-12-19 19:12:45.642', 50.30000, 201, 0.31000) " + + "('2024-12-19 19:12:46.642', 82.60000, 202, 0.33000) " + + "('2024-12-19 19:12:47.642', 92.30000, 203, 0.31000) " + + "('2024-12-19 18:12:45.642', 50.30000, 201, 0.31000) " + + "('2024-12-19 18:12:46.642', 82.60000, 202, 0.33000) " + + "('2024-12-19 18:12:47.642', 92.30000, 203, 0.31000) " + + "('2024-12-19 17:12:45.642', 50.30000, 201, 0.31000) " + + "('2024-12-19 17:12:46.642', 82.60000, 202, 0.33000) " + + "('2024-12-19 17:12:47.642', 92.30000, 203, 0.31000) " + + "power_func_stmt2.q1002 USING power_func_stmt2.query_meters TAGS('Alabama.Montgomery', 2) " + + "VALUES " + + "('2024-12-19 19:12:45.642', 50.30000, 204, 0.25000) " + + "('2024-12-19 19:12:46.642', 62.60000, 205, 0.33000) " + + "('2024-12-19 19:12:47.642', 72.30000, 206, 0.31000) " + + "('2024-12-19 18:12:45.642', 50.30000, 204, 0.25000) " + + "('2024-12-19 18:12:46.642', 62.60000, 205, 0.33000) " + + "('2024-12-19 18:12:47.642', 72.30000, 206, 0.31000) " + + "('2024-12-19 17:12:45.642', 50.30000, 204, 0.25000) " + + "('2024-12-19 17:12:46.642', 62.60000, 205, 0.33000) " + + "('2024-12-19 17:12:47.642', 72.30000, 206, 0.31000) "; await wsSql.exec(insertQuery); - + // let result = await wsSql.exec("select * from query_meters") // console.log(result) - let stmt = await wsSql.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - await stmt.prepare('select * from query_meters where ts >= ? and ts <= ?'); - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp([1734628365642n]) - dataParams.setTimestamp([1734635567642n]) - await stmt.bind(dataParams) - await stmt.exec() - let wsRows = await stmt.resultSet() + let stmt = await wsSql.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + await stmt.prepare( + "select * from query_meters where ts >= ? and ts <= ?" + ); + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp([1734628365642n]); + dataParams.setTimestamp([1734635567642n]); + await stmt.bind(dataParams); + await stmt.exec(); + let wsRows = await stmt.resultSet(); let nRows = 0; while (await wsRows.next()) { let result = wsRows.getData(); - console.log(result) - expect(result).toBeTruthy() + console.log(result); + expect(result).toBeTruthy(); nRows++; } expect(nRows).toEqual(18); - await wsRows.close() - await stmt.close() + await wsRows.close(); + await stmt.close(); await wsSql.close(); }); - - test('error BindParam', async() => { + test("error BindParam", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) + await stmt.setTags(params); let multi = [ [1709183268567, 1709183268568], [10.2, 10.3, 10.4, 10.5], [292, 293, 294], [0.32, 0.33, 0.31], - ]; - try{ - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) - await stmt.batch() - await stmt.exec() - }catch(e) { - let err:any = e - expect(err.message).toMatch(/wrong row length|bind data length error/) + ]; + try { + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); + await stmt.batch(); + await stmt.exec(); + } catch (e) { + let err: any = e; + expect(err.message).toMatch( + /wrong row length|bind data length error/ + ); } - await stmt.close() + await stmt.close(); await connector.close(); }); - test('no Batch', async() => { + test("no Batch", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) + await stmt.setTags(params); let multi = [ [1709183268567, 1709183268568], [10.2, 10.3], [292, 293], [0.32, 0.33], - ]; - try{ - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) - await stmt.exec() - }catch(e) { - let err:any = e - expect(err.message).toMatch("Stmt API usage error") + ]; + try { + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); + await stmt.exec(); + } catch (e) { + let err: any = e; + expect(err.message).toMatch("Stmt API usage error"); } - await stmt.close() + await stmt.close(); await connector.close(); }); - test('Batch after BindParam', async() => { + test("Batch after BindParam", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) + await stmt.setTags(params); let multi1 = [ [1709188881548, 1709188881549], [10.2, 10.3], [292, 293], [0.32, 0.33], - ]; + ]; let multi2 = [ [1709188881550, 1709188881551], [10.2, 10.3], [292, 293], [0.32, 0.33], - ]; - - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi1[0]) - dataParams.setFloat(multi1[1]) - dataParams.setInt(multi1[2]) - dataParams.setFloat(multi1[3]) - await stmt.bind(dataParams) - await stmt.batch() - - await stmt.setTableName('d1002'); - params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + ]; + + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi1[0]); + dataParams.setFloat(multi1[1]); + dataParams.setInt(multi1[2]); + dataParams.setFloat(multi1[3]); + await stmt.bind(dataParams); + await stmt.batch(); + + await stmt.setTableName("d1002"); + params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([5]); - await stmt.setTags(params) - - dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi2[0]) - dataParams.setFloat(multi2[1]) - dataParams.setInt(multi2[2]) - dataParams.setFloat(multi2[3]) - await stmt.bind(dataParams) - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(4) - await stmt.close() + await stmt.setTags(params); + + dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi2[0]); + dataParams.setFloat(multi2[1]); + dataParams.setInt(multi2[2]); + dataParams.setFloat(multi2[3]); + await stmt.bind(dataParams); + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(4); + await stmt.close(); await connector.close(); }); - test('no set tag', async() => { + test("no set tag", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); // await stmt.SetTags(tags) - try{ - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) - await stmt.batch() - await stmt.exec() - }catch(e) { - let err:any = e + try { + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); + await stmt.batch(); + await stmt.exec(); + } catch (e) { + let err: any = e; expect(err.message).toMatch(/Retry needed|Bind tags is empty!/); } - await stmt.close() + await stmt.close(); await connector.close(); }); - test('normal binary BindParam', async() => { + test("normal binary BindParam", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1002'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1002"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) - - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi[0]) - dataParams.setFloat(multi[1]) - dataParams.setInt(multi[2]) - dataParams.setFloat(multi[3]) - await stmt.bind(dataParams) - - await stmt.batch() - await stmt.exec() - - let result = await connector.exec("select * from power_func_stmt2.meters") - console.log(result) - await stmt.close() - await connector.close(); + await stmt.setTags(params); + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi[0]); + dataParams.setFloat(multi[1]); + dataParams.setInt(multi[2]); + dataParams.setFloat(multi[3]); + await stmt.bind(dataParams); + + await stmt.batch(); + await stmt.exec(); + + let result = await connector.exec( + "select * from power_func_stmt2.meters" + ); + console.log(result); + await stmt.close(); + await connector.close(); }); - test('normal json BindParam', async() => { + test("normal json BindParam", async () => { let conf = new WSConfig(dns); - conf.setUser('root') - conf.setPwd('taosdata') - conf.setDb('power_func_stmt2') - let connector = await WsSql.open(conf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare('INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)'); - await stmt.setTableName('d1001'); - let params = stmt.newStmtParam() - params.setVarchar(['SanFrancisco']); + conf.setUser("root"); + conf.setPwd("taosdata"); + conf.setDb("power_func_stmt2"); + let connector = await WsSql.open(conf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + "INSERT INTO ? USING meters (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)" + ); + await stmt.setTableName("d1001"); + let params = stmt.newStmtParam(); + params.setVarchar(["SanFrancisco"]); params.setInt([7]); - await stmt.setTags(params) + await stmt.setTags(params); let multi1 = [ [1709188881548, 1709188881549], [10.2, 10.3], [292, 293], [0.32, 0.33], - ]; - let dataParams = stmt.newStmtParam() - dataParams.setTimestamp(multi1[0]) - dataParams.setFloat(multi1[1]) - dataParams.setInt(multi1[2]) - dataParams.setFloat(multi1[3]) - await stmt.bind(dataParams) - await stmt.batch() - await stmt.exec() - await stmt.close() + ]; + let dataParams = stmt.newStmtParam(); + dataParams.setTimestamp(multi1[0]); + dataParams.setFloat(multi1[1]); + dataParams.setInt(multi1[2]); + dataParams.setFloat(multi1[3]); + await stmt.bind(dataParams); + await stmt.batch(); + await stmt.exec(); + await stmt.close(); await connector.close(); }); -}) +}); afterAll(async () => { - let conf :WSConfig = new WSConfig(dns); - conf.setUser('root'); - conf.setPwd('taosdata'); + let conf: WSConfig = new WSConfig(dns); + conf.setUser("root"); + conf.setPwd("taosdata"); let wsSql = await WsSql.open(conf); - await wsSql.exec('drop database power_func_stmt2'); + await wsSql.exec("drop database power_func_stmt2"); await wsSql.close(); - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/stmt2.type.test.ts b/nodejs/test/bulkPulling/stmt2.type.test.ts index fb763270..82e2de76 100644 --- a/nodejs/test/bulkPulling/stmt2.type.test.ts +++ b/nodejs/test/bulkPulling/stmt2.type.test.ts @@ -3,91 +3,171 @@ import { WSConfig } from "../../src/common/config"; import { setLevel } from "../../src/common/log"; import { WsSql } from "../../src/sql/wsSql"; import { WsStmt2 } from "../../src/stmt/wsStmt2"; -import { createBaseSTable, createBaseSTableJSON, createSTableJSON, getInsertBind } from "../utils"; +import { + createBaseSTable, + createBaseSTableJSON, + createSTableJSON, + getInsertBind, +} from "../utils"; -const stable = 'ws_stmt_stb'; -const table = 'stmt_001'; -const db = 'ws_stmt2' -const createDB = `create database if not exists ${db} keep 3650` -const useDB = `use ${db}` -const dropDB = `drop database if exists ${db}` +const stable = "ws_stmt_stb"; +const table = "stmt_001"; +const db = "ws_stmt2"; +const createDB = `create database if not exists ${db} keep 3650`; +const useDB = `use ${db}`; +const dropDB = `drop database if exists ${db}`; -const tableCN = 'stmt_cn'; -const stableCN = 'ws_stmt_stb_cn'; -const jsonTable = 'stmt_json'; -const jsonTableCN = 'stmt_json_cn'; +const tableCN = "stmt_cn"; +const stableCN = "ws_stmt_stb_cn"; +const jsonTable = "stmt_json"; +const jsonTableCN = "stmt_json_cn"; - -const stableTags = [true, -1, -2, -3, -4, 1, 2, 3, 4, parseFloat(3.1415.toFixed(5)), parseFloat(3.14159265.toFixed(15)), 'varchar_tag_1', 'nchar_tag_1'] -const stableCNTags = [false, -1 * 2, -2 * 2, -3 * 2, -4 * 2, 1 * 2, 2 * 2, 3 * 2, 4 * 2, parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.14159265 * 2).toFixed(15)), 'varchar_标签_壹', 'nchar_标签_贰'] +const stableTags = [ + true, + -1, + -2, + -3, + -4, + 1, + 2, + 3, + 4, + parseFloat((3.1415).toFixed(5)), + parseFloat((3.14159265).toFixed(15)), + "varchar_tag_1", + "nchar_tag_1", +]; +const stableCNTags = [ + false, + -1 * 2, + -2 * 2, + -3 * 2, + -4 * 2, + 1 * 2, + 2 * 2, + 3 * 2, + 4 * 2, + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.14159265 * 2).toFixed(15)), + "varchar_标签_壹", + "nchar_标签_贰", +]; const tableValues = [ - [1656677710000, 1656677720000, 1656677730000, 1656677740000, 1656677750000], - [0, -1, -2, -3, -4], - [-1, -2,-3, -4, -5], - [-3, -4,-5, -6, -7], + [1656677710000, 1656677720000, 1656677730000, 1656677740000, 1656677750000], + [0, -1, -2, -3, -4], + [-1, -2, -3, -4, -5], + [-3, -4, -5, -6, -7], // [0, 1, 2, 3, 4], - [BigInt(-2), BigInt(-3), BigInt(-4), BigInt(-5), BigInt(-6)], + [BigInt(-2), BigInt(-3), BigInt(-4), BigInt(-5), BigInt(-6)], - [0, 1, 2, 3, 4], - [1, 2, 3, 4,5], - [2, 3, 4,5, 6], + [0, 1, 2, 3, 4], + [1, 2, 3, 4, 5], + [2, 3, 4, 5, 6], // [0, 1, 2, 3, 4], - [BigInt(3), BigInt(4), BigInt(5), BigInt(6), BigInt(7)], + [BigInt(3), BigInt(4), BigInt(5), BigInt(6), BigInt(7)], - [parseFloat(3.1415.toFixed(5)), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.1415 * 3).toFixed(5)), parseFloat((3.1415 * 4).toFixed(5)), parseFloat((3.1415 * 5).toFixed(5))], - [parseFloat(3.14159265.toFixed(15)), parseFloat((3.14159265 * 2).toFixed(15)), parseFloat((3.14159265 * 3).toFixed(15)), parseFloat((3.14159265 * 4).toFixed(15)), parseFloat((3.14159265 * 5).toFixed(15))], - ['varchar_col_1', 'varchar_col_2', 'varchar_col_3', 'varchar_col_4', 'varchar_col_5' ], - ['nchar_col_1', 'nchar_col_2', '', 'nchar_col_4', 'nchar_col_5'], - [true, false, true, false, true], - [null, null, null, null, null] -] + [ + parseFloat((3.1415).toFixed(5)), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.1415 * 3).toFixed(5)), + parseFloat((3.1415 * 4).toFixed(5)), + parseFloat((3.1415 * 5).toFixed(5)), + ], + [ + parseFloat((3.14159265).toFixed(15)), + parseFloat((3.14159265 * 2).toFixed(15)), + parseFloat((3.14159265 * 3).toFixed(15)), + parseFloat((3.14159265 * 4).toFixed(15)), + parseFloat((3.14159265 * 5).toFixed(15)), + ], + [ + "varchar_col_1", + "varchar_col_2", + "varchar_col_3", + "varchar_col_4", + "varchar_col_5", + ], + ["nchar_col_1", "nchar_col_2", "", "nchar_col_4", "nchar_col_5"], + [true, false, true, false, true], + [null, null, null, null, null], +]; const tableCNValues = [ - [BigInt(1656677760000), BigInt(1656677770000), BigInt(1656677780000), BigInt(1656677790000), BigInt(1656677100000)], - [0, -1, -2, -3, -4], - [-1, -2,-3, -4, -5], - [ -2, -3, -4,-5, -6], - [BigInt(-3), BigInt(-4),BigInt(-5), BigInt(-6), BigInt(-7)], - [0, 1, 2, 3, 4], - [1, 2, 3, 4,5], - [2, 3, 4,5, 6], - [BigInt(3), BigInt(4), BigInt(5), BigInt(6), BigInt(7)], - [parseFloat(3.1415.toFixed(5)), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.1415 * 3).toFixed(5)), parseFloat((3.1415 * 4).toFixed(5)), parseFloat((3.1415 * 5).toFixed(5))], - [parseFloat(3.14159265.toFixed(15)), parseFloat((3.14159265 * 2).toFixed(15)), parseFloat((3.14159265 * 3).toFixed(15)), parseFloat((3.14159265 * 4).toFixed(15)), parseFloat((3.14159265 * 5).toFixed(15))], - ['varchar_列_壹','varchar_列_贰','varchar_列_叁','varchar_列_肆','varchar_列_伍'], - ['nchar_列_甲','nchar_列_乙','nchar_列_丙','nchar_列_丁','nchar_列_戊'], - [true, false, true, false, true], - [null, null, null, null, null], -] - -let geoDataArray:any[] = []; -let varbinary:any[] = []; + [ + BigInt(1656677760000), + BigInt(1656677770000), + BigInt(1656677780000), + BigInt(1656677790000), + BigInt(1656677100000), + ], + [0, -1, -2, -3, -4], + [-1, -2, -3, -4, -5], + [-2, -3, -4, -5, -6], + [BigInt(-3), BigInt(-4), BigInt(-5), BigInt(-6), BigInt(-7)], + [0, 1, 2, 3, 4], + [1, 2, 3, 4, 5], + [2, 3, 4, 5, 6], + [BigInt(3), BigInt(4), BigInt(5), BigInt(6), BigInt(7)], + [ + parseFloat((3.1415).toFixed(5)), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.1415 * 3).toFixed(5)), + parseFloat((3.1415 * 4).toFixed(5)), + parseFloat((3.1415 * 5).toFixed(5)), + ], + [ + parseFloat((3.14159265).toFixed(15)), + parseFloat((3.14159265 * 2).toFixed(15)), + parseFloat((3.14159265 * 3).toFixed(15)), + parseFloat((3.14159265 * 4).toFixed(15)), + parseFloat((3.14159265 * 5).toFixed(15)), + ], + [ + "varchar_列_壹", + "varchar_列_贰", + "varchar_列_叁", + "varchar_列_肆", + "varchar_列_伍", + ], + ["nchar_列_甲", "nchar_列_乙", "nchar_列_丙", "nchar_列_丁", "nchar_列_戊"], + [true, false, true, false, true], + [null, null, null, null, null], +]; + +let geoDataArray: any[] = []; +let varbinary: any[] = []; const encoder = new TextEncoder(); -for (let i = 0; i< 5; i++) { - let data = new Uint8Array([0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x59,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x40,]) - geoDataArray.push(data.buffer) ; - let vdata = encoder.encode(`varchar_col_${i+1}`) - varbinary.push(vdata.buffer) +for (let i = 0; i < 5; i++) { + let data = new Uint8Array([ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40, + ]); + geoDataArray.push(data.buffer); + let vdata = encoder.encode(`varchar_col_${i + 1}`); + varbinary.push(vdata.buffer); } -const jsonTags = ["{\"key1\":\"taos\",\"key2\":null,\"key3\":\"TDengine\",\"key4\":0,\"key5\":false}"] -const jsonTagsCN = ["{\"key1\":\"taosdata\",\"key2\":null,\"key3\":\"TDengine涛思数据\",\"key4\":1,\"key5\":true}"] +const jsonTags = [ + '{"key1":"taos","key2":null,"key3":"TDengine","key4":0,"key5":false}', +]; +const jsonTagsCN = [ + '{"key1":"taosdata","key2":null,"key3":"TDengine涛思数据","key4":1,"key5":true}', +]; -const selectStable = `select * from ${stable}` -const selectStableCN = `select * from ${stableCN}` -const selectTable = `select * from ${table}` -const selectTableCN = `select * from ${tableCN}` -const selectJsonTable = `select * from ${jsonTable}` -const selectJsonTableCN = `select * from ${jsonTableCN}` +const selectStable = `select * from ${stable}`; +const selectStableCN = `select * from ${stableCN}`; +const selectTable = `select * from ${table}`; +const selectTableCN = `select * from ${tableCN}`; +const selectJsonTable = `select * from ${jsonTable}`; +const selectJsonTableCN = `select * from ${jsonTableCN}`; -let dsn = 'ws://root:taosdata@localhost:6041'; -setLevel("debug") +let dsn = "ws://root:taosdata@localhost:6041"; +setLevel("debug"); beforeAll(async () => { - let conf :WSConfig = new WSConfig(dsn) + let conf: WSConfig = new WSConfig(dsn); let ws = await WsSql.open(conf); await ws.exec(dropDB); await ws.exec(createDB); @@ -95,272 +175,290 @@ beforeAll(async () => { await ws.exec(createBaseSTable(stable)); await ws.exec(createSTableJSON(jsonTable)); await ws.close(); -}) +}); -describe('TDWebSocket.Stmt()', () => { - jest.setTimeout(20 * 1000) - test('normal BindParam', async() => { +describe("TDWebSocket.Stmt()", () => { + jest.setTimeout(20 * 1000); + test("normal BindParam", async () => { let wsConf = new WSConfig(dsn); - wsConf.setDb(db) - let connector = await WsSql.open(wsConf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare(getInsertBind(tableValues.length + 2, stableTags.length, db, stable)); + wsConf.setDb(db); + let connector = await WsSql.open(wsConf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + getInsertBind(tableValues.length + 2, stableTags.length, db, stable) + ); await stmt.setTableName(table); let tagParams = stmt.newStmtParam(); - tagParams.setBoolean([stableTags[0]]) - tagParams.setTinyInt([stableTags[1]]) - tagParams.setSmallInt([stableTags[2]]) - tagParams.setInt([stableTags[3]]) - tagParams.setBigint([BigInt(stableTags[4])]) - tagParams.setUTinyInt([stableTags[5]]) - - tagParams.setUSmallInt([stableTags[6]]) - tagParams.setUInt([stableTags[7]]) - tagParams.setUBigint([BigInt(stableTags[8])]) - tagParams.setFloat([stableTags[9]]) - tagParams.setDouble([stableTags[10]]) - tagParams.setBinary([stableTags[11]]) - tagParams.setNchar([stableTags[12]]) + tagParams.setBoolean([stableTags[0]]); + tagParams.setTinyInt([stableTags[1]]); + tagParams.setSmallInt([stableTags[2]]); + tagParams.setInt([stableTags[3]]); + tagParams.setBigint([BigInt(stableTags[4])]); + tagParams.setUTinyInt([stableTags[5]]); + + tagParams.setUSmallInt([stableTags[6]]); + tagParams.setUInt([stableTags[7]]); + tagParams.setUBigint([BigInt(stableTags[8])]); + tagParams.setFloat([stableTags[9]]); + tagParams.setDouble([stableTags[10]]); + tagParams.setBinary([stableTags[11]]); + tagParams.setNchar([stableTags[12]]); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); - bindParams.setTimestamp(tableValues[0]) - bindParams.setTinyInt(tableValues[1]) - bindParams.setSmallInt(tableValues[2]) - bindParams.setInt(tableValues[3]) - bindParams.setBigint(tableValues[4]) - bindParams.setUTinyInt(tableValues[5]) - bindParams.setUSmallInt(tableValues[6]) - bindParams.setUInt(tableValues[7]) - bindParams.setUBigint(tableValues[8]) - bindParams.setFloat(tableValues[9]) - bindParams.setDouble(tableValues[10]) - - bindParams.setBinary(tableValues[11]) - bindParams.setNchar(tableValues[12]) - bindParams.setBoolean(tableValues[13]) - bindParams.setInt(tableValues[14]) - bindParams.setGeometry(geoDataArray) - bindParams.setVarBinary(varbinary) - + bindParams.setTimestamp(tableValues[0]); + bindParams.setTinyInt(tableValues[1]); + bindParams.setSmallInt(tableValues[2]); + bindParams.setInt(tableValues[3]); + bindParams.setBigint(tableValues[4]); + bindParams.setUTinyInt(tableValues[5]); + bindParams.setUSmallInt(tableValues[6]); + bindParams.setUInt(tableValues[7]); + bindParams.setUBigint(tableValues[8]); + bindParams.setFloat(tableValues[9]); + bindParams.setDouble(tableValues[10]); + + bindParams.setBinary(tableValues[11]); + bindParams.setNchar(tableValues[12]); + bindParams.setBoolean(tableValues[13]); + bindParams.setInt(tableValues[14]); + bindParams.setGeometry(geoDataArray); + bindParams.setVarBinary(varbinary); + await stmt.bind(bindParams); - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(5) - await stmt.close() - let result = await connector.exec(`select * from ${db}.${stable}`) - console.log(result) + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(5); + await stmt.close(); + let result = await connector.exec(`select * from ${db}.${stable}`); + console.log(result); await connector.close(); }); - test('normal CN BindParam', async() => { + test("normal CN BindParam", async () => { let wsConf = new WSConfig(dsn); - wsConf.setDb(db) - let connector = await WsSql.open(wsConf) - let stmt = await (await connector).stmtInit() - expect(stmt).toBeTruthy() - expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare(getInsertBind(tableValues.length + 2, stableTags.length, db, stable)); + wsConf.setDb(db); + let connector = await WsSql.open(wsConf); + let stmt = await (await connector).stmtInit(); + expect(stmt).toBeTruthy(); + expect(stmt).toBeInstanceOf(WsStmt2); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + getInsertBind(tableValues.length + 2, stableTags.length, db, stable) + ); await stmt.setTableName(table); let tagParams = stmt.newStmtParam(); - tagParams.setBoolean([stableCNTags[0]]) - tagParams.setTinyInt([stableCNTags[1]]) - tagParams.setSmallInt([stableCNTags[2]]) - tagParams.setInt([stableCNTags[3]]) - tagParams.setBigint([BigInt(stableCNTags[4])]) - tagParams.setUTinyInt([stableCNTags[5]]) - - tagParams.setUSmallInt([stableCNTags[6]]) - tagParams.setUInt([stableCNTags[7]]) - tagParams.setUBigint([BigInt(stableCNTags[8])]) - tagParams.setFloat([stableCNTags[9]]) - tagParams.setDouble([stableCNTags[10]]) - tagParams.setBinary([stableCNTags[11]]) - tagParams.setNchar([stableCNTags[12]]) + tagParams.setBoolean([stableCNTags[0]]); + tagParams.setTinyInt([stableCNTags[1]]); + tagParams.setSmallInt([stableCNTags[2]]); + tagParams.setInt([stableCNTags[3]]); + tagParams.setBigint([BigInt(stableCNTags[4])]); + tagParams.setUTinyInt([stableCNTags[5]]); + + tagParams.setUSmallInt([stableCNTags[6]]); + tagParams.setUInt([stableCNTags[7]]); + tagParams.setUBigint([BigInt(stableCNTags[8])]); + tagParams.setFloat([stableCNTags[9]]); + tagParams.setDouble([stableCNTags[10]]); + tagParams.setBinary([stableCNTags[11]]); + tagParams.setNchar([stableCNTags[12]]); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); - bindParams.setTimestamp(tableCNValues[0]) - bindParams.setTinyInt(tableCNValues[1]) - bindParams.setSmallInt(tableCNValues[2]) - bindParams.setInt(tableCNValues[3]) - bindParams.setBigint(tableCNValues[4]) - bindParams.setUTinyInt(tableCNValues[5]) - bindParams.setUSmallInt(tableCNValues[6]) - bindParams.setUInt(tableCNValues[7]) - bindParams.setUBigint(tableCNValues[8]) - bindParams.setFloat(tableCNValues[9]) - bindParams.setDouble(tableCNValues[10]) - - bindParams.setBinary(tableCNValues[11]) - bindParams.setNchar(tableCNValues[12]) - bindParams.setBoolean(tableCNValues[13]) - bindParams.setInt(tableCNValues[14]) - bindParams.setGeometry(geoDataArray) - bindParams.setVarBinary(varbinary) - + bindParams.setTimestamp(tableCNValues[0]); + bindParams.setTinyInt(tableCNValues[1]); + bindParams.setSmallInt(tableCNValues[2]); + bindParams.setInt(tableCNValues[3]); + bindParams.setBigint(tableCNValues[4]); + bindParams.setUTinyInt(tableCNValues[5]); + bindParams.setUSmallInt(tableCNValues[6]); + bindParams.setUInt(tableCNValues[7]); + bindParams.setUBigint(tableCNValues[8]); + bindParams.setFloat(tableCNValues[9]); + bindParams.setDouble(tableCNValues[10]); + + bindParams.setBinary(tableCNValues[11]); + bindParams.setNchar(tableCNValues[12]); + bindParams.setBoolean(tableCNValues[13]); + bindParams.setInt(tableCNValues[14]); + bindParams.setGeometry(geoDataArray); + bindParams.setVarBinary(varbinary); + await stmt.bind(bindParams); - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(5) - await stmt.close() - let result = await connector.exec(`select count(*) from ${db}.${stable}`) - console.log(result) + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(5); + await stmt.close(); + let result = await connector.exec( + `select count(*) from ${db}.${stable}` + ); + console.log(result); await connector.close(); }); - test('normal json tag BindParam', async() => { + test("normal json tag BindParam", async () => { let wsConf = new WSConfig(dsn); - wsConf.setDb(db) - let connector = await WsSql.open(wsConf) - let stmt = await (await connector).stmtInit() - expect(stmt).toBeTruthy() + wsConf.setDb(db); + let connector = await WsSql.open(wsConf); + let stmt = await (await connector).stmtInit(); + expect(stmt).toBeTruthy(); expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare(getInsertBind(tableValues.length + 2, jsonTags.length, db, jsonTable)); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + getInsertBind( + tableValues.length + 2, + jsonTags.length, + db, + jsonTable + ) + ); await stmt.setTableName(`${jsonTable}_001`); let tagParams = stmt.newStmtParam(); tagParams.setJson(jsonTags); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); - bindParams.setTimestamp(tableCNValues[0]) - bindParams.setTinyInt(tableCNValues[1]) - bindParams.setSmallInt(tableCNValues[2]) - bindParams.setInt(tableCNValues[3]) - bindParams.setBigint(tableCNValues[4]) - bindParams.setUTinyInt(tableCNValues[5]) - bindParams.setUSmallInt(tableCNValues[6]) - bindParams.setUInt(tableCNValues[7]) - bindParams.setUBigint(tableCNValues[8]) - bindParams.setFloat(tableCNValues[9]) - bindParams.setDouble(tableCNValues[10]) - - bindParams.setBinary(tableCNValues[11]) - bindParams.setNchar(tableCNValues[12]) - bindParams.setBoolean(tableCNValues[13]) - bindParams.setInt(tableCNValues[14]) - bindParams.setGeometry(geoDataArray) - bindParams.setVarBinary(varbinary) - + bindParams.setTimestamp(tableCNValues[0]); + bindParams.setTinyInt(tableCNValues[1]); + bindParams.setSmallInt(tableCNValues[2]); + bindParams.setInt(tableCNValues[3]); + bindParams.setBigint(tableCNValues[4]); + bindParams.setUTinyInt(tableCNValues[5]); + bindParams.setUSmallInt(tableCNValues[6]); + bindParams.setUInt(tableCNValues[7]); + bindParams.setUBigint(tableCNValues[8]); + bindParams.setFloat(tableCNValues[9]); + bindParams.setDouble(tableCNValues[10]); + + bindParams.setBinary(tableCNValues[11]); + bindParams.setNchar(tableCNValues[12]); + bindParams.setBoolean(tableCNValues[13]); + bindParams.setInt(tableCNValues[14]); + bindParams.setGeometry(geoDataArray); + bindParams.setVarBinary(varbinary); + await stmt.bind(bindParams); - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(5) - await stmt.close() - let result = await connector.exec(`select * from ${db}.${jsonTable}`) - console.log(result) + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(5); + await stmt.close(); + let result = await connector.exec(`select * from ${db}.${jsonTable}`); + console.log(result); await connector.close(); }); - test('normal json cn tag BindParam', async() => { + test("normal json cn tag BindParam", async () => { let wsConf = new WSConfig(dsn); - wsConf.setDb(db) - let connector = await WsSql.open(wsConf) - let stmt = await connector.stmtInit() - expect(stmt).toBeTruthy() + wsConf.setDb(db); + let connector = await WsSql.open(wsConf); + let stmt = await connector.stmtInit(); + expect(stmt).toBeTruthy(); expect(stmt).toBeInstanceOf(WsStmt2); - expect(connector.state()).toBeGreaterThan(0) - await stmt.prepare(getInsertBind(tableValues.length + 2, jsonTags.length, db, jsonTable)); + expect(connector.state()).toBeGreaterThan(0); + await stmt.prepare( + getInsertBind( + tableValues.length + 2, + jsonTags.length, + db, + jsonTable + ) + ); await stmt.setTableName(`${jsonTable}_001`); let tagParams = stmt.newStmtParam(); tagParams.setJson(jsonTagsCN); await stmt.setTags(tagParams); let bindParams = stmt.newStmtParam(); - bindParams.setTimestamp(tableCNValues[0]) - bindParams.setTinyInt(tableCNValues[1]) - bindParams.setSmallInt(tableCNValues[2]) - bindParams.setInt(tableCNValues[3]) - bindParams.setBigint(tableCNValues[4]) - bindParams.setUTinyInt(tableCNValues[5]) - bindParams.setUSmallInt(tableCNValues[6]) - bindParams.setUInt(tableCNValues[7]) - bindParams.setUBigint(tableCNValues[8]) - bindParams.setFloat(tableCNValues[9]) - bindParams.setDouble(tableCNValues[10]) - - bindParams.setBinary(tableCNValues[11]) - bindParams.setNchar(tableCNValues[12]) - bindParams.setBoolean(tableCNValues[13]) - bindParams.setInt(tableCNValues[14]) - bindParams.setGeometry(geoDataArray) - bindParams.setVarBinary(varbinary) - + bindParams.setTimestamp(tableCNValues[0]); + bindParams.setTinyInt(tableCNValues[1]); + bindParams.setSmallInt(tableCNValues[2]); + bindParams.setInt(tableCNValues[3]); + bindParams.setBigint(tableCNValues[4]); + bindParams.setUTinyInt(tableCNValues[5]); + bindParams.setUSmallInt(tableCNValues[6]); + bindParams.setUInt(tableCNValues[7]); + bindParams.setUBigint(tableCNValues[8]); + bindParams.setFloat(tableCNValues[9]); + bindParams.setDouble(tableCNValues[10]); + + bindParams.setBinary(tableCNValues[11]); + bindParams.setNchar(tableCNValues[12]); + bindParams.setBoolean(tableCNValues[13]); + bindParams.setInt(tableCNValues[14]); + bindParams.setGeometry(geoDataArray); + bindParams.setVarBinary(varbinary); + await stmt.bind(bindParams); - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(5) - await stmt.close() - let result = await connector.exec(`select * from ${db}.${jsonTable}`) - console.log(result) + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(5); + await stmt.close(); + let result = await connector.exec(`select * from ${db}.${jsonTable}`); + console.log(result); await connector.close(); }); +}); -}) - -test('test bind exception cases', async() => { +test("test bind exception cases", async () => { let wsConf = new WSConfig(dsn); - let connector = await WsSql.open(wsConf) - let stmt = await connector.stmtInit() + let connector = await WsSql.open(wsConf); + let stmt = await connector.stmtInit(); expect(stmt).toBeInstanceOf(WsStmt2); const params = stmt.newStmtParam(); - + const emptyArrayMethods = [ - { method: 'setBoolean', name: 'SetBooleanColumn' }, - { method: 'setTinyInt', name: 'SetTinyIntColumn' }, - { method: 'setUTinyInt', name: 'SetUTinyIntColumn' }, - { method: 'setSmallInt', name: 'SetSmallIntColumn' }, - { method: 'setUSmallInt', name: 'SetSmallIntColumn' }, - { method: 'setInt', name: 'SetIntColumn' }, - { method: 'setUInt', name: 'SetUIntColumn' }, - { method: 'setBigint', name: 'SetBigIntColumn' }, - { method: 'setUBigint', name: 'SetUBigIntColumn' }, - { method: 'setFloat', name: 'SetFloatColumn' }, - { method: 'setDouble', name: 'SetDoubleColumn' }, - { method: 'setTimestamp', name: 'SeTimestampColumn' } + { method: "setBoolean", name: "SetBooleanColumn" }, + { method: "setTinyInt", name: "SetTinyIntColumn" }, + { method: "setUTinyInt", name: "SetUTinyIntColumn" }, + { method: "setSmallInt", name: "SetSmallIntColumn" }, + { method: "setUSmallInt", name: "SetSmallIntColumn" }, + { method: "setInt", name: "SetIntColumn" }, + { method: "setUInt", name: "SetUIntColumn" }, + { method: "setBigint", name: "SetBigIntColumn" }, + { method: "setUBigint", name: "SetUBigIntColumn" }, + { method: "setFloat", name: "SetFloatColumn" }, + { method: "setDouble", name: "SetDoubleColumn" }, + { method: "setTimestamp", name: "SeTimestampColumn" }, ]; - + emptyArrayMethods.forEach(({ method, name }) => { expect(() => { (params as any)[method]([]); }).toThrow(`${name} params is invalid!`); - + expect(() => { (params as any)[method](null); }).toThrow(`${name} params is invalid!`); - + expect(() => { (params as any)[method](undefined); }).toThrow(`${name} params is invalid!`); }); - + expect(() => { - params.setBoolean(['not boolean']); + params.setBoolean(["not boolean"]); params.encode(); - }).toThrow('SetTinyIntColumn params is invalid!'); - + }).toThrow("SetTinyIntColumn params is invalid!"); + expect(() => { - params.setTinyInt(['not number']); + params.setTinyInt(["not number"]); params.encode(); - }).toThrow('SetTinyIntColumn params is invalid!'); - + }).toThrow("SetTinyIntColumn params is invalid!"); + expect(() => { - params.setBigint(['not bigint']); + params.setBigint(["not bigint"]); params.encode(); - }).toThrow('SetTinyIntColumn params is invalid!'); + }).toThrow("SetTinyIntColumn params is invalid!"); await connector.close(); }); - afterAll(async () => { - let conf :WSConfig = new WSConfig(dsn) + let conf: WSConfig = new WSConfig(dsn); let ws = await WsSql.open(conf); await ws.exec(dropDB); await ws.close(); - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/tmq.test.ts b/nodejs/test/bulkPulling/tmq.test.ts index 3b0095db..13397f92 100644 --- a/nodejs/test/bulkPulling/tmq.test.ts +++ b/nodejs/test/bulkPulling/tmq.test.ts @@ -1,4 +1,3 @@ - import { TMQConstants } from "../../src/tmq/constant"; import { WsConsumer } from "../../src/tmq/wsTmq"; import { WSConfig } from "../../src/common/config"; @@ -8,43 +7,237 @@ import { WebSocketConnectionPool } from "../../src/client/wsConnectorPool"; import logger, { setLevel } from "../../src/common/log"; setLevel("debug"); -const stable = 'st'; -const db = 'ws_tmq_test' -const topics:string[] = ['topic_ws_bean'] +const stable = "st"; +const db = "ws_tmq_test"; +const topics: string[] = ["topic_ws_bean"]; // const topic2 = 'topic_ws_bean_2' // let createTopic = `create topic if not exists ${topic} as select ts, c1, c2, c3, c4, c5, t1 from ${db}.${stable}` // let createTopic2 = `create topic if not exists ${topic2} as select ts, c1, c4, c5, t1 from ${db}.${stable}` -let createTopic = `create topic if not exists ${topics[0]} as select * from ${db}.${stable}` -let dropTopic = `DROP TOPIC IF EXISTS ${topics[0]};` +let createTopic = `create topic if not exists ${topics[0]} as select * from ${db}.${stable}`; +let dropTopic = `DROP TOPIC IF EXISTS ${topics[0]};`; // let dropTopic2 = `DROP TOPIC IF EXISTS ${topic2};` -let dsn = 'ws://root:taosdata@localhost:6041'; -let tmqDsn = 'ws://localhost:6041' +let dsn = "ws://root:taosdata@localhost:6041"; +let tmqDsn = "ws://localhost:6041"; beforeAll(async () => { - let conf :WSConfig = new WSConfig(dsn) - const createDB = `create database if not exists ${db} keep 3650` - const dropDB = `drop database if exists ${db}` - const useDB = `use ${db}` - - const stableTags = [true, -1, -2, -3, BigInt(-4), 1, 2, 3, BigInt(4), parseFloat(3.1415.toFixed(5)), parseFloat(3.14159265.toFixed(15)), 'varchar_tag_1', 'nchar_tag_1'] - + let conf: WSConfig = new WSConfig(dsn); + const createDB = `create database if not exists ${db} keep 3650`; + const dropDB = `drop database if exists ${db}`; + const useDB = `use ${db}`; + + const stableTags = [ + true, + -1, + -2, + -3, + BigInt(-4), + 1, + 2, + 3, + BigInt(4), + parseFloat((3.1415).toFixed(5)), + parseFloat((3.14159265).toFixed(15)), + "varchar_tag_1", + "nchar_tag_1", + ]; + const tableValues = [ - [BigInt(1656677710000), 0, -1, -2, BigInt(-3), 0, 1, 2, BigInt(3), parseFloat(3.1415.toFixed(5)), parseFloat(3.14159265.toFixed(15)), 'varchar_col_1', 'nchar_col_1', true, 'NULL', 'POINT (4.0 8.0)', '0x7661726332'], - [BigInt(1656677720000), -1, -2, -3, BigInt(-4), 1, 2, 3, BigInt(4), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.14159265 * 2).toFixed(15)), 'varchar_col_2', 'nchar_col_2', false, 'NULL', 'POINT (3.0 5.0)', '0x7661726333'], - [BigInt(1656677730000), -2, -3, -4, BigInt(-5), 2, 3, 4, BigInt(5), parseFloat((3.1415 * 3).toFixed(5)), parseFloat((3.14159265 * 3).toFixed(15)), 'varchar_col_3', 'nchar_col_3', true, 'NULL', 'LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)', '0x7661726334'], - [BigInt(1656677740000), -3, -4, -5, BigInt(-6), 3, 4, 5, BigInt(6), parseFloat((3.1415 * 4).toFixed(5)), parseFloat((3.14159265 * 4).toFixed(15)), 'varchar_col_4', 'nchar_col_4', false, 'NULL', 'POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))', '0x7661726335'], - [BigInt(1656677750000), -4, -5, -6, BigInt(-7), 4, 5, 6, BigInt(7), parseFloat((3.1415 * 5).toFixed(5)), parseFloat((3.14159265 * 5).toFixed(15)), 'varchar_col_5', 'nchar_col_5', true, 'NULL', 'POINT (7.0 9.0)', '0x7661726335'], - ] - + [ + BigInt(1656677710000), + 0, + -1, + -2, + BigInt(-3), + 0, + 1, + 2, + BigInt(3), + parseFloat((3.1415).toFixed(5)), + parseFloat((3.14159265).toFixed(15)), + "varchar_col_1", + "nchar_col_1", + true, + "NULL", + "POINT (4.0 8.0)", + "0x7661726332", + ], + [ + BigInt(1656677720000), + -1, + -2, + -3, + BigInt(-4), + 1, + 2, + 3, + BigInt(4), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.14159265 * 2).toFixed(15)), + "varchar_col_2", + "nchar_col_2", + false, + "NULL", + "POINT (3.0 5.0)", + "0x7661726333", + ], + [ + BigInt(1656677730000), + -2, + -3, + -4, + BigInt(-5), + 2, + 3, + 4, + BigInt(5), + parseFloat((3.1415 * 3).toFixed(5)), + parseFloat((3.14159265 * 3).toFixed(15)), + "varchar_col_3", + "nchar_col_3", + true, + "NULL", + "LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)", + "0x7661726334", + ], + [ + BigInt(1656677740000), + -3, + -4, + -5, + BigInt(-6), + 3, + 4, + 5, + BigInt(6), + parseFloat((3.1415 * 4).toFixed(5)), + parseFloat((3.14159265 * 4).toFixed(15)), + "varchar_col_4", + "nchar_col_4", + false, + "NULL", + "POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))", + "0x7661726335", + ], + [ + BigInt(1656677750000), + -4, + -5, + -6, + BigInt(-7), + 4, + 5, + 6, + BigInt(7), + parseFloat((3.1415 * 5).toFixed(5)), + parseFloat((3.14159265 * 5).toFixed(15)), + "varchar_col_5", + "nchar_col_5", + true, + "NULL", + "POINT (7.0 9.0)", + "0x7661726335", + ], + ]; + const tableCNValues = [ - [BigInt(1656677760000), 0, -1, -2, BigInt(-3), 0, 1, 2, BigInt(3), parseFloat(3.1415.toFixed(5)), parseFloat(3.14159265.toFixed(15)), 'varchar_列_壹', 'nchar_列_甲', true, 'NULL', 'POINT (4.0 8.0)', '0x7661726332'], - [BigInt(1656677770000), -1, -2, -3, BigInt(-4), 1, 2, 3, BigInt(4), parseFloat((3.1415 * 2).toFixed(5)), parseFloat((3.14159265 * 2).toFixed(15)), 'varchar_列_贰', 'nchar_列_乙', false, 'NULL', 'POINT (3.0 5.0)', '0x7661726333'], - [BigInt(1656677780000), -2, -3, -4, BigInt(-5), 2, 3, 4, BigInt(5), parseFloat((3.1415 * 3).toFixed(5)), parseFloat((3.14159265 * 3).toFixed(15)), 'varchar_列_叁', 'nchar_列_丙', true, 'NULL', 'LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)', '0x7661726334'], - [BigInt(1656677790000), -3, -4, -5, BigInt(-6), 3, 4, 5, BigInt(6), parseFloat((3.1415 * 4).toFixed(5)), parseFloat((3.14159265 * 4).toFixed(15)), 'varchar_列_肆', 'nchar_列_丁', false, 'NULL', 'POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))', '0x7661726335'], - [BigInt(1656677800000), -4, -5, -6, BigInt(-7), 4, 5, 6, BigInt(7), parseFloat((3.1415 * 5).toFixed(5)), parseFloat((3.14159265 * 5).toFixed(15)), 'varchar_列_伍', 'nchar_列_戊', true, 'NULL', 'POINT (7.0 9.0)', '0x7661726335'], - ] - + [ + BigInt(1656677760000), + 0, + -1, + -2, + BigInt(-3), + 0, + 1, + 2, + BigInt(3), + parseFloat((3.1415).toFixed(5)), + parseFloat((3.14159265).toFixed(15)), + "varchar_列_壹", + "nchar_列_甲", + true, + "NULL", + "POINT (4.0 8.0)", + "0x7661726332", + ], + [ + BigInt(1656677770000), + -1, + -2, + -3, + BigInt(-4), + 1, + 2, + 3, + BigInt(4), + parseFloat((3.1415 * 2).toFixed(5)), + parseFloat((3.14159265 * 2).toFixed(15)), + "varchar_列_贰", + "nchar_列_乙", + false, + "NULL", + "POINT (3.0 5.0)", + "0x7661726333", + ], + [ + BigInt(1656677780000), + -2, + -3, + -4, + BigInt(-5), + 2, + 3, + 4, + BigInt(5), + parseFloat((3.1415 * 3).toFixed(5)), + parseFloat((3.14159265 * 3).toFixed(15)), + "varchar_列_叁", + "nchar_列_丙", + true, + "NULL", + "LINESTRING (1.000000 1.000000, 2.000000 2.000000, 5.000000 5.000000)", + "0x7661726334", + ], + [ + BigInt(1656677790000), + -3, + -4, + -5, + BigInt(-6), + 3, + 4, + 5, + BigInt(6), + parseFloat((3.1415 * 4).toFixed(5)), + parseFloat((3.14159265 * 4).toFixed(15)), + "varchar_列_肆", + "nchar_列_丁", + false, + "NULL", + "POLYGON ((3.000000 6.000000, 5.000000 6.000000, 5.000000 8.000000, 3.000000 8.000000, 3.000000 6.000000))", + "0x7661726335", + ], + [ + BigInt(1656677800000), + -4, + -5, + -6, + BigInt(-7), + 4, + 5, + 6, + BigInt(7), + parseFloat((3.1415 * 5).toFixed(5)), + parseFloat((3.14159265 * 5).toFixed(15)), + "varchar_列_伍", + "nchar_列_戊", + true, + "NULL", + "POINT (7.0 9.0)", + "0x7661726335", + ], + ]; + let ws = await WsSql.open(conf); await ws.exec(dropTopic); // await ws.Exec(dropTopic2); @@ -54,75 +247,74 @@ beforeAll(async () => { await ws.exec(createSTable(stable)); await ws.exec(createTopic); // await ws.Exec(createTopic2); - let insert = insertStable(tableValues, stableTags, stable) - let insertRes = await ws.exec(insert) - insert = insertStable(tableCNValues, stableTags, stable) - insertRes = await ws.exec(insert) - await ws.close() -}) - + let insert = insertStable(tableValues, stableTags, stable); + let insertRes = await ws.exec(insert); + insert = insertStable(tableCNValues, stableTags, stable); + insertRes = await ws.exec(insert); + await ws.close(); +}); -describe('TDWebSocket.Tmq()', () => { - jest.setTimeout(20 * 1000) +describe("TDWebSocket.Tmq()", () => { + jest.setTimeout(20 * 1000); let configMap = new Map([ [TMQConstants.GROUP_ID, "gId"], [TMQConstants.CONNECT_USER, "root"], [TMQConstants.CONNECT_PASS, "taosdata"], [TMQConstants.AUTO_OFFSET_RESET, "earliest"], - [TMQConstants.CLIENT_ID, 'test_tmq_client'], + [TMQConstants.CLIENT_ID, "test_tmq_client"], [TMQConstants.WS_URL, tmqDsn], - [TMQConstants.ENABLE_AUTO_COMMIT, 'true'], - [TMQConstants.AUTO_COMMIT_INTERVAL_MS, '1000'], + [TMQConstants.ENABLE_AUTO_COMMIT, "true"], + [TMQConstants.AUTO_COMMIT_INTERVAL_MS, "1000"], ["session.timeout.ms", "10000"], ["max.poll.interval.ms", "30000"], - ["msg.with.table.name", "true"] + ["msg.with.table.name", "true"], ]); console.log(configMap); - - test('normal connect', async() => { + + test("normal connect", async () => { let consumer = await WsConsumer.newConsumer(configMap); await consumer.close(); }); - test('connect error', async() => { - expect.assertions(1) + test("connect error", async () => { + expect.assertions(1); let consumer = null; let errConfigMap = new Map([ [TMQConstants.GROUP_ID, "test"], [TMQConstants.CONNECT_USER, "root"], [TMQConstants.CONNECT_PASS, "test"], [TMQConstants.AUTO_OFFSET_RESET, "earliest1"], - [TMQConstants.CLIENT_ID, 'test_tmq_client'], + [TMQConstants.CLIENT_ID, "test_tmq_client"], [TMQConstants.WS_URL, tmqDsn], - [TMQConstants.ENABLE_AUTO_COMMIT, 'true'], - [TMQConstants.AUTO_COMMIT_INTERVAL_MS, '1000'], + [TMQConstants.ENABLE_AUTO_COMMIT, "true"], + [TMQConstants.AUTO_COMMIT_INTERVAL_MS, "1000"], ["session.timeout.ms", "10000"], ["max.poll.interval.ms", "30000"], - ["msg.with.table.name", "true"] + ["msg.with.table.name", "true"], ]); try { consumer = await WsConsumer.newConsumer(errConfigMap); await consumer.subscribe(topics); - }catch(e :any){ - console.log(e) - expect(e.code).toBe(65535) - }finally{ - if(consumer) { - await consumer.close() + } catch (e: any) { + console.log(e); + expect(e.code).toBe(280); + } finally { + if (consumer) { + await consumer.close(); } } - }) + }); - test('normal Subscribe', async() => { + test("normal Subscribe", async () => { let consumer = await WsConsumer.newConsumer(configMap); await consumer.subscribe(topics); - let assignment = await consumer.assignment() - console.log(assignment) - let counts:number = 0; - let useTime:number[] = []; - for (let i = 0; i < 5; i++) { + let assignment = await consumer.assignment(); + console.log(assignment); + let counts: number = 0; + let useTime: number[] = []; + for (let i = 0; i < 5; i++) { let startTime = new Date().getTime(); let res = await consumer.poll(500); let currTime = new Date().getTime(); @@ -134,18 +326,17 @@ describe('TDWebSocket.Tmq()', () => { if (data == null || data.length == 0) { break; } - - for (let record of data ) { - console.log("-----===>>", record) - } - + + for (let record of data) { + console.log("-----===>>", record); + } } // await Sleep(100) } - await consumer.seekToBeginning(assignment) + await consumer.seekToBeginning(assignment); - for (let i = 0; i < 5; i++) { + for (let i = 0; i < 5; i++) { let startTime = new Date().getTime(); let res = await consumer.poll(500); let currTime = new Date().getTime(); @@ -156,9 +347,8 @@ describe('TDWebSocket.Tmq()', () => { if (data == null || data.length == 0) { break; } - - counts += data.length - + + counts += data.length; } // await Sleep(100) } @@ -167,56 +357,55 @@ describe('TDWebSocket.Tmq()', () => { for (let index = 0; index < topicArray.length; index++) { expect(topics[index]).toEqual(topicArray[index]); } - + assignment = await consumer.commit(); - console.log(assignment) - assignment = await consumer.committed(assignment) - assignment = await consumer.commitOffsets(assignment) - console.log(assignment) - await consumer.unsubscribe() + console.log(assignment); + assignment = await consumer.committed(assignment); + assignment = await consumer.commitOffsets(assignment); + console.log(assignment); + await consumer.unsubscribe(); await consumer.close(); - console.log("------------->", useTime) - console.log("------------->", counts) - expect(counts).toEqual(10) + console.log("------------->", useTime); + console.log("------------->", counts); + expect(counts).toEqual(10); }); - test('Topic not exist', async() => { + test("Topic not exist", async () => { let consumer = await WsConsumer.newConsumer(configMap); try { - await consumer.subscribe(["aaa"]); - }catch(e:any) { + await consumer.subscribe(["aaa"]); + } catch (e: any) { expect(e.message).toMatch("Topic not exist"); } await consumer.close(); }); - test('normal seek', async() => { + test("normal seek", async () => { let consumer = await WsConsumer.newConsumer(configMap); await consumer.subscribe(topics); - let assignment = await consumer.assignment() - console.log("------START--------",assignment) - - await consumer.seekToEnd(assignment) - await consumer.seekToBeginning(assignment) - await consumer.seekToEnd(assignment) - assignment = await consumer.assignment() - console.log("------END--------",assignment) - for (let i = 0; i< assignment.length; i++) { - expect(assignment[i].offset).toEqual(assignment[i].end) + let assignment = await consumer.assignment(); + console.log("------START--------", assignment); + + await consumer.seekToEnd(assignment); + await consumer.seekToBeginning(assignment); + await consumer.seekToEnd(assignment); + assignment = await consumer.assignment(); + console.log("------END--------", assignment); + for (let i = 0; i < assignment.length; i++) { + expect(assignment[i].offset).toEqual(assignment[i].end); } - - await consumer.unsubscribe() + + await consumer.unsubscribe(); await consumer.close(); }); - -}) +}); afterAll(async () => { - const dropDB = `drop database if exists ${db}` - let conf :WSConfig = new WSConfig(dsn) + const dropDB = `drop database if exists ${db}`; + let conf: WSConfig = new WSConfig(dsn); let ws = await WsSql.open(conf); await ws.exec(dropTopic); await ws.exec(dropDB); - await ws.close() - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + await ws.close(); + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/bulkPulling/utils.test.ts b/nodejs/test/bulkPulling/utils.test.ts index 4cd1b244..689f81ee 100644 --- a/nodejs/test/bulkPulling/utils.test.ts +++ b/nodejs/test/bulkPulling/utils.test.ts @@ -1,7 +1,7 @@ -import { compareVersions } from "../../src/common/utils" +import { compareVersions } from "../../src/common/utils"; -describe('utils test', () => { - test('compare versions test', async() => { +describe("utils test", () => { + test("compare versions test", async () => { expect(compareVersions("3.3.6.3-alpha", "3.3.6.2")).toBe(1); expect(compareVersions("3.3.6.2", "3.3.6.3")).toBe(-1); expect(compareVersions("3.3.6.3", "3.3.6.3")).toBe(0); @@ -9,4 +9,4 @@ describe('utils test', () => { expect(compareVersions("3.3.6.3-beta", "3.3.6.3-alpha")).toBe(1); expect(compareVersions("3.3", "3.3.0.0")).toBe(0); }); -}) \ No newline at end of file +}); diff --git a/nodejs/test/bulkPulling/wsConnectPool.test.ts b/nodejs/test/bulkPulling/wsConnectPool.test.ts index 36067df2..280b7d0d 100644 --- a/nodejs/test/bulkPulling/wsConnectPool.test.ts +++ b/nodejs/test/bulkPulling/wsConnectPool.test.ts @@ -5,163 +5,164 @@ import { WsSql } from "../../src/sql/wsSql"; import { TMQConstants } from "../../src/tmq/constant"; import { WsConsumer } from "../../src/tmq/wsTmq"; import { Sleep } from "../utils"; -import { setLevel } from "../../src/common/log" +import { setLevel } from "../../src/common/log"; import { WsStmt1 } from "../../src/stmt/wsStmt1"; -let dsn = 'ws://root:taosdata@localhost:6041'; -let tags = ['California.SanFrancisco', 3]; +let dsn = "ws://root:taosdata@localhost:6041"; +let tags = ["California.SanFrancisco", 3]; let multi = [ -[1709183268567, 1709183268568, 1709183268569], -[10.2, 10.3, 10.4], -[292, 293, 294], -[0.32, 0.33, 0.34], + [1709183268567, 1709183268568, 1709183268569], + [10.2, 10.3, 10.4], + [292, 293, 294], + [0.32, 0.33, 0.34], ]; - let configMap = new Map([ [TMQConstants.GROUP_ID, "gId"], [TMQConstants.CONNECT_USER, "root"], [TMQConstants.CONNECT_PASS, "taosdata"], [TMQConstants.AUTO_OFFSET_RESET, "earliest"], - [TMQConstants.CLIENT_ID, 'test_tmq_client'], - [TMQConstants.WS_URL, 'ws://localhost:6041'], - [TMQConstants.ENABLE_AUTO_COMMIT, 'true'], - [TMQConstants.AUTO_COMMIT_INTERVAL_MS, '1000'] + [TMQConstants.CLIENT_ID, "test_tmq_client"], + [TMQConstants.WS_URL, "ws://localhost:6041"], + [TMQConstants.ENABLE_AUTO_COMMIT, "true"], + [TMQConstants.AUTO_COMMIT_INTERVAL_MS, "1000"], ]); -const stable = 'meters'; -const db = 'power_connect' -const topics:string[] = ['pwer_meters_topic'] -let createTopic = `create topic if not exists ${topics[0]} as select * from ${db}.${stable}` -let stmtIds:bigint[] = [] -setLevel("debug") +const stable = "meters"; +const db = "power_connect"; +const topics: string[] = ["pwer_meters_topic"]; +let createTopic = `create topic if not exists ${topics[0]} as select * from ${db}.${stable}`; +let stmtIds: bigint[] = []; +setLevel("debug"); async function connect() { - let dsn = 'ws://root:taosdata@localhost:6041'; + let dsn = "ws://root:taosdata@localhost:6041"; let wsSql = null; - let conf :WSConfig = new WSConfig(dsn) - conf.setDb(db) - wsSql = await WsSql.open(conf) - expect(wsSql.state()).toBeGreaterThan(0) - console.log(await wsSql.version()) + let conf: WSConfig = new WSConfig(dsn); + conf.setDb(db); + wsSql = await WsSql.open(conf); + expect(wsSql.state()).toBeGreaterThan(0); + console.log(await wsSql.version()); await wsSql.close(); } async function stmtConnect() { - let dsn = 'ws://root:taosdata@localhost:6041'; + let dsn = "ws://root:taosdata@localhost:6041"; let wsConf = new WSConfig(dsn, "100.100.100.100"); - wsConf.setDb(db) - // let connector = WsStmtConnect.NewConnector(wsConf) + wsConf.setDb(db); + // let connector = WsStmtConnect.NewConnector(wsConf) // let stmt = await connector.Init() - let connector = await WsSql.open(wsConf) - let stmt = (await connector.stmtInit()) as WsStmt1 - let id = stmt.getStmtId() + let connector = await WsSql.open(wsConf); + let stmt = (await connector.stmtInit()) as WsStmt1; + let id = stmt.getStmtId(); if (id) { - stmtIds.push(id) + stmtIds.push(id); } - expect(stmt).toBeTruthy() - await stmt.prepare(`INSERT INTO ? USING ${stable} (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)`); - await stmt.setTableName('d1001'); - await stmt.setJsonTags(tags) - let lastTs = 0 - const allp:any[] = [] + expect(stmt).toBeTruthy(); + await stmt.prepare( + `INSERT INTO ? USING ${stable} (location, groupId) TAGS (?, ?) VALUES (?, ?, ?, ?)` + ); + await stmt.setTableName("d1001"); + await stmt.setJsonTags(tags); + let lastTs = 0; + const allp: any[] = []; for (let i = 0; i < 10; i++) { for (let j = 0; j < multi[0].length; j++) { multi[0][j] = multi[0][0] + j; - lastTs = multi[0][j] + lastTs = multi[0][j]; } - allp.push(stmt.jsonBind(multi)) - multi[0][0] = lastTs + 1 - + allp.push(stmt.jsonBind(multi)); + multi[0][0] = lastTs + 1; } - await Promise.all(allp) - await stmt.batch() - await stmt.exec() - expect(stmt.getLastAffected()).toEqual(30) - await stmt.close() + await Promise.all(allp); + await stmt.batch(); + await stmt.exec(); + expect(stmt.getLastAffected()).toEqual(30); + await stmt.close(); await connector.close(); } async function tmqConnect() { - let consumer = null + let consumer = null; try { consumer = await WsConsumer.newConsumer(configMap); await consumer.subscribe(topics); - - let res = await consumer.poll(100); + + let res = await consumer.poll(100); for (let [key, value] of res) { console.log(key, value.getMeta()); let data = value.getData(); if (data == null || data.length == 0) { break; } - - for (let record of data ) { - console.log(record) - } - + + for (let record of data) { + console.log(record); + } } await consumer.commit(); - - - let assignment = await consumer.assignment() - console.log(assignment) + + let assignment = await consumer.assignment(); + console.log(assignment); if (arguments && arguments.length > 0) - await consumer.seekToBeginning(assignment) - - await consumer.unsubscribe() + await consumer.seekToBeginning(assignment); + + await consumer.unsubscribe(); } catch (e) { console.error(e); } finally { if (consumer) { - await consumer.close(); + await consumer.close(); } } } beforeAll(async () => { - let conf :WSConfig = new WSConfig(dsn) - let ws = await WsSql.open(conf); - await ws.exec(`create database if not exists ${db} KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;`); - await Sleep(100); - await ws.exec(`CREATE STABLE if not exists ${db}.${stable} (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);`); + let conf: WSConfig = new WSConfig(dsn); + let ws = await WsSql.open(conf); + await ws.exec( + `create database if not exists ${db} KEEP 3650 DURATION 10 BUFFER 16 WAL_LEVEL 1;` + ); + await Sleep(100); + await ws.exec( + `CREATE STABLE if not exists ${db}.${stable} (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);` + ); await Sleep(100); await ws.exec(createTopic, ReqId.getReqID()); - await ws.close() -}) - -describe('TDWebSocket.WsSql()', () => { - jest.setTimeout(60 * 1000) - test('ReqId', async()=> { - const allp:any[] = [] - for (let i =0; i < 10; i++) { - allp.push(console.log(ReqId.getReqID())) + await ws.close(); +}); + +describe("TDWebSocket.WsSql()", () => { + jest.setTimeout(60 * 1000); + test("ReqId", async () => { + const allp: any[] = []; + for (let i = 0; i < 10; i++) { + allp.push(console.log(ReqId.getReqID())); } - await Promise.all(allp) + await Promise.all(allp); }); - test('normal connect', async() => { - const allp:any[] = [] - for (let i =0; i < 20; i++) { - allp.push(connect()) - allp.push(stmtConnect()) - allp.push(tmqConnect()) + test("normal connect", async () => { + const allp: any[] = []; + for (let i = 0; i < 20; i++) { + allp.push(connect()); + allp.push(stmtConnect()); + allp.push(tmqConnect()); } - await Promise.all(allp) - console.log(stmtIds) + await Promise.all(allp); + console.log(stmtIds); }); - -}) +}); afterAll(async () => { - let conf :WSConfig = new WSConfig(dsn) - conf.setUser('root') - conf.setPwd('taosdata') + let conf: WSConfig = new WSConfig(dsn); + conf.setUser("root"); + conf.setPwd("taosdata"); - let wsSql = await WsSql.open(conf) - await wsSql.exec(`drop topic if exists ${topics[0]};`) - await wsSql.exec(`drop database if exists ${db};`) - await wsSql.close() + let wsSql = await WsSql.open(conf); + await wsSql.exec(`drop topic if exists ${topics[0]};`); + await wsSql.exec(`drop database if exists ${db};`); + await wsSql.close(); - WebSocketConnectionPool.instance().destroyed() -}) \ No newline at end of file + WebSocketConnectionPool.instance().destroyed(); +}); diff --git a/nodejs/test/utils.ts b/nodejs/test/utils.ts index 1d61cfce..d0f32e36 100644 --- a/nodejs/test/utils.ts +++ b/nodejs/test/utils.ts @@ -1,292 +1,308 @@ import logger from "../src/common/log"; import { TDengineMeta } from "../src/common/taosResult"; - - -export function getInsertBind(valuesLen: number, tagsLen: number, db: string, stable: string): string { - let sql = `insert into ? using ${db}.${stable} tags ( ?` +export function getInsertBind( + valuesLen: number, + tagsLen: number, + db: string, + stable: string +): string { + let sql = `insert into ? using ${db}.${stable} tags ( ?`; for (let i = 1; i < tagsLen; i++) { - sql += ', ?' + sql += ", ?"; } - sql += ') values( ?' + sql += ") values( ?"; for (let i = 1; i < valuesLen; i++) { - sql += ', ?' + sql += ", ?"; } - sql += ')' + sql += ")"; logger.debug(`Insert bind sql: ${sql}`); return sql; } -export function insertStable(values: Array>, tags: Array, stable: string, table: string = 'empty'): string { - let childTable = table == 'empty' ? stable + '_s_01' : table; - let sql = `insert into ${childTable} using ${stable} tags (` +export function insertStable( + values: Array>, + tags: Array, + stable: string, + table: string = "empty" +): string { + let childTable = table == "empty" ? stable + "_s_01" : table; + let sql = `insert into ${childTable} using ${stable} tags (`; tags.forEach((tag) => { - if ((typeof tag) == 'string') { - if (tag == 'NULL') { - sql += tag + ',' + if (typeof tag == "string") { + if (tag == "NULL") { + sql += tag + ","; } else { - sql += `\'${tag}\',` + sql += `\'${tag}\',`; } } else { - sql += tag - sql += ',' + sql += tag; + sql += ","; } - }) + }); - sql = sql.slice(0, sql.length - 1) - sql += ')' + sql = sql.slice(0, sql.length - 1); + sql += ")"; - sql += 'values' - values.forEach(value => { - sql += '(' - value.forEach(v => { - if ((typeof v) == 'string') { - sql += `\'${v}\',` + sql += "values"; + values.forEach((value) => { + sql += "("; + value.forEach((v) => { + if (typeof v == "string") { + sql += `\'${v}\',`; } else { - sql += v - sql += ',' + sql += v; + sql += ","; } - }) - sql = sql.slice(0, sql.length - 1) - sql += ')' - }) + }); + sql = sql.slice(0, sql.length - 1); + sql += ")"; + }); return sql; } export function insertNTable(values: Array>, table: string): string { - let sql = `insert into ${table} values ` - values.forEach(value => { - sql += '(' - value.forEach(v => { - if ((typeof v) == 'string') { - if (v == 'NULL') { - sql += v + ',' + let sql = `insert into ${table} values `; + values.forEach((value) => { + sql += "("; + value.forEach((v) => { + if (typeof v == "string") { + if (v == "NULL") { + sql += v + ","; } else { - sql += `\'${v}\',` + sql += `\'${v}\',`; } } else { - sql += v - sql += ',' + sql += v; + sql += ","; } - }) - sql = sql.slice(0, sql.length - 1) - sql += ')' - }) + }); + sql = sql.slice(0, sql.length - 1); + sql += ")"; + }); return sql; } - export const tableMeta: Array = [ { - name: 'ts', - type: 'TIMESTAMP', - length: 8 + name: "ts", + type: "TIMESTAMP", + length: 8, }, { - name: 'i1', - type: 'TINYINT', - length: 1 + name: "i1", + type: "TINYINT", + length: 1, }, { - name: 'i2', - type: 'SMALLINT', - length: 2 + name: "i2", + type: "SMALLINT", + length: 2, }, { - name: 'i4', - type: 'INT', - length: 4 + name: "i4", + type: "INT", + length: 4, }, { - name: 'i8', - type: 'BIGINT', - length: 8 + name: "i8", + type: "BIGINT", + length: 8, }, { - name: 'u1', - type: 'TINYINT UNSIGNED', - length: 1 + name: "u1", + type: "TINYINT UNSIGNED", + length: 1, }, { - name: 'u2', - type: 'SMALLINT UNSIGNED', - length: 2 + name: "u2", + type: "SMALLINT UNSIGNED", + length: 2, }, { - name: 'u4', - type: 'INT UNSIGNED', - length: 4 + name: "u4", + type: "INT UNSIGNED", + length: 4, }, { - name: 'u8', - type: 'BIGINT UNSIGNED', - length: 8 + name: "u8", + type: "BIGINT UNSIGNED", + length: 8, }, { - name: 'f4', - type: 'FLOAT', - length: 4 + name: "f4", + type: "FLOAT", + length: 4, }, { - name: 'd8', - type: 'DOUBLE', - length: 8 + name: "d8", + type: "DOUBLE", + length: 8, }, { - name: 'bnr', - type: 'VARCHAR', - length: 200 + name: "bnr", + type: "VARCHAR", + length: 200, }, { - name: 'nchr', - type: 'NCHAR', - length: 200 + name: "nchr", + type: "NCHAR", + length: 200, }, { - name: 'b', - type: 'BOOL', - length: 1 + name: "b", + type: "BOOL", + length: 1, }, { - name: 'nilcol', - type: 'INT', - length: 4 + name: "nilcol", + type: "INT", + length: 4, }, { - name: 'geo', - type: 'GEOMETRY', - length: 512 + name: "geo", + type: "GEOMETRY", + length: 512, }, { - name: 'vbinary', - type: 'VARBINARY', - length: 32 + name: "vbinary", + type: "VARBINARY", + length: 32, }, -] +]; export const jsonMeta: Array = [ { - name: 'json_tag', - type: 'JSON', - length: 4095 + name: "json_tag", + type: "JSON", + length: 4095, }, -] +]; export const tagMeta: Array = [ { - name: 'tb', - type: 'BOOL', - length: 1 + name: "tb", + type: "BOOL", + length: 1, }, { - name: 'ti1', - type: 'TINYINT', - length: 1 + name: "ti1", + type: "TINYINT", + length: 1, }, { - name: 'ti2', - type: 'SMALLINT', - length: 2 + name: "ti2", + type: "SMALLINT", + length: 2, }, { - name: 'ti4', - type: 'INT', - length: 4 + name: "ti4", + type: "INT", + length: 4, }, { - name: 'ti8', - type: 'BIGINT', - length: 8 + name: "ti8", + type: "BIGINT", + length: 8, }, { - name: 'tu1', - type: 'TINYINT UNSIGNED', - length: 1 + name: "tu1", + type: "TINYINT UNSIGNED", + length: 1, }, { - name: 'tu2', - type: 'SMALLINT UNSIGNED', - length: 2 + name: "tu2", + type: "SMALLINT UNSIGNED", + length: 2, }, { - name: 'tu4', - type: 'INT UNSIGNED', - length: 4 + name: "tu4", + type: "INT UNSIGNED", + length: 4, }, { - name: 'tu8', - type: 'BIGINT UNSIGNED', - length: 8 + name: "tu8", + type: "BIGINT UNSIGNED", + length: 8, }, { - name: 'tf4', - type: 'FLOAT', - length: 4 + name: "tf4", + type: "FLOAT", + length: 4, }, { - name: 'td8', - type: 'DOUBLE', - length: 8 + name: "td8", + type: "DOUBLE", + length: 8, }, { - name: 'tbnr', - type: 'VARCHAR', - length: 200 + name: "tbnr", + type: "VARCHAR", + length: 200, }, { - name: 'tnchr', - type: 'NCHAR', - length: 200 + name: "tnchr", + type: "NCHAR", + length: 200, }, -] +]; export function createBaseSTable(stable: string): string { - return `create table if not exists ${stable}( ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int, g1 geometry(512), c4 varbinary(100))` + - 'tags( tb bool,ti1 tinyint,ti2 smallint,ti4 int,ti8 bigint,tu1 tinyint unsigned,tu2 smallint unsigned,tu4 int unsigned,tu8 bigint unsigned,tf4 float,td8 double,tbnr binary(200),tnchr nchar(200));' + return ( + `create table if not exists ${stable}( ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int, g1 geometry(512), c4 varbinary(100))` + + "tags( tb bool,ti1 tinyint,ti2 smallint,ti4 int,ti8 bigint,tu1 tinyint unsigned,tu2 smallint unsigned,tu4 int unsigned,tu8 bigint unsigned,tf4 float,td8 double,tbnr binary(200),tnchr nchar(200));" + ); } export function createBaseSTableJSON(stable: string): string { - return `create table if not exists ${stable}(ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int)` + - 'tags(json_tag json);' + return ( + `create table if not exists ${stable}(ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int)` + + "tags(json_tag json);" + ); } export function createBaseTable(table: string): string { - return `create table if not exists ${table}(ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int)` + return `create table if not exists ${table}(ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int)`; } export function createSTable(stable: string): string { - return `create table if not exists ${stable}( ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int, geo geometry(512), vbinary varbinary(32))` + - 'tags( tb bool,ti1 tinyint,ti2 smallint,ti4 int,ti8 bigint,tu1 tinyint unsigned,tu2 smallint unsigned,tu4 int unsigned,tu8 bigint unsigned,tf4 float,td8 double,tbnr binary(200),tnchr nchar(200));' + return ( + `create table if not exists ${stable}( ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int, geo geometry(512), vbinary varbinary(32))` + + "tags( tb bool,ti1 tinyint,ti2 smallint,ti4 int,ti8 bigint,tu1 tinyint unsigned,tu2 smallint unsigned,tu4 int unsigned,tu8 bigint unsigned,tf4 float,td8 double,tbnr binary(200),tnchr nchar(200));" + ); } export function createSTableJSON(stable: string): string { - return `create table if not exists ${stable}(ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int, geo geometry(512), vbinary varbinary(32))` + - 'tags(json_tag json);' + return ( + `create table if not exists ${stable}(ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int, geo geometry(512), vbinary varbinary(32))` + + "tags(json_tag json);" + ); } export function createTable(table: string): string { - return `create table if not exists ${table}(ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int, geo geometry(512), vbinary varbinary(32))` + return `create table if not exists ${table}(ts timestamp,i1 tinyint,i2 smallint,i4 int,i8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,d8 double,bnr binary(200),nchr nchar(200),b bool,nilcol int, geo geometry(512), vbinary varbinary(32))`; } - - -export function expectStableData(rows: Array>, tags: Array): Array> { - let resArr:Array> =[] +export function expectStableData( + rows: Array>, + tags: Array +): Array> { + let resArr: Array> = []; rows.forEach((row, index, rows) => { - resArr.push(row.concat(tags)) - }) + resArr.push(row.concat(tags)); + }); return resArr; } export function hexToBytes(hex: string): ArrayBuffer { let byteLen = hex.length / 2; - let a = new Uint8Array(byteLen) + let a = new Uint8Array(byteLen); for (let i = 0, count = 0; i < hex.length; i += 2, count++) { - let item = parseInt(hex.slice(i, i+2), 16); - a[count] = item + let item = parseInt(hex.slice(i, i + 2), 16); + a[count] = item; } - return a.buffer + return a.buffer; } -// export function createStmtData(varbinary:string = "ab", +// export function createStmtData(varbinary:string = "ab", // geoHex:string = "0101000020E6100000000000000000F03F0000000000000040"):Array> { // let multi:any[][] = [ // [1709183268567, 1709183268568, 1709183268569], @@ -298,27 +314,29 @@ export function hexToBytes(hex: string): ArrayBuffer { // let geom = Array.from(new Uint8Array(res)) // multi.push([geom, geom, geom]) - // res = new TextEncoder().encode(varbinary) // let binary = Array.from(new Uint8Array(res)) // multi.push([binary, binary, binary]) // return multi // } -export function compareUint8Arrays(arr1: Uint8Array, arr2: Uint8Array): boolean { - if (arr1.length !== arr2.length) { - logger.debug(`${arr1.length} !== ${arr2.length}`) - return false; - } - for (let i = 0; i < arr1.length; i++) { - if (arr1[i] !== arr2[i]) { - logger.debug(`${arr1[i]} !== ${arr2[i]}`) - return false; - } - } - return true; -} +export function compareUint8Arrays( + arr1: Uint8Array, + arr2: Uint8Array +): boolean { + if (arr1.length !== arr2.length) { + logger.debug(`${arr1.length} !== ${arr2.length}`); + return false; + } + for (let i = 0; i < arr1.length; i++) { + if (arr1[i] !== arr2[i]) { + logger.debug(`${arr1[i]} !== ${arr2[i]}`); + return false; + } + } + return true; +} export function Sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); } diff --git a/nodejs/tsconfig.json b/nodejs/tsconfig.json index 38e6f8bb..e75363d2 100644 --- a/nodejs/tsconfig.json +++ b/nodejs/tsconfig.json @@ -25,7 +25,7 @@ /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ - "rootDir": "./", /* Specify the root folder within your source files. */ + "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ @@ -42,12 +42,12 @@ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ /* Emit */ - "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - "declarationMap": true, /* Create sourcemaps for d.ts files. */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./lib/", /* Specify an output folder for all emitted files. */ + "outDir": "./lib/", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */