Skip to content

Commit 9ac75e4

Browse files
Merge pull request #304 from skyflowapi/release/26.3.1
Release/26.3.1
2 parents 9c4f8e7 + 84a3a63 commit 9ac75e4

16 files changed

Lines changed: 1293 additions & 101 deletions

Samples/ComposableElements/ComposableElements/Untitled.swift

Whitespace-only changes.

Skyflow.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Pod::Spec.new do |spec|
22

33
spec.name = "Skyflow"
44

5-
spec.version = "1.24.2"
5+
spec.version = "1.24.2-dev.53162a1"
66

77
spec.summary = "skyflow-iOS"
88

@@ -20,7 +20,7 @@ Pod::Spec.new do |spec|
2020

2121
spec.ios.deployment_target = "9.0"
2222

23-
spec.source = { :git => "https://github.com/skyflowapi/skyflow-iOS.git", :tag => "1.24.2" }
23+
spec.source = { :git => "https://github.com/skyflowapi/skyflow-iOS.git", :commit => "53162a1" }
2424

2525
spec.source_files = "Sources/Skyflow/**/*.{swift}"
2626

Sources/Skyflow/Version.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ import Foundation
1313

1414
var LangAndVersion = "iOS SDK v\(SDK_VERSION)"
1515

16-
var SDK_VERSION = "1.24.2"
16+
var SDK_VERSION = "1.24.2-dev.53162a1"

Sources/Skyflow/collect/CollectAPICallback.swift

Lines changed: 191 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,120 @@ internal class CollectAPICallback: Callback {
2121
self.options = options
2222
self.contextOptions = contextOptions
2323
}
24+
2425
internal func onSuccess(_ responseBody: Any) {
25-
guard let url = URL(string: self.apiClient.vaultURL + self.apiClient.vaultID) else {
26-
self.callback.onFailure(ErrorCodes.INVALID_URL().getErrorObject(contextOptions: self.contextOptions))
26+
let insertRecords = records["records"] as? [[String: Any]]
27+
let hasInsert = insertRecords?.isEmpty == false
28+
let updateRecords = records["update"] as? [String: Any]
29+
let hasUpdate = updateRecords?.isEmpty == false
30+
let group = DispatchGroup()
31+
var insertResponse: [String: Any]? = nil
32+
var updateResponses: [[String: Any]] = []
33+
var requestError: [Any]? = []
34+
var requestUpdateError: [Any]? = []
35+
36+
let callbackQueue = DispatchQueue.main
37+
38+
if !hasInsert && !hasUpdate {
39+
self.callback.onSuccess([:])
2740
return
2841
}
29-
30-
do {
31-
let (request, session) = try self.getRequestSession(url: url)
32-
33-
34-
let task = session.dataTask(with: request) { data, response, error in
42+
43+
if hasInsert {
44+
group.enter()
45+
guard let url = URL(string: self.apiClient.vaultURL + self.apiClient.vaultID) else {
46+
self.callback.onFailure(ErrorCodes.INVALID_URL().getErrorObject(contextOptions: self.contextOptions))
47+
return
48+
}
49+
do {
50+
let (request, session) = try self.getRequestSession(url: url)
51+
let task = session.dataTask(with: request) { data, response, error in
52+
defer {
53+
group.leave()
54+
}
55+
do {
56+
let response = try self.processResponse(data: data, response: response, error: error)
57+
if response["error"] != nil {
58+
requestError?.append(response)
59+
} else {
60+
insertResponse = response
61+
}
62+
} catch {
63+
requestError?.append(error)
64+
}
65+
}
66+
task.resume()
67+
} catch let error {
68+
requestError?.append(error)
69+
}
70+
}
71+
if hasUpdate, let updateArray = records["update"] as? [String: [String: Any]] {
72+
for (_, updateRecord) in updateArray {
73+
group.enter()
74+
guard let table = updateRecord["table"] as? String, let skyflowID = updateRecord["skyflowID"] as? String else {
75+
group.leave()
76+
continue
77+
}
78+
let urlString = self.apiClient.vaultURL + self.apiClient.vaultID + "/" + table + "/" + skyflowID
79+
guard let url = URL(string: urlString) else {
80+
group.leave()
81+
requestError?.append(ErrorCodes.INVALID_URL().getErrorObject(contextOptions: self.contextOptions))
82+
continue
83+
}
3584
do {
36-
let response = try self.processResponse(data: data, response: response, error: error)
37-
self.callback.onSuccess(response)
38-
} catch {
39-
self.callback.onFailure(error)
85+
var singleUpdateRecords: [String: Any] = [:]
86+
singleUpdateRecords["fields"] = updateRecord["fields"]
87+
singleUpdateRecords["table"] = table
88+
singleUpdateRecords["skyflowID"] = skyflowID
89+
let (request, session) = try self.getRequestSessionForUpdate(url: url, updateRecords: singleUpdateRecords)
90+
let task = session.dataTask(with: request) { data, response, error in
91+
defer {
92+
group.leave() }
93+
do {
94+
let response = try self.processUpdateResponse(data: data, response: response, error: error, table: table)
95+
if response["error"] != nil {
96+
requestUpdateError?.append(response)
97+
} else {
98+
updateResponses.append(response)
99+
}
100+
} catch {
101+
requestUpdateError?.append(error)
102+
}
103+
}
104+
task.resume()
105+
} catch let error {
106+
group.leave()
107+
requestUpdateError?.append(error)
108+
continue
40109
}
41110
}
42-
task.resume()
43-
} catch let error {
44-
self.callback.onFailure(error)
45-
return
111+
}
112+
113+
group.notify(queue: callbackQueue) {
114+
var mergedRecords: [Any] = []
115+
var mergedErrors: [Any] = []
116+
if let insert = insertResponse?["records"] as? [Any] {
117+
mergedRecords.append(contentsOf: insert)
118+
}
119+
for updateResp in updateResponses {
120+
if let update = updateResp["records"] as? [Any] {
121+
mergedRecords.append(contentsOf: update)
122+
}
123+
}
124+
if requestUpdateError != nil {
125+
mergedErrors.append(contentsOf: requestUpdateError!)
126+
}
127+
if requestError != nil {
128+
mergedErrors.append(contentsOf: requestError!)
129+
}
130+
if mergedRecords.isEmpty {
131+
self.callback.onFailure(["errors": mergedErrors])
132+
} else if requestError?.isEmpty == true {
133+
self.callback.onSuccess(["records": mergedRecords])
134+
}
135+
if !mergedErrors.isEmpty && !mergedRecords.isEmpty {
136+
self.callback.onFailure(["records": mergedRecords, "errors": mergedErrors])
137+
}
46138
}
47139
}
48140

@@ -86,31 +178,104 @@ internal class CollectAPICallback: Callback {
86178

87179
}
88180

181+
// Helper for single update request
182+
private func getRequestSessionForUpdate(url: URL, updateRecords: [String: Any]) throws -> (URLRequest, URLSession) {
183+
var jsonString = ""
184+
do {
185+
let deviceDetails = FetchMetrices().getMetrices()
186+
let jsonData = try JSONSerialization.data(withJSONObject: deviceDetails, options: [])
187+
jsonString = String(data: jsonData, encoding: .utf8) ?? ""
188+
} catch {
189+
jsonString = ""
190+
}
191+
var request = URLRequest(url: url)
192+
request.httpMethod = "PUT"
193+
do {
194+
let data = try JSONSerialization.data(withJSONObject: self.apiClient.constructUpdateRequestBody(records: updateRecords, options: options))
195+
request.httpBody = data
196+
}
197+
request.setValue(("Bearer " + self.apiClient.token), forHTTPHeaderField: "Authorization")
198+
request.setValue(jsonString, forHTTPHeaderField: "sky-metadata")
199+
return (request, URLSession(configuration: .default))
200+
}
201+
202+
func processUpdateResponse(data: Data?, response: URLResponse?, error: Error?, table: String) throws -> [String: Any] {
203+
if error != nil || response == nil {
204+
return ["error": ["message": (error)?.localizedDescription ?? "Unknown error"]]
205+
}
206+
if let httpResponse = response as? HTTPURLResponse {
207+
let range = 400...599
208+
if range ~= httpResponse.statusCode {
209+
var description = "Update call failed with the following status code" + String(httpResponse.statusCode)
210+
if let safeData = data {
211+
do {
212+
let desc = try JSONSerialization.jsonObject(with: safeData, options: .allowFragments) as! [String: Any]
213+
let error = desc["error"] as? [String: Any]
214+
if let error = error, let message = error["message"] as? String {
215+
description = message
216+
}
217+
if let requestId = httpResponse.allHeaderFields["x-request-id"] {
218+
description += " - request-id: \(requestId)"
219+
}
220+
} catch {
221+
return ["error": ["message": String(data: safeData, encoding: .utf8) ?? "Unknown error", "code": httpResponse.statusCode]]
222+
}
223+
}
224+
return ["error": ["message": description, "code": httpResponse.statusCode]]
225+
}
226+
}
227+
guard let safeData = data else {
228+
return ["records": []]
229+
}
230+
let jsonData = try JSONSerialization.jsonObject(with: safeData, options: .allowFragments) as! [String: Any]
231+
var record: [String: Any] = [:]
232+
var id = ""
233+
if let skyflowId = jsonData["skyflow_id"] as? String{
234+
id = skyflowId
235+
} else {
236+
id = String(describing: jsonData["skyflow_id"] ?? "")
237+
}
238+
239+
if self.options.tokens {
240+
let fieldsDict = jsonData["tokens"] as? [String: Any]
241+
if fieldsDict != nil {
242+
let fieldsData = try JSONSerialization.data(withJSONObject: fieldsDict!)
243+
let fieldsObj = try JSONSerialization.jsonObject(with: fieldsData, options: .allowFragments)
244+
var fieldsSkyflowId: [String: Any] = self.buildFieldsDict(dict: fieldsObj as? [String: Any] ?? [:])
245+
fieldsSkyflowId["skyflow_id"] = id
246+
record["fields"] = fieldsSkyflowId
247+
}
248+
} else {
249+
record["skyflow_id"] = id
250+
}
251+
record["table"] = table
252+
return ["records": [record]]
253+
}
254+
89255
func processResponse(data: Data?, response: URLResponse?, error: Error?) throws -> [String: Any] {
90256
if error != nil || response == nil {
91-
throw error!
257+
return ["error": ["message": (error)?.localizedDescription ?? "Unknown error"]]
92258
}
93259

94260
if let httpResponse = response as? HTTPURLResponse {
95261
let range = 400...599
96262
if range ~= httpResponse.statusCode {
97-
var description = "Insert call failed with the following status code" + String(httpResponse.statusCode)
98-
var errorObject: Error = ErrorCodes.APIError(code: httpResponse.statusCode, message: description).getErrorObject(contextOptions: self.contextOptions)
99-
263+
var description = "Insert call failed with the following status code " + String(httpResponse.statusCode)
100264
if let safeData = data {
101265
do {
102-
let desc = try JSONSerialization.jsonObject(with: safeData, options: .allowFragments) as! [String: Any]
103-
let error = desc["error"] as! [String: Any]
104-
description = error["message"] as! String
266+
let errorResponse = try JSONSerialization.jsonObject(with: safeData, options: .allowFragments) as! [String: Any]
267+
if let errorDetails = errorResponse["error"] as? [String: Any],
268+
let message = errorDetails["message"] as? String {
269+
description = message
270+
}
105271
if let requestId = httpResponse.allHeaderFields["x-request-id"] {
106272
description += " - request-id: \(requestId)"
107273
}
108-
errorObject = ErrorCodes.APIError(code: httpResponse.statusCode, message: description).getErrorObject(contextOptions: self.contextOptions)
109274
} catch {
110-
errorObject = ErrorCodes.APIError(code: httpResponse.statusCode, message: String(data: safeData, encoding: .utf8)!).getErrorObject(contextOptions: self.contextOptions)
275+
return ["error": ["message": String(data: safeData, encoding: .utf8) ?? "Unknown error", "code": httpResponse.statusCode]]
111276
}
112277
}
113-
throw errorObject
278+
return ["error": ["message": description, "code": httpResponse.statusCode]]
114279
}
115280
}
116281

Sources/Skyflow/collect/CollectContainer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public extension Container {
9999
onFailureHandler: {
100100
}
101101
)
102-
self.skyflow.apiClient.post(records: records!, callback: logCallback, options: icOptions, contextOptions: tempContextOptions)
102+
self.skyflow.apiClient.postAndUpdate(records: records!, callback: logCallback, options: icOptions, contextOptions: tempContextOptions)
103103
}
104104
}
105105

0 commit comments

Comments
 (0)