HealthImport/HealthImport/Model/LocationSample.swift
2024-01-31 11:02:26 +01:00

93 lines
4.3 KiB
Swift

import Foundation
import SQLite
import CoreLocation
typealias LocationSample = CLLocation
extension LocationSample {
private static let table = Table("location_series_data")
/// `location_series_data[series_identifier]` <-> `workout_activities[ROW_ID]`
private static let columnSeriesIdentifier = Expression<Int>("series_identifier")
private static let columnTimestamp = Expression<Double>("timestamp")
private static let columnLongitude = Expression<Double>("longitude")
private static let columnLatitude = Expression<Double>("latitude")
private static let columnAltitude = Expression<Double>("altitude")
private static let columnSpeed = Expression<Double>("speed")
private static let columnCourse = Expression<Double>("course")
private static let columnHorizontalAccuracy = Expression<Double>("horizontal_accuracy")
private static let columnVerticalAccuracy = Expression<Double>("vertical_accuracy")
private static let columnSpeedAccuracy = Expression<Double>("speed_accuracy")
private static let columnCourseAccuracy = Expression<Double>("course_accuracy")
private static let columnSignalEnvironment = Expression<Double>("signal_environment")
static func locationSamples(for seriesId: Int, in database: Database) throws -> [LocationSample] {
try database.prepare(table.filter(columnSeriesIdentifier == seriesId)).map(location)
}
static func locationSampleCount(for seriesId: Int, in database: Database) throws -> Int {
try database.scalar(table.filter(columnSeriesIdentifier == seriesId).count)
}
static func locationSamples(from start: Date, to end: Date, in database: Database) throws -> [LocationSample] {
let startTime = start.timeIntervalSinceReferenceDate
let endTime = end.timeIntervalSinceReferenceDate
return try database.prepare(table.filter(columnTimestamp >= startTime && columnTimestamp <= endTime)).map(location)
}
static func locationSampleCount(from start: Date, to end: Date, in database: Database) throws -> Int {
let startTime = start.timeIntervalSinceReferenceDate
let endTime = end.timeIntervalSinceReferenceDate
return try database.scalar(table.filter(columnTimestamp >= startTime && columnTimestamp <= endTime).count)
}
private static func location(row: Row) -> LocationSample {
.init(
coordinate: .init(
latitude: row[columnLatitude],
longitude: row[columnLongitude]),
altitude: row[columnAltitude],
horizontalAccuracy: row[columnHorizontalAccuracy],
verticalAccuracy: row[columnHorizontalAccuracy],
course: row[columnCourse],
courseAccuracy: row[columnCourseAccuracy],
speed: row[columnSpeed],
speedAccuracy: row[columnSpeedAccuracy],
timestamp: .init(timeIntervalSinceReferenceDate: row[columnTimestamp]),
sourceInfo: .init())
}
static func createTable(in database: Connection) throws {
try database.execute("CREATE TABLE location_series_data (series_identifier INTEGER NOT NULL REFERENCES data_series(hfd_key) DEFERRABLE INITIALLY DEFERRED, timestamp REAL NOT NULL, longitude REAL NOT NULL, latitude REAL NOT NULL, altitude REAL NOT NULL, speed REAL NOT NULL, course REAL NOT NULL, horizontal_accuracy REAL NOT NULL, vertical_accuracy REAL NOT NULL, speed_accuracy REAL NOT NULL, course_accuracy REAL NOT NULL, signal_environment INTEGER NOT NULL, PRIMARY KEY (series_identifier, timestamp)) WITHOUT ROWID")
}
static func insert(_ sample: LocationSample, in database: Connection, seriesId: Int) throws {
try database.run(table.insert(
columnSeriesIdentifier <- seriesId,
columnTimestamp <- sample.timestamp.timeIntervalSinceReferenceDate,
columnLongitude <- sample.coordinate.longitude,
columnLatitude <- sample.coordinate.latitude,
columnAltitude <- sample.altitude,
columnSpeed <- sample.speed,
columnCourse <- sample.course,
columnHorizontalAccuracy <- sample.horizontalAccuracy,
columnHorizontalAccuracy <- sample.verticalAccuracy,
columnSpeedAccuracy <- sample.speedAccuracy,
columnCourseAccuracy <- sample.courseAccuracy,
columnSignalEnvironment <- 1
))
}
}