Skip to content

Commit 9b25d79

Browse files
author
Oscar Franco
authored
Merge pull request #24 from EduFrazao/sql_batch
2 parents ba33ed2 + 629b181 commit 9b25d79

3 files changed

Lines changed: 149 additions & 7 deletions

File tree

README.md

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,16 @@ It is also possible to directly execute SQL against the db:
5050
```typescript
5151
interface ISQLite {
5252
open: (dbName: string, location?: string) => any;
53-
close: (dbName: string, location?: string) => any;
53+
close: (dbName: string) => any;
5454
executeSql: (
5555
dbName: string,
5656
query: string,
5757
params: any[] | undefined
58-
) => {
59-
status: 0 | 1; // 0 for correct execution
60-
message: string; // if status === 1, here you will find error description
61-
rows: any[];
62-
insertId?: number;
63-
};
58+
) => QueryResult;
59+
executeSqlBatch: (
60+
dbName: string,
61+
commands: SQLBatchParams[]
62+
) => BatchExecutionResult;
6463
}
6564
```
6665

@@ -79,6 +78,36 @@ try {
7978
}
8079
```
8180

81+
Some query examples:
82+
```typescript
83+
let result = sqlite.executeSql('myDatabase', 'SELECT somevalue FROM sometable');
84+
if(!result.status) { // result.status undefined or 0 === sucess
85+
for(let i = 0; i<result.rows.length; i++) {
86+
const row = result.rows.item(i);
87+
console.log(row.somevalue);
88+
}
89+
}
90+
91+
result = sqlite.executeSql('myDatabase', 'UPDATE sometable set somecolumn = ? where somekey = ?', [0, 1]);
92+
if(!result.status) { // result.status undefined or 0 === sucess
93+
console.log(`Update affected ${result.rowsAffected} rows`);
94+
}
95+
```
96+
97+
Bulkupdate allows transactional execution of a set of commands
98+
```typescript
99+
const commands = [
100+
['CREATE TABLE TEST (id integer)'],
101+
['INSERT INTO TABLE TEST (id) VALUES (?)', [1]]
102+
['INSERT INTO TABLE TEST (id) VALUES (?)', [2]]
103+
['INSERT INTO TABLE TEST (id) VALUES (?)', [[3], [4], [5], [6]]]
104+
];
105+
const result = sqlite.executeSqlBatch('myDatabase', commands);
106+
if(!result.status) { // result.status undefined or 0 === sucess
107+
console.log(`Batch affected ${result.rowsAffected} rows`);
108+
}
109+
```
110+
82111
## JSI Cheatsheet
83112

84113
If you want to learn how to make your own JSI module and also get a reference guide for all things C++/JSI you can buy my [JSI/C++ Cheatsheet](http://ospfranco.gumroad.com/l/IeeIvl)

cpp/react-native-quick-sqlite.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,88 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
177177
return move(result.value);
178178
});
179179

180+
// Parameters can be: [[sql: string, arguments: any[] | arguments: any[][] ]]
181+
auto execSQLBatch = jsi::Function::createFromHostFunction(
182+
rt,
183+
jsi::PropNameID::forAscii(rt, "sequel_execSQLBatch"),
184+
2,
185+
[](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value
186+
{
187+
if(sizeof(args) < 2) {
188+
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite][execSQLBatch] - Incorrect parameter count");
189+
return {};
190+
}
191+
const string dbName = args[0].asString(rt).utf8(rt);
192+
const jsi::Value &params = args[1];
193+
if(params.isNull() || params.isUndefined())
194+
{
195+
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite][execSQLBatch] - An array of SQL commands or parameters is needed");
196+
return {};
197+
}
198+
int rowsAffected = 0;
199+
const jsi::Array &batchParams = params.asObject(rt).asArray(rt);
200+
try
201+
{
202+
sequel_execute(rt, dbName, "BEGIN TRANSACTION", jsi::Value::undefined());
203+
for(int i = 0; i<batchParams.length(rt); i++)
204+
{
205+
const jsi::Array &command = batchParams.getValueAtIndex(rt, i).asObject(rt).asArray(rt);
206+
if(command.length(rt) == 0) {
207+
sequel_execute(rt, dbName, "ROLLBACK", jsi::Value::undefined());
208+
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite][execSQLBatch] - No SQL Commands found");
209+
return {};
210+
}
211+
const string query = command.getValueAtIndex(rt, 0).asString(rt).utf8(rt);
212+
const jsi::Value &commandParams = command.length(rt) > 1 ? command.getValueAtIndex(rt, 1) : jsi::Value::undefined();
213+
if(!commandParams.isUndefined() && commandParams.asObject(rt).isArray(rt) && commandParams.asObject(rt).asArray(rt).length(rt) > 0 && commandParams.asObject(rt).asArray(rt).getValueAtIndex(rt, 0).isObject())
214+
{
215+
// This arguments are an array of arrays, like a batch update of a single sql command.
216+
const jsi::Array &batchUpdateParams = commandParams.asObject(rt).asArray(rt);
217+
for(int x = 0; x<batchUpdateParams.length(rt); x++)
218+
{
219+
const jsi::Value &p = batchUpdateParams.getValueAtIndex(rt, x);
220+
SequelResult result = sequel_execute(rt, dbName, query, p);
221+
if (result.type == SequelResultError)
222+
{
223+
sequel_execute(rt, dbName, "ROLLBACK", jsi::Value::undefined());
224+
auto res = jsi::Object(rt);
225+
res.setProperty(rt, "status", jsi::Value(1));
226+
res.setProperty(rt, "message", jsi::String::createFromUtf8(rt, result.message.c_str()));
227+
return move(res);
228+
} else {
229+
if(result.value.getObject(rt).hasProperty(rt, jsi::PropNameID::forAscii(rt, "rowsAffected")))
230+
{
231+
rowsAffected += result.value.getObject(rt).getProperty(rt, jsi::PropNameID::forAscii(rt, "rowsAffected")).asNumber();
232+
}
233+
}
234+
}
235+
} else {
236+
SequelResult result = sequel_execute(rt, dbName, query, commandParams);
237+
if (result.type == SequelResultError)
238+
{
239+
sequel_execute(rt, dbName, "ROLLBACK", jsi::Value::undefined());
240+
auto res = jsi::Object(rt);
241+
res.setProperty(rt, "status", jsi::Value(1));
242+
res.setProperty(rt, "message", jsi::String::createFromUtf8(rt, result.message.c_str()));
243+
return move(res);
244+
} else {
245+
if(result.value.getObject(rt).hasProperty(rt, jsi::PropNameID::forAscii(rt, "rowsAffected")))
246+
{
247+
rowsAffected += result.value.getObject(rt).getProperty(rt, jsi::PropNameID::forAscii(rt, "rowsAffected")).asNumber();
248+
}
249+
}
250+
}
251+
}
252+
sequel_execute(rt, dbName, "COMMIT", jsi::Value::undefined());
253+
} catch (...) {
254+
sequel_execute(rt, dbName, "ROLLBACK", jsi::Value::undefined());
255+
}
256+
auto res = jsi::Object(rt);
257+
res.setProperty(rt, "status", jsi::Value(0));
258+
res.setProperty(rt, "rowsAffected", jsi::Value(rowsAffected));
259+
return move(res);
260+
});
261+
180262
// Async Execute SQL
181263
// auto asyncExecSQL = jsi::Function::createFromHostFunction(
182264
// rt,
@@ -220,6 +302,8 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
220302
module.setProperty(rt, "delete", move(remove));
221303

222304
module.setProperty(rt, "executeSql", move(execSQL));
305+
module.setProperty(rt, "executeSqlBatch", move(execSQLBatch));
306+
223307
// module.setProperty(rt, "backgroundExecuteSql", move(asyncExecSQL));
224308

225309
rt.global().setProperty(rt, "sqlite", move(module));

src/index.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ interface QueryResult {
3131
item: (idx: number) => any;
3232
};
3333
}
34+
35+
/**
36+
* Allows the execution of bulk of sql commands
37+
* inside a transaction
38+
* If a single query must be executed many times with different arguments, its preferred
39+
* to declare it a single time, and use an array of array parameters.
40+
*/
41+
type SQLBatchParams = [string, Array<any> | Array<Array<any>> | undefined];
42+
43+
/**
44+
* status: 0 or undefined for correct execution, 1 for error
45+
* message: if status === 1, here you will find error description
46+
* rowsAffected: Number of affected rows if status == 0
47+
*/
48+
interface BatchExecutionResult {
49+
status?: 0 | 1;
50+
rowsAffected?: number;
51+
message?: string;
52+
}
53+
3454
interface ISQLite {
3555
open: (dbName: string, location?: string) => any;
3656
close: (dbName: string) => any;
@@ -39,6 +59,10 @@ interface ISQLite {
3959
query: string,
4060
params: any[] | undefined
4161
) => QueryResult;
62+
executeSqlBatch: (
63+
dbName: string,
64+
commands: SQLBatchParams[]
65+
) => BatchExecutionResult;
4266
// backgroundExecuteSql: (dbName: string, query: string, params: any[]) => any;
4367
}
4468

@@ -57,6 +81,7 @@ interface IDBConnection {
5781
ok: (res: QueryResult) => void,
5882
fail: (msg: string) => void
5983
) => void;
84+
executeSqlBatch: (commands: SQLBatchParams[], callback?: (res: BatchExecutionResult) => void) => void;
6085
close: (ok: (res: any) => void, fail: (msg: string) => void) => void;
6186
}
6287

@@ -89,6 +114,10 @@ export const openDatabase = (
89114
fail(e);
90115
}
91116
},
117+
executeSqlBatch: (commands: SQLBatchParams[], callback?: (res: BatchExecutionResult) => void) => {
118+
const response = sqlite.executeSqlBatch(options.name, commands);
119+
if (callback) callback(response);
120+
},
92121
close: (ok: any, fail: any) => {
93122
try {
94123
sqlite.close(options.name);

0 commit comments

Comments
 (0)