Skip to content

Commit bf384da

Browse files
authored
Generate AppendUrlQueryPairs & FromUrlQueryPairs trait implementations from WpDeriveParamsField (#871)
* Add pagination attribute parsing and comprehensive error handling Implement #[pagination(true/false)] container attribute support for WpDeriveParamsField macro with complete error validation. Changes: - Register pagination attribute in proc_macro_derive definition - Add pagination parsing logic with proper boolean value validation - Update ParsedParamsStruct to include pagination field for future trait generation - Add field_type to ParsedField for upcoming automatic type detection - Implement comprehensive error handling for all pagination scenarios - Add complete test coverage for all error cases New error types: - PaginationAttributeRequired: when #[pagination] is missing - DuplicatePaginationAttribute: when multiple #[pagination] exist - PaginationRequiresValue: when #[pagination] has no value - PaginationMustBeBool: when #[pagination] value is not boolean Test coverage: 6 tests (2 passing, 4 error scenarios) * Implement AppendUrlQueryPairs and FromUrlQueryPairs trait generation Complete the WpDeriveParamsField macro by adding automatic trait implementations for URL query parameter handling. Changes: - Add AppendUrlQueryPairs trait implementation generation with automatic method selection - Add FromUrlQueryPairs trait implementation with pagination support - Implement type detection for Option<T>, Vec<T>, and Option<WpGmtDateTime> fields - Use proc_macro_crate to resolve correct module paths for trait references - Make generated enum public for external access - Add comprehensive unit tests for type detection logic * Rename pagination attribute to supports_pagination Update all references from #[pagination] to #[supports_pagination] for clarity. Changes: - Update attribute name constant and error messages - Update all test files to use new attribute name - Update expected error messages in stderr files * Replace manual trait implementations with macro-generated traits Complete the migration from manual AppendUrlQueryPairs and FromUrlQueryPairs implementations to macro-generated ones for all standard parameter structs. Changes: - Add #[supports_pagination(true/false)] attributes based on existing supports_pagination() methods - Remove all manual AppendUrlQueryPairs and FromUrlQueryPairs implementations - Keep users.rs with manual implementation (requires override attributes for WpApiParamUsersWho) - Net result: -461 lines of boilerplate code, +12 lines of attributes All files now use macro-generated traits except users.rs which needs special handling. The macro correctly handles: - Option<T> fields -> get() and append_option_query_value_pair() - Vec<T> fields -> get_csv() and append_vec_query_value_pair() - Option<WpGmtDateTime> fields -> get_wp_date_time() and append_option_query_value_pair() - Custom field names via #[field_name("name")] attributes * Fix wp_derive tests with minimal mock trait implementations Add minimal mock trait and method implementations to test files to enable compilation and testing of the macro-generated code. Changes: - Add minimal AppendUrlQueryPairs and FromUrlQueryPairs traits - Add mock QueryPairs and UrlQueryPairsMap structs - Add required method implementations with minimal signatures - Tests now pass and validate macro functionality without requiring wp_api dependency All wp_derive tests now pass: ✅ * Add override attributes support for WpDeriveParamsField macro Implement `from_query_method` and `append_query_custom` attributes to handle special field mappings that require custom serialization. Changes: - Add parsing for `from_query_method` and `append_query_custom` attributes - Update macro to generate custom method calls when overrides are specified - Replace manual UserListParams trait implementations with macro-generated ones - Add special handling for `who` field using override attributes - All existing tests pass confirming backward compatibility * Fix clippy warnings in WpDeriveParamsField macro Address clippy issues identified in cargo clippy --tests: Changes: - Remove redundant enum variant prefixes (AppendQueryMethod variants) - Collapse nested if statements in is_wp_date_time_option method using let-chain patterns - Update all enum variant references and test assertions * Update MediaListParams test expectations to match generated field order Fix failing tests by updating expected query parameter ordering to match the macro-generated trait implementations which follow struct field order. Changes: - Move parent_exclude parameter to appear directly after parent parameter - Update both media.rs and media_endpoint.rs test expectations - No functional change - only reordering of query string parameters - All 812 unit tests now pass The generated macro correctly follows MediaListParams struct field order: parent → parent_exclude → search_columns → slug → status
1 parent d92e4d8 commit bf384da

25 files changed

+554
-568
lines changed

wp_api/src/categories.rs

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub enum WpApiParamCategoriesOrderBy {
4040
impl_as_query_value_from_to_string!(WpApiParamCategoriesOrderBy);
4141

4242
#[derive(Debug, Default, PartialEq, Eq, uniffi::Record, WpDeriveParamsField)]
43+
#[supports_pagination(true)]
4344
pub struct CategoryListParams {
4445
/// Current page of the collection.
4546
/// Default: `1`
@@ -86,53 +87,6 @@ pub struct CategoryListParams {
8687
pub slug: Vec<String>,
8788
}
8889

89-
impl AppendUrlQueryPairs for CategoryListParams {
90-
fn append_query_pairs(&self, query_pairs_mut: &mut QueryPairs) {
91-
query_pairs_mut
92-
.append_option_query_value_pair(CategoryListParamsField::Page, self.page.as_ref())
93-
.append_option_query_value_pair(
94-
CategoryListParamsField::PerPage,
95-
self.per_page.as_ref(),
96-
)
97-
.append_option_query_value_pair(CategoryListParamsField::Search, self.search.as_ref())
98-
.append_vec_query_value_pair(CategoryListParamsField::Exclude, &self.exclude)
99-
.append_vec_query_value_pair(CategoryListParamsField::Include, &self.include)
100-
.append_option_query_value_pair(CategoryListParamsField::Offset, self.offset.as_ref())
101-
.append_option_query_value_pair(CategoryListParamsField::Order, self.order.as_ref())
102-
.append_option_query_value_pair(CategoryListParamsField::Orderby, self.orderby.as_ref())
103-
.append_option_query_value_pair(
104-
CategoryListParamsField::HideEmpty,
105-
self.hide_empty.as_ref(),
106-
)
107-
.append_option_query_value_pair(CategoryListParamsField::Parent, self.parent.as_ref())
108-
.append_option_query_value_pair(CategoryListParamsField::Post, self.post.as_ref())
109-
.append_vec_query_value_pair(CategoryListParamsField::Slug, &self.slug);
110-
}
111-
}
112-
113-
impl FromUrlQueryPairs for CategoryListParams {
114-
fn from_url_query_pairs(query_pairs: UrlQueryPairsMap) -> Option<Self> {
115-
Some(Self {
116-
page: query_pairs.get(CategoryListParamsField::Page),
117-
per_page: query_pairs.get(CategoryListParamsField::PerPage),
118-
search: query_pairs.get(CategoryListParamsField::Search),
119-
exclude: query_pairs.get_csv(CategoryListParamsField::Exclude),
120-
include: query_pairs.get_csv(CategoryListParamsField::Include),
121-
offset: query_pairs.get(CategoryListParamsField::Offset),
122-
order: query_pairs.get(CategoryListParamsField::Order),
123-
orderby: query_pairs.get(CategoryListParamsField::Orderby),
124-
hide_empty: query_pairs.get(CategoryListParamsField::HideEmpty),
125-
parent: query_pairs.get(CategoryListParamsField::Parent),
126-
post: query_pairs.get(CategoryListParamsField::Post),
127-
slug: query_pairs.get_csv(CategoryListParamsField::Slug),
128-
})
129-
}
130-
131-
fn supports_pagination() -> bool {
132-
true
133-
}
134-
}
135-
13690
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
13791
pub struct CategoryDeleteResponse {
13892
pub deleted: bool,

wp_api/src/comments.rs

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub enum CommentType {
7070
impl_as_query_value_from_to_string!(CommentType);
7171

7272
#[derive(Debug, Default, PartialEq, Eq, uniffi::Record, WpDeriveParamsField)]
73+
#[supports_pagination(true)]
7374
pub struct CommentListParams {
7475
/// Current page of the collection.
7576
/// Default: `1`
@@ -140,76 +141,6 @@ pub struct CommentListParams {
140141
pub password: Option<String>,
141142
}
142143

143-
impl AppendUrlQueryPairs for CommentListParams {
144-
fn append_query_pairs(&self, query_pairs_mut: &mut QueryPairs) {
145-
query_pairs_mut
146-
.append_option_query_value_pair(CommentListParamsField::Page, self.page.as_ref())
147-
.append_option_query_value_pair(CommentListParamsField::PerPage, self.per_page.as_ref())
148-
.append_option_query_value_pair(CommentListParamsField::Search, self.search.as_ref())
149-
.append_option_query_value_pair(CommentListParamsField::After, self.after.as_ref())
150-
.append_vec_query_value_pair(CommentListParamsField::Author, &self.author)
151-
.append_vec_query_value_pair(
152-
CommentListParamsField::AuthorExclude,
153-
&self.author_exclude,
154-
)
155-
.append_option_query_value_pair(
156-
CommentListParamsField::AuthorEmail,
157-
self.author_email.as_ref(),
158-
)
159-
.append_option_query_value_pair(CommentListParamsField::Before, self.before.as_ref())
160-
.append_vec_query_value_pair(CommentListParamsField::Exclude, &self.exclude)
161-
.append_vec_query_value_pair(CommentListParamsField::Include, &self.include)
162-
.append_option_query_value_pair(CommentListParamsField::Offset, self.offset.as_ref())
163-
.append_option_query_value_pair(CommentListParamsField::Order, self.order.as_ref())
164-
.append_option_query_value_pair(CommentListParamsField::Orderby, self.orderby.as_ref())
165-
.append_vec_query_value_pair(CommentListParamsField::Parent, self.parent.as_ref())
166-
.append_vec_query_value_pair(
167-
CommentListParamsField::ParentExclude,
168-
self.parent_exclude.as_ref(),
169-
)
170-
.append_vec_query_value_pair(CommentListParamsField::Post, self.post.as_ref())
171-
.append_option_query_value_pair(CommentListParamsField::Status, self.status.as_ref())
172-
.append_option_query_value_pair(
173-
CommentListParamsField::CommentType,
174-
self.comment_type.as_ref(),
175-
)
176-
.append_option_query_value_pair(
177-
CommentListParamsField::Password,
178-
self.password.as_ref(),
179-
);
180-
}
181-
}
182-
183-
impl FromUrlQueryPairs for CommentListParams {
184-
fn from_url_query_pairs(query_pairs: UrlQueryPairsMap) -> Option<Self> {
185-
Some(Self {
186-
page: query_pairs.get(CommentListParamsField::Page),
187-
per_page: query_pairs.get(CommentListParamsField::PerPage),
188-
search: query_pairs.get(CommentListParamsField::Search),
189-
after: query_pairs.get(CommentListParamsField::After),
190-
author: query_pairs.get_csv(CommentListParamsField::Author),
191-
author_exclude: query_pairs.get_csv(CommentListParamsField::AuthorExclude),
192-
author_email: query_pairs.get(CommentListParamsField::AuthorEmail),
193-
before: query_pairs.get(CommentListParamsField::Before),
194-
exclude: query_pairs.get_csv(CommentListParamsField::Exclude),
195-
include: query_pairs.get_csv(CommentListParamsField::Include),
196-
offset: query_pairs.get(CommentListParamsField::Offset),
197-
order: query_pairs.get(CommentListParamsField::Order),
198-
orderby: query_pairs.get(CommentListParamsField::Orderby),
199-
parent: query_pairs.get_csv(CommentListParamsField::Parent),
200-
parent_exclude: query_pairs.get_csv(CommentListParamsField::ParentExclude),
201-
post: query_pairs.get_csv(CommentListParamsField::Post),
202-
status: query_pairs.get(CommentListParamsField::Status),
203-
comment_type: query_pairs.get(CommentListParamsField::CommentType),
204-
password: query_pairs.get(CommentListParamsField::Password),
205-
})
206-
}
207-
208-
fn supports_pagination() -> bool {
209-
true
210-
}
211-
}
212-
213144
#[derive(Debug, Default, uniffi::Record)]
214145
pub struct CommentRetrieveParams {
215146
/// The password for the parent post of the comment (if the post is password protected).

wp_api/src/media.rs

Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ pub enum MediaStatus {
108108
impl_as_query_value_from_to_string!(MediaStatus);
109109

110110
#[derive(Debug, Default, PartialEq, Eq, uniffi::Record, WpDeriveParamsField)]
111+
#[supports_pagination(true)]
111112
pub struct MediaListParams {
112113
/// Current page of the collection.
113114
/// Default: `1`
@@ -183,80 +184,6 @@ pub struct MediaListParams {
183184
pub mime_type: Option<String>,
184185
}
185186

186-
impl AppendUrlQueryPairs for MediaListParams {
187-
fn append_query_pairs(&self, query_pairs_mut: &mut QueryPairs) {
188-
query_pairs_mut
189-
.append_option_query_value_pair(MediaListParamsField::Page, self.page.as_ref())
190-
.append_option_query_value_pair(MediaListParamsField::PerPage, self.per_page.as_ref())
191-
.append_option_query_value_pair(MediaListParamsField::Search, self.search.as_ref())
192-
.append_option_query_value_pair(MediaListParamsField::After, self.after.as_ref())
193-
.append_option_query_value_pair(
194-
MediaListParamsField::ModifiedAfter,
195-
self.modified_after.as_ref(),
196-
)
197-
.append_vec_query_value_pair(MediaListParamsField::Author, &self.author)
198-
.append_vec_query_value_pair(MediaListParamsField::AuthorExclude, &self.author_exclude)
199-
.append_option_query_value_pair(MediaListParamsField::Before, self.before.as_ref())
200-
.append_option_query_value_pair(
201-
MediaListParamsField::ModifiedBefore,
202-
self.modified_before.as_ref(),
203-
)
204-
.append_vec_query_value_pair(MediaListParamsField::Exclude, &self.exclude)
205-
.append_vec_query_value_pair(MediaListParamsField::Include, &self.include)
206-
.append_option_query_value_pair(MediaListParamsField::Offset, self.offset.as_ref())
207-
.append_option_query_value_pair(MediaListParamsField::Order, self.order.as_ref())
208-
.append_option_query_value_pair(MediaListParamsField::Orderby, self.orderby.as_ref())
209-
.append_vec_query_value_pair(MediaListParamsField::Parent, self.parent.as_ref())
210-
.append_vec_query_value_pair(MediaListParamsField::SearchColumns, &self.search_columns)
211-
.append_vec_query_value_pair(MediaListParamsField::Slug, &self.slug)
212-
.append_vec_query_value_pair(MediaListParamsField::Status, &self.status)
213-
.append_vec_query_value_pair(
214-
MediaListParamsField::ParentExclude,
215-
self.parent_exclude.as_ref(),
216-
)
217-
.append_option_query_value_pair(
218-
MediaListParamsField::MediaType,
219-
self.media_type.as_ref(),
220-
)
221-
.append_option_query_value_pair(
222-
MediaListParamsField::MimeType,
223-
self.mime_type.as_ref(),
224-
);
225-
}
226-
}
227-
228-
impl FromUrlQueryPairs for MediaListParams {
229-
fn from_url_query_pairs(query_pairs: UrlQueryPairsMap) -> Option<Self> {
230-
Some(Self {
231-
page: query_pairs.get(MediaListParamsField::Page),
232-
per_page: query_pairs.get(MediaListParamsField::PerPage),
233-
search: query_pairs.get(MediaListParamsField::Search),
234-
after: query_pairs.get(MediaListParamsField::After),
235-
modified_after: query_pairs.get(MediaListParamsField::ModifiedAfter),
236-
author: query_pairs.get_csv(MediaListParamsField::Author),
237-
author_exclude: query_pairs.get_csv(MediaListParamsField::AuthorExclude),
238-
before: query_pairs.get(MediaListParamsField::Before),
239-
modified_before: query_pairs.get(MediaListParamsField::ModifiedBefore),
240-
exclude: query_pairs.get_csv(MediaListParamsField::Exclude),
241-
include: query_pairs.get_csv(MediaListParamsField::Include),
242-
offset: query_pairs.get(MediaListParamsField::Offset),
243-
order: query_pairs.get(MediaListParamsField::Order),
244-
orderby: query_pairs.get(MediaListParamsField::Orderby),
245-
parent: query_pairs.get_csv(MediaListParamsField::Parent),
246-
parent_exclude: query_pairs.get_csv(MediaListParamsField::ParentExclude),
247-
search_columns: query_pairs.get_csv(MediaListParamsField::SearchColumns),
248-
slug: query_pairs.get_csv(MediaListParamsField::Slug),
249-
status: query_pairs.get_csv(MediaListParamsField::Status),
250-
media_type: query_pairs.get(MediaListParamsField::MediaType),
251-
mime_type: query_pairs.get(MediaListParamsField::MimeType),
252-
})
253-
}
254-
255-
fn supports_pagination() -> bool {
256-
true
257-
}
258-
}
259-
260187
#[derive(Debug, Default, Serialize, uniffi::Record)]
261188
pub struct MediaUpdateParams {
262189
/// The date the post was published, in the site's timezone.
@@ -689,7 +616,7 @@ mod tests {
689616
let before = unit_test_example_date_as_query_value("before");
690617
let modified_before = unit_test_example_date_as_query_value("modified_before");
691618
format!(
692-
"page=11&per_page=22&search=s_q&{after}&{modified_after}&author=111%2C112&author_exclude=211%2C212&{before}&{modified_before}&exclude=1111%2C1112&include=2111%2C2112&offset=11111&order=desc&orderby=slug&parent=44444%2C44445&search_columns=post_content%2Cpost_excerpt&slug=sl_1%2Csl_2&status=inherit%2Cprivate%2Ctrash&parent_exclude=55555%2C55556&media_type=image&mime_type=image%2Fjpeg"
619+
"page=11&per_page=22&search=s_q&{after}&{modified_after}&author=111%2C112&author_exclude=211%2C212&{before}&{modified_before}&exclude=1111%2C1112&include=2111%2C2112&offset=11111&order=desc&orderby=slug&parent=44444%2C44445&parent_exclude=55555%2C55556&search_columns=post_content%2Cpost_excerpt&slug=sl_1%2Csl_2&status=inherit%2Cprivate%2Ctrash&media_type=image&mime_type=image%2Fjpeg"
693620
)
694621
}
695622

wp_api/src/post_revisions.rs

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub enum WpApiParamPostRevisionsOrderBy {
4040
impl_as_query_value_from_to_string!(WpApiParamPostRevisionsOrderBy);
4141

4242
#[derive(Debug, Default, PartialEq, Eq, uniffi::Record, WpDeriveParamsField)]
43+
#[supports_pagination(true)]
4344
pub struct PostRevisionListParams {
4445
/// Current page of the collection.
4546
/// Default: `1`
@@ -73,51 +74,6 @@ pub struct PostRevisionListParams {
7374
pub orderby: Option<WpApiParamPostRevisionsOrderBy>,
7475
}
7576

76-
impl AppendUrlQueryPairs for PostRevisionListParams {
77-
fn append_query_pairs(&self, query_pairs_mut: &mut QueryPairs) {
78-
query_pairs_mut
79-
.append_option_query_value_pair(PostRevisionListParamsField::Page, self.page.as_ref())
80-
.append_option_query_value_pair(
81-
PostRevisionListParamsField::PerPage,
82-
self.per_page.as_ref(),
83-
)
84-
.append_option_query_value_pair(
85-
PostRevisionListParamsField::Search,
86-
self.search.as_ref(),
87-
)
88-
.append_vec_query_value_pair(PostRevisionListParamsField::Exclude, &self.exclude)
89-
.append_vec_query_value_pair(PostRevisionListParamsField::Include, &self.include)
90-
.append_option_query_value_pair(
91-
PostRevisionListParamsField::Offset,
92-
self.offset.as_ref(),
93-
)
94-
.append_option_query_value_pair(PostRevisionListParamsField::Order, self.order.as_ref())
95-
.append_option_query_value_pair(
96-
PostRevisionListParamsField::Orderby,
97-
self.orderby.as_ref(),
98-
);
99-
}
100-
}
101-
102-
impl FromUrlQueryPairs for PostRevisionListParams {
103-
fn from_url_query_pairs(query_pairs: UrlQueryPairsMap) -> Option<Self> {
104-
Some(Self {
105-
page: query_pairs.get(PostRevisionListParamsField::Page),
106-
per_page: query_pairs.get(PostRevisionListParamsField::PerPage),
107-
search: query_pairs.get(PostRevisionListParamsField::Search),
108-
exclude: query_pairs.get_csv(PostRevisionListParamsField::Exclude),
109-
include: query_pairs.get_csv(PostRevisionListParamsField::Include),
110-
offset: query_pairs.get(PostRevisionListParamsField::Offset),
111-
order: query_pairs.get(PostRevisionListParamsField::Order),
112-
orderby: query_pairs.get(PostRevisionListParamsField::Orderby),
113-
})
114-
}
115-
116-
fn supports_pagination() -> bool {
117-
true
118-
}
119-
}
120-
12177
#[derive(Debug, Serialize, Deserialize, uniffi::Record, WpContextual)]
12278
pub struct SparsePostRevision {
12379
#[WpContext(edit, embed, view)]

0 commit comments

Comments
 (0)