mardi 12 avril 2016

I found a generic way to turn a class into a dictionary, is there a generic way to reverse that process?

So I'm trying to build a data-mapper style ORM in Swift. I was trying to find a way to turn any entity into a dictionary so I could map that to a database table. I managed to do that with this code:

public protocol Entity: class {
    var id: Int? { get set }
}

func unwrap(any:Any) -> Any? {
    let mi = Mirror(reflecting: any)

    if mi.displayStyle != .Optional {
        return any
    }

    if mi.children.count == 0 {
        return nil
    }

    let (_, some) = mi.children.first!

    return some
}

public func serialize<T: Entity>(entity: T) -> [String:String] {
    let aMirror = Mirror(reflecting: entity)
    var dict = [String:String]()

    for child in aMirror.children {
        if let label = child.label where !label.hasPrefix("_") {
            switch unwrap(child.value) {
            case let entity as Entity:
                if let id = entity.id {
                    dict[label] = String(id)
                }
            case let .Some(test):
                dict[child.label!] = String(test)
            default: break
            }
        }
    }

    return dict
}

public class User: Entity {
    public var id: Int?
    var username: String
    var password: String
    var role: UserRole?

    public init(username: String, password: String) {
        self.username = username
        self.password = password
    }

    public func assignRole(role: UserRole) {
        self.role = role
    }
}

public class UserRole: Entity {
    public var id: Int?
    var name: String
    var description: String

    public init(name: String, description: String) {
        self.name = name
        self.description = description
    }
}

So now I can do:

let newUser = User(username: "NotMyRealName", password: "SomeKindOfPassword")
let adminRole = UserRole(name: "admin", description: "Administrator of the website")
adminRole.id = 1

newUser.assignRole(adminRole)

print(serialize(newUser))

Which will print: ["password": "SomeKindOfPassword", "role": "1", "username": "NotMyRealName"]

That's all well and good, but now I want to reverse this process.

I'd like to write a function that could use like so:

let user = unserialize(["username":"Me", "password":"secret"]) as? User

Is that possible you think? I understand it might be a bit of a hack if I'd try to bypass the init method, but I'd like to try.





Aucun commentaire:

Enregistrer un commentaire