Reflection.swift 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. //
  2. // Relfection.swift
  3. // Swifter
  4. //
  5. // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. import Foundation
  8. public protocol DatabaseReflectionProtocol {
  9. var id: UInt64? { get }
  10. init()
  11. }
  12. public class DatabaseReflection: DatabaseReflectionProtocol {
  13. static var sharedDatabase: SQLite?
  14. public var id: UInt64? = nil
  15. required public init() { }
  16. }
  17. public extension DatabaseReflectionProtocol {
  18. public func schemeWithValuesMethod1() -> (String, [String: Any?]) {
  19. let reflections = _reflect(self)
  20. var fields = [String: Any?]()
  21. for index in stride(from: 0, to: reflections.count, by: 1) {
  22. let reflection = reflections[index]
  23. fields[reflection.0] = reflection.1.value
  24. }
  25. return (reflections.summary, fields)
  26. }
  27. public func schemeWithValuesMethod2() -> (String, [String: Any?]) {
  28. let mirror = Mirror(reflecting: self)
  29. var fields = [String: Any?]()
  30. for case let (label?, value) in mirror.children {
  31. fields[label] = value
  32. }
  33. return ("\(mirror.subjectType)", fields)
  34. }
  35. public func schemeWithValuesAsString() -> (String, [(String, String?)]) {
  36. let (name, fields) = schemeWithValuesMethod2()
  37. let (_, _) = schemeWithValuesMethod1()
  38. var map = [(String, String?)]()
  39. for (key, value) in fields {
  40. // TODO - Replace this by extending all supported types by a protocol.
  41. // Example: 'extenstion Int: DatabaseConvertible { convert() -> something ( not necessary String type ) }'
  42. if let intValue = value as? Int { map.append((key, String(intValue))) }
  43. if let int32Value = value as? Int32 { map.append((key, String(int32Value))) }
  44. if let int64Value = value as? Int64 { map.append((key, String(int64Value))) }
  45. if let doubleValue = value as? Double { map.append((key, String(doubleValue))) }
  46. if let stringValue = value as? String { map.append((key, stringValue)) }
  47. }
  48. return (name, map)
  49. }
  50. public static func classInstanceWithSchemeMethod1() -> (Self, String, [String: Any?]) {
  51. let instance = Self()
  52. let (name, fields) = instance.schemeWithValuesMethod1()
  53. return (instance, name, fields)
  54. }
  55. public static func classInstanceWithSchemeMethod2() -> (Self, String, [String: Any?]) {
  56. let instance = Self()
  57. let (name, fields) = instance.schemeWithValuesMethod2()
  58. return (instance, name, fields)
  59. }
  60. static func find(id: UInt64) -> Self? {
  61. let (instance, _, _) = classInstanceWithSchemeMethod1()
  62. // TODO - make a query to DB
  63. return instance
  64. }
  65. public func insert() throws {
  66. guard let database = DatabaseReflection.sharedDatabase else {
  67. throw SQLiteError.OpenFailed("Database connection is not opened.")
  68. }
  69. let (name, fields) = schemeWithValuesAsString()
  70. try database.exec("CREATE TABLE IF NOT EXISTS \(name) (" + fields.map { "\($0.0) TEXT" }.joined(separator: ", ") + ");")
  71. let names = fields.map { "\($0.0)" }.joined(separator: ", ")
  72. let values = Array(repeating: "?", count: fields.count).joined(separator: ", ")
  73. try database.exec("INSERT INTO \(name)(" + names + ") VALUES(" + values + ");", fields.map { $0.1 })
  74. }
  75. }