Skip to content

Commit 17e46f1

Browse files
authored
Update ProductsRemote to load products with async/throws network methods to parse response in a background thread (#15781)
2 parents 64baf4f + f664c25 commit 17e46f1

File tree

5 files changed

+228
-211
lines changed

5 files changed

+228
-211
lines changed

Modules/Sources/Networking/Remote/ProductsRemote.swift

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public protocol ProductsRemoteProtocol {
88
func addProduct(product: Product, completion: @escaping (Result<Product, Error>) -> Void)
99
func deleteProduct(for siteID: Int64, productID: Int64, completion: @escaping (Result<Product, Error>) -> Void)
1010
func loadProduct(for siteID: Int64, productID: Int64, completion: @escaping (Result<Product, Error>) -> Void)
11-
func loadProducts(for siteID: Int64, by productIDs: [Int64], pageNumber: Int, pageSize: Int, completion: @escaping (Result<[Product], Error>) -> Void)
11+
func loadProducts(for siteID: Int64, by productIDs: [Int64], pageNumber: Int, pageSize: Int) async throws -> [Product]
1212
func loadAllProducts(for siteID: Int64,
1313
context: String?,
1414
pageNumber: Int,
@@ -29,18 +29,15 @@ public protocol ProductsRemoteProtocol {
2929
productStatus: ProductStatus?,
3030
productType: ProductType?,
3131
productCategory: ProductCategory?,
32-
excludedProductIDs: [Int64],
33-
completion: @escaping (Result<[Product], Error>) -> Void)
32+
excludedProductIDs: [Int64]) async throws -> [Product]
3433
func searchProductsBySKU(for siteID: Int64,
3534
keyword: String,
3635
pageNumber: Int,
37-
pageSize: Int,
38-
completion: @escaping (Result<[Product], Error>) -> Void)
36+
pageSize: Int) async throws -> [Product]
3937
func searchProductsByGlobalUniqueIdentifier(for siteID: Int64,
4038
keyword: String,
4139
pageNumber: Int,
42-
pageSize: Int,
43-
completion: @escaping (Result<[Product], Error>) -> Void)
40+
pageSize: Int) async throws -> [Product]
4441
func searchSku(for siteID: Int64,
4542
sku: String,
4643
completion: @escaping (Result<String, Error>) -> Void)
@@ -102,12 +99,11 @@ public protocol ProductsRemoteProtocol {
10299
}
103100

104101
extension ProductsRemoteProtocol {
105-
public func loadProducts(for siteID: Int64, by productIDs: [Int64], completion: @escaping (Result<[Product], Error>) -> Void) {
106-
loadProducts(for: siteID,
107-
by: productIDs,
108-
pageNumber: ProductsRemote.Default.pageNumber,
109-
pageSize: ProductsRemote.Default.pageSize,
110-
completion: completion)
102+
public func loadProducts(for siteID: Int64, by productIDs: [Int64]) async throws -> [Product] {
103+
try await loadProducts(for: siteID,
104+
by: productIDs,
105+
pageNumber: ProductsRemote.Default.pageNumber,
106+
pageSize: ProductsRemote.Default.pageSize)
111107
}
112108
}
113109

@@ -387,16 +383,13 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
387383
/// - productIDs: The array of product IDs that are requested.
388384
/// - pageNumber: Number of page that should be retrieved.
389385
/// - pageSize: Number of products to be retrieved per page.
390-
/// - completion: Closure to be executed upon completion.
391386
///
392387
public func loadProducts(for siteID: Int64,
393388
by productIDs: [Int64],
394389
pageNumber: Int = Default.pageNumber,
395-
pageSize: Int = Default.pageSize,
396-
completion: @escaping (Result<[Product], Error>) -> Void) {
390+
pageSize: Int = Default.pageSize) async throws -> [Product] {
397391
guard productIDs.isEmpty == false else {
398-
completion(.success([]))
399-
return
392+
return []
400393
}
401394

402395
let stringOfProductIDs = productIDs.map { String($0) }
@@ -409,9 +402,9 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
409402
]
410403
let path = Path.products
411404
let request = JetpackRequest(wooApiVersion: .mark3, method: .get, siteID: siteID, path: path, parameters: parameters, availableAsRESTRequest: true)
412-
let mapper = ProductListMapper(siteID: siteID)
405+
let mapper = ListMapper<Product>(siteID: siteID)
413406

414-
enqueue(request, mapper: mapper, completion: completion)
407+
return try await enqueue(request, mapper: mapper)
415408
}
416409

417410

@@ -438,7 +431,6 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
438431
/// - pageNumber: Number of page that should be retrieved.
439432
/// - pageSize: Number of products to be retrieved per page.
440433
/// - excludedProductIDs: a list of product IDs to be excluded from the results.
441-
/// - completion: Closure to be executed upon completion.
442434
///
443435
public func searchProducts(for siteID: Int64,
444436
keyword: String,
@@ -448,8 +440,7 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
448440
productStatus: ProductStatus? = nil,
449441
productType: ProductType? = nil,
450442
productCategory: ProductCategory? = nil,
451-
excludedProductIDs: [Int64] = [],
452-
completion: @escaping (Result<[Product], Error>) -> Void) {
443+
excludedProductIDs: [Int64] = []) async throws -> [Product] {
453444
let stringOfExcludedProductIDs = excludedProductIDs.map { String($0) }
454445
.joined(separator: ",")
455446

@@ -471,9 +462,9 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
471462

472463
let path = Path.products
473464
let request = JetpackRequest(wooApiVersion: .mark3, method: .get, siteID: siteID, path: path, parameters: parameters, availableAsRESTRequest: true)
474-
let mapper = ProductListMapper(siteID: siteID)
465+
let mapper = ListMapper<Product>(siteID: siteID)
475466

476-
enqueue(request, mapper: mapper, completion: completion)
467+
return try await enqueue(request, mapper: mapper)
477468
}
478469

479470
/// Retrieves all of the `Product`s that match the SKU. Partial SKU search is supported for WooCommerce version 6.6+, otherwise full SKU match is performed.
@@ -482,12 +473,10 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
482473
/// - keyword: Search string that should be matched by the SKU (partial or full depending on the WC version).
483474
/// - pageNumber: Number of page that should be retrieved.
484475
/// - pageSize: Number of products to be retrieved per page.
485-
/// - completion: Closure to be executed upon completion.
486476
public func searchProductsBySKU(for siteID: Int64,
487477
keyword: String,
488478
pageNumber: Int,
489-
pageSize: Int,
490-
completion: @escaping (Result<[Product], Error>) -> Void) {
479+
pageSize: Int) async throws -> [Product] {
491480
let parameters = [
492481
ParameterKey.sku: keyword,
493482
ParameterKey.partialSKUSearch: keyword,
@@ -497,15 +486,14 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
497486
]
498487
let path = Path.products
499488
let request = JetpackRequest(wooApiVersion: .mark3, method: .get, siteID: siteID, path: path, parameters: parameters, availableAsRESTRequest: true)
500-
let mapper = ProductListMapper(siteID: siteID)
501-
enqueue(request, mapper: mapper, completion: completion)
489+
let mapper = ListMapper<Product>(siteID: siteID)
490+
return try await enqueue(request, mapper: mapper)
502491
}
503492

504493
public func searchProductsByGlobalUniqueIdentifier(for siteID: Int64,
505494
keyword: String,
506495
pageNumber: Int,
507-
pageSize: Int,
508-
completion: @escaping (Result<[Product], Error>) -> Void) {
496+
pageSize: Int) async throws -> [Product] {
509497
let parameters = [
510498
ParameterKey.globalUniqueID: keyword,
511499
ParameterKey.page: String(pageNumber),
@@ -514,8 +502,8 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
514502
]
515503
let path = Path.products
516504
let request = JetpackRequest(wooApiVersion: .mark3, method: .get, siteID: siteID, path: path, parameters: parameters, availableAsRESTRequest: true)
517-
let mapper = ProductListMapper(siteID: siteID)
518-
enqueue(request, mapper: mapper, completion: completion)
505+
let mapper = ListMapper<Product>(siteID: siteID)
506+
return try await enqueue(request, mapper: mapper)
519507
}
520508

521509
/// Retrieves a product SKU if available.

Modules/Sources/Yosemite/Stores/ProductStore.swift

Lines changed: 63 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -231,35 +231,31 @@ private extension ProductStore {
231231
productCategory: ProductCategory?,
232232
excludedProductIDs: [Int64],
233233
onCompletion: @escaping (Result<Bool, Error>) -> Void) {
234-
switch filter {
235-
case .all:
236-
remote.searchProducts(for: siteID,
237-
keyword: keyword,
238-
pageNumber: pageNumber,
239-
pageSize: pageSize,
240-
stockStatus: stockStatus,
241-
productStatus: productStatus,
242-
productType: productType,
243-
productCategory: productCategory,
244-
excludedProductIDs: excludedProductIDs) { [weak self] result in
245-
self?.handleSearchResults(siteID: siteID,
246-
keyword: keyword,
247-
filter: filter,
248-
pageSize: pageSize,
249-
result: result,
250-
onCompletion: onCompletion)
251-
}
252-
case .sku:
253-
remote.searchProductsBySKU(for: siteID,
254-
keyword: keyword,
255-
pageNumber: pageNumber,
256-
pageSize: pageSize) { [weak self] result in
257-
self?.handleSearchResults(siteID: siteID,
258-
keyword: keyword,
259-
filter: filter,
260-
pageSize: pageSize,
261-
result: result,
262-
onCompletion: onCompletion)
234+
Task { @MainActor in
235+
do {
236+
let products: [Product]
237+
switch filter {
238+
case .all:
239+
products = try await remote.searchProducts(for: siteID,
240+
keyword: keyword,
241+
pageNumber: pageNumber,
242+
pageSize: pageSize,
243+
stockStatus: stockStatus,
244+
productStatus: productStatus,
245+
productType: productType,
246+
productCategory: productCategory,
247+
excludedProductIDs: excludedProductIDs)
248+
case .sku:
249+
products = try await remote.searchProductsBySKU(for: siteID,
250+
keyword: keyword,
251+
pageNumber: pageNumber,
252+
pageSize: pageSize)
253+
}
254+
await upsertSearchResultsInBackground(siteID: siteID, keyword: keyword, filter: filter, readOnlyProducts: products)
255+
let hasNextPage = products.count == pageSize
256+
onCompletion(.success(hasNextPage))
257+
} catch {
258+
onCompletion(.failure(error))
263259
}
264260
}
265261
}
@@ -340,13 +336,12 @@ private extension ProductStore {
340336
return
341337
}
342338

343-
remote.loadProducts(for: order.siteID, by: missingIDs) { [weak self] result in
344-
switch result {
345-
case .success(let products):
346-
self?.upsertStoredProductsInBackground(readOnlyProducts: products, siteID: order.siteID, onCompletion: {
347-
onCompletion(nil)
348-
})
349-
case .failure(let error):
339+
Task { @MainActor in
340+
do {
341+
let products = try await remote.loadProducts(for: order.siteID, by: missingIDs)
342+
await upsertStoredProductsInBackground(readOnlyProducts: products, siteID: order.siteID)
343+
onCompletion(nil)
344+
} catch {
350345
onCompletion(error)
351346
}
352347
}
@@ -365,14 +360,13 @@ private extension ProductStore {
365360
return
366361
}
367362

368-
remote.loadProducts(for: siteID, by: productIDs, pageNumber: pageNumber, pageSize: pageSize) { [weak self] result in
369-
switch result {
370-
case .success(let products):
371-
self?.upsertStoredProductsInBackground(readOnlyProducts: products, siteID: siteID, onCompletion: {
372-
let hasNextPage = products.count == pageSize
373-
onCompletion(.success((products: products, hasNextPage: hasNextPage)))
374-
})
375-
case .failure(let error):
363+
Task { @MainActor in
364+
do {
365+
let products = try await remote.loadProducts(for: siteID, by: productIDs, pageNumber: pageNumber, pageSize: pageSize)
366+
await upsertStoredProductsInBackground(readOnlyProducts: products, siteID: siteID)
367+
let hasNextPage = products.count == pageSize
368+
onCompletion(.success((products: products, hasNextPage: hasNextPage)))
369+
} catch {
376370
onCompletion(.failure(error))
377371
}
378372
}
@@ -1271,6 +1265,23 @@ private extension ProductStore {
12711265
}, completion: onCompletion, on: .main)
12721266
}
12731267

1268+
func upsertSearchResultsInBackground(siteID: Int64,
1269+
keyword: String,
1270+
filter: ProductSearchFilter,
1271+
readOnlyProducts: [Networking.Product]) async {
1272+
await withCheckedContinuation { [weak self] continuation in
1273+
guard let self else {
1274+
return continuation.resume()
1275+
}
1276+
upsertSearchResultsInBackground(siteID: siteID,
1277+
keyword: keyword,
1278+
filter: filter,
1279+
readOnlyProducts: readOnlyProducts) {
1280+
continuation.resume()
1281+
}
1282+
}
1283+
}
1284+
12741285
/// Upserts the Products, and associates them to the Search Results Entity (in the specified Storage)
12751286
///
12761287
private func upsertStoredResults(siteID: Int64,
@@ -1319,35 +1330,17 @@ private extension ProductStore {
13191330
}
13201331

13211332
func searchProductsBySKU(for siteID: Int64, keyword: String) async throws -> [Product] {
1322-
try await withCheckedThrowingContinuation { continuation in
1323-
remote.searchProductsBySKU(for: siteID,
1324-
keyword: keyword,
1325-
pageNumber: Remote.Default.firstPageNumber,
1326-
pageSize: ProductsRemote.Default.pageSize) { result in
1327-
switch result {
1328-
case let .success(products):
1329-
continuation.resume(returning: products)
1330-
case let .failure(error):
1331-
continuation.resume(throwing: error)
1332-
}
1333-
}
1334-
}
1333+
try await remote.searchProductsBySKU(for: siteID,
1334+
keyword: keyword,
1335+
pageNumber: Remote.Default.firstPageNumber,
1336+
pageSize: ProductsRemote.Default.pageSize)
13351337
}
13361338

13371339
func searchProductsByGlobalUniqueIdentifier(for siteID: Int64, keyword: String) async throws -> [Product] {
1338-
try await withCheckedThrowingContinuation { continuation in
1339-
remote.searchProductsByGlobalUniqueIdentifier(for: siteID,
1340-
keyword: keyword,
1341-
pageNumber: Remote.Default.firstPageNumber,
1342-
pageSize: ProductsRemote.Default.pageSize) { result in
1343-
switch result {
1344-
case let .success(products):
1345-
continuation.resume(returning: products)
1346-
case let .failure(error):
1347-
continuation.resume(throwing: error)
1348-
}
1349-
}
1350-
}
1340+
try await remote.searchProductsByGlobalUniqueIdentifier(for: siteID,
1341+
keyword: keyword,
1342+
pageNumber: Remote.Default.firstPageNumber,
1343+
pageSize: ProductsRemote.Default.pageSize)
13511344
}
13521345
}
13531346

0 commit comments

Comments
 (0)