Skip to content

Commit 00f6e18

Browse files
committed
add exec multiple statements
1 parent 32f86d5 commit 00f6e18

File tree

5 files changed

+237
-73
lines changed

5 files changed

+237
-73
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"name": "Launch via NPM",
99
"request": "launch",
1010
"runtimeArgs": [
11-
"start"
11+
"test"
1212
],
1313
"runtimeExecutable": "npm",
1414
"skipFiles": [

README.md

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@
33
## Pre-requirement
44
You need to [install](https://crossdb.org/get-started/install/) crossdb lib first
55

6-
> ### Not ready for production
7-
86
## Install
97
```sh
108
npm install @croosdb/crossdb-nodejs
119
```
12-
### to Use
10+
## Use
1311

1412
```javascript
1513
const CrossDB = require('@croosdb/crossdb-nodejs');
@@ -19,10 +17,129 @@ You need to [install](https://crossdb.org/get-started/install/) crossdb lib firs
1917
const db = new CrossDB('./<<path>>/<<db name>>');
2018
```
2119

20+
## Contributors
2221

23-
## Run Example
22+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
23+
<!-- prettier-ignore-start -->
24+
<!-- markdownlint-disable -->
25+
<table>
26+
<tr>
27+
<td align="center">
28+
<a href="https://github.com/efremropelato">
29+
<img src="https://avatars.githubusercontent.com/u/6368884?v=4?s=100" width="100px;" alt=""/><br />
30+
<sub><b>Efrem Ropelato</b></sub>
31+
</a><br />
32+
<a href="https://github.com/crossdb-org/crossdb-nodejs/commits?author=efremropelato" title="Code">💻 <i>Maintainer</i></a>
33+
</td>
34+
</tr>
35+
</table>
36+
<!-- markdownlint-restore -->
37+
<!-- prettier-ignore-end -->
38+
<!-- ALL-CONTRIBUTORS-LIST:END -->
2439

25-
```sh
26-
npm install
27-
npm start
40+
## Example
41+
42+
```javascript
43+
// Import the CrossDB module
44+
const CrossDB = require('@croosdb/crossdb-nodejs');
45+
46+
// Create an in-memory database instance
47+
const db = new CrossDB(':memory:');
48+
49+
try {
50+
// Create tables if they do not already exist
51+
db.exec("CREATE TABLE IF NOT EXISTS student (id INT PRIMARY KEY, name CHAR(16), age INT, class CHAR(16), score FLOAT, info VARCHAR(255))");
52+
db.exec("CREATE TABLE IF NOT EXISTS teacher (id INT PRIMARY KEY, name CHAR(16), age INT, info CHAR(255), INDEX (name))");
53+
db.exec("CREATE TABLE IF NOT EXISTS book (id INT PRIMARY KEY, name CHAR(64), author CHAR(32), count INT, INDEX (name))");
54+
console.log("Tables 'student','teacher' and 'book' created.");
55+
56+
// Clean (empty) all tables
57+
db.exec("DELETE FROM student");
58+
db.exec("DELETE FROM teacher");
59+
db.exec("DELETE FROM book");
60+
61+
// Start a transaction
62+
db.begin();
63+
console.log("Begin transaction");
64+
65+
// Insert sample data into the student, teacher, and book tables
66+
db.exec("INSERT INTO student (id,name,age,class,score) VALUES (1,'jack',10,'3-1',90),(2,'tom',11,'2-5',91),(3,'jack',11,'1-6',92),(4,'rose',10,'4-2',90),(5,'tim',10,'3-1',95)");
67+
db.exec("INSERT INTO student (id,name,age,class,score,info) VALUES (6,'Tony',10,'3-1',95,'%s')", "He is a boy.\nHe likes playing football.\nWe all like him!");
68+
db.exec("INSERT INTO student (id,name,age,class,score,info) VALUES (7,'Wendy',10,'3-1',95,'%s')", "She is a girl.\nShe likes cooking.\nWe all love her!");
69+
db.exec("INSERT INTO teacher (id,name,age) VALUES (1,'Tomas',40),(2,'Steven',50),(3,'Bill',31),(4,'Lucy',29)");
70+
db.exec("INSERT INTO book (id,name,author,count) VALUES (1,'Romeo and Juliet','Shakespeare',10),(2,'Pride and Prejudice','Austen',5),(3,'Great Expectations','Dickens',8),(4,'Sorrows of Young Werther','Von Goethe',4)");
71+
console.log("Data inserted.");
72+
73+
// Query to select all students
74+
let res = db.exec("SELECT * FROM student");
75+
res.forEach((element,i) => {
76+
console.log(i,"Select all students: ", element);
77+
});
78+
79+
// Update a student's age and query the updated record
80+
db.exec("UPDATE student set age=9 WHERE id = 2");
81+
console.log("Updated age to 9 for student with id = 2");
82+
83+
res = db.exec("SELECT id,name,age,class,score from student WHERE id = 2");
84+
res.forEach((element,i) => {
85+
console.log(i,"Select student with id = 2: ", element);
86+
});
87+
88+
// Delete a student and query the deleted record
89+
db.exec("DELETE FROM student WHERE id = 3");
90+
console.log("Deleted student with id = 3");
91+
92+
res = db.exec("SELECT * from student WHERE id = 3");
93+
res.forEach((element,i) => {
94+
console.log(i,"Select student with id = 3: ", element);
95+
});
96+
97+
// Perform aggregation on the student table
98+
res = db.exec("SELECT COUNT(*),MIN(score),MAX(score),SUM(score),AVG(score) FROM student");
99+
res.forEach((element,i) => {
100+
console.log(i,"Student aggregation (COUNT, MIN, MAX, SUM, AVG): ", element);
101+
});
102+
103+
// Commit the transaction
104+
db.commit();
105+
console.log("Transaction committed");
106+
107+
// Start a new transaction
108+
db.begin();
109+
console.log("Begin transaction");
110+
111+
// Update a student's age, query, and roll back the transaction
112+
db.exec("UPDATE student set age=15 WHERE id = 2");
113+
console.log("Updated age to 15 for student with id = 2");
114+
115+
res = db.exec("SELECT id,name,age,class,score from student WHERE id = 2");
116+
res.forEach((element,i) => {
117+
console.log(i,"Select student with id = 2: ", element);
118+
});
119+
120+
db.rollback();
121+
console.log("Transaction rolled back");
122+
123+
res = db.exec("SELECT id,name,age,class,score from student WHERE id = 2");
124+
res.forEach((element,i) => {
125+
console.log(i,"Select student with id = 2 after rollback: ", element);
126+
});
127+
128+
// Execute multiple statements and query the results
129+
res = db.exec("SELECT COUNT(*) as Count FROM student; SELECT id, name, age FROM student WHERE id=2;SELECT MIN(score) as min, MAX(score) as max, SUM(score) as sum, AVG(score) as avg FROM student");
130+
res.forEach((element,i) => {
131+
console.log(i,"Multi-statement select: ", element);
132+
});
133+
134+
} catch (err) {
135+
// Handle errors, roll back any pending transaction, and log the error
136+
console.error("Error during operation:", err);
137+
db.rollback();
138+
console.log("Transaction rolled back due to error");
139+
} finally {
140+
// Ensure the database connection is closed
141+
console.log("\nCrossDB Simulation Complete.");
142+
db.close();
143+
console.log("Database connection closed.");
144+
}
28145
```

example/index.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,33 @@ try {
3030

3131
// Query to select all students
3232
let res = db.exec("SELECT * FROM student");
33-
console.log("Select all students: ", res);
33+
res.forEach((element,i) => {
34+
console.log(i,"Select all students: ", element);
35+
});
3436

3537
// Update a student's age and query the updated record
3638
db.exec("UPDATE student set age=9 WHERE id = 2");
3739
console.log("Updated age to 9 for student with id = 2");
3840

3941
res = db.exec("SELECT id,name,age,class,score from student WHERE id = 2");
40-
console.log("Select student with id = 2: ", res);
42+
res.forEach((element,i) => {
43+
console.log(i,"Select student with id = 2: ", element);
44+
});
4145

4246
// Delete a student and query the deleted record
4347
db.exec("DELETE FROM student WHERE id = 3");
4448
console.log("Deleted student with id = 3");
4549

4650
res = db.exec("SELECT * from student WHERE id = 3");
47-
console.log("Select student with id = 3: ", res);
51+
res.forEach((element,i) => {
52+
console.log(i,"Select student with id = 3: ", element);
53+
});
4854

4955
// Perform aggregation on the student table
5056
res = db.exec("SELECT COUNT(*),MIN(score),MAX(score),SUM(score),AVG(score) FROM student");
51-
console.log("Student aggregation (COUNT, MIN, MAX, SUM, AVG): ", res);
57+
res.forEach((element,i) => {
58+
console.log(i,"Student aggregation (COUNT, MIN, MAX, SUM, AVG): ", element);
59+
});
5260

5361
// Commit the transaction
5462
db.commit();
@@ -63,17 +71,23 @@ try {
6371
console.log("Updated age to 15 for student with id = 2");
6472

6573
res = db.exec("SELECT id,name,age,class,score from student WHERE id = 2");
66-
console.log("Select student with id = 2: ", res);
74+
res.forEach((element,i) => {
75+
console.log(i,"Select student with id = 2: ", element);
76+
});
6777

6878
db.rollback();
6979
console.log("Transaction rolled back");
7080

7181
res = db.exec("SELECT id,name,age,class,score from student WHERE id = 2");
72-
console.log("Select student with id = 2 after rollback: ", res);
82+
res.forEach((element,i) => {
83+
console.log(i,"Select student with id = 2 after rollback: ", element);
84+
});
7385

7486
// Execute multiple statements and query the results
75-
res = db.exec("SELECT COUNT(*) as Count FROM student; SELECT id,name FROM student WHERE id=2");
76-
console.log("Multi-statement select: ", res);
87+
res = db.exec("SELECT COUNT(*) as Count FROM student; SELECT id, name, age FROM student WHERE id=2;SELECT MIN(score) as min, MAX(score) as max, SUM(score) as sum, AVG(score) as avg FROM student");
88+
res.forEach((element,i) => {
89+
console.log(i,"Multi-statement select: ", element);
90+
});
7791

7892
} catch (err) {
7993
// Handle errors, roll back any pending transaction, and log the error

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@croosdb/crossdb-nodejs",
3-
"version": "1.2.9",
3+
"version": "1.3.0",
44
"main": "index.js",
55
"author": "Efrem Ropelato",
66
"contributors":[

src/crossdb_binding.cc

Lines changed: 89 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
#include <napi.h>
22
#include <crossdb.h>
33
#include <string>
4+
#include <vector>
5+
#include <sstream>
6+
#include <cassert>
7+
#include <cstring>
8+
#include <memory>
9+
10+
std::vector<std::string> str_split(const std::string &str, char delim)
11+
{
12+
std::vector<std::string> tokens;
13+
std::stringstream ss(str);
14+
std::string token;
15+
16+
while (std::getline(ss, token, delim))
17+
{
18+
tokens.push_back(token);
19+
}
20+
return tokens;
21+
}
422

523
class Connection : public Napi::ObjectWrap<Connection>
624
{
@@ -42,69 +60,84 @@ class Connection : public Napi::ObjectWrap<Connection>
4260
xdb_conn_t *conn;
4361
xdb_res_t *res;
4462

45-
Napi::Value Exec(const Napi::CallbackInfo &info) {
46-
Napi::Env env = info.Env();
47-
48-
if (info.Length() < 1 || !info[0].IsString()) {
49-
Napi::TypeError::New(env, "SQL query string expected").ThrowAsJavaScriptException();
50-
return env.Null();
51-
}
63+
Napi::Value Exec(const Napi::CallbackInfo &info)
64+
{
65+
Napi::Env env = info.Env();
5266

53-
std::string sql = info[0].As<Napi::String>().Utf8Value();
54-
res = xdb_exec(conn, sql.c_str());
67+
if (info.Length() < 1 || !info[0].IsString())
68+
{
69+
Napi::TypeError::New(env, "SQL query string expected").ThrowAsJavaScriptException();
70+
return env.Null();
71+
}
5572

56-
if (res == nullptr) {
57-
Napi::Error::New(env, "Failed to execute SQL command").ThrowAsJavaScriptException();
58-
return env.Null();
59-
}
73+
std::string sql = info[0].As<Napi::String>().Utf8Value();
74+
Napi::Array results = Napi::Array::New(env);
75+
int statementIndex = 0;
76+
// Splitting example
77+
auto tokens = str_split(sql, ';');
78+
for (const auto &token : tokens)
79+
{
80+
res = xdb_exec(conn, token.c_str());
81+
if (res == nullptr)
82+
{
83+
Napi::Error::New(env, "Failed to execute SQL command").ThrowAsJavaScriptException();
84+
return env.Null();
85+
}
6086

61-
if (res->errcode != 0) {
62-
std::string errMsg = xdb_errmsg(res);
63-
xdb_free_result(res); // Liberare la risorsa
64-
Napi::Error::New(env, "SQL error " + std::to_string(res->errcode) + ": " + errMsg).ThrowAsJavaScriptException();
65-
return env.Null();
66-
}
87+
if (res->errcode != 0)
88+
{
89+
std::string errMsg = xdb_errmsg(res);
90+
xdb_free_result(res); // Liberare la risorsa
91+
Napi::Error::New(env, "SQL error " + std::to_string(res->errcode) + ": " + errMsg).ThrowAsJavaScriptException();
92+
return env.Null();
93+
}
6794

68-
Napi::Array result = Napi::Array::New(env);
69-
int rowIndex = 0;
70-
71-
// Itera attraverso tutte le righe del risultato
72-
while (xdb_row_t *row = xdb_fetch_row(res)) {
73-
Napi::Object rowObj = Napi::Object::New(env);
74-
75-
// Processa ogni colonna per la riga corrente
76-
for (int i = 0; i < res->col_count; ++i) {
77-
xdb_col_t *pCol = xdb_column_meta(res->col_meta, i);
78-
Napi::Value value;
79-
80-
switch (pCol->col_type) {
81-
case XDB_TYPE_INT:
82-
value = Napi::Number::New(env, xdb_column_int(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
83-
break;
84-
case XDB_TYPE_BIGINT:
85-
value = Napi::Number::New(env, xdb_column_int64(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
86-
break;
87-
case XDB_TYPE_FLOAT:
88-
value = Napi::Number::New(env, xdb_column_float(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
89-
break;
90-
case XDB_TYPE_DOUBLE:
91-
value = Napi::Number::New(env, xdb_column_double(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
92-
break;
93-
case XDB_TYPE_CHAR:
94-
value = Napi::String::New(env, xdb_column_str(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
95-
break;
96-
default:
97-
value = env.Null();
98-
break;
95+
Napi::Array result = Napi::Array::New(env);
96+
int rowIndex = 0;
97+
98+
// Itera attraverso tutte le righe del risultato
99+
while (xdb_row_t *row = xdb_fetch_row(res))
100+
{
101+
Napi::Object rowObj = Napi::Object::New(env);
102+
103+
// Processa ogni colonna per la riga corrente
104+
for (int i = 0; i < res->col_count; ++i)
105+
{
106+
xdb_col_t *pCol = xdb_column_meta(res->col_meta, i);
107+
Napi::Value value;
108+
109+
switch (pCol->col_type)
110+
{
111+
case XDB_TYPE_INT:
112+
value = Napi::Number::New(env, xdb_column_int(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
113+
break;
114+
case XDB_TYPE_BIGINT:
115+
value = Napi::Number::New(env, xdb_column_int64(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
116+
break;
117+
case XDB_TYPE_FLOAT:
118+
value = Napi::Number::New(env, xdb_column_float(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
119+
break;
120+
case XDB_TYPE_DOUBLE:
121+
value = Napi::Number::New(env, xdb_column_double(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
122+
break;
123+
case XDB_TYPE_CHAR:
124+
value = Napi::String::New(env, xdb_column_str(static_cast<uint64_t>(res->col_meta), row, static_cast<uint16_t>(i)));
125+
break;
126+
default:
127+
value = env.Null();
128+
break;
129+
}
130+
rowObj.Set(Napi::String::New(env, pCol->col_name), value);
131+
}
132+
result.Set(rowIndex++, rowObj);
99133
}
100-
rowObj.Set(Napi::String::New(env, pCol->col_name), value);
134+
135+
xdb_free_result(res); // Rilascia il risultato una volta completato
136+
results.Set(statementIndex++, result);
101137
}
102-
result.Set(rowIndex++, rowObj);
103-
}
104138

105-
xdb_free_result(res); // Rilascia il risultato una volta completato
106-
return result;
107-
}
139+
return results;
140+
}
108141

109142
void Close(const Napi::CallbackInfo &info)
110143
{

0 commit comments

Comments
 (0)