Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2663eda

Browse files
committed
Reuse connection
1 parent24898e1 commit2663eda

File tree

5 files changed

+257
-15
lines changed

5 files changed

+257
-15
lines changed

‎index.js‎

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function queryBind(query, args = {}, format = "CSV") {
1919
returnchdbNode.QueryBindSession(query,args,format);
2020
}
2121

22-
// Session class with path handling
22+
// Session class withconnection-basedpath handling
2323
classSession{
2424
constructor(path=""){
2525
if(path===""){
@@ -30,21 +30,38 @@ class Session {
3030
this.path=path;
3131
this.isTemp=false;
3232
}
33+
34+
// Create a connection for this session
35+
this.connection=chdbNode.CreateConnection(this.path);
36+
if(!this.connection){
37+
thrownewError("Failed to create connection");
38+
}
3339
}
3440

3541
query(query,format="CSV"){
3642
if(!query)return"";
37-
returnchdbNode.QuerySession(query,format,this.path);
43+
if(!this.connection){
44+
thrownewError("No active connection available");
45+
}
46+
returnchdbNode.QueryWithConnection(this.connection,query,format);
3847
}
3948

4049
queryBind(query,args={},format="CSV"){
41-
if(!query)return"";
42-
returnchdbNode.QueryBindSession(query,args,format,this.path)
50+
thrownewError("QueryBind is not supported with connection-based sessions. Please use the standalone queryBind function instead.");
4351
}
4452

45-
// Cleanup method todelete the temporarydirectory
53+
// Cleanup method toclose connection and deletedirectory if temp
4654
cleanup(){
47-
rmSync(this.path,{recursive:true});// Replaced rmdirSync with rmSync
55+
// Close the connection if it exists
56+
if(this.connection){
57+
chdbNode.CloseConnection(this.connection);
58+
this.connection=null;
59+
}
60+
61+
// Only delete directory if it's temporary
62+
if(this.isTemp){
63+
rmSync(this.path,{recursive:true});
64+
}
4865
}
4966
}
5067

‎lib/chdb_node.cpp‎

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
#include"chdb.h"
22
#include"chdb_node.h"
3+
#include<cstddef>
34
#include<stdio.h>
45
#include<stdlib.h>
56
#include<string.h>
67
#include<iostream>
78
#include<napi.h>
89

10+
typedefvoid * ChdbConnection;
11+
ChdbConnectionCreateConnection(constchar * path);
12+
voidCloseConnection(ChdbConnection conn);
13+
char *QueryWithConnection(ChdbConnection conn,constchar * query,constchar * format,char ** error_message);
14+
915
#defineMAX_FORMAT_LENGTH64
1016
#defineMAX_PATH_LENGTH4096
1117
#defineMAX_ARG_COUNT6
@@ -189,6 +195,56 @@ char *QueryBindSession(const char *query, const char *format, const char *path,
189195
returnquery_stable_v2(static_cast<int>(argv.size()), argv.data())->buf;
190196
}
191197

198+
ChdbConnectionCreateConnection(constchar * path) {
199+
char dataPath[MAX_PATH_LENGTH];
200+
char * args[MAX_ARG_COUNT] = {"clickhouse",NULL};
201+
int argc =1;
202+
203+
if (path && path[0]) {
204+
construct_arg(dataPath,"--path=", path, MAX_PATH_LENGTH);
205+
args[1] = dataPath;
206+
argc =2;
207+
}
208+
209+
returnstatic_cast<ChdbConnection>(chdb_connect(argc, args));
210+
}
211+
212+
voidCloseConnection(ChdbConnection conn) {
213+
if (conn) {
214+
chdb_close_conn(static_cast<chdb_connection *>(conn));
215+
}
216+
}
217+
218+
char *QueryWithConnection(ChdbConnection conn,constchar * query,constchar * format,char ** error_message) {
219+
if (!conn || !query || !format) {
220+
returnnullptr;
221+
}
222+
223+
chdb_connection * inner_conn =static_cast<chdb_connection *>(conn);
224+
chdb_result * result =chdb_query(*inner_conn, query, format);
225+
if (!result) {
226+
returnnullptr;
227+
}
228+
229+
constchar * error =chdb_result_error(result);
230+
if (error) {
231+
if (error_message) {
232+
*error_message =strdup(error);
233+
}
234+
chdb_destroy_query_result(result);
235+
returnnullptr;
236+
}
237+
238+
constchar * buffer =chdb_result_buffer(result);
239+
char * output =nullptr;
240+
if (buffer) {
241+
output =strdup(buffer);
242+
}
243+
244+
chdb_destroy_query_result(result);
245+
return output;
246+
}
247+
192248
Napi::StringQueryWrapper(const Napi::CallbackInfo &info) {
193249
Napi::Env env = info.Env();
194250

@@ -291,11 +347,81 @@ Napi::String QueryBindSessionWrapper(const Napi::CallbackInfo& info) {
291347
returnNapi::String::New(env, out);
292348
}
293349

350+
Napi::ValueCreateConnectionWrapper(const Napi::CallbackInfo & info) {
351+
Napi::Env env = info.Env();
352+
353+
if (info.Length() <1 || !info[0].IsString()) {
354+
Napi::TypeError::New(env,"Path string expected").ThrowAsJavaScriptException();
355+
return env.Null();
356+
}
357+
358+
std::string path = info[0].As<Napi::String>().Utf8Value();
359+
ChdbConnection conn =CreateConnection(path.c_str());
360+
361+
if (!conn) {
362+
Napi::Error::New(env,"Failed to create connection").ThrowAsJavaScriptException();
363+
return env.Null();
364+
}
365+
366+
return Napi::External<void>::New(env, conn);
367+
}
368+
369+
Napi::ValueCloseConnectionWrapper(const Napi::CallbackInfo & info) {
370+
Napi::Env env = info.Env();
371+
372+
if (info.Length() <1 || !info[0].IsExternal()) {
373+
Napi::TypeError::New(env,"Connection handle expected").ThrowAsJavaScriptException();
374+
return env.Undefined();
375+
}
376+
377+
ChdbConnection conn = info[0].As<Napi::External<void>>().Data();
378+
CloseConnection(conn);
379+
380+
return env.Undefined();
381+
}
382+
383+
Napi::StringQueryWithConnectionWrapper(const Napi::CallbackInfo & info) {
384+
Napi::Env env = info.Env();
385+
386+
if (info.Length() <3 || !info[0].IsExternal() || !info[1].IsString() || !info[2].IsString()) {
387+
Napi::TypeError::New(env,"Usage: connection, query, format").ThrowAsJavaScriptException();
388+
returnNapi::String::New(env,"");
389+
}
390+
391+
ChdbConnection conn = info[0].As<Napi::External<void>>().Data();
392+
std::string query = info[1].As<Napi::String>().Utf8Value();
393+
std::string format = info[2].As<Napi::String>().Utf8Value();
394+
395+
char * error_message =nullptr;
396+
char * result =QueryWithConnection(conn, query.c_str(), format.c_str(), &error_message);
397+
398+
if (error_message) {
399+
std::string error_msg =std::string("Query failed:") + error_message;
400+
free(error_message);
401+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
402+
returnNapi::String::New(env,"");
403+
}
404+
405+
if (!result) {
406+
returnNapi::String::New(env,"");
407+
}
408+
409+
Napi::String output =Napi::String::New(env, result);
410+
free(result);
411+
return output;
412+
}
413+
294414
Napi::ObjectInit(Napi::Env env, Napi::Object exports) {
295415
// Export the functions
296416
exports.Set("Query",Napi::Function::New(env, QueryWrapper));
297417
exports.Set("QuerySession",Napi::Function::New(env, QuerySessionWrapper));
298418
exports.Set("QueryBindSession",Napi::Function::New(env, QueryBindSessionWrapper));
419+
420+
// Export connection management functions
421+
exports.Set("CreateConnection",Napi::Function::New(env, CreateConnectionWrapper));
422+
exports.Set("CloseConnection",Napi::Function::New(env, CloseConnectionWrapper));
423+
exports.Set("QueryWithConnection",Napi::Function::New(env, QueryWithConnectionWrapper));
424+
299425
return exports;
300426
}
301427

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
},
1010
"scripts": {
1111
"install":"npm run libchdb && npm run build",
12-
"test":"mocha --timeout 15000",
12+
"test":"mochatest_basic.js test_connection.js--timeout 15000",
1313
"libchdb":"bash ./update_libchdb.sh",
1414
"fixloaderpath":"bash ./fix_loader_path.sh",
1515
"build":"node-gyp configure build --verbose && npm run fixloaderpath"

test.js renamed to test_basic.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,16 @@ describe('chDB Queries', function () {
5656
letsession;
5757

5858
before(function(){
59-
// Create a new session instance before running the tests
60-
session=newSession("./chdb-node-tmp");
59+
// Delete existing directory and create a new session instance
60+
constfs=require('fs');
61+
constpath=require('path');
62+
consttmpDir="./chdb-node-tmp";
63+
64+
if(fs.existsSync(tmpDir)){
65+
fs.rmSync(tmpDir,{recursive:true,force:true});
66+
}
67+
68+
session=newSession(tmpDir);
6169
});
6270

6371
after(function(){
@@ -92,12 +100,10 @@ describe('chDB Queries', function () {
92100
}).to.throw(Error,/Unknowntableexpressionidentifier/);
93101
});
94102

95-
it('should return result of the query made using bind parameters',()=>{
96-
constret=session.queryBind("SELECT * from testdb.testtable where id > {id: UInt32}",{id:2},"CSV");
97-
console.log("Bind Session result:",ret);
98-
expect(ret).to.not.include('1');
99-
expect(ret).to.not.include('2');
100-
expect(ret).to.include('3');
103+
it('should throw an error when using queryBind with session',()=>{
104+
expect(()=>{
105+
session.queryBind("SELECT * from testdb.testtable where id > {id: UInt32}",{id:2},"CSV");
106+
}).to.throw(Error,/QueryBindisnotsupportedwithconnection-basedsessions.PleaseusethestandalonequeryBindfunctioninstead./);
101107
})
102108
});
103109

‎test_connection.js‎

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
const{ expect}=require('chai');
2+
const{ Session}=require(".");
3+
4+
describe('chDB Connection Tests',function(){
5+
6+
describe('Session Connection Management',function(){
7+
letsession;
8+
9+
before(function(){
10+
// Delete existing directory and create a new session instance
11+
constfs=require('fs');
12+
consttmpDir="./test-connection-tmp";
13+
14+
if(fs.existsSync(tmpDir)){
15+
fs.rmSync(tmpDir,{recursive:true,force:true});
16+
}
17+
18+
session=newSession(tmpDir);
19+
});
20+
21+
after(function(){
22+
// Clean up the session after all tests are done
23+
session.cleanup();
24+
});
25+
26+
it('should create session successfully with path and connection ID',function(){
27+
expect(session.path).to.equal("./test-connection-tmp");
28+
expect(session.connection).to.not.be.null;
29+
expect(session.connection).to.not.be.undefined;
30+
console.log("✓ Session created successfully, path:",session.path);
31+
console.log("✓ Connection:",session.connection);
32+
});
33+
34+
it('should execute simple query and return correct result',function(){
35+
constresult=session.query("SELECT 1 as test_col","CSV");
36+
console.log("Query result:",result.trim());
37+
expect(result).to.be.a('string');
38+
expect(result.trim()).to.equal('1');
39+
});
40+
41+
it('should return version information',function(){
42+
constresult=session.query("SELECT version()","CSV");
43+
console.log("Version info:",result.trim());
44+
expect(result).to.be.a('string');
45+
expect(result).to.include('.');
46+
});
47+
48+
it('should create database and table successfully',function(){
49+
// This should not throw an error
50+
expect(()=>{
51+
session.query("CREATE DATABASE IF NOT EXISTS test_conn_db");
52+
session.query("CREATE TABLE IF NOT EXISTS test_conn_db.test_table (id UInt32, name String) ENGINE = MergeTree() ORDER BY id");
53+
}).to.not.throw();
54+
console.log("✓ Database and table created successfully");
55+
});
56+
57+
it('should insert data successfully',function(){
58+
expect(()=>{
59+
session.query("INSERT INTO test_conn_db.test_table VALUES (1, 'Alice'), (2, 'Bob')");
60+
}).to.not.throw();
61+
console.log("✓ Data inserted successfully");
62+
});
63+
64+
it('should query inserted data and verify connection reuse',function(){
65+
constresult=session.query("SELECT * FROM test_conn_db.test_table ORDER BY id","CSV");
66+
console.log("Query result:",result.trim());
67+
expect(result).to.be.a('string');
68+
expect(result).to.include('Alice');
69+
expect(result).to.include('Bob');
70+
expect(result).to.include('1');
71+
expect(result).to.include('2');
72+
});
73+
74+
it('should throw error when using queryBind with session',function(){
75+
expect(()=>{
76+
session.queryBind("SELECT {id:UInt32}",{id:42});
77+
}).to.throw(Error,/QueryBindisnotsupportedwithconnection-basedsessions.PleaseusethestandalonequeryBindfunctioninstead./);
78+
console.log("✓ queryBind correctly throws error");
79+
});
80+
81+
it('should handle multiple queries in sequence (connection persistence)',function(){
82+
constresult1=session.query("SELECT COUNT(*) FROM test_conn_db.test_table","CSV");
83+
constresult2=session.query("SELECT MAX(id) FROM test_conn_db.test_table","CSV");
84+
constresult3=session.query("SELECT name FROM test_conn_db.test_table WHERE id = 1","CSV");
85+
86+
expect(result1.trim()).to.equal('2');
87+
expect(result2.trim()).to.equal('2');
88+
expect(result3.trim()).to.include('Alice');
89+
console.log("✓ Connection persistence test passed");
90+
});
91+
});
92+
93+
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp