|
| 1 | +# Adding Database Support for New WordPress Entities |
| 2 | + |
| 3 | +This guide explains how to add caching support for WordPress REST API entity types (posts, comments, users, etc.). |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +WordPress REST API returns different fields based on the `context` parameter (`edit`, `view`, `embed`). Each context requires its own database table since field sets differ significantly. |
| 8 | + |
| 9 | +**Architecture:** |
| 10 | +- `context.rs` - Generic `IsContext` trait and context marker types (EditContext, ViewContext, EmbedContext) |
| 11 | +- `db_types/{entity}/` - Column enums and wrapper structs (types only, no logic) |
| 12 | +- `repository/{entity}.rs` - Entity-specific trait definitions and all database operations |
| 13 | + |
| 14 | +Use the existing `posts` implementation in `src/repository/posts.rs` as the primary reference. |
| 15 | + |
| 16 | +## Discovering Context Fields |
| 17 | + |
| 18 | +The `wp_api` crate uses procedural macros to generate context-specific types. To see what fields are actually available: |
| 19 | + |
| 20 | +```bash |
| 21 | +# Generate expanded code for an entity |
| 22 | +cargo expand -p wp_api posts > /tmp/generated_posts.rs |
| 23 | +# or |
| 24 | +cargo expand -p wp_api comments > /tmp/generated_comments.rs |
| 25 | +``` |
| 26 | + |
| 27 | +Open the generated file and search for the context-specific types (e.g., `AnyPostWithEditContext`, `AnyPostWithViewContext`, `AnyPostWithEmbedContext`). Compare fields across contexts to understand what differs. |
| 28 | + |
| 29 | +**Important**: Don't assume patterns - field availability varies by endpoint. Always verify against the expanded types. |
| 30 | + |
| 31 | +## Implementation Steps |
| 32 | + |
| 33 | +When adding a new entity type (e.g., implementing cache support for comments): |
| 34 | + |
| 35 | +1. **Create type definitions** in `src/db_types/comments/`: |
| 36 | + - `mod.rs` - Re-exports |
| 37 | + - `edit.rs`, `view.rs`, `embed.rs` - One file per context |
| 38 | + - Each file contains: column enum (matching SQL table order) + database wrapper struct |
| 39 | + |
| 40 | +2. **Define entity-specific trait and implement database logic** in `src/repository/comments.rs`: |
| 41 | + - Define `CommentContext` trait extending `IsContext` with associated types and row mapping method |
| 42 | + - The method signature depends on your entity's needs (e.g., posts use lazy closures for term loading) |
| 43 | + - Implement trait for each context (EditContext, ViewContext, EmbedContext) |
| 44 | + - Create generic `CommentRepository<C: CommentContext>` |
| 45 | + - Implement upsert methods for contexts that need write operations |
| 46 | + |
| 47 | +3. **Create migrations** for each context table: |
| 48 | + - `migrations/NNNN-create-comments-edit-context-table.sql` |
| 49 | + - `migrations/NNNN-create-comments-view-context-table.sql` |
| 50 | + - `migrations/NNNN-create-comments-embed-context-table.sql` |
| 51 | + - Add to `MIGRATION_QUERIES` array in `lib.rs` |
| 52 | + - Update migration count assertions in platform test files: |
| 53 | + - `native/swift/Tests/wordpress-api-cache/WordPressApiCacheTests.swift` |
| 54 | + - `native/kotlin/api/kotlin/src/integrationTest/kotlin/WordPressApiCacheTest.kt` |
| 55 | + |
| 56 | +4. **Add module exports** in `src/db_types/mod.rs`: |
| 57 | + ```rust |
| 58 | + pub mod comments; |
| 59 | + ``` |
| 60 | + |
| 61 | +5. **Write tests** in the repository file covering round-trip persistence and enum variants |
| 62 | + |
| 63 | +## Key Design Decisions |
| 64 | + |
| 65 | +**Column enum ordering**: Column indexes in the enum must match the exact order in SQL `CREATE TABLE` statements and all `SELECT *` queries. Add PRAGMA-based integration tests to verify this (see `test_post_edit_context_column_enum_matches_schema` in `repository/posts.rs` for reference). |
| 66 | + |
| 67 | +**Lazy data loading**: If your entity requires optional related data (e.g., posts use term relationships for categories/tags), use `FnOnce()` closures in the trait method. This allows contexts that don't need the data to avoid unnecessary database queries by simply not calling the closure. See `PostContext::from_row_with_terms` for an example. |
| 68 | + |
| 69 | +**Repository pattern**: All database operations belong in `repository/` - this includes both SQL execution AND row-to-type mapping logic. The `db_types/` module contains only type definitions. |
| 70 | + |
| 71 | +**RETURNING optimization**: Use SQLite's `RETURNING rowid` clause in upsert statements to eliminate separate SELECT queries. Our bundled SQLite version (3.50.2) fully supports this. |
| 72 | + |
| 73 | +**Platform requirements**: The minimum supported iOS version for this library is iOS 15, which bundles SQLite 3.36.0. This ensures RETURNING clause support (added in SQLite 3.35.0) across all target platforms. See [SQLite versions bundled with OS](https://github.com/yapstudios/YapDatabase/wiki/SQLite-version-(bundled-with-OS)) for reference. |
| 74 | + |
| 75 | +## Reference Implementation |
| 76 | + |
| 77 | +See `src/repository/posts.rs` for a complete working example including: |
| 78 | +- Context trait implementations with lazy closure pattern |
| 79 | +- Generic repository with context-specific methods |
| 80 | +- PRAGMA tests for column schema verification |
| 81 | +- Comprehensive test coverage |
0 commit comments