Skip to content

Commit

Permalink
Add Documentation SQLiteTransaction.md and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jepiqueau committed Mar 12, 2024
1 parent a9c2aa0 commit 4d5a7f2
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 13 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# 5.6.3 (2024-03-12)

### Added Features

- Add SQLite Transactions Documentation SQLiteTransaction.md

### Bug Fixes

- Fix Error in executeTransaction

# 5.6.2 (2024-03-07)

### Added Features
Expand Down
Binary file modified android/.gradle/buildOutputCleanup/buildOutputCleanup.lock
Binary file not shown.
18 changes: 13 additions & 5 deletions docs/APIDBConnection.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,13 @@ Remove rows with sql_deleted = 1 after an export
### executeTransaction(...)

```typescript
executeTransaction(txn: { statement: string; values?: any[]; }[], isSQL92: boolean) => Promise<capSQLiteChanges>
executeTransaction(txn: capTask[], isSQL92: boolean) => Promise<capSQLiteChanges>
```

| Param | Type |
| ------------- | ----------------------------------------------------- |
| **`txn`** | <code>{ statement: string; values?: any[]; }[]</code> |
| **`isSQL92`** | <code>boolean</code> |
| Param | Type |
| ------------- | ---------------------- |
| **`txn`** | <code>capTask[]</code> |
| **`isSQL92`** | <code>boolean</code> |

**Returns:** <code>Promise&lt;<a href="#capsqlitechanges">capSQLiteChanges</a>&gt;</code>

Expand Down Expand Up @@ -610,4 +610,12 @@ executeTransaction(txn: { statement: string; values?: any[]; }[], isSQL92: boole
| **`name`** | <code>string</code> | The view name |
| **`value`** | <code>string</code> | The view create statement |


#### capTask

| Prop | Type | Description |
| --------------- | ------------------- | --------------------------------------------------- |
| **`statement`** | <code>string</code> | A SQLite statement |
| **`values`** | <code>any[]</code> | A set of values to bind to the statement (optional) |

</docgen-api>
158 changes: 158 additions & 0 deletions docs/SQLiteTransaction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<p align="center"><br><img src="https://user-images.githubusercontent.com/236501/85893648-1c92e880-b7a8-11ea-926d-95355b8175c7.png" width="128" height="128" /></p>
<h2 align="center">SQLite Transaction DOCUMENTATION</h2>
<p align="center"><strong><code>@capacitor-community/sqlite</code></strong></p>
<p align="center">
Capacitor community plugin for Native and Electron SQLite Databases. For <strong>Native</strong> and <strong>Electron</strong> platforms, databases could be encrypted with SQLCipher</p>


## SQLite Transaction

### By Default

The three SQLite methods <strong>(execute, executeSet, and run)</strong> in the `@capacitor-community/sqlite` plugin are inherently transactional.
On the Web platform, the in-memory database is saved in the store after the execution of each method if you enable the autosave property of the jeep-sqlite web component.

This approach is suitable and secure when the methods are executed from a UI component. However, it can be notably slow when dealing with a batch of commands.

Code example:

```ts
const testTransactionDefault = async (db: SQLiteDBConnection) => {
setLog(prevLog => prevLog + '### Start Transaction Default ###\n');

if (db !== null) {
// Delete all data if any
await db.execute('DELETE FROM DemoTable');

// run command
let insertQuery = 'INSERT INTO DemoTable (name, score) VALUES (?, ?);';
let bindValues = ["Sue", 102];
let ret = await db.run(insertQuery, bindValues);
console.log(`>>> run ret 1: ${JSON.stringify(ret)}`)
// execute command
const statements = `
INSERT INTO DemoTable (name, score) VALUES ('Andrew',415);
INSERT INTO DemoTable (name, score) VALUES ('Josh',310);
INSERT INTO DemoTable (name, score) VALUES ('Billy',253);
`;
ret = await db.execute(statements);
console.log(`>>> execute ret 1: ${JSON.stringify(ret)}`)

// executeSet command
ret = await db.executeSet(setScores);
console.log(`>>> executeSet 1 ret: ${JSON.stringify(ret)}`)

let selectQuery = "SELECT * /* all columns */ FROM Demotable;";
const retQuery = await db.query(selectQuery);
console.log(`>>> query All retQuery: ${JSON.stringify(retQuery)}`)

}
setLog(prevLog => prevLog + '### End Test Transaction Default ###\n');

}
```

### For Batch of Commands

Since the release of version 5.0.7 of the @capacitor-community/sqlite plugin, several new methods have been introduced to aid developers in efficiently managing the transactional flow process:

- beginTransaction
- commitTransaction
- rollbackTransaction
- isTransactionActive

Now the transactional process flow will resemble the following:

```ts
const testTransactionManage = async (db: SQLiteDBConnection) => {
setLog(prevLog => prevLog + '### Start Transaction Manage ###\n');
if (db !== null) {
await db.beginTransaction();
const isTransAct = await db.isTransactionActive();
if(!isTransAct) {
throw new Error('db Transaction not Active');
}
try {
// run command
let insertQuery = 'INSERT INTO DemoTable (name, score) VALUES (?, ?);';
let bindValues = ["Betty", 152];
let ret = await db.run(insertQuery, bindValues, false);
console.log(`>>> run ret 2: ${JSON.stringify(ret)}`)
// execute command
const statements = `
INSERT INTO DemoTable (name, score) VALUES ('Aimie',115);
INSERT INTO DemoTable (name, score) VALUES ('Test1',330);
INSERT INTO DemoTable (name, score) VALUES ('George',223);
`;
ret = await db.execute(statements,false);
console.log(`>>> execute ret 2: ${JSON.stringify(ret)}`)

// executeSet command
ret = await db.executeSet(setScores1,false);
console.log(`>>> executeSet 2 ret: ${JSON.stringify(ret)}`)


// Commit Transaction
await db.commitTransaction()
if (platform === 'web') {
await sqliteServ.saveToStore(dbName);
}
setLog(prevLog => prevLog + '### Commit Test Transaction Manage ###\n');
} catch (err) {
console.log(`in catch : ${err}`)
// Rollback Transaction
await db.rollbackTransaction()
setLog(prevLog => prevLog + '### RollBack Test Transaction Manage ###\n');

} finally {
let selectQuery = "SELECT * /* all columns */ FROM Demotable;";
const retQuery = await db.query(selectQuery);
console.log(`>>> query All retQuery2: ${JSON.stringify(retQuery)}`)
setLog(prevLog => prevLog + '### End Test Transaction Manage ###\n');
}
}
}
```

### Using executeTransaction method

This method has been updated to utilize the new techniques outlined in the `For Batch of Commands` chapter. It accepts a collection of tasks of type `capTask` as its input parameter.

```ts
const testExecuteTransaction = async (db: SQLiteDBConnection) => {
setLog(prevLog => prevLog + '### Start Execute Transaction ###\n');
if (db !== null) {
const txn: any[] = [];
// Create the task set
txn.push({statement:'DELETE FROM DemoTable;'});
const stmt = 'INSERT INTO DemoTable (name, score) VALUES (?, ?);';
for (let i=0; i<100; i++ ) {
const values = [`test${i}`, getRandomNumber(1, 1000)];
txn.push({statement: stmt, values: values});
}
txn.push({statement: "DELETE FROM DemoTable WHERE name='test50';"});
txn.push({statement:"UPDATE DemoTable SET score = ? WHERE name = ?",
values:[152,"test10"]});
try {
// execute the transaction for that task set
const ret = await db.executeTransaction(txn);
console.log(`testExecuteTransaction ret: ${JSON.stringify(ret)}`);
setLog(prevLog => prevLog + '### Test ExecuteTransaction successfull###\n');

} catch(err:any) {
const msg = err.message ? err.message : err;
console.log(`testExecuteTransaction msg: ${msg}`)
setLog(prevLog => prevLog + `### Test ExecuteTransaction failed : ${msg} ###\n`);

} finally {
let selectQuery = "SELECT * /* all columns */ FROM Demotable;";
const retQuery = await db.query(selectQuery);
console.log(`>>> query All retQuery3: ${JSON.stringify(retQuery)}`)
setLog(prevLog => prevLog + '### End Test ExecuteTransaction ###\n');
}

}
}
```


8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,6 @@
}
},
"dependencies": {
"jeep-sqlite": "^2.6.0"
"jeep-sqlite": "^2.6.1"
}
}
23 changes: 20 additions & 3 deletions src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,20 @@ export interface capSQLiteQueryOptions {
*/
isSQL92?: boolean;
}
export interface capTask {
/**
* define task for executeTransaction
* @since 5.6.3
*/
/**
* A SQLite statement
*/
statement: string;
/**
* A set of values to bind to the statement (optional)
*/
values?: any[];
}
export interface capSQLiteImportOptions {
/**
* Set the JSON object to import
Expand Down Expand Up @@ -2000,7 +2014,7 @@ export interface ISQLiteDBConnection {
* @since 3.4.0
*/
executeTransaction(
txn: { statement: string; values?: any[] }[],
txn: capTask[],
isSQL92: boolean,
): Promise<capSQLiteChanges>;
}
Expand Down Expand Up @@ -2389,7 +2403,7 @@ export class SQLiteDBConnection implements ISQLiteDBConnection {
}

async executeTransaction(
txn: { statement: string; values?: any[] }[],
txn: capTask[],
isSQL92 = true,
): Promise<capSQLiteChanges> {
let changes = 0;
Expand All @@ -2412,7 +2426,10 @@ export class SQLiteDBConnection implements ISQLiteDBConnection {
}
try {
for (const task of txn) {
if (task.values && task.values.length > 0) {
if(typeof task !== 'object' || !('statement' in task)) {
throw new Error('Error a task.statement must be provided');
}
if ('values' in task && task.values && task.values.length > 0) {
const retMode = task.statement.toUpperCase().includes('RETURNING')
? 'all'
: 'no';
Expand Down

0 comments on commit 4d5a7f2

Please sign in to comment.