1

I have a struct that has some properties, a CodingKey enum (in order to conforms to Codable protocol) and some computed-vars that returns an array of keys mapped to string.

What I'm trying to do, is to extract those computed-vars to a protocol (super-class if I have to change the struct to a class) for avoiding to repeat the implementation in every struct/class. And I need a lot of them.

The problem is that I cannot find a way to know the CodingKey enum.

Edit: DBentity

/// Basic protocol for any object directly related with a database table.
public protocol DBEntity: Codable, Equatable {}

The code:

///////////////////////////////////////////////////////////////////////

// MARK: - Entity Properties

struct AccountsAddresses: DBEntity {

    let statusMobile: String?
    let codeAccount: Int?
    let codeUnitOrg: String?
    let codeSalesOrg: String?
    let codeAddress: Int?
    let codeType: String?
    let byDefault: String?
    let transfered: String?
}

///////////////////////////////////////////////////////////////////////

// MARK: - Table Columns

extension AccountsAddresses {

    /// Table name.
    static var tableName = "ACCOUNTS_ADDRESSES"

    /// Table columns keys.
    enum CodingKeys: String, CodingKey, CaseIterable {
        case statusMobile   = "status_mobile"
        case codeAccount    = "code_account"
        case codeUnitOrg    = "code_unit_org"
        case codeSalesOrg   = "code_sales_org"
        case codeAddress    = "code_address"
        case codeType       = "code_type"
        case byDefault      = "by_default"
        case transfered
    }

/* This is what I'm trying to extract to a protocol(extension) or super-class. */

    /// All table columns keys.
    static var columns: [String] = CodingKeys.allCases.map { $0.rawValue }
    static var columnsJoined: String = columns.joined(separator: String.commaSpace)
    static var columnsTableName: [String] = columns.map { tableName + String.dot + $0 }
    static var columnsJoinedTableName: String = columnsTableName.joined(separator: String.commaSpace)
}

EDIT

Using the given code from Sweeper's answer, I'm trying to implement the protocol in a new struct, but the compiler asks to set a type to the typealias CodingKeyType (since the defined protocol has the associatedtype).

public protocol Table {
    associatedtype ColumnKeysType: (CodingKey & CaseIterable & RawRepresentable)
    static var tablename: String { get }
}

Here the struct to test:

struct AccountsTest: Table {

    typealias CodingKeyType = <#type#>
}

I've tried to make another struct in order to have a type to assign to the typealias, but there's something that I'm missing/doing wrong (I had to implement this vars, constructors & typealias).

struct Keys: (CodingKey & CaseIterable & RawRepresentable) {

    var stringValue: String
    var rawValue: String
    var intValue: Int?

    init?(stringValue: String) {}
    init?(rawValue: String) {}
    init?(intValue: Int) {}

    typealias AllCases = Keys.RawValue
    typealias RawValue = String
}

The compiler continues showing errors and I can't find the way to accomplish this.

'CaseIterable' requires the types 'Keys' and 'String.Element' (aka 'Character') be equivalent

Any tip to get this done?

Thank you

2
  • So what is DBEntity? Commented Apr 23, 2019 at 13:38
  • @matt (post edited) DBEntity is protocol for any object directly related with a database table. Commented Apr 23, 2019 at 13:46

2 Answers 2

1

Note that the properties you are trying to extract are not computed properties.

The properties you want to extract seems to only depend on tableName and CodingKeys, so we can write a protocol like this:

protocol SomeProtocol {
    associatedtype CodingKeyType : (CodingKey & CaseIterable & RawRepresentable)
    static var tableName: String { get }
}

and then an extension like this (I have converted the properties to computed properties):

extension SomeProtocol where CodingKeyType.RawValue == String {
    static var columns: [String] { return CodingKeyType.allCases.map { $0.rawValue } }
    static var columnsJoined: String { return columns.joined(separator: " ") }
    static var columnsTableName: [String] { return columns.map { tableName + "." + $0 } }
    static var columnsJoinedTableName: String { return columnsTableName.joined(separator: " ") }
}
Sign up to request clarification or add additional context in comments.

4 Comments

You're completely right, I was wrong about the computed properties (what a mistake). Thankyou so much for the answer! This is exactly what I was looking for! You rock!
I've edit the original post to add new code that is showing me errors. I cannot find a type to set to the typealias CodingKeyType...
@JavierFernandezMartínez you should put the CodingKeys Enum as the typealias. There is no need to create a new type.
I already tried that: typealias ColumnKeysType = CodingKeys but the compiler continued showing errors. My mistake now was that I removed accidentally the protocols CodingKey, CaseIterable from the CodingKeys enum. Now is working as expected. Thank you again!
-1

You don't need to do the conversion by yourself. You can use decoder.keyDecodingStrategy = .convertFromSnakeCase and your json will get mapped to your camel case properties.

For More information:

https://developer.apple.com/documentation/foundation/jsondecoder/keydecodingstrategy/convertfromsnakecase

1 Comment

thankyou for the answer! I'd tried working with the keyDecodingStrategy but (unfortunately) some keys are not conforming an exactly snakecase naming.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.