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
This commit is contained in:
fbachus
2026-07-28 02:16:46 +02:00
parent 25ecd69b5f
commit 6dc3e9569a
+117 -54
View File
@@ -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<String, Object?> 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<String, Object>,
),
end: Departure.fromMap(
map["end"] as Map<String, Object>,
),
vehicle: Vehicle.fromMap(map["vehicle"] as Map<String, Object>),
);
}
factory Segment.fromJson(Map<String, dynamic> 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<Segment> 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<Segment> 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<List<Segment>> 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<String, Object?> _toMap() {
return {
"id": id,
"id": vehicleid,
"name": name,
"line": vehicleLineId,
};
@@ -609,7 +672,7 @@ class Vehicle {
Map<String, Object?> 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<String, dynamic> 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)
);
""");
}