mike4aday / SwiftlySalesforce

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

Enhance SOSL to support AnyPublisher<QueryResult<T> #123

Closed perbrondum closed 1 year ago

perbrondum commented 4 years ago

Is there any reason SOSL can not support AnyPublisher<QueryResult?

mike4aday commented 4 years ago

@perbrondum the Salesforce REST API search resource returns an array of records, and those records could be of different types depending on the domain of the SOSL search. In contrast, QueryResult for a SOQL search includes records of only 1 type, and includes metadata about the search results.

What is your requirement? What are you trying to achieve?

perbrondum commented 4 years ago

Finding an efficient fast way to find all object records (or nil) belonging to a company.

FIND {tap2sales} In name FIELDS RETURNING Account(id, name), opportunity(id, name), contact(id, name, accountId)

Basically if I could get the above (simplified) query to work, and separate the records by type, I'd be happy. How would you refer to the "contact ID" in the above sosl?. Using id.prefix(4) == 0061 to identify an Opportunity post query does not seem ideal but it may be the only way.

I have it working in SOQL (multiple queries) but the power of SOSL when looking for a name across types is simpler and I'd like to use it.

Per

On Mon, Sep 14, 2020 at 6:42 PM Michael Epstein notifications@github.com wrote:

@perbrondum https://github.com/perbrondum the Salesforce REST API search resource returns an array of records, and those records could be of different types depending on the domain of the SOSL search. In contrast, QueryResult for a SOQL search includes records of only 1 type, and includes metadata about the search results.

What is your requirement? What are you trying to achieve?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mike4aday/SwiftlySalesforce/issues/123#issuecomment-692176423, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALCYWDAHZTD2NCVVF3AWNFTSFZBY3ANCNFSM4RIN3XWA .

mike4aday commented 4 years ago

@perbrondum do all the objects you're looking for have a lookup relationship to Account (e.g. Opportunity and Contact)? If so, you could use a parent-to-child SOQL query.

I don't understand your second paragraph about ID prefixes and referring to Contact ID - would you clarify? (Also: only the first 3 characters of the record ID could be used to discern the object type -- see this help article.)

perbrondum commented 4 years ago

Using parent-child gets complicated with outer joins especially as we want to expose null records.

Below's an example of what I meant with contact Id. let sosl = "FIND {%(searchStr)%} IN name FIELDS RETURNING Account(id, name), opportunity(id, name), contact(id, name, accountId) DB.salesforce.search(sosl: sosl).sink(receiveCompletion: { (completion) in switch completion { case .finished: break case let .failure(error) : print(error) } }) { (searchResults: [SObject]) in let name = searchResults.string(forField: "Name")! ... How do I refer to a specific 'name' (contact or account) in the above line?

mike4aday commented 4 years ago

Hi @perbrondum the results will be returned in an array of Records. The object property of each Record will tell you its type (e.g. "Contact") and then you could call record.value(forField: "Name").

perbrondum commented 4 years ago

Beautiful. This is just awesome. Thanks.

let sosl = "FIND {%(textField.text!)%} IN Name FIELDS RETURNING Account(id, Name, BillingStreet, BillingCity, BillingPostalCode, BillingState, BillingCountry, lastActivityDate), Contact(id, name, MailingStreet, MailingCity, MailingPostalCode, MailingState, MailingCountry), Opportunity(id, name, expectedRevenue)"

        DB.salesforce.search(sosl: sosl)
            .sink(receiveCompletion: { (completion) in
                switch completion {
                case .finished:
                    print("Success SOSL query")
                case let .failure(error) :
                    print(error.localizedDescription)
                }
            }) { [self] (searchResults: [SObject]) in
                for row in searchResults {
                    switch row.object {
                    case objects.Account.rawValue:
                        existingAccounts.append(row)
                    case objects.Contact.rawValue:
                        existingContacts.append(row)
                    case objects.Opportunity.rawValue:
                        existingOpportunities.append(row)
                    default:
                        break
                    }
                }
                DispatchQueue.main.async {
                    accTable.reloadData()
                    ...
                }
            }.store(in: &self.subscriptions)