Request: Implement a `rename_all = ...` attribute for types
💡 Feature description
Similar to serde's rename_all attribute, this would reformat all of the type's fields / variants for de/serialization to the format specified.
Individual field / variant rename must take precedence over rename_all.
Valid format values should be, at minimum:
snake_casekebab-casecamelCasePascalCaseSCREAMING_SNAKE_CASESCREAMING-KEBAB-CASEUPPERCASElowercase
This rename_all attribute should probably be applicable to types and enum variants.
💻 Basic example
#[derive(Item, PartialEq, Debug, Clone)]
#[dynomite(rename_all = "kebab-case")]
struct Recipe {
#[dynomite(partition_key]
#[dynomite(rename = "recipe_id")]
id: String,
net_carbs: u64,
}
Should be serialized (to JSON just as an example) as:
{
"recipe_id": "...",
"net-carbs": 0
}
references / prior work
We should consider adding heck, an opinionated & non-customizable case-conversion 3rd-party library crate, as a dependency to the dynomite-derive crate to reduce rework and (potentially) simplify implementation (and testing!) of this feature (since it reformats the existing name, instead of providing a new name entirely).
I've written code that makes the following test pass (using the heck crate, just an implementation detail though).
If there is any interest (not seeing any so far on the ticket; no thumbs-up etc),
I could continue working on the implementation I currently have.
Of course I prefer to not unnecessarily bloat dynomite.
rename_all type-level dynomite attr
#[test]
#[allow(non_snake_case /* specifically testing mixed-case fields */)]
fn derive_item_rename_all_attr_kebab_case() {
// GIVEN
#[derive(Item)]
#[dynomite(rename_all = "kebab-case")]
struct MyItem {
#[dynomite(partition_key)]
_pk: String,
#[dynomite(sort_key)]
sk: String,
#[dynomite(rename = "fooBar")]
with_Field_levelRename: Option<i32>,
snake_case: bool,
camelCase: bool,
PascalCase: bool,
SCREAMING_SNAKE_CASE: bool,
UPPERCASE: bool,
lowercase: bool,
}
let original = MyItem {
_pk: "6956abd4-665f-433a-b9ad-c038f9c64601".into(),
sk: "2021-01-20T22:41:41.603Z".into(),
with_Field_levelRename: Some(1024),
snake_case: true,
camelCase: true,
PascalCase: true,
SCREAMING_SNAKE_CASE: true,
UPPERCASE: true,
lowercase: true,
};
// WHEN
let attrs: Attributes = original.into();
// THEN
assert_eq!(attrs.len(), 9);
assert!(attrs.contains_key("_pk"), "leading underscore retained");
assert!(attrs.contains_key("sk"), "unchanged");
assert!(attrs.contains_key("fooBar"), "field-level rename has precedent");
assert!(attrs.contains_key("snake-case"));
assert!(attrs.contains_key("camel-case"));
assert!(attrs.contains_key("pascal-case"));
assert!(attrs.contains_key("screaming-snake-case"));
assert!(attrs.contains_key("uppercase"));
assert!(attrs.contains_key("lowercase"));
}