FileStorage.swift 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import Disk
  2. import Foundation
  3. protocol FileStorage {
  4. func save<Value: JSON>(_ value: Value, as name: String) throws
  5. func retrieve<Value: JSON>(_ name: String, as type: Value.Type) throws -> Value
  6. func append<Value: JSON>(_ newValue: Value, to name: String) throws
  7. func append<Value: JSON>(_ newValues: [Value], to name: String) throws
  8. func append<Value: JSON, T: Equatable>(_ newValue: Value, to name: String, uniqBy keyPath: KeyPath<Value, T>) throws
  9. func append<Value: JSON, T: Equatable>(_ newValues: [Value], to name: String, uniqBy keyPath: KeyPath<Value, T>) throws
  10. func remove(_ name: String) throws
  11. func rename(_ name: String, to newName: String) throws
  12. }
  13. final class BaseFileStorage: FileStorage {
  14. private let processQueue = DispatchQueue(label: "BaseFileStorage.processQueue")
  15. private var encoder: JSONEncoder {
  16. let encoder = JSONEncoder()
  17. encoder.outputFormatting = .prettyPrinted
  18. encoder.dateEncodingStrategy = .iso8601
  19. return encoder
  20. }
  21. private var decoder: JSONDecoder {
  22. let decoder = JSONDecoder()
  23. decoder.dateDecodingStrategy = .iso8601
  24. return decoder
  25. }
  26. func save<Value: JSON>(_ value: Value, as name: String) throws {
  27. try processQueue.sync {
  28. try Disk.save(value, to: .documents, as: name, encoder: self.encoder)
  29. }
  30. }
  31. func retrieve<Value: JSON>(_ name: String, as type: Value.Type) throws -> Value {
  32. try processQueue.sync {
  33. try Disk.retrieve(name, from: .documents, as: type, decoder: decoder)
  34. }
  35. }
  36. func append<Value: JSON>(_ newValue: Value, to name: String) throws {
  37. try processQueue.sync {
  38. try Disk.append(newValue, to: name, in: .documents, decoder: decoder, encoder: encoder)
  39. }
  40. }
  41. func append<Value: JSON>(_ newValues: [Value], to name: String) throws {
  42. try processQueue.sync {
  43. try Disk.append(newValues, to: name, in: .documents, decoder: decoder, encoder: encoder)
  44. }
  45. }
  46. func append<Value: JSON, T: Equatable>(_ newValue: Value, to name: String, uniqBy keyPath: KeyPath<Value, T>) throws {
  47. if let value = try? retrieve(name, as: Value.self) {
  48. if value[keyPath: keyPath] != newValue[keyPath: keyPath] {
  49. try append(newValue, to: name)
  50. }
  51. } else if let values = try? retrieve(name, as: [Value].self) {
  52. guard values.first(where: { $0[keyPath: keyPath] == newValue[keyPath: keyPath] }) == nil else {
  53. return
  54. }
  55. try append(newValue, to: name)
  56. } else {
  57. try save(newValue, as: name)
  58. }
  59. }
  60. func append<Value: JSON, T: Equatable>(_ newValues: [Value], to name: String, uniqBy keyPath: KeyPath<Value, T>) throws {
  61. if let value = try? retrieve(name, as: Value.self) {
  62. guard newValues.first(where: { $0[keyPath: keyPath] == value[keyPath: keyPath] }) == nil else {
  63. return
  64. }
  65. try append(newValues, to: name)
  66. } else if let values = try? retrieve(name, as: [Value].self) {
  67. try newValues.forEach { newValue in
  68. guard values.first(where: { $0[keyPath: keyPath] == newValue[keyPath: keyPath] }) == nil else {
  69. return
  70. }
  71. try append(newValue, to: name)
  72. }
  73. } else {
  74. try save(newValues, as: name)
  75. }
  76. }
  77. func remove(_ name: String) throws {
  78. try processQueue.sync {
  79. try Disk.remove(name, from: .documents)
  80. }
  81. }
  82. func rename(_ name: String, to newName: String) throws {
  83. try processQueue.sync {
  84. try Disk.rename(name, in: .documents, to: newName)
  85. }
  86. }
  87. }