Skip to content

Commit 8ce5785

Browse files
committed
Fix paginated reporting decoding
1 parent b33e12b commit 8ce5785

File tree

3 files changed

+40
-15
lines changed

3 files changed

+40
-15
lines changed

Sources/API/APIProvider+Reports.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public extension APIProvider {
77
/// `ReportingRequest.selector.fields` property. Omit this if no fields are being filtered out,
88
/// which will result in decoding `ReportingCampaign` type.
99
///
10-
/// - Returns: An object of type `Reporting<Empty, Model>`.
10+
/// - Returns: A paginated object of type `Reporting<Empty, Model>`.
1111
///
1212
/// - Throws: An error of type `APIError`.
1313
///
@@ -21,8 +21,8 @@ public extension APIProvider {
2121
func getCampaignsReport<Model: Decodable & Sendable>(
2222
request: ReportingRequest<ReportingCampaign>,
2323
decoding: Model.Type = ReportingCampaign.self
24-
) async throws -> Response<Paginated<Reporting<Empty, Model>>> {
25-
try await provider.requestPaginatedModel(from: CampaignReportRequest(request: request))
24+
) async throws -> Response<PaginatedObject<Reporting<Empty, Model>>> {
25+
try await provider.requestPaginatedObject(from: CampaignReportRequest(request: request))
2626
}
2727

2828
/// Fetches reports for ad groups within a campaign.
@@ -34,7 +34,7 @@ public extension APIProvider {
3434
/// `ReportingRequest.selector.fields` property. Omit this if no fields are being filtered out,
3535
/// which will result in decoding `ReportingAdGroup` type.
3636
///
37-
/// - Returns: An object of type `Reporting<Empty, Model>`.
37+
/// - Returns: A paginated object of type `Reporting<Empty, Model>`.
3838
///
3939
/// - Throws: An error of type `APIError`.
4040
///
@@ -47,8 +47,8 @@ public extension APIProvider {
4747
campaignId: Int,
4848
request: ReportingRequest<ReportingAdGroup>,
4949
decoding: Model.Type = ReportingAdGroup.self
50-
) async throws -> Response<Paginated<Reporting<Empty, Model>>> {
51-
try await provider.requestPaginatedModel(from: AdGroupReportRequest(campaignId: campaignId, request: request))
50+
) async throws -> Response<PaginatedObject<Reporting<Empty, Model>>> {
51+
try await provider.requestPaginatedObject(from: AdGroupReportRequest(campaignId: campaignId, request: request))
5252
}
5353

5454
/// Fetches reports for targeting keywords within a campaign and / or ad group.
@@ -61,7 +61,7 @@ public extension APIProvider {
6161
/// `ReportingRequest.selector.fields` property. Omit this if no fields are being filtered out,
6262
/// which will result in decoding `ReportingKeyword` type.
6363
///
64-
/// - Returns: An object of type `Reporting<KeywordInsights, Model>`.
64+
/// - Returns: A paginated object of type `Reporting<KeywordInsights, Model>`.
6565
///
6666
/// - Throws: An error of type `APIError`.
6767
///
@@ -74,8 +74,8 @@ public extension APIProvider {
7474
adGroupId: Int? = nil,
7575
request: ReportingRequest<ReportingKeyword>,
7676
decoding: Model.Type = ReportingKeyword.self
77-
) async throws -> Response<Paginated<Reporting<KeywordInsights, Model>>> {
78-
try await provider.requestPaginatedModel(from: KeywordReportRequest(
77+
) async throws -> Response<PaginatedObject<Reporting<KeywordInsights, Model>>> {
78+
try await provider.requestPaginatedObject(from: KeywordReportRequest(
7979
campaignId: campaignId,
8080
adGroupId: adGroupId,
8181
request: request
@@ -92,7 +92,7 @@ public extension APIProvider {
9292
/// `ReportingRequest.selector.fields` property. Omit this if no fields are being filtered out,
9393
/// which will result in decoding `ReportingSearchTerm` type.
9494
///
95-
/// - Returns: An object of type `Reporting<Empty, Model>`.
95+
/// - Returns: A paginated object of type `Reporting<Empty, Model>`.
9696
///
9797
/// - Throws: An error of type `APIError`.
9898
///
@@ -107,8 +107,8 @@ public extension APIProvider {
107107
adGroupId: Int? = nil,
108108
request: ReportingRequest<ReportingSearchTerm>,
109109
decoding: Model.Type = ReportingSearchTerm.self
110-
) async throws -> Response<Paginated<Reporting<Empty, Model>>> {
111-
try await provider.requestPaginatedModel(from: SearchTermReportRequest(
110+
) async throws -> Response<PaginatedObject<Reporting<Empty, Model>>> {
111+
try await provider.requestPaginatedObject(from: SearchTermReportRequest(
112112
campaignId: campaignId,
113113
adGroupId: adGroupId,
114114
request: request
@@ -124,7 +124,7 @@ public extension APIProvider {
124124
/// `ReportingRequest.selector.fields` property. Omit this if no fields are being filtered out,
125125
/// which will result in decoding `ReportingAd` type.
126126
///
127-
/// - Returns: An object of type `Reporting<Empty, Model>`.
127+
/// - Returns: A paginated object of type `Reporting<Empty, Model>`.
128128
///
129129
/// - Throws: An error of type `APIError`.
130130
///
@@ -137,8 +137,8 @@ public extension APIProvider {
137137
campaignId: Int,
138138
request: ReportingRequest<ReportingAd>,
139139
decoding: Model.Type = ReportingAd.self
140-
) async throws -> Response<Paginated<Reporting<Empty, Model>>> {
141-
try await provider.requestPaginatedModel(from: AdReportRequest(campaignId: campaignId, request: request))
140+
) async throws -> Response<PaginatedObject<Reporting<Empty, Model>>> {
141+
try await provider.requestPaginatedObject(from: AdReportRequest(campaignId: campaignId, request: request))
142142
}
143143

144144
/// Obtain a report ID.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/// A container for paginated API responses.
2+
public struct PaginatedObject<T: Sendable>: Sendable {
3+
/// Response data that the API provides.
4+
public let data: T
5+
/// Page detail information that the API provides.
6+
public let pagination: PageDetail
7+
8+
public init(data: T, pagination: PageDetail) {
9+
self.data = data
10+
self.pagination = pagination
11+
}
12+
}
13+
14+
extension PaginatedObject: Decodable where T: Decodable {}
15+
extension PaginatedObject: Encodable where T: Encodable {}
16+
extension PaginatedObject: Equatable where T: Equatable {}
17+
extension PaginatedObject: Hashable where T: Hashable {}

Sources/Core/Provider/ProviderType.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,12 @@ extension ProviderType {
3333
) async throws -> Response<Paginated<Model>> {
3434
try await requestModel(from: request, type: Paginated<Model>.self)
3535
}
36+
37+
func requestPaginatedObject<Request: RequestType, Model: Decodable>(
38+
from request: Request,
39+
type: Model.Type = Model.self,
40+
decoder: JSONDecoder = .default
41+
) async throws -> Response<PaginatedObject<Model>> {
42+
try await requestModel(from: request, type: PaginatedObject<Model>.self)
43+
}
3644
}

0 commit comments

Comments
 (0)