SQLite - executing multiple calls within a single transaction

Greetings, I am currently working on developing a front end Single Page Application (SPA) using Typescript. I have chosen to utilize capacitorJS for cross-platform compatibility and have integrated the @capacitor-community/sqlite plugin into my project. While I am relatively experienced with databases, I am new to SQLite specifically.

My progress may be hindered by the use of a specific API over SQLite.
You can find the API documentation here: https://github.com/capacitor-community/sqlite#supported-methods

Unfortunately, the API behavior is not aligning with my expectations.

I am in search of a method that allows me to initiate a transaction, perform multiple operations within that transaction, and then either commit or roll back based on the outcomes. It would be ideal if I could execute read operations within the same transaction or at least outside it while a write transaction is active.

It appears that the wrapper provided by capacitor-community/sqlite is automatically creating a transaction for each individual call I make unless I specify otherwise using a boolean parameter. If I choose to override this default behavior, the responsibility falls on me to include the transaction logic within the SQL statement block.

Initially, I attempted to start a transaction with a statement, carry out additional API calls meant to be part of the transaction, and ultimately finalize with a command to `commit` the transaction.
For example:

async Transaction(actions: () => Promise<void>): Promise<void> {
    await SqliteService.Instance.db.execute('BEGIN TRANSACTION;', 
    try {
      await actions();
      await SqliteService.Instance.db.execute('COMMIT TRANSACTION;', false); //useTransaction = false
    } catch (e) {
      await SqliteService.Instance.db.execute('ROLLBACK TRANSACTION;', false); //useTransaction = false
      throw e;
    }

However, this approach proved unsuccessful as it seemed that the state was not maintained between calls. While certain elements like an open cursor might keep the session active, typically the session should establish and close with each API call.

Upon reflecting on the situation, it seems that submitting a single comprehensive block of SQL statements within a transaction might be necessary to achieve my desired outcome.

Therefore, I am contemplating revising my documentStore API to entail implementing a sqlBuilder type class instead of directly executing statements with SQLite. This way, when I need to perform multiple tasks within a transaction, I could concatenate various statements together.

...

Yet, I am fond of the current interface and transforming the 'write' methods on my documentStore to incorporate a sqlBuilder entity feels like a significant deviation from the original course. For instance:

async Transaction(sqlBuilder: (builder: WriteSqlBuilder<T>) => {statement: string, values: unknown[]} []) {
...

I am curious to know - how do other developers typically handle executing multiple operations (queries, writes) in SQLite within a single transaction?

Thank you!

Answer №1

It turned out that the issue I encountered was related to the behavior of the wrapper plugin capacitor-community/sqlite.

When using functions like

executeSet({sql, params}[], transaction)
, you have the option to specify whether to use a transaction or not by passing a boolean value. This is a convenient feature provided by the plugin. The default setting for the transaction parameter is true. If set to true, the wrapper library automatically adds BEGIN TRANSACTION and COMMIT TRANSACTION (and ROLLBACK TRANSACTION in case of errors) around your SQL statements within a single call.

If you explicitly set transaction to false, it will behave similar to vanilla SQLite, starting an implicit transaction for the call which is then committed after the statement execution.

The issue for me arose as I was developing my project in a web browser (for cross-platform compatibility) using the jeep-sqlite plugin. This plugin utilizes an in-memory SQLite database and provides a method saveToStore(dbName) to store the data into IndexedDB.

It seems that the problem occurred when I tried to flush the data in the middle of a transaction, causing the transaction to terminate prematurely.


To resolve this, I implemented the use of async-lock to manage access to the SQLite database wrapper and created my own

async Transaction(actions: () => Promise<void>)
method to handle the transaction operations such as BEGIN/COMMIT/ROLLBACK. Additionally, I developed some custom DocumentStore methods that are designed to work seamlessly within the transaction context.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The system does not acknowledge 'NODE_OPTIONS' as a command that can be used internally or externally, or as an operational program or batch file

While trying to build my react + vite project, I encountered an error after running npm run build. https://i.stack.imgur.com/XfeBe.png Here is a snapshot of my package.json file. https://i.stack.imgur.com/MbbmY.png ...

Pause for Progress - Angular 6

I'm looking for a solution to solve the following issue. I need to access a property that will store data from an http request. Therefore, I want to verify this property only after the transaction is completed. validateAuthorization(path: string): ...

Use Typescript in combination with React/Redux to showcase a dynamic table on the

Looking to create a React TypeScript Redux application that showcases a table using an API endpoint provided at https://example.com/users The goal is to construct a table with 4 columns: Name, Email, City, and Company, utilizing the API response to popula ...

Issue: The element p-button (and p-password) is unrecognized

After installing primeng using the command npm install primeng --save, I have version ^12.0.1 of primeng listed in both dependencies and devDependencies in my package.json file. In my angular.json file, I have included the necessary styles: "styles& ...

Steps for disabling Type 'string' does not match Type 'null'. ts (2322) & (2345) error

Is there a way to disable When I write code, I often use a null type check instead of an empty string check. However, TypeScript shows an error stating 'Type 'string' is not assignable to type 'null'.ts(2322)'. If I try to fol ...

The parent component can successfully call the setState function, but for some reason, the

In my code structure, I have the following setup (simplified): Here is the parent component: //code... const {handleClick} = useClick; <ul> {actions.map((action: string) => ( <li onClick={() => handleClick()} key={uuidv4()}> ...

Attempting to utilize Array Methods with an Array Union Type

Currently, I am in the process of refactoring an Angular application to enable strict typing. One issue I have encountered is using array methods with an array union type in our LookupService. When attempting to call const lookup = lookupConfig.find(l =&g ...

Ways to efficiently update the API_BASE_URL in a TypeScript Angular client generated by NSwag

Is it possible to dynamically change the API_BASE_URL set in my TypeScript client generated by NSWAG? I want to be able to utilize the same client with different API_BASE_URLs in separate Angular modules. Is this achievable? Thank you for your assistance. ...

What is the best way to call an Angular component function from a global function, ensuring compatibility with IE11?

Currently, I am facing a challenge while integrating the Mastercard payment gateway api into an Angular-based application. The api requires a callback for success and error handling, which is passed through the data-error and data-success attributes of the ...

What could be causing the ngOnInit() method to execute before canActivate() in this scenario

When working with route guards, I am using the canActivate() method. However, I have noticed that Angular is triggering the ngOnInit() of my root AppComponent before calling canActivate. In my scenario, I need to ensure that certain data is fetched in the ...

The type 'MutableRefObject<undefined>' cannot be assigned to the type 'LegacyRef<HTMLDivElement> | undefined'

I have created a customized hook that takes a ref object and observes its behavior: import { useState, useEffect, MutableRefObject } from "react"; const UseOnScreen = (ref: MutableRefObject<undefined>) => { const [isIntersecting, setI ...

Employing an unchanging Map format for observation

I'm currently working on implementing a synchronization mechanism using observable and Map structures from Immutable.js. However, I'm encountering an issue where the Map is unable to function as an observable or perhaps I might be approaching it ...

`Sorry, encountering issues with the ListView and Arraylist.insert() functionality`

I've been developing a note-taking app and I've encountered an issue with inserting new notes into the arraylist that stores them. Currently, I use a listview to display notes from my sqlite database, with the latest notes appearing first. To ach ...

What is the best way to reset a dropdown list value in angular?

Is there a way to erase the selected value from an Angular dropdown list using either an x button or a clear button? Thank you. Code <div fxFlex fxLayout="row" formGroupName="people"> <mat-form-field appearance=&quo ...

Is it possible for a React selector to retrieve a particular data type?

As a newcomer to React and Typescript, I am currently exploring whether a selector can be configured to return a custom type. Below is a basic selector that returns a user of type Map<string, any>: selectors/user.ts import { createSelector } from ...

Prettier seems to be producing varied outcomes across various machines

My teammate and I are collaborating on the same project, but we're facing an issue where our Prettier configurations conflict. Each time we push our code to Github, his Prettier format overrides mine. Here's an example of his formatting: const in ...

Discovering new bugs in VSCode Playwright Tests but failing to see any progress

This morning, everything was running smoothly with debugging tests. However, after a forced reboot, I encountered an issue where it seems like the debugger is running, but nothing actually happens. This has happened before, but usually resolves itself. Unf ...

How can variables from state be imported into a TypeScript file?

Utilizing vue.js along with vuetify, I have a boolean value stored in state via Vuex defined in src/store/index.ts (named darkMode). This value is used within one of my view components inside a .vue file. However, I now wish to access the same variable in ...

Divide a string using multiple delimiters just one time

Having trouble splitting a string with various delimiters just once? It can be tricky! For instance: test/date-2020-02-10Xinfo My goal is to create an array like this: [test,Date,2020-02-10,info] I've experimented with different approaches, such ...

How can I design a Typescript interface that accommodates both strings and other data types?

I am working on designing an interface that allows for an array of objects and strings to be stored. For instance: const array = [ '', {id: '', labels: ['']} ] I attempted to achieve this using the following code: export ...