watchFloor method

Stream<CampusMapFloorData> watchFloor(
  1. String layerName
)

Watches cached geometry for one published layerName.

A missing or 14-day-old floor refreshes once per subscription. Errors retain cached spaces; CampusMapFloorData.hasCache distinguishes an empty floor from a failed first load. Other buildings and floors are never fetched.

Implementation

Stream<CampusMapFloorData> watchFloor(String layerName) {
  var attempted = false;
  final query = _db.select(_db.campusMapFloors).join([
    innerJoin(
      _db.campusMapBuildings,
      _db.campusMapBuildings.code.equalsExp(_db.campusMapFloors.building),
    ),
    leftOuterJoin(
      _db.campusMapRooms,
      _db.campusMapRooms.layerName.equalsExp(_db.campusMapFloors.layerName),
    ),
  ])..where(_db.campusMapFloors.layerName.equals(layerName));
  List<(MapFloorRecord, MapBuildingRecord, MapRoomRecord?)> snapshot(
    List<TypedResult> rows,
  ) => [
    for (final row in rows)
      (
        row.readTable(_db.campusMapFloors),
        row.readTable(_db.campusMapBuildings),
        row.readTableOrNull(_db.campusMapRooms),
      ),
  ];
  // Stream transforms propagate cancellation to Drift even while idle.
  // Filtering inside async* would leave an idle await-for waiting forever
  // after an unrelated-floor update was discarded.
  return query
      .watch()
      .asyncMap((rows) async {
        final floor = rows.firstOrNull?.readTable(_db.campusMapFloors);
        if (floor?.fetchedAt == null && !attempted) {
          attempted = true;
          try {
            await refreshFloor(layerName);
            return await query.get();
          } catch (_) {
            // Retain hasCache=false so the screen offers a retry.
          }
        }
        final stamp = floor?.fetchedAt;
        if (!attempted &&
            (stamp == null || _now().difference(stamp) >= _cacheTtl)) {
          attempted = true;
          unawaited(
            refreshFloor(layerName).catchError((Object _) {
              // Retain stale geometry already in this snapshot.
            }),
          );
        }
        return rows;
      })
      .distinct(
        (previous, next) =>
            const ListEquality().equals(snapshot(previous), snapshot(next)),
      )
      .map(
        (rows) => CampusMapFloorData(
          rooms: [
            for (final row in rows)
              if (row.readTableOrNull(_db.campusMapRooms)?.geometry != null)
                _room(row),
          ],
          hasCache:
              rows.firstOrNull?.readTable(_db.campusMapFloors).fetchedAt !=
              null,
        ),
      );
}