Commit 2cb188f
committed
feat(derive): Implement advanced nested and flattened field handling
This commit introduces a comprehensive and robust implementation for handling complex document structures within the `#[derive(Typesense)]` macro, enabling powerful schema generation directly from Rust structs.
The macro now supports the full range of advanced indexing strategies offered by Typesense, including automatic object indexing, field flattening with prefix control, and patterns for manual flattening.
### Key Features & Implementation Details
- **Automatic Object Indexing:**
- A field containing a nested struct that also derives `Document` is now automatically mapped to a Typesense `object` (or `object[]` for `Vec<T>`).
- This feature requires `#[typesense(enable_nested_fields = true)]` on the parent collection, which the macro now supports.
- **Automatic Field Flattening with `#[typesense(flatten)]`:**
- A field marked `#[typesense(flatten)]` has its sub-fields expanded into the parent schema using dot-notation.
- By default, the Rust field's name is used as the prefix for all sub-fields (e.g., `details: ProductDetails` results in schema fields like `details.part_number`).
- **Prefix Override for Flattening:**
- The `flatten` attribute can be combined with `rename` to provide a custom prefix for the flattened fields.
- Usage: `#[typesense(flatten, rename = "custom_prefix")]`
- This provides powerful schema mapping flexibility, allowing the Rust struct's field name to differ from the prefix used in the Typesense schema.
- **Manual Flattening Pattern (`skip` + `rename`):**
- A new `#[typesense(skip)]` attribute has been introduced to completely exclude a field from the generated Typesense schema.
- This enables the powerful pattern of sending both nested and flattened data to Typesense: the nested version can be used for display/deserialization, while a separate set of flattened fields is used for indexing. This is achieved by:
1. Marking the nested struct field (e.g., `details: Details`) with `#[typesense(skip)]`.
2. Adding corresponding top-level fields to the Rust struct, marked with `#[typesense(rename = "details.field_name")]`.
- **Ergonomic Boolean Attributes:**
- All boolean attributes (`facet`, `sort`, `index`, `store`, `infix`, `stem`, `optional`, `range_index`) now support shorthand "flag" syntax.
- For example, `#[typesense(sort)]` is a valid and recommended equivalent to `#[typesense(sort = true)]`, dramatically improving readability and consistency.
- **Robust Error Handling & Validation:**
- The macro provides clear, compile-time errors for invalid or ambiguous attribute usage.
- It correctly detects and reports duplicate attributes, whether they are in the same `#[typesense(...)]` block or across multiple attributes on the same field.
### Testing
- **Comprehensive Integration Test (`derive_integration.rs`):**
- A new, full-lifecycle integration test has been added to validate the entire feature set.
- The test defines a complex struct using every new attribute and pattern, generates a schema, creates a real collection, and uses the generic client (`collection_of<T>`) to perform and validate a full Create, Read, Update, Delete, and Search lifecycle.
- A second integration test was added to specifically validate the manual flattening pattern.
- **UI Tests:**
- `trybuild` UI tests have been added to verify that the macro produces the correct compile-time errors for invalid attribute combinations, such as duplicate attributes.1 parent 5a84fb3 commit 2cb188f
File tree
11 files changed
+1413
-172
lines changed- typesense_derive/src
- typesense
- src/field
- tests
- client
- derive
- ui
11 files changed
+1413
-172
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
1 | 2 | | |
2 | | - | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
13 | 26 | | |
14 | 27 | | |
15 | 28 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
23 | 27 | | |
24 | 28 | | |
25 | 29 | | |
| |||
89 | 93 | | |
90 | 94 | | |
91 | 95 | | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
92 | 124 | | |
93 | 125 | | |
94 | 126 | | |
| |||
105 | 137 | | |
106 | 138 | | |
107 | 139 | | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
108 | 144 | | |
109 | 145 | | |
110 | 146 | | |
| |||
0 commit comments