Closed ualch9 closed 11 months ago
What should be persisted (stops only? or everything?). As a first release, the database could operate only in-memory. Need to include some sort of expiration date. AFAIK, API responses do not include an expires header.
Only in memory sounds like a great first step. That'll help us deal with this problem you outline in point 2 (above).
How should bookmarks be stored so they can sync via iCloud.
Let's defer this just for a little bit. I think getting Sqlite up and running in a way we're comfortable with supporting is enough of a bite at this apple for now.
Objective-C support? Is this important enough that we should write wrappers for the new models?
I don't think so, no. I think we can effectively ignore Obj-C from here on out.
I think this is ready for review:
OBAKit does not build. To build & test, run a specific XCTestCase in OBAKitCoreTests
(just "building" will complain about no executable).
Renamed ServiceAlert
→ Situation
(added typealias ServiceAlert = Situation
).
These models have GRDB implementations:
PersistenceService.Configuration.tableCreators
.
Some models may have additional tables, usually to represent relations. These are represented in each model's GRDB implementation as additionalTableCreators
(example: SituationDB.swift).Tests are kinda messy right now, I'll clean it up later:
OBAKitTests/fixtures
have their target memberships set to both OBAKitTests
and OBAKitCoreTests
.Many of the model structures are now closer to their OBA object schema:
public struct TripDetails: Codable {
public let timeZone: String
public let stopTimes: [TripStopTime]
public let previousTripID: String?
public let nextTripID: String?
public let schedule: Schedule
init(decoder: Decoder) throws {
// ...
let schedule = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .schedule)
timeZone = try schedule.decode(String.self, forKey: .timeZone)
stopTimes = try schedule.decode([TripStopTime].self, forKey: .stopTimes)
previousTripID = try schedule.decodeIfPresent(String.self, forKey: .previousTripID)
nextTripID = try schedule.decodeIfPresent(String.self, forKey: .nextTripID)
// ...
} }
public struct Schedule: Codable, Hashable {
public let timeZone: String
public let stopTimes: [TripStopTime]
public let previousTripID: String?
public let nextTripID: String?
}
Another example is representing the `LocationModel` directly, rather than augmenting it into a `CLLocation`.
Need to do next:
let response = try await restAPIService.getTrip(tripID: tripID, vehicleID: vehicleID, serviceDate: .now)
try await persistence.processAPIResponse(response) // ← this isn't ergonomic.
This is the previous PR (#684), but targeting feature branch
ualch9/persistence
and withoutMetaCodable
. GRDB's Codable support was fighting with the code generated by MetaCodable, so I decided to drop it.Added new
OBAKitCoreTests
target for testing againstOBAKitCore.framework
only.OBAKit.framework
andApp.app
.OBAKitCore.framework
, so I can focus on Codable/GRDB without fighting the compiler or working without tests. Where appropriate, I moved some tests were moved from OBAKitTests → OBAKitCoreTests.GRDB and REST implementations are contained in their own files.
OBAKitCore/Models/REST
.OBAKitCore/Persistence/Models
. In general, GRDB models (such as many-to-many relations) are not exposed outside of OBAKitCore.Each model defines their own tables, via
protocol DatabaseTableCreator.createTable(in:)
that is called byPersistenceManager
when initially creating the database.When storing on-disk, each database is stored per-region:
{app_container}/Application Support/regions/{region_id}/onebusaway.sqlite
Undecided:
expires
header.