Skip to content

Commit e4fbe07

Browse files
author
Oscar Franco
committed
Merge branch 'sql_loader'
# Conflicts: # cpp/react-native-quick-sqlite.cpp # src/index.ts
2 parents 50c0bea + 699ab1d commit e4fbe07

File tree

5 files changed

+171
-4
lines changed

5 files changed

+171
-4
lines changed

cpp/SequelResult.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@ struct SequelResult
2828
string message;
2929
jsi::Value value;
3030
};
31+
32+
struct SequelLiteralUpdateResult
33+
{
34+
ResultType type;
35+
string message;
36+
int affectedRows;
37+
};

cpp/react-native-quick-sqlite.cpp

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <vector>
1515
#include <iostream>
1616
#include <thread>
17+
#include <iostream>
18+
#include <fstream>
1719

1820
using namespace std;
1921
using namespace facebook;
@@ -177,6 +179,7 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
177179
return move(result.value);
178180
});
179181

182+
// Execute a batch of SQL queries in a transaction
180183
// Parameters can be: [[sql: string, arguments: any[] | arguments: any[][] ]]
181184
auto execSQLBatch = jsi::Function::createFromHostFunction(
182185
rt,
@@ -258,6 +261,60 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
258261
res.setProperty(rt, "rowsAffected", jsi::Value(rowsAffected));
259262
return move(res);
260263
});
264+
265+
// Load SQL File from disk
266+
auto loadSQLFile = jsi::Function::createFromHostFunction(
267+
rt,
268+
jsi::PropNameID::forAscii(rt, "sequel_loadSQLFile"),
269+
2,
270+
[](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value
271+
{
272+
const string dbName = args[0].asString(rt).utf8(rt);
273+
const string sqlFileName = args[1].asString(rt).utf8(rt);
274+
275+
string line;
276+
ifstream sqFile (sqlFileName);
277+
if (sqFile.is_open())
278+
{
279+
try {
280+
int affectedRows = 0;
281+
int commands = 0;
282+
sequel_execute_literal_update(dbName, "BEGIN TRANSACTION");
283+
while ( std::getline (sqFile, line, '\n') )
284+
{
285+
if (!line.empty()) {
286+
SequelLiteralUpdateResult result = sequel_execute_literal_update(dbName, line);
287+
if( result.type == SequelResultError ) {
288+
sequel_execute_literal_update(dbName, "ROLLBACK");
289+
auto res = jsi::Object(rt);
290+
res.setProperty(rt, "status", jsi::Value(1));
291+
res.setProperty(rt, "message", jsi::String::createFromUtf8(rt, result.message.c_str()));
292+
sqFile.close();
293+
return move(res);
294+
} else {
295+
affectedRows += result.affectedRows;
296+
commands++;
297+
}
298+
}
299+
}
300+
sqFile.close();
301+
sequel_execute_literal_update(dbName, "COMMIT");
302+
auto res = jsi::Object(rt);
303+
res.setProperty(rt, "status", jsi::Value(0));
304+
res.setProperty(rt, "rowsAffected", jsi::Value(affectedRows));
305+
res.setProperty(rt, "commands", jsi::Value(commands));
306+
return move(res);
307+
} catch (...) {
308+
sqFile.close();
309+
sequel_execute_literal_update(dbName, "ROLLBACK");
310+
jsi::detail::throwJSError(rt, "Unexpected error, transaction was rolledback");
311+
return {};
312+
}
313+
} else {
314+
jsi::detail::throwJSError(rt, "Unable to open file");
315+
return {};
316+
}
317+
});
261318

262319
// Async Execute SQL
263320
// auto asyncExecSQL = jsi::Function::createFromHostFunction(
@@ -292,18 +349,18 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
292349
// return promise;
293350
// });
294351

295-
// Create final object that will be injected into the global object
352+
// Global object
296353
jsi::Object module = jsi::Object(rt);
297354

298-
// Open/Close
355+
356+
// Callable properties
299357
module.setProperty(rt, "open", move(open));
300358
module.setProperty(rt, "close", move(close));
301359
// module.setProperty(rt, "attach", move(attach));
302360
module.setProperty(rt, "delete", move(remove));
303-
304361
module.setProperty(rt, "executeSql", move(execSQL));
305362
module.setProperty(rt, "executeSqlBatch", move(execSQLBatch));
306-
363+
module.setProperty(rt, "loadSqlFile", move(loadSQLFile));
307364
// module.setProperty(rt, "backgroundExecuteSql", move(asyncExecSQL));
308365

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

cpp/sequel.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,3 +429,79 @@ SequelResult sequel_execute(jsi::Runtime &rt, string const dbName, string const
429429
"",
430430
move(res)};
431431
}
432+
433+
SequelLiteralUpdateResult sequel_execute_literal_update(string const dbName, string const &query)
434+
{
435+
// Check if db connection is opened
436+
if (dbMap.count(dbName) == 0)
437+
{
438+
return {
439+
SequelResultError,
440+
"[react-native-quick-sqlite] Database not opened: " + dbName,
441+
0
442+
};
443+
}
444+
445+
sqlite3 *db = dbMap[dbName];
446+
447+
// SQLite statements need to be compiled before executed
448+
sqlite3_stmt *statement;
449+
450+
// Compile and move result into statement memory spot
451+
int statementStatus = sqlite3_prepare_v2(db, query.c_str(), -1, &statement, NULL);
452+
453+
if (statementStatus != SQLITE_OK) // statemnet is correct, bind the passed parameters
454+
{
455+
const char *message = sqlite3_errmsg(db);
456+
return {
457+
SequelResultError,
458+
"[react-native-quick-sqlite] SQL execution error: " + string(message),
459+
0
460+
};
461+
}
462+
463+
bool isConsuming = true;
464+
bool isFailed = false;
465+
466+
int result, i, count, column_type;
467+
string column_name;
468+
469+
while (isConsuming)
470+
{
471+
result = sqlite3_step(statement);
472+
473+
switch (result)
474+
{
475+
case SQLITE_ROW:
476+
isConsuming = true;
477+
break;
478+
479+
case SQLITE_DONE:
480+
isConsuming = false;
481+
break;
482+
483+
default:
484+
isFailed = true;
485+
isConsuming = false;
486+
}
487+
}
488+
489+
sqlite3_finalize(statement);
490+
491+
if (isFailed)
492+
{
493+
const char *message = sqlite3_errmsg(db);
494+
return {
495+
SequelResultError,
496+
"[react-native-quick-sqlite] SQL execution error: " + string(message),
497+
0
498+
};
499+
}
500+
501+
int changedRowCount = sqlite3_changes(db);
502+
return {
503+
SequelResultOk,
504+
"",
505+
changedRowCount
506+
};
507+
}

cpp/sequel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ SequelResult sequel_remove(string const dbName, string const docPath);
2424
//SequelResult sequel_attach(string const &dbName);
2525

2626
SequelResult sequel_execute(jsi::Runtime &rt, string const dbName, string const &query, jsi::Value const &params);
27+
28+
SequelLiteralUpdateResult sequel_execute_literal_update(string const dbName, string const &query);

src/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ interface BatchQueryResult {
5151
message?: string;
5252
}
5353

54+
/**
55+
* Result of loading a file and executing every line as a SQL command
56+
* Similar to BatchQueryResult
57+
*/
58+
interface FileLoadResult {
59+
rowsAffected?: number;
60+
commands?: number;
61+
message?: string;
62+
status?: 0 | 1;
63+
}
64+
5465
interface ISQLite {
5566
open: (dbName: string, location?: string) => any;
5667
close: (dbName: string) => any;
@@ -63,6 +74,7 @@ interface ISQLite {
6374
dbName: string,
6475
commands: SQLBatchParams[]
6576
) => BatchQueryResult;
77+
loadSqlFile: (dbName: string, location: string) => FileLoadResult;
6678
// backgroundExecuteSql: (dbName: string, query: string, params: any[]) => any;
6779
}
6880

@@ -86,6 +98,10 @@ interface IDBConnection {
8698
callback?: (res: BatchQueryResult) => void
8799
) => void;
88100
close: (ok: (res: any) => void, fail: (msg: string) => void) => void;
101+
loadSqlFile: (
102+
location: string,
103+
callback: (result: FileLoadResult) => void
104+
) => void;
89105
}
90106

91107
export const openDatabase = (
@@ -132,6 +148,15 @@ export const openDatabase = (
132148
fail(e);
133149
}
134150
},
151+
loadSqlFile: (
152+
location: string,
153+
callback: (result: FileLoadResult) => void
154+
) => {
155+
const result = sqlite.loadSqlFile(options.name, location);
156+
if (callback) {
157+
callback(result);
158+
}
159+
},
135160
};
136161

137162
ok(connection);

0 commit comments

Comments
 (0)