iosswiftsap-cloud-sdk

Encode/Decode Array of SAPOData.EntityValue to CompositeStorage


I'm working with SAP Cloud Platform SDK for iOS, trying to figure out how to put an array of EntityValues into a CompositeStorage, and get them out. I'm getting error:

typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [Foundation.(_PlistKey in _5692656F4C05BA2A580AE9322E9FB0A6)(stringValue: "Index 0", intValue: Optional(0)), Foundation.(_PlistKey in _5692656F4C05BA2A580AE9322E9FB0A6)(stringValue: "Index 0", intValue: Optional(0))], debugDescription: "Expected to decode Dictionary but found __NSCFData instead.", underlyingError: nil))

I'm trying to get the values from the CompositeStore here:

var entities: [ExpensereportType] {
    do {
        guard let results = try Cache.shared.store.get(Array<ExpensereportType>.self, for: CollectionType.expensereport.rawValue) else {
            return []
        }
        return results
    }
    catch {
        print(error)
        return []
    }
}

And they're being encoded here:

self.service.fetchReservation(matching: query) { result, error in
    guard let result = result else { return completionHandler(error!) }

    do {
        let encodedResult = try JSONEncoder().encode(result)
        try self.store.put(encodedResult, for: CollectionType.reservation.rawValue)
    }
    catch {
        completionHandler(error)
    }
    completionHandler(nil)
}

Any ideas?


Solution

  • The solution for this one is interesting: it turns out that the JSONEncoder is smart enough to handle either the Array<EntityValue> as-is, or have the individual items be map-encoded. But, the JSONDecoder automatically handles the top-level Array item, and it is up to you to map-decode the items.

    Working solution:

    // MARK: - Encode
    self.service.fetchReservation(matching: query) { result, error in
            guard let result = result else {
                completionHandler(error!)
                return
            }
    
            do {
                let encodedResult = try JSONEncoder().encode(result)
                // try result.map { try JSONEncoder().encode($0) }   ALSO VALID
                try self.store.put(encodedResult, for: CollectionType.expensereport.rawValue)
            }
    //...
    
    // MARK: - Decode `Array<ExpensereportType>`
    guard let results = try Cache.shared.store.get(Array<ExpensereportType>.self, for: CollectionType.expensereport.rawValue) else {
        return []
    }
    let decoder = JSONDecoder()
    decoder.userInfo.updateValue(myDataService.metadata, forKey: CSDLDocument.csdlInfoKey)
    return try results.map { try decoder.decode(ExpensereportType.self, from: $0)}