1
votes

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?matt
@matt (post edited) DBEntity is protocol for any object directly related with a database table.Javier Fernandez Martínez

2 Answers

1
votes

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: " ") }
}
-1
votes

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