DatabaseAdapter class

One database, described by what flutterware may do with it.

DatabaseAdapter(
  query: (sql, args) => db.getAll(sql, args),
  updates: db.updates.map((u) => u.tables),
  watch: (sql) => db.watch(sql),
)

A database that is not open yet

Plenty of apps have no database at runApp: it is opened at login, closed at logout, and replaced when the user switches environment. There is nothing to hand this constructor at the moment the devbar is built.

The adapter is the shape; the session is the data. Close over the lookup rather than over the database, and resolve it inside each function:

DatabaseAdapter(
  query: (sql, args) => _db().getAll(sql, args),
  watch: (sql) => _db().watch(sql),
  updates: _updates.stream,
)

Database _db() {
  var db = session?.database;
  if (db == null) {
    throw DatabaseUnavailable('No session is open — sign in to reach the '
        'database.');
  }
  return db;
}

Two things about that are not optional. Presence is read once, when the panel is described: an adapter that leaves execute null while logged out declares an app with no write door, permanently, and the same goes for watch and updates. Pass every function the app will ever offer, and let the ones with nothing to work on throw. And updates is the one field that cannot be resolved late — it is a stream, handed over once, not a function called per query. Own a broadcast controller that outlives every session and forward the current database into it:

final _updates = StreamController<Set<String>>.broadcast();
StreamSubscription<void>? _forwarding;

void _sessionChanged(Session? session) {
  unawaited(_forwarding?.cancel());
  _forwarding = session?.database.updates
      .listen((update) => _updates.add(update.tables));
}

Why a panel that answers rather than one that disappears. The other shape — declaring the panel only while a session is open, which AddDevbarPanel and DevbarPanels make possible — leaves the absence unexplained. Ask for db:main when it is gone and every surface says the same thing, "this app declares no panel db:main", whether the app has no database at all or the user is one tap from opening one. A panel that is always listed and answers DatabaseUnavailable tells those apart, and it is the same call flutterware makes for an app that never reached runApp: say what is wrong, do not go missing.

Constructors

DatabaseAdapter({String name = 'main', required DatabaseQuery query, Stream<Set<String>>? updates, DatabaseWatch? watch, DatabaseQuery? execute, DatabaseSync? sync})

Properties

execute → DatabaseQuery?
Presence is the write opt-in. No function, no execute action, on any surface — an agent cannot even see it.
final
hashCode → int
The hash code for this object.
no setterinherited
name → String
Names the panel — db:main — and nothing else. Two databases are two adapters with two names.
final
query → DatabaseQuery
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
sync → DatabaseSync?
The sync engine that keeps this database, when one does. Said, not guessed: an app on plain sqlite gets nothing it has no use for.
final
updates → Stream<Set<String>>?
Table names touched, per write transaction. Feeds the changes feed and the watch fallback; without it neither exists.
final
watch → DatabaseWatch?
Optional native live query. When absent, a watch falls back to re-running its SQL on every coalesced updates tick — correct, just wasteful.
final

Methods

noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toString() → String
A string representation of this object.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited