AlgorithmGlucose.swift 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import Foundation
  2. /// Helper class so that we can have a plain Swift object to serialize GlucoseStorage
  3. struct AlgorithmGlucose: Codable {
  4. var date: Date?
  5. var direction: String?
  6. var glucose: Int16
  7. var id: UUID?
  8. var isManual: Bool
  9. enum CodingKeys: String, CodingKey {
  10. case date
  11. case dateString
  12. case sgv
  13. case glucose
  14. case direction
  15. case id
  16. case type
  17. }
  18. init(date: Date?, direction: String?, glucose: Int16, id: UUID?, isManual: Bool) {
  19. self.date = date
  20. self.direction = direction
  21. self.glucose = glucose
  22. self.id = id
  23. self.isManual = isManual
  24. }
  25. // this constructor is just for testing
  26. public init(from decoder: Decoder) throws {
  27. let container = try decoder.container(keyedBy: CodingKeys.self)
  28. if let dateString = try container.decodeIfPresent(String.self, forKey: .dateString) {
  29. let dateFormatter = ISO8601DateFormatter()
  30. dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
  31. date = dateFormatter.date(from: dateString)
  32. } else if let dateStringTimestamp = try container.decodeIfPresent(String.self, forKey: .date),
  33. let dateTimestamp = TimeInterval(dateStringTimestamp)
  34. {
  35. date = Date(timeIntervalSince1970: dateTimestamp / 1000)
  36. } else {
  37. date = nil
  38. }
  39. direction = try container.decodeIfPresent(String.self, forKey: .direction)
  40. id = try container.decodeIfPresent(UUID.self, forKey: .id)
  41. if let glucoseValue = try container.decodeIfPresent(Int16.self, forKey: .glucose) {
  42. glucose = glucoseValue
  43. isManual = true
  44. } else if let sgvValue = try container.decodeIfPresent(Int16.self, forKey: .sgv) {
  45. glucose = sgvValue
  46. isManual = false
  47. } else {
  48. throw DecodingError.dataCorruptedError(
  49. forKey: .sgv,
  50. in: container,
  51. debugDescription: "Neither 'glucose' nor 'sgv' key found or value is not Int16"
  52. )
  53. }
  54. }
  55. public func encode(to encoder: Encoder) throws {
  56. var container = encoder.container(keyedBy: CodingKeys.self)
  57. let dateFormatter = ISO8601DateFormatter()
  58. dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
  59. try container.encode(dateFormatter.string(from: date ?? Date()), forKey: .dateString)
  60. let dateAsUnixTimestamp = Int64((date?.timeIntervalSince1970 ?? Date().timeIntervalSince1970) * 1000)
  61. try container.encode(dateAsUnixTimestamp, forKey: .date)
  62. try container.encode(direction, forKey: .direction)
  63. try container.encode(id, forKey: .id)
  64. // TODO: Handle the type of the glucose entry conditionally not hardcoded
  65. try container.encode("sgv", forKey: .type)
  66. if isManual {
  67. try container.encode(glucose, forKey: .glucose)
  68. } else {
  69. try container.encode(glucose, forKey: .sgv)
  70. }
  71. }
  72. }