Skip to content

Commit 810c75c

Browse files
author
Oscar Franco
authored
Merge pull request #41 from ospfranco/transactions
2 parents 11d2916 + 36ddaa6 commit 810c75c

29 files changed

Lines changed: 444 additions & 191 deletions

File tree

.editorconfig

Lines changed: 0 additions & 15 deletions
This file was deleted.

README.md

Lines changed: 76 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
<h1 align="center">React Native Quick SQLite</h1>
2-
31
![screenshot](https://raw.githubusercontent.com/ospfranco/react-native-quick-sqlite/main/header.png)
42

53
<div align="center">
@@ -24,7 +22,7 @@
2422
</div>
2523
<br />
2624

27-
This library embeds the latest version of SQLite and provides a low-level API to execute SQL queries, fast bindings via [JSI](https://formidable.com/blog/2019/jsi-jsc-part-2). By using the latest version of SQLite instead of the phone's you get all the latest security fixes and also all new features.
25+
Quick SQLite embeds the latest version of SQLite and provides a low-level API to execute SQL queries, uses fast bindings via [JSI](https://formidable.com/blog/2019/jsi-jsc-part-2). By using an embedded SQLite you get access the latest security patches and latest features.
2826

2927
Inspired/compatible with [react-native-sqlite-storage](https://github.com/andpor/react-native-sqlite-storage) and [react-native-sqlite2](https://github.com/craftzdog/react-native-sqlite-2).
3028

@@ -57,14 +55,11 @@ interface QueryResult {
5755
/**
5856
* Column metadata
5957
* Describes some information about columns fetched by the query
58+
* columnDeclaredType - declared column type for this column, when fetched directly from a table or a View resulting from a table column. "UNKNOWN" for dynamic values, like function returned ones.
6059
*/
61-
declare type ColumnMetadata = {
62-
/** The name used for this column for this resultset */
60+
interface ColumnMetadata = {
6361
columnName: string;
64-
/** The declared column type for this column, when fetched directly from a table or a View resulting from a table column. "UNKNOWN" for dynamic values, like function returned ones. */
6562
columnDeclaredType: string;
66-
/**
67-
* The index for this column for this resultset*/
6863
columnIndex: number;
6964
};
7065

@@ -108,13 +103,13 @@ interface ISQLite {
108103

109104
# Usage
110105

106+
Import as early as possible, auto-installs bindings in a thread-safe manner.
107+
111108
```typescript
112-
// Import as early as possible, auto-installs bindings.
113109
// Thanks to @mrousavy for this installation method, see one example: https://github.com/mrousavy/react-native-mmkv/blob/75b425db530e26cf10c7054308583d03ff01851f/src/createMMKV.ts#L56
114110
import 'react-native-quick-sqlite';
115111

116-
// `sqlite` is a globally registered object, so you can directly call it from anywhere in your javascript
117-
// the import on the top of the file only registers typescript types but it is not mandatory
112+
// Afterwards `sqlite` is a globally registered object, so you can directly call it from anywhere in your javascript
118113
const dbOpenResult = sqlite.open('myDatabase', 'databases');
119114

120115
// status === 1, operation failed
@@ -123,51 +118,56 @@ if (dbOpenResult.status) {
123118
}
124119
```
125120

126-
### Example queries
121+
### Simple queries
122+
123+
The basic query is **synchronous**, it will block rendering on large operations, below there are async versions.
127124

128125
```typescript
129-
let result = sqlite.executeSql('myDatabase', 'SELECT somevalue FROM sometable');
130-
if (!result.status) {
131-
// result.status undefined or 0 === sucess
132-
for (let i = 0; i < result.rows.length; i++) {
133-
const row = result.rows.item(i);
134-
console.log(row.somevalue);
135-
}
126+
let { status, rows } = sqlite.executeSql(
127+
'myDatabase',
128+
'SELECT somevalue FROM sometable'
129+
);
130+
if (!status) {
131+
rows.forEach((row) => {
132+
console.log(row);
133+
});
136134
}
137135

138-
result = sqlite.executeSql(
136+
let { status, rowsAffected } = sqlite.executeSql(
139137
'myDatabase',
140-
'UPDATE sometable set somecolumn = ? where somekey = ?',
138+
'UPDATE sometable SET somecolumn = ? where somekey = ?',
141139
[0, 1]
142140
);
143-
if (!result.status) {
144-
// result.status undefined or 0 === sucess
145-
console.log(`Update affected ${result.rowsAffected} rows`);
141+
if (!status) {
142+
console.log(`Update affected ${rowsAffected} rows`);
146143
}
147144
```
148145

149-
In some scenarios, dynamic applications may need to get some metadata information about the returned resultset.
150-
This can be done testing the returned data directly, but in some cases may not be enough, like when data is stored outside
151-
storage datatypes, like booleans or datetimes. When fetching data directly from tables or views linked to table columns, SQLite is able
152-
to identify the table declared types:
146+
### Transactions
147+
148+
Transactions are supported. However, due to the library being opionionated and mostly not throwing errors you need to return a boolean (true for correct exceution, false for incorrect execution) to either commit or rollback the transaction.
149+
150+
JSI bindings are fast but there is still some overhead calling `executeSql` for single queries, if you want to execute a large set of commands as fast as possible you should use the `executeSqlBatch` method below, it still uses transactions, but only transmits data between JS and native once.
153151

154152
```typescript
155-
let result = sqlite.executeSql(
156-
'myDatabase',
157-
'SELECT int_column_1, bol_column_2 FROM sometable'
158-
);
159-
if (!result.status) {
160-
// result.status undefined or 0 === sucess
161-
for (let i = 0; i < result.metadata.length; i++) {
162-
const column = result.metadata[i];
163-
console.log(`${column.columnName} - ${column.columnDeclaredType}`);
164-
// Output:
165-
// int_column_1 - INTEGER
166-
// bol_column_2 - BOOLEAN
153+
sqlite.transaction('myDatabase', (tx) => {
154+
const {
155+
status,
156+
} = tx.executeSql('UPDATE sometable SET somecolumn = ? where somekey = ?', [
157+
0,
158+
1,
159+
]);
160+
161+
if (status) {
162+
return false;
167163
}
168-
}
164+
165+
return true;
166+
});
169167
```
170168

169+
### Batch operation
170+
171171
Batch execution allows transactional execution of a set of commands
172172

173173
```typescript
@@ -184,14 +184,44 @@ if (!result.status) {
184184
}
185185
```
186186

187-
Async versions are also available if you have too much SQL to execute
187+
### Dynamic Column Metadata
188+
189+
In some scenarios, dynamic applications may need to get some metadata information about the returned result set.
190+
191+
This can be done testing the returned data directly, but in some cases may not be enough, for example when data is stored outside
192+
sqlite datatypes. When fetching data directly from tables or views linked to table columns, SQLite is able
193+
to identify the table declared types:
194+
195+
```typescript
196+
let { status, metadata } = sqlite.executeSql(
197+
'myDatabase',
198+
'SELECT int_column_1, bol_column_2 FROM sometable'
199+
);
200+
if (!status) {
201+
metadata.forEach((column) => {
202+
// Output:
203+
// int_column_1 - INTEGER
204+
// bol_column_2 - BOOLEAN
205+
console.log(`${column.columnName} - ${column.columnDeclaredType}`);
206+
});
207+
}
208+
```
209+
210+
### Async operations
211+
212+
You might have too much SQL too process and it will cause your application to freeze. There are async versions for some of the operations. This will offload the SQLite processing to a different thread.
188213

189214
```ts
190-
sqlite.asyncExecuteSql('myDatabase', 'SELECT * FROM "User";', [], (result) => {
191-
if (result.status === 0) {
192-
console.log('users', result.rows);
215+
sqlite.asyncExecuteSql(
216+
'myDatabase',
217+
'SELECT * FROM "User";',
218+
[],
219+
({ status, rows }) => {
220+
if (status === 0) {
221+
console.log('users', rows);
222+
}
193223
}
194-
});
224+
);
195225
```
196226

197227
## Use TypeORM

example/android/app/src/main/java/com/example/reactnativesequel/MainActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ public class MainActivity extends ReactActivity {
1010
*/
1111
@Override
1212
protected String getMainComponentName() {
13-
return "SequelExample";
13+
return "QuickSQLiteExample";
1414
}
1515
}

example/app.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"name": "SequelExample",
3-
"displayName": "Sequel Example"
2+
"name": "QuickSQLiteExample",
3+
"displayName": "Quick SQLite Example"
44
}

example/ios/Podfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ PODS:
228228
- React-jsinspector (0.67.3)
229229
- React-logger (0.67.3):
230230
- glog
231-
- react-native-quick-sqlite (3.0.2):
231+
- react-native-quick-sqlite (3.0.4):
232232
- React
233233
- React-callinvoker
234234
- React-Core
@@ -431,7 +431,7 @@ SPEC CHECKSUMS:
431431
React-jsiexecutor: 15ea57ead631a11fad57634ff69f78e797113a39
432432
React-jsinspector: 1e1e03345cf6d47779e2061d679d0a87d9ae73d8
433433
React-logger: 1e10789cb84f99288479ba5f20822ce43ced6ffe
434-
react-native-quick-sqlite: d8d711b42c9df78e1983a02d5f29cd541a78b713
434+
react-native-quick-sqlite: 6e2ccab68e66b0a09f1ce5b7eeae097d32230ec5
435435
React-perflogger: 93d3f142d6d9a46e635f09ba0518027215a41098
436436
React-RCTActionSheet: 87327c3722203cc79cf79d02fb83e7332aeedd18
437437
React-RCTAnimation: 009c87c018d50e0b38692699405ebe631ff4872d
@@ -446,6 +446,6 @@ SPEC CHECKSUMS:
446446
ReactCommon: 650e33cde4fb7d36781cd3143f5276da0abb2f96
447447
Yoga: 90dcd029e45d8a7c1ff059e8b3c6612ff409061a
448448

449-
PODFILE CHECKSUM: 23fbb34cc9cd3db2810e5bb10e37bce3ce025dee
449+
PODFILE CHECKSUM: 21282804cb7b559416f2717812c3f6c182daa539
450450

451-
COCOAPODS: 1.11.2
451+
COCOAPODS: 1.11.3

example/ios/SequelExample.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@
297297
"-ObjC",
298298
"-lc++",
299299
);
300-
PRODUCT_BUNDLE_IDENTIFIER = com.example.reactnativequicksqlite;
300+
PRODUCT_BUNDLE_IDENTIFIER = com.ospfranco.quicksqlite;
301301
PRODUCT_NAME = SequelExample;
302302
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
303303
SWIFT_VERSION = 5.0;
@@ -321,7 +321,7 @@
321321
"-ObjC",
322322
"-lc++",
323323
);
324-
PRODUCT_BUNDLE_IDENTIFIER = com.example.reactnativequicksqlite;
324+
PRODUCT_BUNDLE_IDENTIFIER = com.ospfranco.quicksqlite;
325325
PRODUCT_NAME = SequelExample;
326326
SWIFT_VERSION = 5.0;
327327
VERSIONING_SYSTEM = "apple-generic";

example/ios/SequelExample/AppDelegate.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
1010
{
1111
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
1212
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
13-
moduleName:@"SequelExample"
13+
moduleName:@"QuickSQLiteExample"
1414
initialProperties:nil];
1515

1616
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,62 @@
11
{
22
"images" : [
33
{
4+
"filename" : "Icon-20@2x.png",
45
"idiom" : "iphone",
5-
"size" : "29x29",
6-
"scale" : "2x"
6+
"scale" : "2x",
7+
"size" : "20x20"
78
},
89
{
10+
"filename" : "Icon-20@3x.png",
911
"idiom" : "iphone",
10-
"size" : "29x29",
11-
"scale" : "3x"
12+
"scale" : "3x",
13+
"size" : "20x20"
1214
},
1315
{
16+
"filename" : "Icon-29@2x.png",
1417
"idiom" : "iphone",
15-
"size" : "40x40",
16-
"scale" : "2x"
18+
"scale" : "2x",
19+
"size" : "29x29"
1720
},
1821
{
22+
"filename" : "Icon-29@3x.png",
1923
"idiom" : "iphone",
20-
"size" : "40x40",
21-
"scale" : "3x"
24+
"scale" : "3x",
25+
"size" : "29x29"
2226
},
2327
{
28+
"filename" : "Icon-40@2x.png",
2429
"idiom" : "iphone",
25-
"size" : "60x60",
26-
"scale" : "2x"
30+
"scale" : "2x",
31+
"size" : "40x40"
2732
},
2833
{
34+
"filename" : "Icon-40@3x.png",
2935
"idiom" : "iphone",
30-
"size" : "60x60",
31-
"scale" : "3x"
36+
"scale" : "3x",
37+
"size" : "40x40"
38+
},
39+
{
40+
"filename" : "Icon-60@2x.png",
41+
"idiom" : "iphone",
42+
"scale" : "2x",
43+
"size" : "60x60"
44+
},
45+
{
46+
"filename" : "Icon-60@3x.png",
47+
"idiom" : "iphone",
48+
"scale" : "3x",
49+
"size" : "60x60"
50+
},
51+
{
52+
"filename" : "Icon-1024.png",
53+
"idiom" : "ios-marketing",
54+
"scale" : "1x",
55+
"size" : "1024x1024"
3256
}
3357
],
3458
"info" : {
35-
"version" : 1,
36-
"author" : "xcode"
59+
"author" : "xcode",
60+
"version" : 1
3761
}
38-
}
62+
}
139 KB
Loading
1.38 KB
Loading

0 commit comments

Comments
 (0)