mike4aday / SwiftlySalesforce

The Swift-est way to build native mobile apps that connect to Salesforce.
MIT License
136 stars 43 forks source link

Is there another way to perform salesforce.nextResultPage in V10? #144

Closed perbrondum closed 2 years ago

mike4aday commented 2 years ago

@perbrondum sorry, I missed this issue. I neglected to include a 'convenience' method in Connection+API.swift but you could quickly create your own:

func nextResultsPage(path: String) async throws -> QueryResult<Record> {
    return try await request(service: Resource.Query.NextResultsPage(path: path))
}

I will add this to Connection+API.swift for next release.

perbrondum commented 2 years ago

I tried to create the extension:

import Foundation
import SwiftlySalesforce

extension Connection {
    func nextResultsPage(path: String) async throws -> QueryResult<Record> {
        return try await request(service: Resource.Query.NextResultsPage(path: path))
    }
}

But I get: 'Query' is inaccessible due to 'internal' protection level

mike4aday commented 2 years ago

Sorry @perbrondum - since Query is inaccessible, you could instead just create your own struct by copying Resource.Query.NextResults as:

struct MyOwnNextResultsPage<T: Decodable>: DataService {

    typealias Output = QueryResult<T>

    let path: String

    var batchSize: Int? = nil

    func createRequest(with credential: Credential) throws -> URLRequest {
        let headers = batchSize.map { ["Sforce-Query-Options" : "batchSize=\($0)"] }
        return try URLRequest(credential: credential, path: path, headers: headers)
    }
}

and then in your extension:

func nextResultsPage(path: String) async throws -> QueryResult<Record> {
    return try await request(service: MyOwnNextResultsPage(path: path))
}

(Or you could define the struct above within the extension method if the struct won't be reused elsewhere.)

perbrondum commented 2 years ago

That works, thanks. Is there a reason that nextResultsPage returns <QueryResult and not a generic?

mike4aday commented 2 years ago

Hi @perbrondum not sure I understand your question - the above nextResultsPage method returns a QueryResult<Record> but you could modify it to return QueryResult<T> instead where T is your own custom Decodable type, and Swiftly Salesforce would automatically decode the result's records, if any, into that type. I included my own type, Record, for those who don't want to define their own Decodable types and don't mind using strings to access the field values.

perbrondum commented 2 years ago

I got the above to work with both Record and my own decodable type SFDCTask, by creating two versions of nextResultsPage. I tried but, my generics is not strong enough to be able to write a version of nextResultsPage that supports it. My only concern was if the official version of nextResultsPage will support generics? Btw, one of the reasons I continue to use my own type [SFDCTask] is that I'm not sure how to address items like 'task.Account.Name' using strings. Can you point me to a source (or example) for how to address this using strings?