From e4d6cc00c4af6818461ff2d2094039f153713de6 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:39:09 -0700 Subject: [PATCH 1/6] Add Swift support for Posts --- native/swift/Example/Example/ListViewData.swift | 10 ++++++++++ native/swift/Sources/wordpress-api/Exports.swift | 7 +++++++ native/swift/Sources/wordpress-api/WordPressAPI.swift | 4 ++++ 3 files changed, 21 insertions(+) diff --git a/native/swift/Example/Example/ListViewData.swift b/native/swift/Example/Example/ListViewData.swift index 44684d2ce..6340f23c4 100644 --- a/native/swift/Example/Example/ListViewData.swift +++ b/native/swift/Example/Example/ListViewData.swift @@ -141,3 +141,13 @@ extension SiteSettingsWithEditContext { } } } + +extension PostWithEditContext: ListViewDataConvertable { + public var id: String { + self.slug + } + + var asListViewData: ListViewData { + ListViewData(id: self.id, title: self.title.raw, subtitle: self.slug, fields: [:]) + } +} diff --git a/native/swift/Sources/wordpress-api/Exports.swift b/native/swift/Sources/wordpress-api/Exports.swift index 9c0352db0..c21b5a948 100644 --- a/native/swift/Sources/wordpress-api/Exports.swift +++ b/native/swift/Sources/wordpress-api/Exports.swift @@ -67,6 +67,13 @@ public typealias PostTypeDetailsWithEditContext = WordPressAPIInternal.PostTypeD public typealias PostTypeDetailsWithViewContext = WordPressAPIInternal.PostTypeDetailsWithViewContext public typealias PostTypeDetailsWithEmbedContext = WordPressAPIInternal.PostTypeDetailsWithEmbedContext +// MARK: - Posts +public typealias SparsePost = WordPressAPIInternal.SparsePost +public typealias PostWithEditContext = WordPressAPIInternal.PostWithEditContext +public typealias PostWithViewContext = WordPressAPIInternal.PostWithViewContext +public typealias PostWithEmbedContext = WordPressAPIInternal.PostWithEmbedContext +public typealias PostListParams = WordPressAPIInternal.PostListParams + // MARK: – Site Settings public typealias SparseSiteSettings = WordPressAPIInternal.SparseSiteSettings public typealias SiteSettingsWithEditContext = WordPressAPIInternal.SiteSettingsWithEditContext diff --git a/native/swift/Sources/wordpress-api/WordPressAPI.swift b/native/swift/Sources/wordpress-api/WordPressAPI.swift index 7d87a4c9c..b3935ed61 100644 --- a/native/swift/Sources/wordpress-api/WordPressAPI.swift +++ b/native/swift/Sources/wordpress-api/WordPressAPI.swift @@ -59,6 +59,10 @@ public struct WordPressAPI { self.requestBuilder.postTypes() } + public var posts: PostsRequestExecutor { + self.requestBuilder.posts() + } + public var siteSettings: SiteSettingsRequestExecutor { self.requestBuilder.siteSettings() } From 3d49d39d4bc178eb2fa4789ded90138f467a7174 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:39:18 -0700 Subject: [PATCH 2/6] Add auto-pagination support --- .../Sources/wordpress-api/Pagination.swift | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 native/swift/Sources/wordpress-api/Pagination.swift diff --git a/native/swift/Sources/wordpress-api/Pagination.swift b/native/swift/Sources/wordpress-api/Pagination.swift new file mode 100644 index 000000000..c09bee7e1 --- /dev/null +++ b/native/swift/Sources/wordpress-api/Pagination.swift @@ -0,0 +1,91 @@ +import WordPressAPIInternal + +public protocol PaginatableResponse { + associatedtype ParamsType + associatedtype DataType + + var nextPageParams: ParamsType? { get } + var prevPageParams: ParamsType? { get } + + var data: [DataType] { get } +} + +public protocol PaginationAwareExecutor { + associatedtype EditContextResponseType: PaginatableResponse + associatedtype ViewContextResponseType: PaginatableResponse + associatedtype EmbedContextResponseType: PaginatableResponse + + /// Known function signatures for Request Executors + func listWithEditContext(params: EditContextResponseType.ParamsType) async throws -> EditContextResponseType + func listWithViewContext(params: ViewContextResponseType.ParamsType) async throws -> ViewContextResponseType + func listWithEmbedContext(params: EmbedContextResponseType.ParamsType) async throws -> EmbedContextResponseType + + /// Generated implementation + func paginatedWithEditContext( + params: EditContextResponseType.ParamsType + ) async throws -> [EditContextResponseType.DataType] +} + +extension PaginationAwareExecutor { + /// Fetches all objects from all pages + /// + /// This method waits until all objects have been downloaded then returns the results. This can have unexpected memory and time implications. + public func paginatedWithEditContext( + params: EditContextResponseType.ParamsType + ) async throws -> [EditContextResponseType.DataType] { + var workingResponse = try await self.listWithEditContext(params: params) + var allObjects: [EditContextResponseType.DataType] = workingResponse.data + + while let nextPageParams = workingResponse.nextPageParams { + workingResponse = try await self.listWithEditContext(params: nextPageParams) + allObjects.append(contentsOf: workingResponse.data) + } + + return allObjects + } +} + +// MARK: - Posts + +extension PostsRequestListWithEditContextResponse: PaginatableResponse { + public typealias ParamsType = PostListParams + public typealias DataType = PostWithEditContext +} + +extension PostsRequestListWithViewContextResponse: PaginatableResponse { + public typealias ParamsType = PostListParams + public typealias DataType = PostWithViewContext +} + +extension PostsRequestListWithEmbedContextResponse: PaginatableResponse { + public typealias ParamsType = PostListParams + public typealias DataType = PostWithEmbedContext +} + +extension PostsRequestExecutor: PaginationAwareExecutor { + public typealias EditContextResponseType = PostsRequestListWithEditContextResponse + public typealias ViewContextResponseType = PostsRequestListWithViewContextResponse + public typealias EmbedContextResponseType = PostsRequestListWithEmbedContextResponse +} + +// MARK: - Users +extension UsersRequestListWithEditContextResponse: PaginatableResponse { + public typealias ParamsType = UserListParams + public typealias DataType = UserWithEditContext +} + +extension UsersRequestListWithViewContextResponse: PaginatableResponse { + public typealias ParamsType = UserListParams + public typealias DataType = UserWithViewContext +} + +extension UsersRequestListWithEmbedContextResponse: PaginatableResponse { + public typealias ParamsType = UserListParams + public typealias DataType = UserWithEmbedContext +} + +extension UsersRequestExecutor: PaginationAwareExecutor { + public typealias EditContextResponseType = UsersRequestListWithEditContextResponse + public typealias ViewContextResponseType = UsersRequestListWithViewContextResponse + public typealias EmbedContextResponseType = UsersRequestListWithEmbedContextResponse +} From 063fb1403c8fbcb238b29438be8b6813db83b3a3 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:39:30 -0700 Subject: [PATCH 3/6] Adopt auto-pagination in the example app --- native/swift/Example/Example/ExampleApp.swift | 7 +++++-- native/swift/Sources/wordpress-api/Pagination.swift | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/native/swift/Example/Example/ExampleApp.swift b/native/swift/Example/Example/ExampleApp.swift index baa1d481c..30272e1cc 100644 --- a/native/swift/Example/Example/ExampleApp.swift +++ b/native/swift/Example/Example/ExampleApp.swift @@ -14,8 +14,7 @@ struct ExampleApp: App { .map { $0.asListViewData } }), RootListData(name: "Users", callback: { - try await WordPressAPI.globalInstance.users.listWithEditContext(params: .init()) - .data + try await WordPressAPI.globalInstance.users.paginatedWithEditContext(params: UserListParams(perPage: 100)) .map { $0.asListViewData } }), RootListData(name: "Plugins", callback: { @@ -28,6 +27,10 @@ struct ExampleApp: App { value.asListViewData } }), + RootListData(name: "Posts", callback: { + try await WordPressAPI.globalInstance.posts.paginatedWithEditContext(params: PostListParams(perPage: 100)) + .map { $0.asListViewData } + }), RootListData(name: "Site Health Tests", callback: { let items: [any ListViewDataConvertable] = [ try await WordPressAPI.globalInstance.siteHealthTests.authorizationHeader().data, diff --git a/native/swift/Sources/wordpress-api/Pagination.swift b/native/swift/Sources/wordpress-api/Pagination.swift index c09bee7e1..3d9f83beb 100644 --- a/native/swift/Sources/wordpress-api/Pagination.swift +++ b/native/swift/Sources/wordpress-api/Pagination.swift @@ -46,7 +46,6 @@ extension PaginationAwareExecutor { } // MARK: - Posts - extension PostsRequestListWithEditContextResponse: PaginatableResponse { public typealias ParamsType = PostListParams public typealias DataType = PostWithEditContext From ef35db7fdb1ecb42646c278aec2938cc1f7cca06 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:02:12 -0700 Subject: [PATCH 4/6] Add view and embed context types --- .../Sources/wordpress-api/Pagination.swift | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/native/swift/Sources/wordpress-api/Pagination.swift b/native/swift/Sources/wordpress-api/Pagination.swift index 3d9f83beb..1551305f5 100644 --- a/native/swift/Sources/wordpress-api/Pagination.swift +++ b/native/swift/Sources/wordpress-api/Pagination.swift @@ -24,12 +24,21 @@ public protocol PaginationAwareExecutor { func paginatedWithEditContext( params: EditContextResponseType.ParamsType ) async throws -> [EditContextResponseType.DataType] + + func paginatedWithViewContext( + params: ViewContextResponseType.ParamsType + ) async throws -> [ViewContextResponseType.DataType] + + func paginatedWithEmbedContext( + params: EmbedContextResponseType.ParamsType + ) async throws -> [EmbedContextResponseType.DataType] } extension PaginationAwareExecutor { /// Fetches all objects from all pages /// - /// This method waits until all objects have been downloaded then returns the results. This can have unexpected memory and time implications. + /// This method waits until all objects have been downloaded then returns the results. This can have + /// unexpected memory and time implications. public func paginatedWithEditContext( params: EditContextResponseType.ParamsType ) async throws -> [EditContextResponseType.DataType] { @@ -43,6 +52,42 @@ extension PaginationAwareExecutor { return allObjects } + + /// Fetches all objects from all pages + /// + /// This method waits until all objects have been downloaded then returns the results. This can have + /// unexpected memory and time implications. + public func paginatedWithViewContext( + params: ViewContextResponseType.ParamsType + ) async throws -> [ViewContextResponseType.DataType] { + var workingResponse = try await self.listWithViewContext(params: params) + var allObjects: [ViewContextResponseType.DataType] = workingResponse.data + + while let nextPageParams = workingResponse.nextPageParams { + workingResponse = try await self.listWithViewContext(params: nextPageParams) + allObjects.append(contentsOf: workingResponse.data) + } + + return allObjects + } + + /// Fetches all objects from all pages + /// + /// This method waits until all objects have been downloaded then returns the results. This can have + /// unexpected memory and time implications. + public func paginatedWithEmbedContext( + params: EmbedContextResponseType.ParamsType + ) async throws -> [EmbedContextResponseType.DataType] { + var workingResponse = try await self.listWithEmbedContext(params: params) + var allObjects: [EmbedContextResponseType.DataType] = workingResponse.data + + while let nextPageParams = workingResponse.nextPageParams { + workingResponse = try await self.listWithEmbedContext(params: nextPageParams) + allObjects.append(contentsOf: workingResponse.data) + } + + return allObjects + } } // MARK: - Posts From 098c1e8b65b4a1e5ad133814900300ecf9889b68 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:41:15 -0700 Subject: [PATCH 5/6] Adopt do/while for pagination --- .../Sources/wordpress-api/Pagination.swift | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/native/swift/Sources/wordpress-api/Pagination.swift b/native/swift/Sources/wordpress-api/Pagination.swift index 1551305f5..121da880a 100644 --- a/native/swift/Sources/wordpress-api/Pagination.swift +++ b/native/swift/Sources/wordpress-api/Pagination.swift @@ -42,13 +42,19 @@ extension PaginationAwareExecutor { public func paginatedWithEditContext( params: EditContextResponseType.ParamsType ) async throws -> [EditContextResponseType.DataType] { - var workingResponse = try await self.listWithEditContext(params: params) - var allObjects: [EditContextResponseType.DataType] = workingResponse.data + var allObjects: [EditContextResponseType.DataType] = [] + var mutableParams: EditContextResponseType.ParamsType = params - while let nextPageParams = workingResponse.nextPageParams { - workingResponse = try await self.listWithEditContext(params: nextPageParams) - allObjects.append(contentsOf: workingResponse.data) - } + repeat { + let response = try await self.listWithEditContext(params: mutableParams) + allObjects.append(contentsOf: response.data) + + guard let newParams = response.nextPageParams else { + break + } + + mutableParams = newParams + } while true return allObjects } @@ -60,13 +66,19 @@ extension PaginationAwareExecutor { public func paginatedWithViewContext( params: ViewContextResponseType.ParamsType ) async throws -> [ViewContextResponseType.DataType] { - var workingResponse = try await self.listWithViewContext(params: params) - var allObjects: [ViewContextResponseType.DataType] = workingResponse.data + var allObjects: [ViewContextResponseType.DataType] = [] + var mutableParams: ViewContextResponseType.ParamsType = params + + repeat { + let response = try await self.listWithViewContext(params: mutableParams) + allObjects.append(contentsOf: response.data) - while let nextPageParams = workingResponse.nextPageParams { - workingResponse = try await self.listWithViewContext(params: nextPageParams) - allObjects.append(contentsOf: workingResponse.data) - } + guard let newParams = response.nextPageParams else { + break + } + + mutableParams = newParams + } while true return allObjects } @@ -78,13 +90,19 @@ extension PaginationAwareExecutor { public func paginatedWithEmbedContext( params: EmbedContextResponseType.ParamsType ) async throws -> [EmbedContextResponseType.DataType] { - var workingResponse = try await self.listWithEmbedContext(params: params) - var allObjects: [EmbedContextResponseType.DataType] = workingResponse.data + var allObjects: [EmbedContextResponseType.DataType] = [] + var mutableParams: EmbedContextResponseType.ParamsType = params + + repeat { + let response = try await self.listWithEmbedContext(params: mutableParams) + allObjects.append(contentsOf: response.data) + + guard let newParams = response.nextPageParams else { + break + } - while let nextPageParams = workingResponse.nextPageParams { - workingResponse = try await self.listWithEmbedContext(params: nextPageParams) - allObjects.append(contentsOf: workingResponse.data) - } + mutableParams = newParams + } while true return allObjects } From 4f40bbcd4060a44217b1da67aa168c944807fb64 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:51:05 -0700 Subject: [PATCH 6/6] Fix lint issue --- native/swift/Example/Example/ListViewData.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/swift/Example/Example/ListViewData.swift b/native/swift/Example/Example/ListViewData.swift index 6340f23c4..ab5df794c 100644 --- a/native/swift/Example/Example/ListViewData.swift +++ b/native/swift/Example/Example/ListViewData.swift @@ -146,7 +146,7 @@ extension PostWithEditContext: ListViewDataConvertable { public var id: String { self.slug } - + var asListViewData: ListViewData { ListViewData(id: self.id, title: self.title.raw, subtitle: self.slug, fields: [:]) }