Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit071dfa3

Browse files
committed
added a rename_all container attribute for enums and structs
1 parent7061671 commit071dfa3

File tree

9 files changed

+299
-21
lines changed

9 files changed

+299
-21
lines changed

‎postgres-derive-test/src/composites.rs‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,49 @@ fn name_overrides() {
8989
);
9090
}
9191

92+
#[test]
93+
fnrename_all_overrides(){
94+
#[derive(FromSql,ToSql,Debug,PartialEq)]
95+
#[postgres(name ="inventory_item", rename_all ="SCREAMING_SNAKE_CASE")]
96+
structInventoryItem{
97+
name:String,
98+
supplier_id:i32,
99+
#[postgres(name ="Price")]
100+
price:Option<f64>,
101+
}
102+
103+
letmut conn =Client::connect("user=postgres host=localhost port=5433",NoTls).unwrap();
104+
conn.batch_execute(
105+
"CREATE TYPE pg_temp.inventory_item AS (
106+
\"NAME\" TEXT,
107+
\"SUPPLIER_ID\" INT,
108+
\"Price\" DOUBLE PRECISION
109+
);",
110+
)
111+
.unwrap();
112+
113+
let item =InventoryItem{
114+
name:"foobar".to_owned(),
115+
supplier_id:100,
116+
price:Some(15.50),
117+
};
118+
119+
let item_null =InventoryItem{
120+
name:"foobar".to_owned(),
121+
supplier_id:100,
122+
price:None,
123+
};
124+
125+
test_type(
126+
&mut conn,
127+
"inventory_item",
128+
&[
129+
(item,"ROW('foobar', 100, 15.50)"),
130+
(item_null,"ROW('foobar', 100, NULL)"),
131+
],
132+
);
133+
}
134+
92135
#[test]
93136
fnwrong_name(){
94137
#[derive(FromSql,ToSql,Debug,PartialEq)]

‎postgres-derive-test/src/enums.rs‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,35 @@ fn name_overrides() {
5353
);
5454
}
5555

56+
#[test]
57+
fnrename_all_overrides(){
58+
#[derive(Debug,ToSql,FromSql,PartialEq)]
59+
#[postgres(name ="mood", rename_all ="snake_case")]
60+
enumMood{
61+
Sad,
62+
#[postgres(name ="okay")]
63+
Ok,
64+
Happy,
65+
}
66+
67+
letmut conn =Client::connect("user=postgres host=localhost port=5433",NoTls).unwrap();
68+
conn.execute(
69+
"CREATE TYPE pg_temp.mood AS ENUM ('sad', 'okay', 'happy')",
70+
&[],
71+
)
72+
.unwrap();
73+
74+
test_type(
75+
&mut conn,
76+
"mood",
77+
&[
78+
(Mood::Sad,"'sad'"),
79+
(Mood::Ok,"'okay'"),
80+
(Mood::Happy,"'happy'"),
81+
],
82+
);
83+
}
84+
5685
#[test]
5786
fnwrong_name(){
5887
#[derive(Debug,ToSql,FromSql,PartialEq)]

‎postgres-derive/src/case.rs‎

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#[allow(deprecated, unused_imports)]
2+
use std::ascii::AsciiExt;
3+
4+
useself::RenameRule::*;
5+
6+
/// The different possible ways to change case of fields in a struct, or variants in an enum.
7+
#[allow(clippy::enum_variant_names)]
8+
#[derive(Copy,Clone,PartialEq)]
9+
pubenumRenameRule{
10+
/// Rename direct children to "lowercase" style.
11+
LowerCase,
12+
/// Rename direct children to "UPPERCASE" style.
13+
UpperCase,
14+
/// Rename direct children to "PascalCase" style, as typically used for
15+
/// enum variants.
16+
PascalCase,
17+
/// Rename direct children to "camelCase" style.
18+
CamelCase,
19+
/// Rename direct children to "snake_case" style, as commonly used for
20+
/// fields.
21+
SnakeCase,
22+
/// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly
23+
/// used for constants.
24+
ScreamingSnakeCase,
25+
/// Rename direct children to "kebab-case" style.
26+
KebabCase,
27+
/// Rename direct children to "SCREAMING-KEBAB-CASE" style.
28+
ScreamingKebabCase,
29+
}
30+
31+
pubstaticRENAME_RULES:&[(&str,RenameRule)] =&[
32+
("lowercase",LowerCase),
33+
("UPPERCASE",UpperCase),
34+
("PascalCase",PascalCase),
35+
("camelCase",CamelCase),
36+
("snake_case",SnakeCase),
37+
("SCREAMING_SNAKE_CASE",ScreamingSnakeCase),
38+
("kebab-case",KebabCase),
39+
("SCREAMING-KEBAB-CASE",ScreamingKebabCase),
40+
];
41+
42+
implRenameRule{
43+
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
44+
pubfnapply_to_variant(&self,variant:&str) ->String{
45+
match*self{
46+
PascalCase => variant.to_owned(),
47+
LowerCase => variant.to_ascii_lowercase(),
48+
UpperCase => variant.to_ascii_uppercase(),
49+
CamelCase => variant[..1].to_ascii_lowercase() +&variant[1..],
50+
SnakeCase =>{
51+
letmut snake =String::new();
52+
for(i, ch)in variant.char_indices(){
53+
if i >0 && ch.is_uppercase(){
54+
snake.push('_');
55+
}
56+
snake.push(ch.to_ascii_lowercase());
57+
}
58+
snake
59+
}
60+
ScreamingSnakeCase =>SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
61+
KebabCase =>SnakeCase.apply_to_variant(variant).replace('_',"-"),
62+
ScreamingKebabCase =>ScreamingSnakeCase
63+
.apply_to_variant(variant)
64+
.replace('_',"-"),
65+
}
66+
}
67+
68+
/// Apply a renaming rule to a struct field, returning the version expected in the source.
69+
pubfnapply_to_field(&self,field:&str) ->String{
70+
match*self{
71+
LowerCase |SnakeCase => field.to_owned(),
72+
UpperCase => field.to_ascii_uppercase(),
73+
PascalCase =>{
74+
letmut pascal =String::new();
75+
letmut capitalize =true;
76+
for chin field.chars(){
77+
if ch =='_'{
78+
capitalize =true;
79+
}elseif capitalize{
80+
pascal.push(ch.to_ascii_uppercase());
81+
capitalize =false;
82+
}else{
83+
pascal.push(ch);
84+
}
85+
}
86+
pascal
87+
}
88+
CamelCase =>{
89+
let pascal =PascalCase.apply_to_field(field);
90+
pascal[..1].to_ascii_lowercase() +&pascal[1..]
91+
}
92+
ScreamingSnakeCase => field.to_ascii_uppercase(),
93+
KebabCase => field.replace('_',"-"),
94+
ScreamingKebabCase =>ScreamingSnakeCase.apply_to_field(field).replace('_',"-"),
95+
}
96+
}
97+
}
98+
99+
#[test]
100+
fnrename_variants(){
101+
for&(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab)in&[
102+
(
103+
"Outcome","outcome","OUTCOME","outcome","outcome","OUTCOME","outcome","OUTCOME",
104+
),
105+
(
106+
"VeryTasty",
107+
"verytasty",
108+
"VERYTASTY",
109+
"veryTasty",
110+
"very_tasty",
111+
"VERY_TASTY",
112+
"very-tasty",
113+
"VERY-TASTY",
114+
),
115+
("A","a","A","a","a","A","a","A"),
116+
("Z42","z42","Z42","z42","z42","Z42","z42","Z42"),
117+
]{
118+
assert_eq!(LowerCase.apply_to_variant(original), lower);
119+
assert_eq!(UpperCase.apply_to_variant(original), upper);
120+
assert_eq!(PascalCase.apply_to_variant(original), original);
121+
assert_eq!(CamelCase.apply_to_variant(original), camel);
122+
assert_eq!(SnakeCase.apply_to_variant(original), snake);
123+
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
124+
assert_eq!(KebabCase.apply_to_variant(original), kebab);
125+
assert_eq!(
126+
ScreamingKebabCase.apply_to_variant(original),
127+
screaming_kebab
128+
);
129+
}
130+
}
131+
132+
#[test]
133+
fnrename_fields(){
134+
for&(original, upper, pascal, camel, screaming, kebab, screaming_kebab)in&[
135+
(
136+
"outcome","OUTCOME","Outcome","outcome","OUTCOME","outcome","OUTCOME",
137+
),
138+
(
139+
"very_tasty",
140+
"VERY_TASTY",
141+
"VeryTasty",
142+
"veryTasty",
143+
"VERY_TASTY",
144+
"very-tasty",
145+
"VERY-TASTY",
146+
),
147+
("a","A","A","a","A","a","A"),
148+
("z42","Z42","Z42","z42","Z42","z42","Z42"),
149+
]{
150+
assert_eq!(UpperCase.apply_to_field(original), upper);
151+
assert_eq!(PascalCase.apply_to_field(original), pascal);
152+
assert_eq!(CamelCase.apply_to_field(original), camel);
153+
assert_eq!(SnakeCase.apply_to_field(original), original);
154+
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
155+
assert_eq!(KebabCase.apply_to_field(original), kebab);
156+
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
157+
}
158+
}

‎postgres-derive/src/composites.rs‎

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use syn::{
44
TypeParamBound,
55
};
66

7-
usecrate::overrides::Overrides;
7+
usecrate::{case::RenameRule,overrides::Overrides};
88

99
pubstructField{
1010
pubname:String,
@@ -13,18 +13,26 @@ pub struct Field {
1313
}
1414

1515
implField{
16-
pubfnparse(raw:&syn::Field) ->Result<Field,Error>{
16+
pubfnparse(raw:&syn::Field,rename_all:Option<RenameRule>) ->Result<Field,Error>{
1717
let overrides =Overrides::extract(&raw.attrs)?;
18-
1918
let ident = raw.ident.as_ref().unwrap().clone();
20-
Ok(Field{
21-
name: overrides.name.unwrap_or_else(||{
19+
20+
// field level name override takes precendence over container level rename_all override
21+
let name =match overrides.name{
22+
Some(n) => n,
23+
None =>{
2224
let name = ident.to_string();
23-
match name.strip_prefix("r#"){
24-
Some(name) => name.to_string(),
25-
None => name,
25+
let stripped = name.strip_prefix("r#").map(String::from).unwrap_or(name);
26+
27+
match rename_all{
28+
Some(rule) => rule.apply_to_field(&stripped),
29+
None => stripped,
2630
}
27-
}),
31+
}
32+
};
33+
34+
Ok(Field{
35+
name,
2836
ident,
2937
type_: raw.ty.clone(),
3038
})

‎postgres-derive/src/enums.rs‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use syn::{Error,Fields,Ident};
22

3-
usecrate::overrides::Overrides;
3+
usecrate::{case::RenameRule,overrides::Overrides};
44

55
pubstructVariant{
66
pubident:Ident,
77
pubname:String,
88
}
99

1010
implVariant{
11-
pubfnparse(raw:&syn::Variant) ->Result<Variant,Error>{
11+
pubfnparse(raw:&syn::Variant,rename_all:Option<RenameRule>) ->Result<Variant,Error>{
1212
match raw.fields{
1313
Fields::Unit =>{}
1414
_ =>{
@@ -18,11 +18,16 @@ impl Variant {
1818
))
1919
}
2020
}
21-
2221
let overrides =Overrides::extract(&raw.attrs)?;
22+
23+
// variant level name override takes precendence over container level rename_all override
24+
let name = overrides.name.unwrap_or_else(||match rename_all{
25+
Some(rule) => rule.apply_to_variant(&raw.ident.to_string()),
26+
None => raw.ident.to_string(),
27+
});
2328
Ok(Variant{
2429
ident: raw.ident.clone(),
25-
name: overrides.name.unwrap_or_else(|| raw.ident.to_string()),
30+
name,
2631
})
2732
}
2833
}

‎postgres-derive/src/fromsql.rs‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result<TokenStream, Error> {
2424
));
2525
}
2626

27-
let name = overrides.name.unwrap_or_else(|| input.ident.to_string());
27+
let name = overrides
28+
.name
29+
.clone()
30+
.unwrap_or_else(|| input.ident.to_string());
2831

2932
let(accepts_body, to_sql_body) =if overrides.transparent{
3033
match input.data{
@@ -51,7 +54,7 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result<TokenStream, Error> {
5154
let variants = data
5255
.variants
5356
.iter()
54-
.map(Variant::parse)
57+
.map(|variant|Variant::parse(variant, overrides.rename_all))
5558
.collect::<Result<Vec<_>,_>>()?;
5659
(
5760
accepts::enum_body(&name,&variants),
@@ -75,7 +78,7 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result<TokenStream, Error> {
7578
let fields = fields
7679
.named
7780
.iter()
78-
.map(Field::parse)
81+
.map(|field|Field::parse(field, overrides.rename_all))
7982
.collect::<Result<Vec<_>,_>>()?;
8083
(
8184
accepts::composite_body(&name,"FromSql",&fields),

‎postgres-derive/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use proc_macro::TokenStream;
77
use syn::parse_macro_input;
88

99
mod accepts;
10+
mod case;
1011
mod composites;
1112
mod enums;
1213
mod fromsql;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp