From 6dc3e9569a5908e45a1c2565736e1f170c0ebbdc Mon Sep 17 00:00:00 2001 From: fbachus Date: Tue, 28 Jul 2026 02:16:46 +0200 Subject: [PATCH] feat(transport_helper): store full departures inside segment build out fromMap constructor so that departure and vehicle objects are created from db query rename vehicle.id to vehicle.vehicleid to conform with the rule that id=internal & type int | {tablename}id=api_id & type String --- lib/transport_helper.dart | 171 ++++++++++++++++++++++++++------------ 1 file changed, 117 insertions(+), 54 deletions(-) diff --git a/lib/transport_helper.dart b/lib/transport_helper.dart index eb2becd..acda9b7 100644 --- a/lib/transport_helper.dart +++ b/lib/transport_helper.dart @@ -119,9 +119,11 @@ class Route { /// recalculate some technically redundant data for fast and easy access void sync() async { if (segments.isNotEmpty) { - startStation = segments.first.startPoint.name; - endStation = segments.last.endPoint.name; - duration = segments.first.startTime.difference(segments.last.endTime); + startStation = segments.first.start.stationName; + endStation = segments.last.end.stationName; + duration = segments.first.start.departureTime.difference( + segments.last.end.arrivalTime, + ); } else { // if the route has no segments yet, at least the startStation should remain, // otherwise delete the thing @@ -154,7 +156,9 @@ class Route { void replaceSegment(int idx, Segment replacement) { if ((idx < segments.length - 1 && replacement._fitsBetween(segments[idx - 1], segments[idx + 1])) || - replacement.startTime.isAfter(segments[idx - 1].endTime)) { + replacement.start.departureTime.isAfter( + segments[idx - 1].end.arrivalTime, + )) { segments[idx] = replacement; _dbUpdateRouteSegments(); } else if (idx >= segments.length) { @@ -314,30 +318,28 @@ class Segment { // TODO: add attribute for departures on the way? int? id; String ref; - Station startPoint; - Station endPoint; - DateTime startTime; - DateTime endTime; + Departure start; + Departure end; + // Station startPoint; + // Station endPoint; + // DateTime startTime; + // DateTime endTime; Vehicle vehicle; Segment({ this.id, // might throw errors - needs testing, I guess required this.ref, - required this.startPoint, - required this.endPoint, - required this.startTime, - required this.endTime, + required this.start, + required this.end, required this.vehicle, }); Map toMap() { return { "ref": ref, - "startpoint": startPoint.id, - "endpoint": endPoint.id, - "starttime": startTime, - "endtime": endTime, - "vehicle": vehicle.id, + "startid": start.id, + "endid": end.id, + "vehicleid": vehicle.vehicleid, }; } @@ -345,62 +347,123 @@ class Segment { return Segment( id: map["id"] as int, ref: map["ref"] as String, - startPoint: map["startPoint"] as Station, - endPoint: map["endPoint"] as Station, - startTime: map["startTime"] as DateTime, - endTime: map["endTime"] as DateTime, - vehicle: map["vehicle"] as Vehicle, + start: Departure.fromMap( + map["start"] as Map, + ), + end: Departure.fromMap( + map["end"] as Map, + ), + vehicle: Vehicle.fromMap(map["vehicle"] as Map), ); } factory Segment.fromJson(Map json) { Segment tmp = Segment( ref: json["JourneyDetail"]["ref"], - startPoint: Station.fromJson(json["Origin"]), - endPoint: Station.fromJson(json["Destination"]), - startTime: json["Origin"]["rtTime"], - endTime: json["Destination"]["rtTime"], + start: Departure.fromJson(json["Origin"]), + end: Departure.fromJson(json["Destination"]), vehicle: Vehicle.fromJson(json["Product"]), ); tmp.dbInsert(); return tmp; } + Future fromDepartures(Departure start, Departure end) async { + Segment tmp = Segment( + ref: start.ref, + start: start, + end: end, + vehicle: await Vehicle.dbGet(start.vehicleId), + ); + tmp.dbInsert(); + return tmp; + } + bool _fitsBetween(Segment prev, Segment next) { - return startTime.isAfter(prev.endTime) && endTime.isBefore(next.startTime); + return start.departureTime.isAfter(prev.end.arrivalTime) && + start.arrivalTime.isBefore(next.end.departureTime); } bool _sameEndpoints(Segment other) { - return startPoint == other.startPoint && endPoint == other.endPoint; + return start.stationId == other.start.stationId && + end.stationId == other.end.stationId; } static void initSegmentTable() async { Database database = DbHelper.db; String station = Station.tableName; String vehicle = Vehicle.tableName; + String departure = Departure.tableName; database.execute(""" CREATE TABLE IF NOT EXISTS '$tableName'( id INTEGER PRIMARY KEY AUTOINCREMENT, ref TEXT, - startpoint TEXT, - endpoint TEXT, - starttime TEXT, - endtime TEXT, - vehicle INTEGER, - FOREIGN KEY(startpoint) REFERENCES '$station'(stationid), - FOREIGN KEY(endpoint) REFERENCES '$station'(stationid), - FOREIGN KEY(vehicle) REFERENCES '$vehicle'(vehicleid) + startid TEXT, + endid TEXT, + vehicleid INTEGER, + FOREIGN KEY(startid) REFERENCES '$departure'(stationid), + FOREIGN KEY(endid) REFERENCES '$departure'(stationid), + FOREIGN KEY(vehicleid) REFERENCES '$vehicle'(vehicleid) ); """); } static Future dbGet(int id) async { Database database = DbHelper.db; - var tmp = await database.query(tableName, where: "id = ?", whereArgs: [id]); - var seg = tmp.map((x) => Segment.fromMap(x)); - //since we are querying for the primary key, this list should never be > 1 - assert(seg.length < 2, "found more than one segment for id $id"); - return seg.first; + String vehicle = Vehicle.tableName; + String departure = Departure.tableName; + var tmp = await database.rawQuery( + """SELECT s.id, s.ref, s.startid, s.endid, s.vehicleid, + start.station as start_stationid, + start.stationname as start_stationname, start.arrivaltime as start_arrivaltime, + start.departuretime as start_departuretime, + end.station as end_stationid, end.stationname as end_stationname, + end.arrivaltime as end_arrivaltime, end.departuretime as end_departuretime, + v.name as vehiclename, v.line as vehicleline + FROM $tableName s + JOIN $departure start ON s.startid = start.id + JOIN $departure end ON s.endid = end.id + JOIN $vehicle v ON s.vehicleid = v.id; + """, + ); + // since we are querying for the primary key, this list should never be > 1 + assert(tmp.length < 2, "found more than one segment for id $id"); + // var seg = tmp.map((x) => Segment.fromMap(x)); + // return seg.first; + + var seg = tmp.first; + var fullMap = { + "id": seg["id"], + "ref": seg["ref"], + "start": { + "id": seg["startid"] as int, + "ref": seg["ref"] as String, + "direction": seg["direction"] as String, + "vehicle": seg["vehicleid"] as String, + "vehiclename": seg["vehiclename"] as String, + "station": seg["start_stationid"] as String, + "staionname": seg["start_stationname"] as String, + "arrivaltime": seg["start_arrivalTime"] as String, + "departuretime": seg["start_departuretime"] as String, + }, + "end": { + "id": seg["endid"] as int, + "ref": seg["ref"] as String, + "direction": seg["direction"] as String, + "vehicle": seg["vehicleid"] as String, + "vehiclename": seg["vehiclename"] as String, + "station": seg["end_stationid"] as String, + "staionname": seg["end_stationname"] as String, + "arrivaltime": seg["end_arrivalTime"] as String, + "departuretime": seg["end_departuretime"] as String, + }, + "vehicle": { + "id": seg["vehicleid"] as String, + "name": seg["vehiclename"] as String, + "line": seg["vehicleline"] as String, + }, + }; + return Segment.fromMap(fullMap); } static Future> dbGetAll() async { @@ -423,7 +486,7 @@ class Segment { id = await database.update( tableName, toMap(), - where: "rowid =?", + where: "id =?", whereArgs: [id], ); } @@ -432,7 +495,7 @@ class Segment { Database database = DbHelper.db; database.delete( tableName, - where: "rowid = ?", + where: "id = ?", whereArgs: [id], ); } @@ -587,19 +650,19 @@ class Station { class Vehicle { static const String tableName = "vehicle"; - String id; + String vehicleid; String name; String vehicleLineId; Vehicle({ - required this.id, + required this.vehicleid, required this.name, required this.vehicleLineId, }); Map _toMap() { return { - "id": id, + "id": vehicleid, "name": name, "line": vehicleLineId, }; @@ -609,7 +672,7 @@ class Vehicle { Map map, ) { return Vehicle( - id: map["id"] as String, + vehicleid: map["id"] as String, name: map["name"] as String, vehicleLineId: map["line"] as String, ); @@ -618,7 +681,7 @@ class Vehicle { // we can use the "product" class from within any JSON response // (within hafas API, on the appropriate level) factory Vehicle.fromJson(Map json) => Vehicle( - id: json["num"], + vehicleid: json["num"], name: json["name"], vehicleLineId: Line.fromJson(json).lineId, ); @@ -627,7 +690,7 @@ class Vehicle { Database database = DbHelper.db; String line = Line.tableName; database.execute("""CREATE TABLE IF NOT EXISTS '$tableName'( - id TEXT PRIMARY KEY, + vehicleid TEXT PRIMARY KEY, name TEXT, line TEXT, FOREIGN KEY(line) REFERENCES '$line'(lineid) @@ -656,12 +719,12 @@ class Vehicle { void dbUpdate() async { Database database = DbHelper.db; - database.update(tableName, _toMap(), where: "id=?", whereArgs: [id]); + database.update(tableName, _toMap(), where: "id=?", whereArgs: [vehicleid]); } void dbDelete() async { Database database = DbHelper.db; - database.delete(tableName, where: "id = ?", whereArgs: [id]); + database.delete(tableName, where: "id = ?", whereArgs: [vehicleid]); } } @@ -882,7 +945,7 @@ class Departure { direction: json["direction"] ?? json["Directions"]["Direction"][0]["value"], // this is not healthy - vehicleId: vehicle.id, + vehicleId: vehicle.vehicleid, vehicleName: vehicle.name, stationId: station.id, stationName: station.name, @@ -908,8 +971,8 @@ class Departure { stationname TEXT, arrivaltime TEXT, departuretime TEXT, - FOREIGN KEY(vehicle) REFERENCES '$vehicle'(id), - FOREIGN KEY(station) REFERENCES '$station'(id) + FOREIGN KEY(vehicle) REFERENCES '$vehicle'(vehicleid), + FOREIGN KEY(station) REFERENCES '$station'(stationid) ); """); }