swift中数据模型

59 阅读5分钟

// 运动概要数据

class OPHealthWorkoutInfoModel {

///运动记录ID,唯一标识,字符最大长度32

var sportID: String = String()

///运动类型,参考OPPO运动记录类型列表

var sportType: UInt32 = 0

///运动名称

var sportName: UInt32 = 0

///运动开始时间(UTC秒)

var startTime: UInt32 = 0

///运动结束时间 (UTC秒)

var endTime: UInt32 = 0

///运动的总步数

var totalSteps: UInt32 = 0

///运动的总距离,单位米

var totalDistance: UInt32 = 0

///运动总时间。单位秒

var totalTime: UInt32 = 0

///运动总消耗的卡路里,单位千卡

var totalCalories: UInt32 = 0

///运动的累计上升高度,单位米

var totalHeight: UInt32 = 0

///平均心率

var avgHeartRate: UInt32 = 0

///平均配速,单位 秒/公里

var avgSpeed: UInt32 = 0

///最佳配速,单位 秒/公里

var maxSpeed: UInt32 = 0

///平局步频

var avgFrequency: UInt32 = 0

/// 扩展字段,字符串,不同运动类型定义不同的扩展

var extra: String = String()

var gpsModel: OPHealthWorkoutGPSModel = OPHealthWorkoutGPSModel()

}

class OPHealthWorkoutGPSModel {

///时间戳(UTC秒)

var timestamp: [UInt64] = []

///纬度 * 1000000

var latitude: [Int32] = []

///经度 * 1000000

var longitude: [Int32] = []

///状态:0正常,1暂停

var state: [UInt32] = []

///GPS速度,(单位:秒/公里)

var speed: [Float] = []

}

import Foundation
import SQLite

// 运动概要数据
class OPHealthWorkoutInfoModel {
    ///运动记录ID,唯一标识,字符最大长度32
    var sportID: String = String()
    ///运动类型,参考OPPO运动记录类型列表
    var sportType: UInt32 = 0
    ///运动名称
    var sportName: UInt32 = 0
    ///运动开始时间(UTC秒)
    var startTime: UInt32 = 0
    ///运动结束时间 (UTC秒)
    var endTime: UInt32 = 0
    ///运动的总步数
    var totalSteps: UInt32 = 0
    ///运动的总距离,单位米
    var totalDistance: UInt32 = 0
    ///运动总时间。单位秒
    var totalTime: UInt32 = 0
    ///运动总消耗的卡路里,单位千卡
    var totalCalories: UInt32 = 0
    ///运动的累计上升高度,单位米
    var totalHeight: UInt32 = 0
    ///平均心率
    var avgHeartRate: UInt32 = 0
    ///平均配速,单位 秒/公里
    var avgSpeed: UInt32 = 0
    ///最佳配速,单位 秒/公里
    var maxSpeed: UInt32 = 0
    ///平局步频
    var avgFrequency: UInt32 = 0
    /// 扩展字段,字符串,不同运动类型定义不同的扩展
    var extra: String = String()
    var gpsModel: OPHealthWorkoutGPSModel = OPHealthWorkoutGPSModel()
}

class OPHealthWorkoutGPSModel {
    ///时间戳(UTC秒)
    var timestamp: [UInt64] = []
    ///纬度 * 1000000
    var latitude: [Int32] = []
    ///经度 * 1000000
    var longitude: [Int32] = []
    ///状态:0正常,1暂停
    var state: [UInt32] = []
    ///GPS速度,(单位:秒/公里)
    var speed: [Float] = []
}

class OPHealthHeartRateModel {
    var time_offset = 0.0 // 相对于 start_time 的偏移量(单位秒),可以根据 start_time + time_offset 来获取当前这条数据对应的时间戳
    var heart_rate = 0.0  // 心率值
    var reliability = 0 // 心率结果置信度,范围 0~3 越大越可信(目前穿戴设备在心率预警判断时会用到)
    var type = 0        // 心率类型(0:日常心率,1:静息心率,2:运动心率)
}

class OPHealthBreatheRateModel {
    var time_offset = 0.0   // 对应这条数据的时间戳
    var breath_rate = 0     // 其他bit位的表示呼吸率值
}

class OPHealthSleepInfoModel {
    var time_stamp = 0      // 时间戳
    var state = 0           // 睡眠状态(深睡,浅睡,REM,清醒,短暂清醒),一分钟对应一个状态
}

class OPHealthBloodOxygenModel {
    var time_stamp = 0     // 时间戳
    var type = 0           // 类型(0 睡眠血氧,1 点测,2 全天自动测量)
    var value = 0          // 血氧值
}

class SqliteManager {
    static let shared = SqliteManager()
    private let db: Connection
    
    // Table and columns for WorkoutInfo
    typealias Expression = SQLite.Expression
    private let workoutTable = Table("workout_info")
    private let workoutSportID = Expression<String>("sport_id")
    private let workoutSportType = Expression<Int64>("sport_type")
    private let workoutSportName = Expression<Int64>("sport_name")
    private let workoutStartTime = Expression<Int64>("start_time")
    private let workoutEndTime = Expression<Int64>("end_time")
    private let workoutTotalSteps = Expression<Int64>("total_steps")
    private let workoutTotalDistance = Expression<Int64>("total_distance")
    private let workoutTotalTime = Expression<Int64>("total_time")
    private let workoutTotalCalories = Expression<Int64>("total_calories")
    private let workoutTotalHeight = Expression<Int64>("total_height")
    private let workoutAvgHeartRate = Expression<Int64>("avg_heart_rate")
    private let workoutAvgSpeed = Expression<Int64>("avg_speed")
    private let workoutMaxSpeed = Expression<Int64>("max_speed")
    private let workoutAvgFrequency = Expression<Int64>("avg_frequency")
    private let workoutExtra = Expression<String>("extra")
    
    // Table and columns for GPS data
    private let gpsTable = Table("workout_gps")
    private let gpsSportID = Expression<String>("sport_id")
    private let gpsTimestampArray = Expression<String>("timestamp_array")
    private let gpsLatitudeArray = Expression<String>("latitude_array")
    private let gpsLongitudeArray = Expression<String>("longitude_array")
    private let gpsStateArray = Expression<String>("state_array")
    private let gpsSpeedArray = Expression<String>("speed_array")
    
    // Table and columns for HeartRate data
    private let heartRateTable = Table("heart_rate")
    private let heartRateTimeOffset = Expression<Double>("time_offset")
    private let heartRateValue = Expression<Double>("heart_rate")
    private let heartRateReliability = Expression<Int64>("reliability")
    private let heartRateType = Expression<Int64>("type")
    
    // Table and columns for BreatheRate data
    private let breatheRateTable = Table("breathe_rate")
    private let breatheRateTimeOffset = Expression<Double>("time_offset")
    private let breatheRateValue = Expression<Int64>("breath_rate")
    
    // Table and columns for SleepInfo data
    private let sleepInfoTable = Table("sleep_info")
    private let sleepInfoTimeStamp = Expression<Int64>("time_stamp")
    private let sleepInfoState = Expression<Int64>("state")
    
    // Table and columns for BloodOxygen data
    private let bloodOxygenTable = Table("blood_oxygen")
    private let bloodOxygenTimeStamp = Expression<Int64>("time_stamp")
    private let bloodOxygenType = Expression<Int64>("type")
    private let bloodOxygenValue = Expression<Int64>("value")
    
    private init() {
        let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
        do {
            db = try Connection("\(path)/.dbtest.sqlite")
            try createTables()
        } catch {
            fatalError("Unable to open database: \(error)")
        }
    }
    
    private func createTables() throws {
        // Create WorkoutInfo table
        try db.run(workoutTable.create(ifNotExists: true) { t in
            t.column(workoutSportID, primaryKey: true)
            t.column(workoutSportType)
            t.column(workoutSportName)
            t.column(workoutStartTime)
            t.column(workoutEndTime)
            t.column(workoutTotalSteps)
            t.column(workoutTotalDistance)
            t.column(workoutTotalTime)
            t.column(workoutTotalCalories)
            t.column(workoutTotalHeight)
            t.column(workoutAvgHeartRate)
            t.column(workoutAvgSpeed)
            t.column(workoutMaxSpeed)
            t.column(workoutAvgFrequency)
            t.column(workoutExtra)
        })
        // Create GPS table
        try db.run(gpsTable.create(ifNotExists: true) { t in
            t.column(gpsSportID, primaryKey: true)
            t.column(gpsTimestampArray)
            t.column(gpsLatitudeArray)
            t.column(gpsLongitudeArray)
            t.column(gpsStateArray)
            t.column(gpsSpeedArray)
        })
        // Create HeartRate table
        try db.run(heartRateTable.create(ifNotExists: true) { t in
            t.column(heartRateTimeOffset)
            t.column(heartRateValue)
            t.column(heartRateReliability)
            t.column(heartRateType)
        })
        // Create BreatheRate table
        try db.run(breatheRateTable.create(ifNotExists: true) { t in
            t.column(breatheRateTimeOffset)
            t.column(breatheRateValue)
        })
        // Create SleepInfo table
        try db.run(sleepInfoTable.create(ifNotExists: true) { t in
            t.column(sleepInfoTimeStamp)
            t.column(sleepInfoState)
        })
        // Create BloodOxygen table
        try db.run(bloodOxygenTable.create(ifNotExists: true) { t in
            t.column(bloodOxygenTimeStamp)
            t.column(bloodOxygenType)
            t.column(bloodOxygenValue)
        })
    }
    
    // MARK: - 删除所有数据
    func deleteAllData() throws {
        try db.run(workoutTable.delete())
        try db.run(gpsTable.delete())
        try db.run(heartRateTable.delete())
        try db.run(breatheRateTable.delete())
        try db.run(sleepInfoTable.delete())
        try db.run(bloodOxygenTable.delete())
    }
    
    // MARK: - WorkoutInfo Methods
    func insertWorkoutInfo(_ workout: OPHealthWorkoutInfoModel) throws {
        // Insert workout info
        let insertWorkout = workoutTable.insert(or: .replace,
                                               workoutSportID <- workout.sportID,
                                               workoutSportType <- Int64(workout.sportType),
                                               workoutSportName <- Int64(workout.sportName),
                                               workoutStartTime <- Int64(workout.startTime),
                                               workoutEndTime <- Int64(workout.endTime),
                                               workoutTotalSteps <- Int64(workout.totalSteps),
                                               workoutTotalDistance <- Int64(workout.totalDistance),
                                               workoutTotalTime <- Int64(workout.totalTime),
                                               workoutTotalCalories <- Int64(workout.totalCalories),
                                               workoutTotalHeight <- Int64(workout.totalHeight),
                                               workoutAvgHeartRate <- Int64(workout.avgHeartRate),
                                               workoutAvgSpeed <- Int64(workout.avgSpeed),
                                               workoutMaxSpeed <- Int64(workout.maxSpeed),
                                               workoutAvgFrequency <- Int64(workout.avgFrequency),
                                               workoutExtra <- workout.extra)
        try db.run(insertWorkout)
        
        // Insert GPS data
        let timestampJSON = try JSONEncoder().encode(workout.gpsModel.timestamp).base64EncodedString()
        let latitudeJSON = try JSONEncoder().encode(workout.gpsModel.latitude).base64EncodedString()
        let longitudeJSON = try JSONEncoder().encode(workout.gpsModel.longitude).base64EncodedString()
        let stateJSON = try JSONEncoder().encode(workout.gpsModel.state).base64EncodedString()
        let speedJSON = try JSONEncoder().encode(workout.gpsModel.speed).base64EncodedString()
        
        let insertGPS = gpsTable.insert(or: .replace,
                                       gpsSportID <- workout.sportID,
                                       gpsTimestampArray <- timestampJSON,
                                       gpsLatitudeArray <- latitudeJSON,
                                       gpsLongitudeArray <- longitudeJSON,
                                       gpsStateArray <- stateJSON,
                                       gpsSpeedArray <- speedJSON)
        try db.run(insertGPS)
    }
    
    func fetchAllWorkoutInfo() throws -> [OPHealthWorkoutInfoModel] {
        var result: [OPHealthWorkoutInfoModel] = []
        for row in try db.prepare(workoutTable) {
            let workout = OPHealthWorkoutInfoModel()
            workout.sportID = row[workoutSportID]
            workout.sportType = UInt32(row[workoutSportType])
            workout.sportName = UInt32(row[workoutSportName])
            workout.startTime = UInt32(row[workoutStartTime])
            workout.endTime = UInt32(row[workoutEndTime])
            workout.totalSteps = UInt32(row[workoutTotalSteps])
            workout.totalDistance = UInt32(row[workoutTotalDistance])
            workout.totalTime = UInt32(row[workoutTotalTime])
            workout.totalCalories = UInt32(row[workoutTotalCalories])
            workout.totalHeight = UInt32(row[workoutTotalHeight])
            workout.avgHeartRate = UInt32(row[workoutAvgHeartRate])
            workout.avgSpeed = UInt32(row[workoutAvgSpeed])
            workout.maxSpeed = UInt32(row[workoutMaxSpeed])
            workout.avgFrequency = UInt32(row[workoutAvgFrequency])
            workout.extra = row[workoutExtra]
            
            // Fetch GPS data for this workout
            let gpsQuery = gpsTable.filter(gpsSportID == workout.sportID)
            if let gpsRow = try db.pluck(gpsQuery) {
                let timestampJSON = gpsRow[gpsTimestampArray]
                let latitudeJSON = gpsRow[gpsLatitudeArray]
                let longitudeJSON = gpsRow[gpsLongitudeArray]
                let stateJSON = gpsRow[gpsStateArray]
                let speedJSON = gpsRow[gpsSpeedArray]
                
                workout.gpsModel.timestamp = try JSONDecoder().decode([UInt64].self, from: Data(base64Encoded: timestampJSON)!)
                workout.gpsModel.latitude = try JSONDecoder().decode([Int32].self, from: Data(base64Encoded: latitudeJSON)!)
                workout.gpsModel.longitude = try JSONDecoder().decode([Int32].self, from: Data(base64Encoded: longitudeJSON)!)
                workout.gpsModel.state = try JSONDecoder().decode([UInt32].self, from: Data(base64Encoded: stateJSON)!)
                workout.gpsModel.speed = try JSONDecoder().decode([Float].self, from: Data(base64Encoded: speedJSON)!)
            }
            
            result.append(workout)
        }
        return result
    }
    
    func fetchWorkoutInfoBySportID(_ sportID: String) throws -> OPHealthWorkoutInfoModel? {
        let query = workoutTable.filter(workoutSportID == sportID)
        if let row = try db.pluck(query) {
            let workout = OPHealthWorkoutInfoModel()
            workout.sportID = row[workoutSportID]
            workout.sportType = UInt32(row[workoutSportType])
            workout.sportName = UInt32(row[workoutSportName])
            workout.startTime = UInt32(row[workoutStartTime])
            workout.endTime = UInt32(row[workoutEndTime])
            workout.totalSteps = UInt32(row[workoutTotalSteps])
            workout.totalDistance = UInt32(row[workoutTotalDistance])
            workout.totalTime = UInt32(row[workoutTotalTime])
            workout.totalCalories = UInt32(row[workoutTotalCalories])
            workout.totalHeight = UInt32(row[workoutTotalHeight])
            workout.avgHeartRate = UInt32(row[workoutAvgHeartRate])
            workout.avgSpeed = UInt32(row[workoutAvgSpeed])
            workout.maxSpeed = UInt32(row[workoutMaxSpeed])
            workout.avgFrequency = UInt32(row[workoutAvgFrequency])
            workout.extra = row[workoutExtra]
            
            // Fetch GPS data for this workout
            let gpsQuery = gpsTable.filter(gpsSportID == sportID)
            if let gpsRow = try db.pluck(gpsQuery) {
                let timestampJSON = gpsRow[gpsTimestampArray]
                let latitudeJSON = gpsRow[gpsLatitudeArray]
                let longitudeJSON = gpsRow[gpsLongitudeArray]
                let stateJSON = gpsRow[gpsStateArray]
                let speedJSON = gpsRow[gpsSpeedArray]
                
                workout.gpsModel.timestamp = try JSONDecoder().decode([UInt64].self, from: Data(base64Encoded: timestampJSON)!)
                workout.gpsModel.latitude = try JSONDecoder().decode([Int32].self, from: Data(base64Encoded: latitudeJSON)!)
                workout.gpsModel.longitude = try JSONDecoder().decode([Int32].self, from: Data(base64Encoded: longitudeJSON)!)
                workout.gpsModel.state = try JSONDecoder().decode([UInt32].self, from: Data(base64Encoded: stateJSON)!)
                workout.gpsModel.speed = try JSONDecoder().decode([Float].self, from: Data(base64Encoded: speedJSON)!)
            }
            
            return workout
        }
        return nil
    }
    
    func deleteWorkoutInfoBySportID(_ sportID: String) throws {
        try db.run(workoutTable.filter(workoutSportID == sportID).delete())
        try db.run(gpsTable.filter(gpsSportID == sportID).delete())
    }
    
    // MARK: - HeartRate Methods
    func insertHeartRate(_ heartRate: OPHealthHeartRateModel) throws {
        let insert = heartRateTable.insert(
            heartRateTimeOffset <- heartRate.time_offset,
            heartRateValue <- heartRate.heart_rate,
            heartRateReliability <- Int64(heartRate.reliability),
            heartRateType <- Int64(heartRate.type)
        )
        try db.run(insert)
    }
    
    func fetchAllHeartRate() throws -> [OPHealthHeartRateModel] {
        var result: [OPHealthHeartRateModel] = []
        for row in try db.prepare(heartRateTable) {
            let heartRate = OPHealthHeartRateModel()
            heartRate.time_offset = row[heartRateTimeOffset]
            heartRate.heart_rate = row[heartRateValue]
            heartRate.reliability = Int(row[heartRateReliability])
            heartRate.type = Int(row[heartRateType])
            result.append(heartRate)
        }
        return result
    }
    
    // MARK: - BreatheRate Methods
    func insertBreatheRate(_ breatheRate: OPHealthBreatheRateModel) throws {
        let insert = breatheRateTable.insert(
            breatheRateTimeOffset <- breatheRate.time_offset,
            breatheRateValue <- Int64(breatheRate.breath_rate)
        )
        try db.run(insert)
    }
    
    func fetchAllBreatheRate() throws -> [OPHealthBreatheRateModel] {
        var result: [OPHealthBreatheRateModel] = []
        for row in try db.prepare(breatheRateTable) {
            let breatheRate = OPHealthBreatheRateModel()
            breatheRate.time_offset = row[breatheRateTimeOffset]
            breatheRate.breath_rate = Int(row[breatheRateValue])
            result.append(breatheRate)
        }
        return result
    }
    
    // MARK: - SleepInfo Methods
    func insertSleepInfo(_ sleepInfo: OPHealthSleepInfoModel) throws {
        let insert = sleepInfoTable.insert(
            sleepInfoTimeStamp <- Int64(sleepInfo.time_stamp),
            sleepInfoState <- Int64(sleepInfo.state)
        )
        try db.run(insert)
    }
    
    func fetchAllSleepInfo() throws -> [OPHealthSleepInfoModel] {
        var result: [OPHealthSleepInfoModel] = []
        for row in try db.prepare(sleepInfoTable) {
            let sleepInfo = OPHealthSleepInfoModel()
            sleepInfo.time_stamp = Int(row[sleepInfoTimeStamp])
            sleepInfo.state = Int(row[sleepInfoState])
            result.append(sleepInfo)
        }
        return result
    }
    
    // MARK: - BloodOxygen Methods
    func insertBloodOxygen(_ bloodOxygen: OPHealthBloodOxygenModel) throws {
        let insert = bloodOxygenTable.insert(
            bloodOxygenTimeStamp <- Int64(bloodOxygen.time_stamp),
            bloodOxygenType <- Int64(bloodOxygen.type),
            bloodOxygenValue <- Int64(bloodOxygen.value)
        )
        try db.run(insert)
    }
    
    func fetchAllBloodOxygen() throws -> [OPHealthBloodOxygenModel] {
        var result: [OPHealthBloodOxygenModel] = []
        for row in try db.prepare(bloodOxygenTable) {
            let bloodOxygen = OPHealthBloodOxygenModel()
            bloodOxygen.time_stamp = Int(row[bloodOxygenTimeStamp])
            bloodOxygen.type = Int(row[bloodOxygenType])
            bloodOxygen.value = Int(row[bloodOxygenValue])
            result.append(bloodOxygen)
        }
        return result
    }
}