diff --git a/lib/database/database.dart b/lib/database/database.dart index 2180aa4..a1b0041 100644 --- a/lib/database/database.dart +++ b/lib/database/database.dart @@ -1,10 +1,10 @@ import 'dart:io'; +import 'dart:math'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as p; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:uuid/uuid.dart'; import 'tables.dart'; @@ -15,7 +15,7 @@ class AppDatabase extends _$AppDatabase { AppDatabase() : super(_openConnection()); AppDatabase.forTesting(super.e); - static const _uuid = Uuid(); + static final Random _random = Random.secure(); @override int get schemaVersion => 6; @@ -67,23 +67,56 @@ class AppDatabase extends _$AppDatabase { } catch (_) {} } if (from < 6) { + // Nullable during migration so existing installations can be upgraded + // without losing rides. We immediately backfill every existing ride + // with a stable random identifier that is independent of local ID. await m.addColumn(rides, rides.cloudRideId); - final existingRides = await select(rides).get(); - for (final ride in existingRides) { - final cloudId = 'ride_${_uuid.v4()}'; - await (update(rides)..where((r) => r.id.equals(ride.id))).write( - RidesCompanion(cloudRideId: Value(cloudId)), + final rows = await customSelect('SELECT id FROM rides').get(); + for (final row in rows) { + await customStatement( + 'UPDATE rides SET cloud_ride_id = ? WHERE id = ?', + [_newCloudRideId(), row.data['id']], ); } } }, ); + String _newCloudRideId() { + final bytes = List.generate(16, (_) => _random.nextInt(256)); + final hex = bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); + return 'ride_$hex'; + } + + /// Returns the persisted stable MotorCloud identity for a local ride. + /// Uses raw SQL until `database.g.dart` is regenerated; this keeps the + /// migration deployable without hand-editing generated Drift output. + Future getCloudRideId(int rideId) async { + final rows = await customSelect( + 'SELECT cloud_ride_id FROM rides WHERE id = ?', + variables: [Variable(rideId)], + ).get(); + if (rows.isEmpty) return null; + return rows.first.data['cloud_ride_id'] as String?; + } + + Future ensureCloudRideId(int rideId) async { + final existing = await getCloudRideId(rideId); + if (existing != null && existing.isNotEmpty) return existing; + final created = _newCloudRideId(); + await customStatement( + 'UPDATE rides SET cloud_ride_id = ? WHERE id = ?', + [created, rideId], + ); + return created; + } + Future startRide() async { - return into(rides).insert(RidesCompanion.insert( - cloudRideId: Value('ride_${_uuid.v4()}'), + final id = await into(rides).insert(RidesCompanion.insert( startTime: DateTime.now(), )); + await ensureCloudRideId(id); + return id; } Future endRide(int rideId, RidesCompanion data) async {