Public Access
522 lines
13 KiB
Dart
522 lines
13 KiB
Dart
import 'package:sqflite/sqflite.dart';
|
|
// import './state_helper.dart';
|
|
// import './db_helper.dart';
|
|
|
|
// TODO: get access to DB
|
|
|
|
class DbHelper {
|
|
static late Database db;
|
|
static String dbName = "";
|
|
|
|
// DbHelper({
|
|
// required this.db,
|
|
// required this.dbName,
|
|
// });
|
|
|
|
// remnant from when DB was not static
|
|
// factory DbHelper._openDb(Database database, String dbName) => DbHelper(
|
|
// db: database,
|
|
// dbName: dbName,
|
|
// );
|
|
|
|
static void initDb(String dbName) async {
|
|
// var db = await openDatabase('/var/db/oeffimaster/transport_db.db');
|
|
var databasesPath = await getDatabasesPath();
|
|
var path = databasesPath + dbName;
|
|
// var newDb = await openDatabase(path);
|
|
// var dbHelper = DbHelper._openDb(newDb, dbName);
|
|
db = await openDatabase(path);
|
|
dbName = dbName;
|
|
|
|
// TODO: Make sure the directory exists
|
|
|
|
// TODO: future optimisation: batch transactions
|
|
|
|
Route.initRouteTable();
|
|
Segment.initSegmentTable();
|
|
Station.initStationTable();
|
|
Vehicle.initVehicleTable();
|
|
Departure.initDepartureTable();
|
|
}
|
|
}
|
|
|
|
/// 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 {
|
|
// TODO: add last_viewed, last_modified and such
|
|
int? id;
|
|
List<Segment> segments = List.empty();
|
|
Duration duration = Duration(minutes: 0);
|
|
|
|
Route({
|
|
this.id,
|
|
required this.segments,
|
|
required this.duration,
|
|
});
|
|
|
|
/// toMap for Route but it's just route ids for now
|
|
Map<String, Object?> toMapRoute() {
|
|
return {"id": id};
|
|
}
|
|
|
|
/// toMap for routesegments relational table
|
|
List<Map<String, Object?>> toMapRouteSegments() {
|
|
//asMap() apparently enumerates
|
|
List<Map<String, Object?>> 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<String, dynamic> json) {
|
|
Route newRoute = Route(
|
|
segments: json["LegList"]["Leg"].map((leg) => Segment.fromJson(leg)),
|
|
duration:
|
|
json["LegList"]["Leg"][-1]["Origin"]["time"] -
|
|
json["LegList"]["Leg"][0]["Origin"]["time"],
|
|
);
|
|
newRoute.dbInsertRoute();
|
|
return newRoute;
|
|
}
|
|
|
|
static void initRouteTable() async {
|
|
Database database = DbHelper.db;
|
|
database.execute("""CREATE TABLE IF NOT EXISTS route(
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
);
|
|
""");
|
|
}
|
|
|
|
static void initRouteSegmentsTable() async {
|
|
Database database = DbHelper.db;
|
|
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)
|
|
);
|
|
""");
|
|
}
|
|
|
|
void dbInsertRoute() async {
|
|
Database database = DbHelper.db;
|
|
id = await database.insert(
|
|
"route",
|
|
toMapRoute(),
|
|
conflictAlgorithm: ConflictAlgorithm.replace,
|
|
);
|
|
}
|
|
|
|
void dbInsertRouteSegments() async {
|
|
Database database = DbHelper.db;
|
|
var routeSegments = toMapRouteSegments();
|
|
for (var i = 0; i < routeSegments.length; i++) {
|
|
database.insert(
|
|
"routesegments",
|
|
routeSegments[i],
|
|
);
|
|
}
|
|
}
|
|
|
|
void dbDelete() async {
|
|
Database database = DbHelper.db;
|
|
int result = await database.delete(
|
|
"route",
|
|
where: "id = ?",
|
|
whereArgs: [id],
|
|
);
|
|
assert(result == 0);
|
|
}
|
|
|
|
void dbDeleteLastRouteSegment() {
|
|
Database database = DbHelper.db;
|
|
database.delete(
|
|
"routesegments",
|
|
where: "route = ? AND segmentorder = ?",
|
|
whereArgs: [id, segments.length - 1], // TODO: test the index
|
|
);
|
|
}
|
|
|
|
void dbDeleteTrailingRouteSegment(int position) {
|
|
Database database = DbHelper.db;
|
|
if (position <= segments.length) {
|
|
database.delete(
|
|
"routesegments",
|
|
where: "route = ? AND segmentorder >= ?",
|
|
whereArgs: [id, position],
|
|
);
|
|
}
|
|
}
|
|
|
|
// TODO: delete leading segments and decrement following segments
|
|
}
|
|
|
|
class Segment {
|
|
static const String tableName = "segment";
|
|
|
|
int? id;
|
|
Station startPoint;
|
|
Station endPoint;
|
|
DateTime startTime;
|
|
DateTime endTime;
|
|
Vehicle vehicle;
|
|
|
|
Segment({
|
|
this.id, // might throw errors - needs testing, I guess
|
|
required this.startPoint,
|
|
required this.endPoint,
|
|
required this.startTime,
|
|
required this.endTime,
|
|
required this.vehicle,
|
|
});
|
|
|
|
Map<String, Object?> toMap() {
|
|
return {
|
|
"startPoint": startPoint.id,
|
|
"endpoint": endPoint.id,
|
|
"starttime": startTime,
|
|
"endtime": endTime,
|
|
"vehicle": vehicle.id,
|
|
};
|
|
}
|
|
|
|
factory Segment.fromJson(Map<String, dynamic> json) {
|
|
Database database = DbHelper.db;
|
|
Segment tmp = Segment(
|
|
startPoint: Station.fromJson(json["Origin"]),
|
|
endPoint: Station.fromJson(json["Destination"]),
|
|
startTime: json["Origin"]["rtTime"],
|
|
endTime: json["Destination"]["rtTime"],
|
|
vehicle: Vehicle.fromJson(json["Product"]),
|
|
);
|
|
tmp.dbInsert();
|
|
return tmp;
|
|
}
|
|
|
|
static void initSegmentTable() async {
|
|
Database database = DbHelper.db;
|
|
String station = Station.tableName;
|
|
String vehicle = Vehicle.tableName;
|
|
database.execute("""
|
|
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)
|
|
);
|
|
""");
|
|
}
|
|
|
|
void dbInsert() async {
|
|
Database database = DbHelper.db;
|
|
id = await database.insert(tableName, toMap());
|
|
}
|
|
|
|
void dbDelete() {
|
|
Database database = DbHelper.db;
|
|
database.delete(
|
|
tableName,
|
|
where: "rowid = ?",
|
|
whereArgs: [id],
|
|
);
|
|
}
|
|
}
|
|
|
|
class Station {
|
|
static const String tableName = "station";
|
|
|
|
String id;
|
|
String name;
|
|
List<Line> transportLines; // could be normalized away
|
|
|
|
Station({
|
|
required this.id,
|
|
required this.name,
|
|
required this.transportLines, //TODO: make extra db table
|
|
});
|
|
|
|
Map<String, Object?> toMap() {
|
|
return {"id": id, "name": name};
|
|
}
|
|
|
|
List<Map<String, Object?>> toMapLines() {
|
|
return transportLines
|
|
.map(
|
|
(line) => {"stationid": id, "lineid": line},
|
|
)
|
|
.toList();
|
|
}
|
|
|
|
factory Station.fromJson(Map<String, dynamic> json) => Station(
|
|
id: json["id"] as String? ?? json["extId"] as String,
|
|
name: json["name"],
|
|
transportLines: json.containsKey("productAtStop")
|
|
? json["productAtStop"].map(
|
|
(jsonLine) => Line.fromJson(jsonLine as Map<String, dynamic>),
|
|
)
|
|
: const [],
|
|
);
|
|
|
|
static void initStationTable() async {
|
|
Database database = DbHelper.db;
|
|
database.execute("""CREATE TABLE IF NOT EXISTS station(
|
|
stationid TEXT PRIMARY KEY,
|
|
name TEXT
|
|
);
|
|
""");
|
|
}
|
|
|
|
static void initStationLinesTable() async {
|
|
Database database = DbHelper.db;
|
|
database.execute("""CREATE TABLE IF NOT EXISTS stationlines(
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
stationid TEXT,
|
|
lineid TEXT,
|
|
FOREIGN KEY (stationid) REFERENCES station(stationid),
|
|
FOREIGN KEY (lineid) REFERENCES line(lineid)
|
|
);
|
|
""");
|
|
}
|
|
|
|
void dbInsertStation() async {
|
|
Database database = DbHelper.db;
|
|
database.insert(tableName, toMap());
|
|
}
|
|
|
|
void dbInsertStationLines() async {
|
|
Database database = DbHelper.db;
|
|
var stationLines = toMapLines();
|
|
for (var i = 0; i < stationLines.length; i++) {
|
|
database.insert("stationlines", stationLines[i]);
|
|
}
|
|
}
|
|
|
|
void dbDelete() async {
|
|
Database database = DbHelper.db;
|
|
database.delete(tableName, where: "stationid = ?", whereArgs: [id]);
|
|
}
|
|
|
|
/// remove all Lines connected to a Station - should be used together with some kind of reparsing.
|
|
void dbDeleteStationLines() async {
|
|
Database database = DbHelper.db;
|
|
database.delete("stationlines", where: "stationid = ?", whereArgs: [id]);
|
|
}
|
|
}
|
|
|
|
class Vehicle {
|
|
static const String tableName = "vehicle";
|
|
|
|
String id;
|
|
Line line;
|
|
|
|
Vehicle({
|
|
required this.id,
|
|
required this.line,
|
|
});
|
|
|
|
Map<String, Object?> toMap() {
|
|
return {
|
|
"id": id,
|
|
"line": line.lineId,
|
|
};
|
|
}
|
|
|
|
// 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["matchId"],
|
|
line: Line.fromJson(json),
|
|
);
|
|
|
|
static void initVehicleTable() async {
|
|
Database database = DbHelper.db;
|
|
String line = Line.tableName;
|
|
database.execute("""CREATE TABLE IF NOT EXISTS $tableName(
|
|
id TEXT PRIMARY KEY,
|
|
line TEXT,
|
|
FOREIGN KEY(line) REFERENCES $line(lineid)
|
|
);
|
|
""");
|
|
}
|
|
|
|
void dbInsert() async {
|
|
Database database = DbHelper.db;
|
|
database.insert(tableName, toMap());
|
|
}
|
|
|
|
void dbDelete() async {
|
|
Database database = DbHelper.db;
|
|
database.delete(tableName, where: "id = ?", whereArgs: [id]);
|
|
}
|
|
}
|
|
|
|
class Line {
|
|
static const String tableName = "line";
|
|
|
|
String lineId;
|
|
Station? destination;
|
|
Station? direction;
|
|
VehicleType mode;
|
|
String name;
|
|
Color? fgColor;
|
|
Color? bgColor;
|
|
|
|
Line({
|
|
required this.lineId,
|
|
required this.name,
|
|
required this.mode,
|
|
this.fgColor,
|
|
this.bgColor,
|
|
});
|
|
|
|
Map<String, Object?> toMap() {
|
|
return {
|
|
"lineid": lineId,
|
|
"destination": destination,
|
|
"direction": direction,
|
|
"mode": mode,
|
|
"name": name,
|
|
"fgcolor": fgColor,
|
|
"bgcolor": bgColor,
|
|
};
|
|
}
|
|
|
|
// TODO: EXPLAIN!!!!!!!!!!!!
|
|
static const _vehicleTypeAsCatCode = [
|
|
VehicleType.metro,
|
|
VehicleType.subway,
|
|
VehicleType.PLACEHOLDER,
|
|
VehicleType.bus,
|
|
];
|
|
|
|
factory Line.fromJson(Map<String, dynamic> json) => Line(
|
|
lineId: json["lineId"],
|
|
name: json["name"],
|
|
mode: _vehicleTypeAsCatCode[int.parse(json["catCode"])],
|
|
fgColor:
|
|
Color.fromJson(json["foregroundColor"]) as Color? ??
|
|
Color(r: 255, g: 255, b: 255), // fallback
|
|
bgColor:
|
|
Color.fromJson(json["backgroundColor"]) as Color? ??
|
|
Color(r: 50, g: 50, b: 50), // fallback
|
|
);
|
|
static void initLineTable() async {
|
|
Database database = DbHelper.db;
|
|
database.execute("""CREATE TABLE IF NOT EXISTS $tableName(
|
|
lineid TEXT PRIMARY KEY,
|
|
destination TEXT,
|
|
direction TEXT,
|
|
mode TEXT,
|
|
name TEXT,
|
|
fgcolor TEXT,
|
|
bgcolor TEXT
|
|
);
|
|
""");
|
|
}
|
|
|
|
void dbInsert() async {
|
|
Database database = DbHelper.db;
|
|
database.insert(tableName, toMap());
|
|
}
|
|
|
|
void dbDelete() async {
|
|
Database database = DbHelper.db;
|
|
database.delete(tableName, where: "lineid = ?", whereArgs: [lineId]);
|
|
}
|
|
}
|
|
|
|
// TODO: add fromJson
|
|
class Departure {
|
|
static const String tableName = "departure";
|
|
|
|
int? id;
|
|
Vehicle vehicle;
|
|
Station station;
|
|
DateTime departureTime;
|
|
|
|
Departure({
|
|
this.id,
|
|
required this.vehicle,
|
|
required this.station,
|
|
required this.departureTime,
|
|
});
|
|
|
|
Map<String, Object?> toMap() {
|
|
return {
|
|
"id": id,
|
|
"vehicle": vehicle,
|
|
"station": station,
|
|
"departuretime": departureTime,
|
|
};
|
|
}
|
|
|
|
static void initDepartureTable() async {
|
|
Database database = DbHelper.db;
|
|
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)
|
|
);
|
|
""");
|
|
}
|
|
|
|
void dbInsert() async {
|
|
Database database = DbHelper.db;
|
|
id = await database.insert(tableName, toMap());
|
|
}
|
|
|
|
void dbDelete() async {
|
|
Database database = DbHelper.db;
|
|
database.delete(tableName, where: "id = ?", whereArgs: [id]);
|
|
}
|
|
}
|
|
|
|
class Color {
|
|
int r;
|
|
int g;
|
|
int b;
|
|
|
|
Color({
|
|
required this.r,
|
|
required this.g,
|
|
required this.b,
|
|
});
|
|
|
|
factory Color.fromJson(Map<String, dynamic> json) => Color(
|
|
r: json["r"],
|
|
g: json["g"],
|
|
b: json["b"],
|
|
);
|
|
}
|
|
|
|
enum VehicleType {
|
|
bus,
|
|
tram,
|
|
metro,
|
|
subway,
|
|
regionalTrain,
|
|
PLACEHOLDER,
|
|
}
|