@@ -80,13 +80,15 @@ public final class StatsStoreV4: Store {
8080 let latestDateToInclude,
8181 let quantity,
8282 let forceRefresh,
83+ let saveInStorage,
8384 let onCompletion) :
8485 retrieveTopEarnerStats ( siteID: siteID,
8586 timeRange: timeRange,
8687 earliestDateToInclude: earliestDateToInclude,
8788 latestDateToInclude: latestDateToInclude,
8889 quantity: quantity,
8990 forceRefresh: forceRefresh,
91+ saveInStorage: saveInStorage,
9092 onCompletion: onCompletion)
9193 }
9294 }
@@ -178,36 +180,45 @@ private extension StatsStoreV4 {
178180 }
179181
180182 /// Retrieves the top earner stats associated with the provided Site ID (if any!).
183+ /// Saves to storage if required,
181184 ///
182185 func retrieveTopEarnerStats( siteID: Int64 ,
183186 timeRange: StatsTimeRangeV4 ,
184187 earliestDateToInclude: Date ,
185188 latestDateToInclude: Date ,
186189 quantity: Int ,
187190 forceRefresh: Bool ,
188- onCompletion: @escaping ( Result < Void , Error > ) -> Void ) {
191+ saveInStorage: Bool ,
192+ onCompletion: @escaping ( Result < TopEarnerStats , Error > ) -> Void ) {
189193 Task { @MainActor in
190194 do {
191- try await loadTopEarnerStats ( siteID: siteID,
192- timeRange: timeRange,
193- earliestDateToInclude: earliestDateToInclude,
194- latestDateToInclude: latestDateToInclude,
195- quantity: quantity,
196- forceRefresh: forceRefresh)
197- onCompletion ( . success( ( ) ) )
195+ let topEarnersStats = try await loadTopEarnerStats ( siteID: siteID,
196+ timeRange: timeRange,
197+ earliestDateToInclude: earliestDateToInclude,
198+ latestDateToInclude: latestDateToInclude,
199+ quantity: quantity,
200+ forceRefresh: forceRefresh)
201+ if saveInStorage {
202+ upsertStoredTopEarnerStats ( readOnlyStats: topEarnersStats)
203+ }
204+ onCompletion ( . success( topEarnersStats) )
198205 } catch {
199- if let error = error as? DotcomError , error == . noRestRoute {
200- let result = await Result {
201- try await loadTopEarnerStatsWithDeprecatedAPI ( siteID: siteID,
202- timeRange: timeRange,
203- earliestDateToInclude: earliestDateToInclude,
204- latestDateToInclude: latestDateToInclude,
205- quantity: quantity,
206- forceRefresh: forceRefresh)
207- }
206+ guard let error = error as? DotcomError , error == . noRestRoute else {
207+ return onCompletion ( . failure( error) )
208+ }
208209
209- onCompletion ( result)
210- } else {
210+ do {
211+ let topEarnersStats = try await loadTopEarnerStatsWithDeprecatedAPI ( siteID: siteID,
212+ timeRange: timeRange,
213+ earliestDateToInclude: earliestDateToInclude,
214+ latestDateToInclude: latestDateToInclude,
215+ quantity: quantity,
216+ forceRefresh: forceRefresh)
217+ if saveInStorage {
218+ upsertStoredTopEarnerStats ( readOnlyStats: topEarnersStats)
219+ }
220+ onCompletion ( . success( topEarnersStats) )
221+ } catch {
211222 onCompletion ( . failure( error) )
212223 }
213224 }
@@ -220,8 +231,8 @@ private extension StatsStoreV4 {
220231 earliestDateToInclude: Date ,
221232 latestDateToInclude: Date ,
222233 quantity: Int ,
223- forceRefresh: Bool ) async throws {
224- try await withCheckedThrowingContinuation { ( continuation: CheckedContinuation < Void , Error > ) -> Void in
234+ forceRefresh: Bool ) async throws -> TopEarnerStats {
235+ try await withCheckedThrowingContinuation { ( continuation: CheckedContinuation < TopEarnerStats , Error > ) -> Void in
225236 let dateFormatter = DateFormatter . Defaults. iso8601WithoutTimeZone
226237 let earliestDate = dateFormatter. string ( from: earliestDateToInclude)
227238 let latestDate = dateFormatter. string ( from: latestDateToInclude)
@@ -237,16 +248,12 @@ private extension StatsStoreV4 {
237248
238249 switch result {
239250 case . success( let leaderboards) :
240- self . convertAndStoreLeaderboardsIntoTopEarners ( siteID: siteID,
241- granularity: timeRange. topEarnerStatsGranularity,
242- date: latestDateToInclude,
243- leaderboards: leaderboards,
244- quantity: quantity) { result in
245- if case let . failure( error) = result {
246- continuation. resume ( throwing: error)
247- } else {
248- continuation. resume ( returning: ( ( ) ) )
249- }
251+ self . convertLeaderboardsIntoTopEarners ( siteID: siteID,
252+ granularity: timeRange. topEarnerStatsGranularity,
253+ date: latestDateToInclude,
254+ leaderboards: leaderboards,
255+ quantity: quantity) { result in
256+ continuation. resume ( with: result)
250257 }
251258 case . failure( let error) :
252259 continuation. resume ( throwing: error)
@@ -261,8 +268,8 @@ private extension StatsStoreV4 {
261268 earliestDateToInclude: Date ,
262269 latestDateToInclude: Date ,
263270 quantity: Int ,
264- forceRefresh: Bool ) async throws {
265- try await withCheckedThrowingContinuation { ( continuation: CheckedContinuation < Void , Error > ) -> Void in
271+ forceRefresh: Bool ) async throws -> TopEarnerStats {
272+ try await withCheckedThrowingContinuation { ( continuation: CheckedContinuation < TopEarnerStats , Error > ) -> Void in
266273 let dateFormatter = DateFormatter . Defaults. iso8601WithoutTimeZone
267274 let earliestDate = dateFormatter. string ( from: earliestDateToInclude)
268275 let latestDate = dateFormatter. string ( from: latestDateToInclude)
@@ -278,16 +285,12 @@ private extension StatsStoreV4 {
278285
279286 switch result {
280287 case . success( let leaderboards) :
281- self . convertAndStoreLeaderboardsIntoTopEarners ( siteID: siteID,
282- granularity: timeRange. topEarnerStatsGranularity,
283- date: latestDateToInclude,
284- leaderboards: leaderboards,
285- quantity: quantity) { result in
286- if case let . failure( error) = result {
287- continuation. resume ( throwing: error)
288- } else {
289- continuation. resume ( returning: ( ) )
290- }
288+ self . convertLeaderboardsIntoTopEarners ( siteID: siteID,
289+ granularity: timeRange. topEarnerStatsGranularity,
290+ date: latestDateToInclude,
291+ leaderboards: leaderboards,
292+ quantity: quantity) { result in
293+ continuation. resume ( with: result)
291294 }
292295 case . failure( let error) :
293296 continuation. resume ( throwing: error)
@@ -435,15 +438,15 @@ extension StatsStoreV4 {
435438//
436439private extension StatsStoreV4 {
437440
438- /// Converts and stores a top-product `leaderboard` into a `StatsTopEarner`
441+ /// Converts a top-product `leaderboard` into a `StatsTopEarner`
439442 /// Since a `leaderboard` does not contain the necessary product information, this method fetches the related product before starting the conversion.
440443 ///
441- func convertAndStoreLeaderboardsIntoTopEarners ( siteID: Int64 ,
442- granularity: StatGranularity ,
443- date: Date ,
444- leaderboards: [ Leaderboard ] ,
445- quantity: Int ,
446- onCompletion: @escaping ( Result < Void , Error > ) -> Void ) {
444+ func convertLeaderboardsIntoTopEarners ( siteID: Int64 ,
445+ granularity: StatGranularity ,
446+ date: Date ,
447+ leaderboards: [ Leaderboard ] ,
448+ quantity: Int ,
449+ onCompletion: @escaping ( Result < TopEarnerStats , Error > ) -> Void ) {
447450
448451 // Find the top products leaderboard by its ID
449452 guard let topProducts = leaderboards. first ( where: { $0. id == Constants . topProductsID } ) else {
@@ -457,13 +460,13 @@ private extension StatsStoreV4 {
457460
458461 switch topProductsResult {
459462 case . success( let products) :
460- self . mergeAndStoreTopProductsAndStoredProductsIntoTopEarners ( siteID: siteID,
461- granularity: granularity,
462- date: date,
463- topProducts: topProducts,
464- storedProducts: products,
465- quantityLimit: quantity)
466- onCompletion ( . success( ( ) ) )
463+ let topEarners = self . mergeTopProductsAndStoredProductsIntoTopEarners ( siteID: siteID,
464+ granularity: granularity,
465+ date: date,
466+ topProducts: topProducts,
467+ storedProducts: products,
468+ quantityLimit: quantity)
469+ onCompletion ( . success( ( topEarners ) ) )
467470 case . failure( let error) :
468471 onCompletion ( . failure( error) )
469472 }
@@ -507,24 +510,21 @@ private extension StatsStoreV4 {
507510 return products. map { $0. toReadOnly ( ) }
508511 }
509512
510- /// Merges and stores a top-product leaderboard with an array of stored products into a `TopEarnerStats` object
513+ /// Merges a top-product leaderboard with an array of stored products into a `TopEarnerStats` object
511514 ///
512- func mergeAndStoreTopProductsAndStoredProductsIntoTopEarners ( siteID: Int64 ,
513- granularity: StatGranularity ,
514- date: Date ,
515- topProducts: Leaderboard ,
516- storedProducts: [ Product ] ,
517- quantityLimit: Int ) {
515+ func mergeTopProductsAndStoredProductsIntoTopEarners ( siteID: Int64 ,
516+ granularity: StatGranularity ,
517+ date: Date ,
518+ topProducts: Leaderboard ,
519+ storedProducts: [ Product ] ,
520+ quantityLimit: Int ) -> TopEarnerStats {
518521 let statsDate = Self . buildDateString ( from: date, with: granularity)
519522 let statsItems = LeaderboardStatsConverter . topEarnerStatsItems ( from: topProducts, using: storedProducts)
520- let stats = TopEarnerStats ( siteID: siteID,
521- date: statsDate,
522- granularity: granularity,
523- limit: String ( quantityLimit) ,
524- items: statsItems
525- )
526-
527- upsertStoredTopEarnerStats ( readOnlyStats: stats)
523+ return TopEarnerStats ( siteID: siteID,
524+ date: statsDate,
525+ granularity: granularity,
526+ limit: String ( quantityLimit) ,
527+ items: statsItems)
528528 }
529529}
530530
0 commit comments