Reflection.swift 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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 schemeWithValuesMethod2() -> (String, [String: Any?]) {
  19. let mirror = Mirror(reflecting: self)
  20. var fields = [String: Any?]()
  21. for case let (label?, value) in mirror.children {
  22. fields[label] = value
  23. }
  24. return ("\(mirror.subjectType)", fields)
  25. }
  26. public func schemeWithValuesAsString() -> (String, [(String, String?)]) {
  27. let (name, fields) = schemeWithValuesMethod2()
  28. var map = [(String, String?)]()
  29. for (key, value) in fields {
  30. // TODO - Replace this by extending all supported types by a protocol.
  31. // Example: 'extenstion Int: DatabaseConvertible { convert() -> something ( not necessary String type ) }'
  32. if let intValue = value as? Int { map.append((key, String(intValue))) }
  33. if let uintValue = value as? UInt { map.append((key, String(uintValue))) }
  34. if let int8Value = value as? Int8 { map.append((key, String(int8Value))) }
  35. if let uint8Value = value as? UInt8 { map.append((key, String(uint8Value))) }
  36. if let int16Value = value as? Int16 { map.append((key, String(int16Value))) }
  37. if let uint16Value = value as? UInt16 { map.append((key, String(uint16Value))) }
  38. if let int32Value = value as? Int32 { map.append((key, String(int32Value))) }
  39. if let uint32Value = value as? UInt32 { map.append((key, String(uint32Value))) }
  40. if let int64Value = value as? Int64 { map.append((key, String(int64Value))) }
  41. if let uint64Value = value as? UInt64 { map.append((key, String(uint64Value))) }
  42. if let floatValue = value as? Float { map.append((key, String(floatValue))) }
  43. if let doubleValue = value as? Double { map.append((key, String(doubleValue))) }
  44. if let stringValue = value as? String { map.append((key, stringValue)) }
  45. }
  46. return (name, map)
  47. }
  48. public static func classInstanceWithSchemeMethod2() -> (Self, String, [String: Any?]) {
  49. let instance = Self()
  50. let (name, fields) = instance.schemeWithValuesMethod2()
  51. return (instance, name, fields)
  52. }
  53. static func find(_ id: UInt64) -> Self? {
  54. let (instance, _, _) = classInstanceWithSchemeMethod2()
  55. // TODO - make a query to DB
  56. return instance
  57. }
  58. public func insert() throws {
  59. guard let database = DatabaseReflection.sharedDatabase else {
  60. throw SQLiteError.openFailed("Database connection is not opened.")
  61. }
  62. let (name, fields) = schemeWithValuesAsString()
  63. try database.exec("CREATE TABLE IF NOT EXISTS \(name) (" + fields.map { "\($0.0) TEXT" }.joined(separator: ", ") + ");")
  64. let names = fields.map { "\($0.0)" }.joined(separator: ", ")
  65. let values = Array(repeating: "?", count: fields.count).joined(separator: ", ")
  66. try database.exec("INSERT INTO \(name)(" + names + ") VALUES(" + values + ");", fields.map { $0.1 })
  67. }
  68. }
  69. public func memoryLayoutForStructure(_ object: Any) -> [String: CountableRange<Int>] {
  70. var layout = [String: CountableRange<Int>]()
  71. var size = 0
  72. var alignment = 1
  73. for case let (label?, value) in Mirror(reflecting: object).children {
  74. var fieldLength = 0
  75. // TODO - Replace this with something smarter.
  76. if value is Int { fieldLength = sizeof(Int.self) } else
  77. if value is UInt { fieldLength = sizeof(UInt.self) } else
  78. if value is Int8 { fieldLength = sizeof(Int8.self) } else
  79. if value is UInt8 { fieldLength = sizeof(UInt8.self) } else
  80. if value is Int16 { fieldLength = sizeof(Int16.self) } else
  81. if value is UInt16 { fieldLength = sizeof(UInt16.self)} else
  82. if value is Int32 { fieldLength = sizeof(Int32.self) } else
  83. if value is UInt32 { fieldLength = sizeof(UInt32.self)} else
  84. if value is Int64 { fieldLength = sizeof(Int64.self) } else
  85. if value is UInt64 { fieldLength = sizeof(UInt64.self)} else
  86. if value is Float { fieldLength = sizeof(Float.self) } else
  87. if value is Double { fieldLength = sizeof(Double.self)} else
  88. if value is String { fieldLength = sizeof(String.self)}
  89. if fieldLength <= alignment {
  90. layout[label] = size ..< size + fieldLength
  91. size = size + fieldLength
  92. alignment = fieldLength
  93. } else {
  94. let offset = size + (fieldLength > size ? (fieldLength - size) : (size % fieldLength))
  95. layout[label] = offset ..< offset + fieldLength
  96. size = offset + fieldLength
  97. alignment = fieldLength
  98. }
  99. }
  100. return layout
  101. }