diff --git a/lib/transport_helper.dart b/lib/transport_helper.dart index 431d3a0..6737652 100644 --- a/lib/transport_helper.dart +++ b/lib/transport_helper.dart @@ -37,120 +37,106 @@ class DbHelper { Station.initStationTable(); Vehicle.initVehicleTable(); Departure.initDepartureTable(); - Route.updateHighestId(); } } +/// this class covers two database tables: "route" and "routesegments" +/// while route will for now only hold an id, routesegments will store the +/// m-n/ 1-n relations between routes and segments - the segments contain the most +/// relevant info, while routesegments stores which route the segments belong to +/// and in which order they make up a route class Route { - static int highestId = 0; - static const String tableName = "route"; - - int id; + // TODO: add last_viewed, last_modified and such + int? id; List segments = List.empty(); Duration duration = Duration(minutes: 0); Route({ - required this.id, + this.id, required this.segments, required this.duration, }); + /// toMap for Route but it's just route ids for now + Map toMapRoute() { + return {"id": id}; + } + + /// toMap for routesegments relational table + List> toMapRouteSegments() { + //asMap() apparently enumerates + List> tmp = List.empty(); + for (final (segmentIdx, segment) in segments.indexed) { + tmp.add({ + "route": id, + "segmentid": segment.id, + "segmentorder": segmentIdx, + }); + } + return tmp; + } + // from trip API request // TODO: how to connect this best with the database for read/write? factory Route.fromJson(Map json) { Route newRoute = Route( - id: highestId, segments: json["LegList"]["Leg"].map((leg) => Segment.fromJson(leg)), duration: json["LegList"]["Leg"][-1]["Origin"]["time"] - json["LegList"]["Leg"][0]["Origin"]["time"], ); - highestId += 1; return newRoute; } - // rowids will give us new ids for every route-segment connection, but routeid - // is needed as well, so how do we create these - query highest existing routeid? I think so - // TODO: get highest routeid in route table (fast) static void initRouteTable() async { Database database = DbHelper.db; - database.execute("""CREATE TABLE IF NOT EXISTS routesegments( - id TEXT, - segmentid INTEGER, - segmentorder INTEGER, -- TODO: implement sorting - FOREIGN KEY(segmentid) REFERENCES segment(id) + database.execute("""CREATE TABLE IF NOT EXISTS route( + id INTEGER PRIMARY KEY AUTOINCREMENT, ); """); } - static void updateHighestId() async { + static void initRouteSegmentsTable() async { Database database = DbHelper.db; - int newHigh = await getHighestId(); - highestId = newHigh + 1; + String segment = Segment.tableName; + database.execute("""CREATE TABLE IF NOT EXISTS routesegments( + id TEXT PRIMARY KEY AUTOINCREMENT, + route INTEGER, + segment INTEGER, + segmentorder INTEGER, -- TODO: implement sorting + FOREIGN KEY(route) REFERENCES route(id), + FOREIGN KEY(segment) REFERENCES $segment(id) + ); + """); } - /* TODO: better separation between production db and test db - * they share the highestId field regardless, which wont do - * so is an attribut for database needed? - */ - - /// parse the highest id from the database to continue with ongoing ids but - /// create the db entry after the class, for now - - // -- this might be making it more complicated than it needs to be - static Future getHighestId() async { + void writeRouteToTable() async { Database database = DbHelper.db; - try { - var tmp = await database.query( - "routesegments", - columns: ["id"], - distinct: true, - orderBy: "id", - whereArgs: ["id"], - limit: 1, - ); - if (tmp.isEmpty) { - return 0; - } - if (tmp[0].isEmpty) { - return 0; - } - // entry "routeid" should definitely exist - assert(tmp[0]["id"] != null); - - // Source - https://stackoverflow.com/a/52632172 - // Posted by Günter Zöchbauer, modified by community. See post 'Timeline' for change history - // Retrieved 2026-06-08, License - CC BY-SA 4.0 - T? cast(x) => x is T ? x : null; - // -- - //doing this in two steps go deal with nullability - String highestId = cast(tmp[0]["routeid"]) ?? "0"; - return int.parse(highestId); - } catch (e) { - print('Error: Could not get id: $e'); // TODO: use logging - } - return 0; + database.insert( + "route", + toMapRoute(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); } - void writeNewToTable(Route route) async { + void writeRouteSegmentsToTable() async { Database database = DbHelper.db; - for (var i = 0; i < route.segments.length; i++) { - database.insert("routesegments", { - "id": route.id, - "segmentid": route.segments[i].id, - "segmentorder": i, - }); + var routeSegments = toMapRouteSegments(); + for (var i = 0; i < routeSegments.length; i++) { + database.insert("routesegments", routeSegments[i]); } } } class Segment { - final int id = 0; - final Station startPoint; - final Station endPoint; - final DateTime startTime; - final DateTime endTime; - final Vehicle vehicle; + static const String tableName = "segment"; + + int? id; + Station startPoint; + Station endPoint; + DateTime startTime; + DateTime endTime; + Vehicle vehicle; Segment({ required this.startPoint, @@ -160,6 +146,16 @@ class Segment { required this.vehicle, }); + Map toMap() { + return { + "startPoint": startPoint.id, + "endpoint": endPoint.id, + "starttime": startTime, + "endtime": endTime, + "vehicle": vehicle.id, + }; + } + factory Segment.fromJson(Map json) { Database database = DbHelper.db; Segment tmp = Segment( @@ -175,37 +171,35 @@ class Segment { static void initSegmentTable() async { Database database = DbHelper.db; + String station = Station.tableName; + String vehicle = Vehicle.tableName; database.execute(""" - CREATE TABLE IF NOT EXISTS segment( + CREATE TABLE IF NOT EXISTS $tableName( 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) + FOREIGN KEY(startpoint) REFERENCES $station(stationid), + FOREIGN KEY(endpoint) REFERENCES $station(stationid), + FOREIGN KEY(vehicle) REFERENCES $vehicle(vehicleid) ); """); } Future writeNewToTable() async { Database database = DbHelper.db; - int id = await database.insert("segment", { - "startpoint": startPoint.id, - "endpoint": startPoint.id, - "startTime": startTime, - "endTime": endTime, - "vehicle": vehicle.id, - }); + int id = await database.insert(tableName, toMap()); return id; } } class Station { - final String id; - final String name; - List? transportLines; // could be normalized away + static const String tableName = "station"; + + String id; + String name; + List transportLines; // could be normalized away Station({ required this.id, @@ -213,6 +207,18 @@ class Station { required this.transportLines, //TODO: make extra db table }); + Map toMap() { + return {"id": id, "name": name}; + } + + List> toMapLines() { + return transportLines + .map( + (line) => {"stationid": id, "lineid": line}, + ) + .toList(); + } + factory Station.fromJson(Map json) => Station( id: json["id"] as String? ?? json["extId"] as String, name: json["name"], @@ -226,22 +232,43 @@ class Station { static void initStationTable() async { Database database = DbHelper.db; database.execute("""CREATE TABLE IF NOT EXISTS station( - id TEXT PRIMARY KEY, + stationid TEXT PRIMARY KEY, name TEXT ); """); } + + static void initStationLinesTable() async { + Database database = DbHelper.db; + database.execute("""CREATE TABLE IF NOT EXISTS stationlines( + id INT PRIMARY KEY AUTOINCREMENT, + stationid TEXT, + lineid TEXT, + FOREIGN KEY (stationid) REFERENCES station(stationid), + FOREIGN KEY (lineid) REFERENCES line(lineid) + ); + """); + } } class Vehicle { - final String id; - final Line line; + static const String tableName = "vehicle"; + + String id; + Line line; Vehicle({ required this.id, required this.line, }); + Map toMap() { + return { + "id": id, + "line": line.id, + }; + } + // we can use the "product" class from within any JSON response // (within hafas API, on the appropriate level) factory Vehicle.fromJson(Map json) => Vehicle( @@ -251,21 +278,24 @@ class Vehicle { static void initVehicleTable() async { Database database = DbHelper.db; - database.execute("""CREATE TABLE IF NOT EXISTS vehicle( + String line = Line.tableName; + database.execute("""CREATE TABLE IF NOT EXISTS $tableName( id TEXT PRIMARY KEY, line TEXT, - FOREIGN KEY(line) REFERENCES line(lineid) + FOREIGN KEY(line) REFERENCES $line(lineid) ); """); } } class Line { - final String id; + static const String tableName = "line"; + + String id; Station? destination; Station? direction; - final VehicleType mode; - final String name; + VehicleType mode; + String name; Color? fgColor; Color? bgColor; @@ -277,6 +307,18 @@ class Line { this.bgColor, }); + Map toMap() { + return { + "lineid": id, + "destination": destination, + "direction": direction, + "mode": mode, + "name": name, + "fgcolor": fgColor, + "bgcolor": bgColor, + }; + } + // TODO: EXPLAIN!!!!!!!!!!!! static const _vehicleTypeAsCatCode = [ VehicleType.metro, @@ -298,7 +340,7 @@ class Line { ); static void initLineTable() async { Database database = DbHelper.db; - database.execute("""CREATE TABLE IF NOT EXISTS line( + database.execute("""CREATE TABLE IF NOT EXISTS $tableName( lineid TEXT PRIMARY KEY, destination TEXT, direction TEXT, @@ -312,10 +354,12 @@ class Line { } class Departure { + static const String tableName = "departure"; + String? id; - final Vehicle vehicle; - final Station station; - final DateTime departureTime; + Vehicle vehicle; + Station station; + DateTime departureTime; Departure({ required this.vehicle, @@ -323,24 +367,35 @@ class Departure { required this.departureTime, }); + Map toMap() { + return { + "id": id, + "vehicle": vehicle, + "station": station, + "departuretime": departureTime, + }; + } + static void initDepartureTable() async { Database database = DbHelper.db; - database.execute("""CREATE TABLE IF NOT EXISTS departure( + String vehicle = Vehicle.tableName; + String station = Station.tableName; + database.execute("""CREATE TABLE IF NOT EXISTS $tableName( id INTEGER, vehicle TEXT, station TEXT, departuretime TEXT, - FOREIGN KEY(vehicle) REFERENCES vehicle(id), - FOREIGN KEY(station) REFERENCES station(id) + FOREIGN KEY(vehicle) REFERENCES $vehicle(id), + FOREIGN KEY(station) REFERENCES $station(id) ); """); } } class Color { - final int r; - final int g; - final int b; + int r; + int g; + int b; Color({ required this.r, @@ -362,4 +417,4 @@ enum VehicleType { subway, regionalTrain, PLACEHOLDER, -} +} \ No newline at end of file