@capacitor-community/sqlite

repository·master·Indexed 20 days ago

https://github.com/capacitor-community/sqlite

A Capacitor community plugin providing SQLite database capabilities for Native (iOS/Android), Electron, and Web platforms. It supports encryption via SQLCipher on native platforms and better-sqlite3-multiple-ciphers on Electron. The plugin includes support for DDL, DML, and DQL commands, transaction control, and web persistence via jeep-sqlite and sql.js.

Tokens
54.1K
Snippets
127
Records
177
Agent score
69%

What's inside @capacitor-community/sqlite

  1. Overview of the SQLite Connection Wrapper

    master
    The @capacitor-community/sqlite plugin provides an API Connection Wrapper that manages SQLite connections across different platforms. This wrapper acts as a high-level interface to handle database initialization, connection lifecycle management (creating, retrieving, and closing), and specialized operations like encryption secret management and web store synchronization.
  2. Overview of the SQLite DB Connection Wrapper

    master
    The SQLiteDBConnection (referred to in documentation as the DB Connection Wrapper) is the primary interface for interacting with a specific SQLite database instance. It provides methods for managing the connection lifecycle (opening, closing), handling transactions (begin, commit, rollback), and executing SQL commands (query, execute, run).
  3. Connect to Non-Conformed SQLite databases in Read-Only mode

    master

    The plugin provides a set of 'Non-Conformed' (NC) methods to connect to existing SQLite databases that were created by other plugins or do not follow the standard .db extension convention.

    Important Limitations:

    • Connections created via these methods are strictly Read-Only.
    • These methods are intended for databases that do not conform to the standard plugin expectations (e.g., missing the .db extension).
  4. Understand the underlying dependencies

    master

    The plugin relies on different technologies depending on the platform to provide SQLite and encryption capabilities:

    • iOS & Android: Uses SQLCipher for database encryption.
    • iOS: Uses ZIPFoundation for unzipping asset files.
    • Electron: Uses better-sqlite3-multiple-ciphers, electron-json-storage, and node-fetch (from version 5.0.4).
    • Web: Uses the Stencil component jeep-sqlite, which is based on sql.js, localforage, and jszip.
  5. Use the RETURNING clause with RUN and EXECUTESET

    master

    The plugin supports the SQLite RETURNING clause for INSERT, DELETE, and UPDATE operations. This allows you to retrieve data from the rows that were modified by the statement.

    This functionality is implemented via the run and executeSet methods and is controlled by a mode parameter. When using RETURNING, the capSQLiteChanges result object is amended to include a values field: {changes: {changes: number, lastId: number, values: any[]}}.

    Available modes:

    • 'all': Returns all modified rows in the values array.
    • 'one': Returns only the first modified row in the values array.
    • 'no': (Default) Does not return any modifications in the values array.
    // Example of using 'all' mode with run
    const resI: any = await db.run("INSERT INTO test (name,email) VALUES ('Jeepq','jeepq@example.com') RETURNING *;", [], true, 'all');
    // resI.changes.values will contain the inserted rows
    
    // Example of using 'one' mode with executeSet
    let setUsers = [
      { statement: "INSERT INTO test (name,email) VALUES ('Valley','valley@example.com') RETURNING name;", values: [] }
    ];
    const resS2 = await db.executeSet(setUsers, false, 'one');
    // resS2.changes.values will contain the first modification
  6. Implement Incremental Database Upgrades

    master

    The @capacitor-community/sqlite plugin supports an incremental database upgrade process (introduced in version 4.1.0-6). Instead of the plugin attempting to automatically reconcile schema changes by copying tables, you define a list of incremental changes for each new version. This approach is similar to migrations in frameworks like Laravel or Doctrine.

    Each version object in your upgrade array defines a toVersion and a statements array. The plugin executes these statements sequentially for every version between the current database version and the target version. Each set of statements is executed within a transaction to ensure atomicity. If any statement fails, the plugin restores the database from a backup created before the upgrade process started.

    const version1 = {
      toVersion: 1,
      statements: [
        `CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY NOT NULL, email TEXT UNIQUE NOT NULL, name TEXT);`,
      ],
    };
    
    const version2 = {
      toVersion: 2,
      statements: [`ALTER TABLE users ADD COLUMN age INTEGER;`],
    };
    
    const version3 = {
      toVersion: 3,
      statements: [`UPDATE users SET name = 'Guest' WHERE name IS NULL;`],
    };
  7. Import/Export using JsonSQLite schema

    master

    The plugin supports importing and exporting databases using a structured JSON format defined by JsonSQLite.

    JsonSQLite Structure

    • database: Database name.
    • version: Database version.
    • overwrite: If true, deletes the existing database before importing.
    • encrypted: If true, enables database encryption.
    • mode: Set to "full" or "partial".
    • tables: Array of JsonTable objects.
    • views: Array of JsonView objects.

    JsonTable Structure

    • name: Table name.
    • schema: Array of JsonColumn objects.
    • indexes: Array of JsonIndex objects.
    • triggers: Array of JsonTrigger objects.
    • values: A 2D array (any[][]) representing the table data rows.
  8. Understand default transactional behavior in @capacitor-community/sqlite

    master

    By default, the methods execute, executeSet, and run are inherently transactional. This means each individual call is treated as a single transaction.

    While this is secure and suitable for single operations triggered by UI components, it can be significantly slow when performing a large batch of commands because each command incurs the overhead of its own transaction.

    On the Web platform, if you use the jeep-sqlite web component, the in-memory database is saved to the store after the execution of each method if the autosave property is enabled.

    const testTransactionDefault = async (db: SQLiteDBConnection) => {
      if (db !== null) {
        // Each of these is its own transaction
        await db.execute('DELETE FROM DemoTable');
        await db.run('INSERT INTO DemoTable (name, score) VALUES (?, ?);', ['Sue', 102]);
        await db.execute("INSERT INTO DemoTable (name, score) VALUES ('Andrew',415);");
        const ret = await db.executeSet(setScores);
        const retQuery = await db.query("SELECT * FROM Demotable;");
      }     
    }
  9. How the plugin handles database upgrades

    master

    When openDB is called with a version number higher than the current database version, the plugin follows a transactional process to ensure data integrity:

    1. Backup: Creates a backup file named backup-YOUR_DB_NAME.
    2. Transaction Loop: For every version between the currentVersion and the targetVersion:
      • Starts a new transaction.
      • Executes the SQL statements defined for that specific version.
      • Commits the transaction.
      • Updates the internal database version.
    3. Error Handling: If any step in the process fails, the plugin restores the database from the backup file.
    4. Cleanup: Deletes the backup file upon successful completion.
  10. Manage Encrypted Database secrets

    master

    To manage encryption for your databases, use the following parameter patterns:

    Setting a secret: When using capSetSecretOptions, provide the passphrase (string).

    Changing a secret: When using capChangeSecretOptions, you must provide both the oldpassphrase and the new passphrase (both strings).

  11. How jeep-sqlite handles data storage on the Web

    master

    When running in a web environment, jeep-sqlite uses sql.js to perform in-memory SQL queries. To persist data, it stores the database in the browser using a localforage IndexedDB store named jeepSqliteStore within a table named databases.

    Important Persistence Lifecycle: Because the queries are in-memory, the database is only moved from memory to the localforage IndexedDB store when one of the following actions is performed:

    • Calling saveToStore
    • Calling close
    • Calling closeConnection
  12. Locate SQLite databases by platform

    master

    The plugin automatically appends the suffix SQLite and the extension .db to your database name (e.g., foo becomes fooSQLite.db). If you provide a name with .db already included, the extension is removed before the suffix is added (e.g., foo.db becomes fooSQLite.db).

    Platform Locations:

    • Android: data/data/YOUR_PACKAGE/databases
    • iOS:
      • Default: The Documents folder of your application.
      • Custom: The folder specified in capacitor.config.ts via plugins.CapacitorSQLite.iosDatabaseLocation. Note that custom locations are not visible to iTunes and are not backed up to iCloud.
    • Electron:
      • Default (since 2.4.2-1): User/Databases/APP_NAME/
      • Custom (since 3.4.1): Set via capacitor.config.ts using electronMacLocation, electronWindowsLocation, or electronLinuxLocation.
    • Web:
      • Stored in browser IndexedDB as a localforage store named jeepSqliteStore in a databases table.
    // Example iOS custom location configuration
    const config: CapacitorConfig = {
      plugins: {
        CapacitorSQLite: {
          "iosDatabaseLocation": "Library/CapacitorDatabase"
        }
      }
    };
    
    // Example Electron custom location configuration
    const config: CapacitorConfig = {
      plugins: {
        CapacitorSQLite: {
          electronMacLocation: "/YOUR_DATABASES_PATH",
          electronWindowsLocation: "C:\\ProgramData\\CapacitorDatabases",
          electronLinuxLocation: "/home/CapacitorDatabases"
        }
      }
    };