open static method

Future<WasmDatabaseResult> open({
  1. required String databaseName,
  2. required Uri sqlite3Uri,
  3. required Uri driftWorkerUri,
  4. FutureOr<Uint8List?> initializeDatabase()?,
  5. WasmDatabaseSetup? localSetup,
  6. bool moveExistingIndexedDbToOpfs = false,
  7. bool enableMigrations = true,
})

Opens a database on the web.

Drift will detect features supported by the current browser and picks an appropriate implementation to store data based on those results.

Using this API requires two additional file that you need to copy into the web/ folder of your Flutter or Dart application: A sqlite3.wasm file, which you can get here, and a drift worker, which you can get here.

localSetup will be called to initialize the database only if the database will be opened directly in this JavaScript context. It is likely that the database will actually be opened in a web worker, with drift using communication mechanisms to access the database. As there is no way to send the database over to the main context, localSetup would not be called in that case. Instead, you'd have to compile a custom drift worker with a setup function - see workerMainForOpen for additional information.

When enableMigrations is set to false, drift will not check the user_version pragma when opening the database or run migrations.

If moveExistingIndexedDbToOpfs is enabled (it is currently disabled by default), drift will attempt to move existing databases from IndexedDB to OPFS. This may be useful if previous versions of browsers or your app didn't support OPFS.

For more detailed information, see https://drift.simonbinder.eu/web.

Implementation

static Future<WasmDatabaseResult> open({
  required String databaseName,
  required Uri sqlite3Uri,
  required Uri driftWorkerUri,
  FutureOr<Uint8List?> Function()? initializeDatabase,
  WasmDatabaseSetup? localSetup,
  bool moveExistingIndexedDbToOpfs = false,
  bool enableMigrations = true,
}) async {
  final probed = await probe(
    sqlite3Uri: sqlite3Uri,
    driftWorkerUri: driftWorkerUri,
    databaseName: databaseName,
  );

  // If we have an existing database in storage, we want to keep using that
  // format to avoid data loss (e.g. after a browser update that enables a
  // otherwise preferred storage implementation).
  final availableImplementations = probed.availableStorages.toList();
  // Enum values are ordered by preferrability, so just pick the best option.
  availableImplementations.sortBy<num>((e) => e.index);
  var selectedImplementation = availableImplementations.firstOrNull ??
      WasmStorageImplementation.inMemory;

  // Check if there is an existing DB and restrict implementations to its storage.
  final currentDb = _selectExistingDatabase(
    databaseName,
    availableImplementations,
    probed.existingDatabases,
  );

  // If we have an existing database, we need to use its storage API instead
  // of starting from scratch.
  if (currentDb != null && currentDb != selectedImplementation.storageApi) {
    // ... except if we want to move from IndexedDB to OPFS
    var didMove = false;
    if (currentDb == WebStorageApi.indexedDb &&
        selectedImplementation.storageApi == WebStorageApi.opfs) {
      try {
        await probed.moveFromIndexedDBToOpfs(databaseName);
        didMove = true;
      } catch (e) {
        // Ok, we'll keep using the old database then.
      }
    }

    if (!didMove) {
      selectedImplementation = availableImplementations
          .firstWhere((e) => e.storageApi == currentDb);
    }
  }

  final connection = await probed.open(
    selectedImplementation,
    databaseName,
    localSetup: localSetup,
    initializeDatabase: initializeDatabase,
    enableMigrations: enableMigrations,
  );

  return WasmDatabaseResult(
      connection, selectedImplementation, probed.missingFeatures);
}