Closed perbrondum closed 3 years ago
So this is more of a swift issue and not related to swiftlysalesforce 9.
Thanks. Per
On Aug 4, 2021, at 6:34 PM, Michael Epstein @.***> wrote:
Hi @perbrondum see: https://stackoverflow.com/questions/62252547/value-of-protocol-type-encodable-cannot-conform-to-encodable-only-struct-en
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.
@perbrondum yes, correct. Try a concrete type that conforms to Encodable
instead, e.g. let fields: [String: String] = ...
The whole point about using Encodable, I thought, was to use Encodable (Any) as field values can be a mix of strings/int/Double/Dates.
Most values are Strings, but Account.AnnualRevenue is an Int, Opportunity.Amount is a Double etc.
Per B Jakobsen CEO Tap2Sales.com @.***
On Aug 4, 2021 at 9:54:49 PM, Michael Epstein @.***> wrote:
@perbrondum https://github.com/perbrondum yes, correct. Try a concrete type that conforms to Encodable instead, e.g. let fields: [String: String] = ...
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mike4aday/SwiftlySalesforce/issues/133#issuecomment-892931370, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALCYWDGQJR5QWPXWXH4LQKTT3GLITANCNFSM5BLG2T4A .
@perbrondum - you could use a type-erased wrapper, e.g. AnyEncodable
:
let app = try ConnectedApp()
let fields: [String : AnyEncodable] = [
"Name" : "Acme Corp., Inc.",
"Revenue__c" : 123456.35,
"Employee_Count__c" : 23,
"US_Based__c" : true]
let _ = app.insert(type: "Account", fields: fields)
But I believe it's simpler to just apply a map
function to each field value and convert it to a String
before passing to insert
.
I tried installing AnyCodable, but that just seems to create more issues.
Are you saying we can pass all values as strings? Consider this:
let eventFields : [String : Encodable] = [keys.Subject.rawValue: self. NewSubject.text! ,"whatId": self.eventWhatId!, "whoId": self.eventWhoId! , "StartDateTime": startDateTimeStr!, "EndDateTime": endDateTimeStr!, "DurationInMinutes": minutesInt!, "IsAllDayEvent": allDay!]
Salesforce expects DurationInMinutes to be an Int, and AllDayEvent to be a Bool. How would mapping to Strings before the insert solve this?
I only have a dozen or so update/insert statements that include mixed type fields, so probably not a big deal, but I would need to find a workaround.
Per B Jakobsen CEO Tap2Sales.com @.***
On Aug 5, 2021 at 3:19:10 AM, Michael Epstein @.***> wrote:
@perbrondum https://github.com/perbrondum - you could use a type-erased wrapper, e.g. AnyEncodable https://github.com/Flight-School/AnyCodable:
let app = try ConnectedApp()let fields: [String : AnyEncodable] = [ "Name" : "Acme Corp., Inc.", "Revenuec" : 123456.35, "Employee_Count__c" : 23, "US_Basedc" : true]let _ = app.insert(type: "Account", fields: fields)
But I believe it's simpler to just apply a map function to each field value and convert it to a String before passing to insert.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mike4aday/SwiftlySalesforce/issues/133#issuecomment-893088961, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALCYWDFDYF4MQPOOFS6UVJ3T3HRI5ANCNFSM5BLG2T4A .
I had no idea we could pass all fields as Strings. Was that always the case? Makes life so much easier. Thanks
private func createRecord() throws {
*let* app = *try* ConnectedApp()
*let* oneHour: TimeInterval = 24 * 3600
*let* dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
*let* startDateTimeStr = dateFormatter.string(from: Date())
*let* endDateTimeStr = dateFormatter.string(from: Date().
addingTimeInterval(oneHour))
*let* fields : [String: String] = [
"Subject" : "New Event",
"StartDateTime" : startDateTimeStr,
"EndDateTime" : endDateTimeStr,
"\(NameSpacePrefix)__sentimentValue__c": "3.24", // double
// "DurationInMinutes": "86400", // Int
"IsAllDayEvent": "true" // Bool
]
*let* pub: AnyPublisher<String, Error> = app.insert(type: "Event",
fields: fields)
pub.sink { completion *in*
*switch* completion {
*case* *let* .failure(error):
print("Failed to execute insert. Error: \(error)")
*case* .finished:
print("Success insert")
*break*
}
} receiveValue: { (Id) *in*
print("Created new Event with id: \(Id)")
}.store(in: &subscriptions)
}
Per B Jakobsen CEO Tap2Sales.com @.***
On Aug 5, 2021 at 12:01:48 PM, Per Jakobsen @.***> wrote:
I tried installing AnyCodable, but that just seems to create more issues.
Are you saying we can pass all values as strings? Consider this:
let eventFields : [String : Encodable] = [keys.Subject.rawValue: self. NewSubject.text! ,"whatId": self.eventWhatId!, "whoId": self. eventWhoId! , "StartDateTime": startDateTimeStr!, "EndDateTime": endDateTimeStr!, "DurationInMinutes": minutesInt!, "IsAllDayEvent": allDay !]
Salesforce expects DurationInMinutes to be an Int, and AllDayEvent to be a Bool. How would mapping to Strings before the insert solve this?
I only have a dozen or so update/insert statements that include mixed type fields, so probably not a big deal, but I would need to find a workaround.
Per B Jakobsen CEO Tap2Sales.com @.***
On Aug 5, 2021 at 3:19:10 AM, Michael Epstein @.***> wrote:
@perbrondum https://github.com/perbrondum - you could use a type-erased wrapper, e.g. AnyEncodable https://github.com/Flight-School/AnyCodable:
let app = try ConnectedApp()let fields: [String : AnyEncodable] = [ "Name" : "Acme Corp., Inc.", "Revenuec" : 123456.35, "Employee_Count__c" : 23, "US_Basedc" : true]let _ = app.insert(type: "Account", fields: fields)
But I believe it's simpler to just apply a map function to each field value and convert it to a String before passing to insert.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mike4aday/SwiftlySalesforce/issues/133#issuecomment-893088961, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALCYWDFDYF4MQPOOFS6UVJ3T3HRI5ANCNFSM5BLG2T4A .
@perbrondum as long as Salesforce can deserialize the JSON values from string into the expected type it should work.
FYI you could use Swiftly Salesforce's date formatter and a value map on the fields dictionary:
let fields: [String : String] = [
"Subject__c" : "My Subject",
"Revenue__c" : 123456.35,
"My_Date__c" : Date().addingTimeInterval(-100000),
"Employee_Count__c" : 23,
"US_Based__c" : true
]
.mapValues { value in
switch value {
case let date as Date:
return DateFormatter.salesforce.string(from: date)
default:
return String(describing: value)
}
}
let app = try ConnectedApp()
cancellable = app
.insert(type: "My_Object__c", fields: fields)
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
print(error)
case .finished:
print("Success")
}
}, receiveValue: {
print("NEW RECORD ID: \($0)")
}
)
Used to use [String : Encodable] as type for fields array. In 9.0 Error: Protocol 'Encodable' as a type cannot conform to the protocol itself