sqflite Documentation

repository·master·Indexed 13 days ago

https://github.com/tekartik/sqflite

A Flutter plugin providing SQLite database support for mobile (iOS, Android) and desktop platforms. It features background thread execution for database operations, transaction and batch support, and automatic version management. The ecosystem includes sqflite_common_ffi for Linux, Windows, and DartVM support, sqflite_ffi for cross-isolate database sharing, and sqflite_darwin for Apple platforms.

Tokens
29.1K
Snippets
94
Records
171
Agent score
83%

What's inside sqflite

  1. Overview of sqflite

    master
    sqflite is a SQLite plugin for Flutter that supports iOS, Android, and MacOS. It provides features such as transaction and batch support, automatic version management during database opening, and helpers for common CRUD operations (insert, query, update, delete). Database operations are executed in a background thread on iOS and Android. For Linux, Windows, or DartVM support, use the sqflite_common_ffi package.
  2. Use sqflite_ffi for cross-isolate database sharing

    master
    The sqflite_ffi plugin provides an FFI-based implementation for Flutter that allows all isolates in an application (including the main isolate, compute, and Isolate.run) to share the same sqflite isolate. This ensures that database instances are shared across isolates, making the singleInstance property work globally across your application. It is built upon sqflite_common_ffi.
  3. Understand the sqflite Method Call Protocol

    master
    The sqflite method call protocol defines the communication schema used across different implementations, including the standard sqflite plugin, sqflite_common_ffi isolate communication, and sqflite_common_ffi_web web worker communication. It specifies the input (in) and output (out) structures for core database operations.
  4. Manage database concurrency and transactions

    master

    Concurrency

    sqflite protects every read, write, and transaction operation with a global mutex. Operations are executed sequentially in the order they were called.

    Transactions

    The transaction method ensures an 'all or nothing' execution. If any command within the transaction block fails and throws an error, all other commands executed during that transaction are automatically reverted. You can also manually throw an error to cancel a transaction.

  5. Use sqflite_common/sqlite_api.dart for platform-agnostic shared logic

    master

    If you are developing a Dart package containing shared logic that must run across both Flutter mobile apps and desktop binaries, you can import sqflite_common/sqlite_api.dart directly. This allows your shared logic to remain platform-agnostic.

    In your platform-dependent packages, you would then use the specific implementations:

    • Use sqflite for Flutter apps.
    • Use sqflite_common_ffi for desktop binaries.
  6. Access the database from multiple Isolates

    master

    By default, database access should be performed in the main isolate. The sqflite native access already occurs on a background native thread, and the transaction mechanism is not cross-isolate safe.

    If you must access the database from a separate isolate (such as a push notification isolate or a scheduled task), follow these guidelines:

    1. In both the main isolate and the background isolate:
      • Use singleInstance: false in openDatabase.
      • Do not close the database.
    2. To mitigate hot reload failures when using singleInstance: false, you can try using singleInstance: true in the main isolate only.
  7. Implement SQL logging with sqflite_logger

    master

    To log database activities, implement a logger function that accepts a SqfliteLoggerEvent and use SqfliteDatabaseFactoryLogger to wrap your existing database factory.

    There are 6 types of events you can handle:

    • SqfliteLoggerSqlEvent: For individual SQL commands. Access sql, arguments, error, and sw (stopwatch/elapsed time).
    • SqfliteLoggerBatchEvent: For batch operations. Iterate through event.operations to access individual operation details.
    • SqfliteLoggerDatabaseOpenEvent
    • SqfliteLoggerDatabaseCloseEvent
    • SqfliteLoggerDatabaseDeleteEvent
    • SqfliteLoggerInvokeEvent

    Use SqfliteLoggerOptions to configure the logger, setting the log callback and the type (e.g., SqfliteDatabaseFactoryLoggerType.all).

    import 'package:sqflite_common/sqflite_logger.dart';
    import 'package:sqflite_common_ffi/sqflite_ffi.dart';
    
    // 1. Define your logger function
    void _logger(SqfliteLoggerEvent event) {
      if (event is SqfliteLoggerSqlEvent) {
        print('sql: ${event.sql}${event.arguments != null ? ' ${event.arguments}' : ''}');
      } else if (event is SqfliteLoggerBatchEvent) {
        for (var operation in event.operations) {
          print('sql(batch): ${operation.sql}${operation.arguments != null ? ' ${operation.arguments}' : ''}');
        }
      }
    }
    
    // 2. Wrap your factory with SqfliteDatabaseFactoryLogger
    final factoryWithLogs = SqfliteDatabaseFactoryLogger(
      databaseFactoryFfi, // Your existing factory
      options: SqfliteLoggerOptions(
        log: _logger,
        type: SqfliteDatabaseFactoryLoggerType.all,
      ),
    );
    
    // 3. Use the wrapped factory to open databases
    var db = await factoryWithLogs.openDatabase(inMemoryDatabasePath);
  8. Write unit tests for Flutter using sqflite_common_ffi

    master

    To use your existing sqflite code in Flutter tests, you must replace the global default Flutter database factory with the FFI implementation. This is typically done within a setUpAll block by initializing FFI and assigning databaseFactoryFfi to databaseFactory.

    import 'package:flutter_test/flutter_test.dart';
    import 'package:sqflite_common_ffi/sqflite_ffi.dart';
    import 'package:sqflite/sqflite.dart';
    
    Future main() async {
      // Setup sqflite_common_ffi for flutter test
      setUpAll(() {
        // Initialize FFI
        sqfliteFfiInit();
        // Change the default factory
        databaseFactory = databaseFactoryFfi;
      });
    
      test('Simple test', () async {
        var db = await openDatabase(inMemoryDatabasePath, version: 1,
            onCreate: (db, version) async {
          await db
              .execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, value TEXT)');
        });
        // Insert some data
        await db.insert('Test', {'value': 'my_value'});
        // Check content
        expect(await db.query('Test'), [
          {'id': 1, 'value': 'my_value'}
        ]);
    
        await db.close();
      });
    }
  9. Workarounds for unsupported types (bool and DateTime)

    master

    Certain common Dart types are not directly supported by SQLite and require manual conversion:

    Boolean (bool)

    SQLite does not have a bool type. Use INTEGER columns and store values as 0 (false) or 1 (true).

    Date and Time (DateTime)

    DateTime is not a supported SQLite type. Use one of these two strategies:

    1. Store as int: Save the value as millisecondsSinceEpoch.
    2. Store as String: Save the value as an ISO8601 string.

    Note: If using the TIMESTAMP type in SQLite, values are read back as String, which your application must then parse.