Skip to content

Commit 22c0695

Browse files
committed
Add how-to guides for batch operations, conditional rules, and grouping fields. Update indexes and changelog to reflect extended rewrite rules documentation.
1 parent c5db0e6 commit 22c0695

6 files changed

Lines changed: 739 additions & 2 deletions

File tree

docs/appendix/changelog.md

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,70 @@
22

33
History of documentation updates.
44

5-
## Version 1.0.0
5+
## Version 0.2.0
6+
7+
Extended rules and testkit module release.
8+
9+
### Extended Rewrite Rules
10+
11+
New convenience methods in `Rules` class for common transformation patterns:
12+
13+
**Core Rules:**
14+
- `dynamicTransform(name, ops, fn)` — Custom Dynamic transformation
15+
- `setField(ops, field, value)` — Set field (overwrites existing)
16+
17+
**Batch Operations:**
18+
- `renameFields(ops, map)` — Batch rename multiple fields
19+
- `removeFields(ops, fields...)` — Batch remove multiple fields
20+
21+
**Grouping and Moving:**
22+
- `groupFields(ops, target, fields...)` — Group fields into nested object
23+
- `flattenField(ops, field)` — Flatten nested object to root
24+
- `moveField(ops, source, target)` — Move field between paths
25+
- `copyField(ops, source, target)` — Copy field (keeps original)
26+
27+
**Path-Based Operations:**
28+
- `transformFieldAt(ops, path, fn)` — Transform at nested path
29+
- `renameFieldAt(ops, path, newName)` — Rename at nested path
30+
- `removeFieldAt(ops, path)` — Remove at nested path
31+
- `addFieldAt(ops, path, value)` — Add at nested path
32+
33+
**Conditional Rules:**
34+
- `ifFieldExists(ops, field, rule)` — Apply rule if field exists
35+
- `ifFieldMissing(ops, field, rule)` — Apply rule if field missing
36+
- `ifFieldEquals(ops, field, value, rule)` — Apply rule if field equals value
37+
38+
### New How-To Guides
39+
40+
- [Batch Operations](../how-to/batch-operations.md) — Rename/remove multiple fields
41+
- [Group Fields](../how-to/group-fields.md) — Grouping and flattening structures
42+
- [Conditional Rules](../how-to/conditional-rules.md) — Conditional rule application
43+
44+
### Testkit Module
45+
46+
New module `aether-datafixers-testkit` for testing migrations:
47+
48+
- `TestData` — Fluent test data builders
49+
- `AetherAssertions` — Custom AssertJ assertions for Dynamic, DataResult, Typed
50+
- `DataFixTester` — Test harness for individual DataFix implementations
51+
- `MigrationTester` — Test harness for complete migration chains
52+
- `SchemaTester` — Test harness for Schema validation
53+
- `QuickFix` — Factory methods for common fix patterns
54+
- `MockSchemas` — Factory for mock Schema instances
55+
- `RecordingContext` / `AssertingContext` — Test contexts
56+
57+
### Documentation Updates
58+
59+
- Updated [Rewrite Rules](../concepts/rewrite-rules.md) with extended rules section
60+
- Updated [Concepts Index](../concepts/index.md) with extended rules examples
61+
- Updated [How-To Index](../how-to/index.md) with new guides
62+
- Added [Test Migrations](../how-to/test-migrations.md) guide
63+
- Added [Testkit documentation](../testkit/index.md) section
64+
- Updated [Glossary](glossary.md) with testkit terms
65+
66+
---
67+
68+
## Version 0.1.0
669

770
Initial documentation release covering:
871

docs/concepts/index.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,15 @@ DSL.optional("nickname", DSL.string())
212212
DSL.list(DSL.string())
213213
DSL.taggedChoice("type", entityTypes)
214214

215-
// Rewrite rules
215+
// Rewrite rules (basic)
216216
Rules.renameField(TYPE, "old", "new")
217217
Rules.transformField(TYPE, "field", transformer)
218218
Rules.seq(rule1, rule2, rule3)
219+
220+
// Extended rules (batch, grouping, conditional)
221+
Rules.renameFields(ops, Map.of("old1", "new1", "old2", "new2"))
222+
Rules.groupFields(ops, "position", "x", "y", "z")
223+
Rules.ifFieldExists(ops, "legacy", migrationRule)
219224
```
220225

221226
---

docs/how-to/batch-operations.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# How to Use Batch Operations
2+
3+
This guide shows how to rename or remove multiple fields in a single operation using the extended `Rules` methods.
4+
5+
## Problem
6+
7+
When migrating data, you often need to rename or remove several fields at once. Writing individual rules for each field is verbose:
8+
9+
```java
10+
// Verbose approach
11+
Rules.seq(
12+
Rules.renameField(ops, "playerName", "name"),
13+
Rules.renameField(ops, "xp", "experience"),
14+
Rules.renameField(ops, "hp", "health"),
15+
Rules.renameField(ops, "pos_x", "x"),
16+
Rules.renameField(ops, "pos_y", "y")
17+
)
18+
```
19+
20+
## Solution
21+
22+
Use `Rules.renameFields()` and `Rules.removeFields()` for batch operations.
23+
24+
### Batch Rename
25+
26+
Rename multiple fields using a `Map`:
27+
28+
```java
29+
import de.splatgames.aether.datafixers.api.rewrite.Rules;
30+
import java.util.Map;
31+
32+
TypeRewriteRule rule = Rules.renameFields(GsonOps.INSTANCE, Map.of(
33+
"playerName", "name",
34+
"xp", "experience",
35+
"hp", "health",
36+
"pos_x", "x",
37+
"pos_y", "y"
38+
));
39+
```
40+
41+
**Input:**
42+
```json
43+
{
44+
"playerName": "Steve",
45+
"xp": 1500,
46+
"hp": 20,
47+
"pos_x": 100.5,
48+
"pos_y": 64.0
49+
}
50+
```
51+
52+
**Output:**
53+
```json
54+
{
55+
"name": "Steve",
56+
"experience": 1500,
57+
"health": 20,
58+
"x": 100.5,
59+
"y": 64.0
60+
}
61+
```
62+
63+
### Batch Remove
64+
65+
Remove multiple fields at once:
66+
67+
```java
68+
TypeRewriteRule rule = Rules.removeFields(GsonOps.INSTANCE,
69+
"deprecated1",
70+
"deprecated2",
71+
"legacyField",
72+
"oldData"
73+
);
74+
```
75+
76+
**Input:**
77+
```json
78+
{
79+
"name": "Steve",
80+
"level": 10,
81+
"deprecated1": "old",
82+
"deprecated2": 123,
83+
"legacyField": true,
84+
"oldData": {}
85+
}
86+
```
87+
88+
**Output:**
89+
```json
90+
{
91+
"name": "Steve",
92+
"level": 10
93+
}
94+
```
95+
96+
## Complete Example
97+
98+
A complete DataFix using batch operations:
99+
100+
```java
101+
public class PlayerV1ToV2Fix extends SchemaDataFix {
102+
103+
public PlayerV1ToV2Fix(Schema input, Schema output) {
104+
super("player_v1_to_v2", input, output);
105+
}
106+
107+
@Override
108+
protected TypeRewriteRule makeRule(Schema inputSchema, Schema outputSchema) {
109+
return Rules.seq(
110+
// Batch rename legacy field names
111+
Rules.renameFields(GsonOps.INSTANCE, Map.of(
112+
"playerName", "name",
113+
"xp", "experience",
114+
"hp", "health"
115+
)),
116+
117+
// Remove obsolete fields
118+
Rules.removeFields(GsonOps.INSTANCE,
119+
"legacyId",
120+
"oldFormat",
121+
"deprecated"
122+
),
123+
124+
// Add new required fields
125+
Rules.addField(PLAYER, "version", d -> d.createInt(2))
126+
);
127+
}
128+
}
129+
```
130+
131+
## Combining with Other Rules
132+
133+
Batch operations work seamlessly with other rules:
134+
135+
```java
136+
Rules.seq(
137+
// First: batch rename
138+
Rules.renameFields(ops, Map.of(
139+
"oldName", "name",
140+
"oldLevel", "level"
141+
)),
142+
143+
// Then: transform a field
144+
Rules.transformField(TYPE, "level", this::convertLevel),
145+
146+
// Then: group fields
147+
Rules.groupFields(ops, "stats", "health", "mana", "stamina"),
148+
149+
// Finally: remove obsolete
150+
Rules.removeFields(ops, "temp1", "temp2")
151+
)
152+
```
153+
154+
## Best Practices
155+
156+
1. **Order matters** - Rename fields before transforming them by their new names
157+
2. **Combine logically** - Group related renames together
158+
3. **Document the mapping** - For large migrations, document what each rename means
159+
4. **Test thoroughly** - Verify all field mappings work correctly
160+
161+
## Related
162+
163+
- [Rename a Field](rename-field.md) - Single field renaming
164+
- [Remove a Field](remove-field.md) - Single field removal
165+
- [Compose Fixes](compose-fixes.md) - Combining multiple rules
166+
- [Rewrite Rules](../concepts/rewrite-rules.md) - Complete rules reference
167+

0 commit comments

Comments
 (0)