@@ -263,6 +263,29 @@ public class Stack: CachePolicyAccessible {
263263 performDataTask ( dataTask!, request: request, cachePolicy: cachePolicy, then: completion)
264264 }
265265
266+ // MARK: - Async/Await Support
267+
268+ /// Async version of fetchUrl that returns the result directly
269+ /// - Parameters:
270+ /// - url: The URL to fetch
271+ /// - headers: HTTP headers to include in the request
272+ /// - cachePolicy: The cache policy to use
273+ /// - Returns: A tuple containing the data and response type
274+ /// - Throws: Network or cache errors
275+ @available ( iOS 13 . 0 , macOS 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
276+ private func fetchUrl( _ url: URL , headers: [ String : String ] , cachePolicy: CachePolicy ) async throws -> ( Data , ResponseType ) {
277+ return try await withCheckedThrowingContinuation { continuation in
278+ fetchUrl ( url, headers: headers, cachePolicy: cachePolicy) { result, responseType in
279+ switch result {
280+ case . success( let data) :
281+ continuation. resume ( returning: ( data, responseType) )
282+ case . failure( let error) :
283+ continuation. resume ( throwing: error)
284+ }
285+ }
286+ }
287+ }
288+
266289 internal func fetch< ResourceType> ( endpoint: Endpoint ,
267290 cachePolicy: CachePolicy ,
268291 parameters: Parameters = [ : ] ,
@@ -284,6 +307,25 @@ public class Stack: CachePolicyAccessible {
284307 }
285308 } )
286309 }
310+
311+ /// Async version of fetch that returns the decoded resource directly
312+ /// - Parameters:
313+ /// - endpoint: The API endpoint to fetch from
314+ /// - cachePolicy: The cache policy to use
315+ /// - parameters: Query parameters
316+ /// - headers: HTTP headers
317+ /// - Returns: The decoded resource
318+ /// - Throws: Network, decoding, or cache errors
319+ @available ( iOS 13 . 0 , macOS 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
320+ internal func fetch< ResourceType> ( endpoint: Endpoint ,
321+ cachePolicy: CachePolicy ,
322+ parameters: Parameters = [ : ] ,
323+ headers: [ String : String ] = [ : ] ) async throws -> ResourceType
324+ where ResourceType: Decodable {
325+ let url = self . url ( endpoint: endpoint, parameters: parameters)
326+ let ( data, _) = try await fetchUrl ( url, headers: headers, cachePolicy: cachePolicy)
327+ return try self . jsonDecoder. decode ( ResourceType . self, from: data)
328+ }
287329
288330 private func performDataTask( _ dataTask: URLSessionDataTask ,
289331 request: URLRequest ,
@@ -397,4 +439,45 @@ extension Stack {
397439 }
398440 }
399441 }
442+
443+ /// Async version of sync that returns the SyncStack directly
444+ /// - Parameters:
445+ /// - syncStack: The relevant `SyncStack` to perform the subsequent sync on.
446+ /// Defaults to a new empty instance of `SyncStack`.
447+ /// - syncTypes: `SyncableTypes` that can be sync.
448+ /// - Returns: The SyncStack with synced data
449+ /// - Throws: Network or decoding errors
450+ ///
451+ /// Example usage:
452+ ///```
453+ /// let stack = Contentstack.stack(apiKey: apiKey,
454+ /// deliveryToken: deliveryToken,
455+ /// environment: environment)
456+ ///
457+ /// do {
458+ /// let syncStack = try await stack.sync()
459+ /// let items = syncStack.items
460+ /// } catch {
461+ /// print(error)
462+ /// }
463+ ///```
464+ @available ( iOS 13 . 0 , macOS 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
465+ public func sync( _ syncStack: SyncStack = SyncStack ( ) ,
466+ syncTypes: [ SyncStack . SyncableTypes ] = [ . all] ) async throws -> SyncStack {
467+ var parameter = syncStack. parameter
468+ if syncStack. isInitialSync {
469+ for syncType in syncTypes {
470+ parameter = parameter + syncType. parameters
471+ }
472+ }
473+ let url = self . url ( endpoint: SyncStack . endpoint, parameters: parameter)
474+ let ( data, _) = try await fetchUrl ( url, headers: [ : ] , cachePolicy: . networkOnly)
475+ let result = try self . jsonDecoder. decode ( SyncStack . self, from: data)
476+
477+ if result. hasMorePages {
478+ return try await sync ( result, syncTypes: syncTypes)
479+ }
480+
481+ return result
482+ }
400483}
0 commit comments