openDatabase function

Future<DatabaseOwner> openDatabase(
  1. String path, {
  2. bool directoryEntriesDurable = true,
  3. bool wal = false,
  4. int? version,
  5. OnDatabaseConfigure? onConfigure,
  6. OnDatabaseCreate? onCreate,
  7. OnDatabaseVersionChange? onUpgrade,
  8. OnDatabaseVersionChange? onDowngrade,
  9. OnDatabaseOpen? onOpen,
})

Opens a database file on its own isolate.

A missing database file is written as an empty image, and a missing -journal is written empty, unless wal is true. An existing database file is not replaced. directoryEntriesDurable defaults to true. Passing false writes nothing and throws. That flag is the caller attestation that the directory entries are durable. It is not a power-loss result. wal still requires the -wal sidecar and does not create it.

version runs onCreate when the stored version is 0, onUpgrade when it is older, and onDowngrade when it is newer. The schema change and the new version commit together. Integers in rows and insert ids are BigInt.

Implementation

Future<DatabaseOwner> openDatabase(
  String path, {
  bool directoryEntriesDurable = true,
  bool wal = false,
  int? version,
  OnDatabaseConfigure? onConfigure,
  OnDatabaseCreate? onCreate,
  OnDatabaseVersionChange? onUpgrade,
  OnDatabaseVersionChange? onDowngrade,
  OnDatabaseOpen? onOpen,
}) async {
  if (version != null && version < 1) {
    throw ArgumentError.value(version, 'version', 'version starts at 1');
  }
  if (version != null && onCreate == null) {
    throw ArgumentError('onCreate is required when version is set');
  }
  if (!directoryEntriesDurable) {
    throw UnsupportedError('Durably provision database and sidecar first');
  }
  if (!wal) await _provisionRollback(path);
  final owner =
      await DatabaseOwner.open(path, directoryEntriesDurable: true, wal: wal);
  try {
    if (onConfigure != null) await onConfigure(owner);
    if (version != null) {
      await owner.transaction((txn) async {
        final current = await owner._app.readUserVersion();
        if (current == 0) {
          await onCreate!(owner, version);
        } else if (current < version) {
          if (onUpgrade == null) {
            throw StateError(
                'Database version $current is older than $version');
          }
          await onUpgrade(owner, current, version);
        } else if (current > version) {
          if (onDowngrade == null) {
            throw StateError(
                'Database version $current is newer than $version');
          }
          await onDowngrade(owner, current, version);
        }
        if (current != version) {
          await txn.execute('PRAGMA user_version = $version');
        }
      });
    }
    if (onOpen != null) await onOpen(owner);
    return owner;
  } catch (_) {
    await owner.close();
    rethrow;
  }
}