Skip to content

Commit

Permalink
Refactor all error throwing code out
Browse files Browse the repository at this point in the history
  • Loading branch information
Oscar Franco committed Mar 5, 2022
2 parents e4fbe07 + 4f85109 commit b23c629
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 57 deletions.
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ Inspired/compatible with [react-native-sqlite-storage](https://github.com/andpor

## Gotchas

- **It's not possible to use a browser to debug a JSI app**, use [Flipper](https://github.com/facebook/flipper) (on android Flipper also has an integrated SQLite Database explorer).
- **Javascript cannot represent intergers larger than 53 bits**, be careful when loading data if it came from other systems. [Read more](https://github.com/ospfranco/react-native-quick-sqlite/issues/16#issuecomment-1018412991).
- **It's not possible to use a browser to debug a JSI app**, use [Flipper](https://github.com/facebook/flipper) (for android Flipper also has SQLite Database explorer).
- Your app will now include C++, you will need to install the NDK on your machine for android.
- This library supports SQLite BLOBs which are mapped to JS ArrayBuffers, check out the sample project on how to use it
- From version 2.0.0 onwards errors are no longer thrown on invalid SQL statements. The response contains a `status` number, `0` signals correct execution, `1` signals an error.
- From version 3.0.0 onwards no JS errors are thown, every operation returns an object with a `status` field.
- If you want to run the example project on android, you will have to change the paths on the android/CMakeLists.txt file, they are already there, just uncomment them.
- Starting with version 2.0.0 the library no longer throws errors when an invalid statement is passed, but returns a status (0 or 1) field in the response.
- This library cannot retrieve integers larger than 53 bits because it's not possible to represent such numbers in JavaScript. [Read more](https://github.com/ospfranco/react-native-quick-sqlite/issues/16#issuecomment-1018412991).

## Use TypeORM

Expand Down Expand Up @@ -76,19 +77,19 @@ interface ISQLite {
In your code

```typescript
// If you want to register the (globalThis) types for the low level API do an empty import
import 'react-native-quick-sqlite';

// `sqlite` is a globally registered object, so you can directly call it from anywhere in your javascript
// The methods `throw` when an execution error happens, so try/catch them
try {
sqlite.open('myDatabase', 'databases');
} catch (e) {
console.log(e); // [react-native-quick-sqlite]: Could not open database file: ERR XXX
// the import on the top of the file only registers typescript types but it is not mandatory
const dbOpenResult = sqlite.open('myDatabase', 'databases');

// status === 1, operation failed
if (dbOpenResult.status) {
console.error('Database could not be opened');
}
```

Some query examples:
### Example queries

```typescript
let result = sqlite.executeSql('myDatabase', 'SELECT somevalue FROM sometable');
Expand Down Expand Up @@ -129,7 +130,7 @@ if (!result.status) {

## Learn React Native JSI

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)
If you want to learn how to make your own JSI module buy my [JSI/C++ Cheatsheet](http://ospfranco.gumroad.com/l/IeeIvl), I'm also available for [freelance work](mailto:ospfranco@protonmail.com?subject=Freelance)!

## License

Expand Down
77 changes: 39 additions & 38 deletions cpp/react-native-quick-sqlite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ const vector<string> mapParams(jsi::Runtime &rt, jsi::Array &params)

string docPathStr;

jsi::Object createError(jsi::Runtime &rt, string message) {
auto res = jsi::Object(rt);
res.setProperty(rt, "status", jsi::Value(1));
res.setProperty(rt, "message", jsi::String::createFromUtf8(rt, message));
return res;
}

void installSequel(jsi::Runtime &rt, const char *docPath)
{

Expand All @@ -47,22 +54,19 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
[](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value
{
if(count == 0) {
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite] database name is required");
return {};
return createError(rt, "[react-native-quick-sqlite][open] database name is required");
}

if (!args[0].isString())
{
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite] database name must be a string");
return {};
return createError(rt, "[react-native-quick-sqlite][open] database name must be a string");
}

string dbName = args[0].asString(rt).utf8(rt);
string tempDocPath = string(docPathStr);
if(count > 1) {
if(!args[1].isString()) {
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite] database location must be a string");
return {};
return createError(rt, "[react-native-quick-sqlite][open] database location must be a string");
}

tempDocPath = tempDocPath + "/" + args[1].asString(rt).utf8(rt);
Expand All @@ -73,8 +77,7 @@ void installSequel(jsi::Runtime &rt, const char *docPath)

if (result.type == SequelResultError)
{
jsi::detail::throwJSError(rt, result.message.c_str());
return {};
return createError(rt, result.message.c_str());
}

return move(result.value);
Expand Down Expand Up @@ -110,20 +113,23 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
1,
[](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value
{
if(count == 0) {
return createError(rt, "[react-native-quick-sqlite][close] database name is required");
}

if (!args[0].isString())
{
jsi::detail::throwJSError(rt, "dbName must be a string");
return {};
return createError(rt, "[react-native-quick-sqlite][close] database name must be a string");
}


string dbName = args[0].asString(rt).utf8(rt);

SequelResult result = sequel_close(dbName);

if (result.type == SequelResultError)
{
jsi::detail::throwJSError(rt, result.message.c_str());
return {};
return createError(rt, result.message.c_str());
}

return move(result.value);
Expand All @@ -136,20 +142,23 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
1,
[](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value
{
if(count == 0) {
return createError(rt, "[react-native-quick-sqlite][open] database name is required");
}

if (!args[0].isString())
{
jsi::detail::throwJSError(rt, "dbName must be a string");
return {};
return createError(rt, "[react-native-quick-sqlite][open] database name must be a string");
}


string dbName = args[0].asString(rt).utf8(rt);

SequelResult result = sequel_remove(dbName, docPathStr);

if (result.type == SequelResultError)
{
jsi::detail::throwJSError(rt, result.message.c_str());
return {};
return createError(rt, result.message.c_str());
}

return jsi::Value::undefined();
Expand All @@ -169,11 +178,7 @@ void installSequel(jsi::Runtime &rt, const char *docPath)

if (result.type == SequelResultError)
{
// jsi::detail::throwJSError(rt, result.message.c_str());
auto res = jsi::Object(rt);
res.setProperty(rt, "status", jsi::Value(1));
res.setProperty(rt, "message", jsi::String::createFromUtf8(rt, result.message.c_str()));
return move(res);
return createError(rt, result.message.c_str());
}

return move(result.value);
Expand All @@ -188,16 +193,16 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
[](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value
{
if(sizeof(args) < 2) {
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite][execSQLBatch] - Incorrect parameter count");
return {};
return createError(rt, "[react-native-quick-sqlite][execSQLBatch] - Incorrect parameter count");
}

const string dbName = args[0].asString(rt).utf8(rt);
const jsi::Value &params = args[1];
if(params.isNull() || params.isUndefined())
{
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite][execSQLBatch] - An array of SQL commands or parameters is needed");
return {};
return createError(rt, "[react-native-quick-sqlite][execSQLBatch] - An array of SQL commands or parameters is needed");
}

int rowsAffected = 0;
const jsi::Array &batchParams = params.asObject(rt).asArray(rt);
try
Expand All @@ -208,8 +213,7 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
const jsi::Array &command = batchParams.getValueAtIndex(rt, i).asObject(rt).asArray(rt);
if(command.length(rt) == 0) {
sequel_execute(rt, dbName, "ROLLBACK", jsi::Value::undefined());
jsi::detail::throwJSError(rt, "[react-native-quick-sqlite][execSQLBatch] - No SQL Commands found");
return {};
return createError(rt, "[react-native-quick-sqlite][execSQLBatch] - No SQL Commands found on batch index " + std::to_string(i));
}
const string query = command.getValueAtIndex(rt, 0).asString(rt).utf8(rt);
const jsi::Value &commandParams = command.length(rt) > 1 ? command.getValueAtIndex(rt, 1) : jsi::Value::undefined();
Expand All @@ -224,10 +228,8 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
if (result.type == SequelResultError)
{
sequel_execute(rt, dbName, "ROLLBACK", jsi::Value::undefined());
auto res = jsi::Object(rt);
res.setProperty(rt, "status", jsi::Value(1));
res.setProperty(rt, "message", jsi::String::createFromUtf8(rt, result.message.c_str()));
return move(res);
return createError(rt, result.message.c_str());

} else {
if(result.value.getObject(rt).hasProperty(rt, jsi::PropNameID::forAscii(rt, "rowsAffected")))
{
Expand All @@ -240,10 +242,8 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
if (result.type == SequelResultError)
{
sequel_execute(rt, dbName, "ROLLBACK", jsi::Value::undefined());
auto res = jsi::Object(rt);
res.setProperty(rt, "status", jsi::Value(1));
res.setProperty(rt, "message", jsi::String::createFromUtf8(rt, result.message.c_str()));
return move(res);

return createError(rt, result.message.c_str());
} else {
if(result.value.getObject(rt).hasProperty(rt, jsi::PropNameID::forAscii(rt, "rowsAffected")))
{
Expand All @@ -255,7 +255,9 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
sequel_execute(rt, dbName, "COMMIT", jsi::Value::undefined());
} catch (...) {
sequel_execute(rt, dbName, "ROLLBACK", jsi::Value::undefined());
return createError(rt, "[react-native-quick-sqlite][execSQLBatch] - Unexpected error");
}

auto res = jsi::Object(rt);
res.setProperty(rt, "status", jsi::Value(0));
res.setProperty(rt, "rowsAffected", jsi::Value(rowsAffected));
Expand Down Expand Up @@ -307,11 +309,10 @@ void installSequel(jsi::Runtime &rt, const char *docPath)
} catch (...) {
sqFile.close();
sequel_execute_literal_update(dbName, "ROLLBACK");
jsi::detail::throwJSError(rt, "Unexpected error, transaction was rolledback");
return {};
return createError(rt, "[react-native-quick-sqlite][loadSQLFile] Unexpected error, transaction was rolledback");
}
} else {
jsi::detail::throwJSError(rt, "Unable to open file");
return createError(rt, "[react-native-quick-sqlite][loadSQLFile] Could not open file");
return {};
}
});
Expand Down
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ PODS:
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsinspector (0.63.4)
- react-native-quick-sqlite (1.0.5):
- react-native-quick-sqlite (2.0.3):
- React-Core
- React-RCTActionSheet (0.63.4):
- React-Core/RCTActionSheetHeaders (= 0.63.4)
Expand Down Expand Up @@ -357,7 +357,7 @@ SPEC CHECKSUMS:
React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31
React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
react-native-quick-sqlite: b86820d88ce8c0ee4b5491a2ba1ebbf807a311b4
react-native-quick-sqlite: 132b2712269190bd42c73d044b4ce941e95b6a0a
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b
React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0
Expand Down
11 changes: 9 additions & 2 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from 'react-native';
import { createDb } from './Database';
import type { User } from './model/User';
import { Buffer } from "buffer";
import { Buffer } from 'buffer';

export default function App() {
let [users, setUsers] = React.useState<User[]>([]);
Expand All @@ -36,7 +36,14 @@ export default function App() {
backgroundColor: 'white',
}}
>
<Image style={{width: 64, height: 64}} source={{uri: `data:image/png;base64,${Buffer.from(info.item.avatar).toString("base64")}`}}></Image>
<Image
style={{ width: 64, height: 64 }}
source={{
uri: `data:image/png;base64,${Buffer.from(
info.item.avatar
).toString('base64')}`,
}}
/>
<Text style={{ fontWeight: 'bold' }}>Name</Text>
<Text>{info.item.name}</Text>
<Text style={{ fontWeight: 'bold', marginTop: 10 }}>Age</Text>
Expand Down
Loading

0 comments on commit b23c629

Please sign in to comment.