Reflection.swift 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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 uintValue = value as? UInt { map.append((key, String(uintValue))) }
  44. if let int8Value = value as? Int8 { map.append((key, String(int8Value))) }
  45. if let uint8Value = value as? UInt8 { map.append((key, String(uint8Value))) }
  46. if let int16Value = value as? Int16 { map.append((key, String(int16Value))) }
  47. if let uint16Value = value as? UInt16 { map.append((key, String(uint16Value))) }
  48. if let int32Value = value as? Int32 { map.append((key, String(int32Value))) }
  49. if let uint32Value = value as? UInt32 { map.append((key, String(uint32Value))) }
  50. if let int64Value = value as? Int64 { map.append((key, String(int64Value))) }
  51. if let uint64Value = value as? UInt64 { map.append((key, String(uint64Value))) }
  52. if let floatValue = value as? Float { map.append((key, String(floatValue))) }
  53. if let doubleValue = value as? Double { map.append((key, String(doubleValue))) }
  54. if let stringValue = value as? String { map.append((key, stringValue)) }
  55. }
  56. return (name, map)
  57. }
  58. public static func classInstanceWithSchemeMethod1() -> (Self, String, [String: Any?]) {
  59. let instance = Self()
  60. let (name, fields) = instance.schemeWithValuesMethod1()
  61. return (instance, name, fields)
  62. }
  63. public static func classInstanceWithSchemeMethod2() -> (Self, String, [String: Any?]) {
  64. let instance = Self()
  65. let (name, fields) = instance.schemeWithValuesMethod2()
  66. return (instance, name, fields)
  67. }
  68. static func find(id: UInt64) -> Self? {
  69. let (instance, _, _) = classInstanceWithSchemeMethod1()
  70. // TODO - make a query to DB
  71. return instance
  72. }
  73. public func insert() throws {
  74. guard let database = DatabaseReflection.sharedDatabase else {
  75. throw SQLiteError.OpenFailed("Database connection is not opened.")
  76. }
  77. let (name, fields) = schemeWithValuesAsString()
  78. try database.exec("CREATE TABLE IF NOT EXISTS \(name) (" + fields.map { "\($0.0) TEXT" }.joined(separator: ", ") + ");")
  79. let names = fields.map { "\($0.0)" }.joined(separator: ", ")
  80. let values = Array(repeating: "?", count: fields.count).joined(separator: ", ")
  81. try database.exec("INSERT INTO \(name)(" + names + ") VALUES(" + values + ");", fields.map { $0.1 })
  82. }
  83. }
  84. public func memoryLayoutForStructure(object: Any) -> [String: Range<Int>] {
  85. var layout = [String: Range<Int>]()
  86. var size = 0
  87. var alignment = 1
  88. for case let (label?, value) in Mirror(reflecting: object).children {
  89. var fieldLength = 0
  90. // TODO - Replace this with something smarter.
  91. if value is Int { fieldLength = sizeof(Int) } else
  92. if value is UInt { fieldLength = sizeof(UInt) } else
  93. if value is Int8 { fieldLength = sizeof(Int8) } else
  94. if value is UInt8 { fieldLength = sizeof(UInt8) } else
  95. if value is Int16 { fieldLength = sizeof(Int16) } else
  96. if value is UInt16 { fieldLength = sizeof(UInt16)} else
  97. if value is Int32 { fieldLength = sizeof(Int32) } else
  98. if value is UInt32 { fieldLength = sizeof(UInt32)} else
  99. if value is Int64 { fieldLength = sizeof(Int64) } else
  100. if value is UInt64 { fieldLength = sizeof(UInt64)} else
  101. if value is Float { fieldLength = sizeof(Float) } else
  102. if value is Double { fieldLength = sizeof(Double)} else
  103. if value is String { fieldLength = sizeof(String)}
  104. if fieldLength <= alignment {
  105. layout[label] = size ..< size + fieldLength
  106. size = size + fieldLength
  107. alignment = fieldLength
  108. } else {
  109. let offset = size + (fieldLength > size ? (fieldLength - size) : (size % fieldLength))
  110. layout[label] = offset ..< offset + fieldLength
  111. size = offset + fieldLength
  112. alignment = fieldLength
  113. }
  114. }
  115. return layout
  116. }