Skip to content

Commit b6ce0cf

Browse files
fix: added type rename support for enum, union and interface. (#2793)
1 parent 86b26b8 commit b6ce0cf

6 files changed

+149
-51
lines changed

src/core/config/transformer/improve_type_names.rs

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::{BTreeMap, HashSet};
22

33
use convert_case::{Case, Casing};
44

5+
use super::RenameTypes;
56
use crate::core::config::Config;
67
use crate::core::transform::Transform;
78
use crate::core::valid::Valid;
@@ -113,42 +114,12 @@ impl<'a> CandidateGeneration<'a> {
113114
#[derive(Default)]
114115
pub struct ImproveTypeNames;
115116

116-
impl ImproveTypeNames {
117-
/// Generates type names based on inferred candidates from the provided
118-
/// configuration.
119-
fn generate_type_names(&self, mut config: Config) -> Config {
120-
let finalized_candidates = CandidateGeneration::new(&config).generate().converge();
121-
122-
for (old_type_name, new_type_name) in finalized_candidates {
123-
if let Some(type_) = config.types.remove(old_type_name.as_str()) {
124-
// Add newly generated type.
125-
config.types.insert(new_type_name.to_owned(), type_);
126-
127-
// Replace all the instances of old name in config.
128-
for actual_type in config.types.values_mut() {
129-
for actual_field in actual_type.fields.values_mut() {
130-
if actual_field.type_of.name() == &old_type_name {
131-
// Update the field's type with the new name
132-
actual_field.type_of = actual_field
133-
.type_of
134-
.clone()
135-
.with_name(new_type_name.to_owned());
136-
}
137-
}
138-
}
139-
}
140-
}
141-
config
142-
}
143-
}
144-
145117
impl Transform for ImproveTypeNames {
146118
type Value = Config;
147119
type Error = String;
148120
fn transform(&self, config: Config) -> Valid<Self::Value, Self::Error> {
149-
let config = self.generate_type_names(config);
150-
151-
Valid::succeed(config)
121+
let finalized_candidates = CandidateGeneration::new(&config).generate().converge();
122+
RenameTypes::new(finalized_candidates.iter()).transform(config)
152123
}
153124
}
154125

src/core/config/transformer/rename_types.rs

Lines changed: 108 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashSet;
2+
13
use indexmap::IndexMap;
24

35
use crate::core::config::Config;
@@ -28,12 +30,11 @@ impl Transform for RenameTypes {
2830

2931
// Ensure all types exist in the configuration
3032
Valid::from_iter(self.0.iter(), |(existing_name, suggested_name)| {
31-
if !config.types.contains_key(existing_name) {
32-
Valid::fail(format!(
33-
"Type '{}' not found in configuration.",
34-
existing_name
35-
))
36-
} else {
33+
if config.types.contains_key(existing_name)
34+
|| config.enums.contains_key(existing_name)
35+
|| config.unions.contains_key(existing_name)
36+
{
37+
// handle for the types.
3738
if let Some(type_info) = config.types.remove(existing_name) {
3839
config.types.insert(suggested_name.to_string(), type_info);
3940
lookup.insert(existing_name.clone(), suggested_name.clone());
@@ -46,7 +47,24 @@ impl Transform for RenameTypes {
4647
}
4748
}
4849

50+
// handle for the enums.
51+
if let Some(type_info) = config.enums.remove(existing_name) {
52+
config.enums.insert(suggested_name.to_string(), type_info);
53+
lookup.insert(existing_name.clone(), suggested_name.clone());
54+
}
55+
56+
// handle for the union.
57+
if let Some(type_info) = config.unions.remove(existing_name) {
58+
config.unions.insert(suggested_name.to_string(), type_info);
59+
lookup.insert(existing_name.clone(), suggested_name.clone());
60+
}
61+
4962
Valid::succeed(())
63+
} else {
64+
Valid::fail(format!(
65+
"Type '{}' not found in configuration.",
66+
existing_name
67+
))
5068
}
5169
})
5270
.map(|_| {
@@ -65,6 +83,54 @@ impl Transform for RenameTypes {
6583
}
6684
}
6785
}
86+
87+
// replace in interface.
88+
type_.implements = type_
89+
.implements
90+
.iter()
91+
.map(|interface_type_name| {
92+
lookup
93+
.get(interface_type_name)
94+
.cloned()
95+
.unwrap_or_else(|| interface_type_name.to_owned())
96+
})
97+
.collect();
98+
}
99+
100+
// replace in the union as well.
101+
for union_type_ in config.unions.values_mut() {
102+
// Collect changes to be made
103+
let mut types_to_remove = HashSet::new();
104+
let mut types_to_add = HashSet::new();
105+
106+
for type_name in union_type_.types.iter() {
107+
if let Some(new_type_name) = lookup.get(type_name) {
108+
types_to_remove.insert(type_name.clone());
109+
types_to_add.insert(new_type_name.clone());
110+
}
111+
}
112+
// Apply changes
113+
for type_name in types_to_remove {
114+
union_type_.types.remove(&type_name);
115+
}
116+
117+
for type_name in types_to_add {
118+
union_type_.types.insert(type_name);
119+
}
120+
}
121+
122+
// replace in union as well.
123+
for union_type_ in config.unions.values_mut() {
124+
union_type_.types = union_type_
125+
.types
126+
.iter()
127+
.map(|type_name| {
128+
lookup
129+
.get(type_name)
130+
.cloned()
131+
.unwrap_or_else(|| type_name.to_owned())
132+
})
133+
.collect();
68134
}
69135

70136
config
@@ -92,14 +158,20 @@ mod test {
92158
id: ID!
93159
name: String
94160
}
161+
type B {
162+
name: String
163+
username: String
164+
}
165+
union FooBar = A | B
95166
type Post {
96167
id: ID!
97168
title: String
98169
body: String
99170
}
100-
type B {
101-
name: String
102-
username: String
171+
enum Status {
172+
PENDING
173+
STARTED,
174+
COMPLETED
103175
}
104176
type Query {
105177
posts: [Post] @http(path: "/posts")
@@ -116,6 +188,7 @@ mod test {
116188
"A" => "User",
117189
"B" => "InputUser",
118190
"Mutation" => "UserMutation",
191+
"Status" => "TaskStatus"
119192
}
120193
.iter(),
121194
)
@@ -184,4 +257,30 @@ mod test {
184257
let expected = Err(b_err.combine(c_err));
185258
assert_eq!(actual, expected);
186259
}
260+
261+
#[test]
262+
fn test_inferface_rename() {
263+
let sdl = r#"
264+
schema {
265+
query: Query
266+
}
267+
interface Node {
268+
id: ID
269+
}
270+
type Post implements Node {
271+
id: ID
272+
title: String
273+
}
274+
type Query {
275+
posts: [Post] @http(path: "/posts")
276+
}
277+
"#;
278+
let config = Config::from_sdl(sdl).to_result().unwrap();
279+
280+
let result = RenameTypes::new(hashmap! {"Node" => "NodeTest"}.iter())
281+
.transform(config)
282+
.to_result()
283+
.unwrap();
284+
insta::assert_snapshot!(result.to_sdl())
285+
}
187286
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
source: src/core/config/transformer/rename_types.rs
3+
expression: result.to_sdl()
4+
---
5+
schema @server @upstream {
6+
query: Query
7+
}
8+
9+
interface NodeTest {
10+
id: ID
11+
}
12+
13+
type Post implements NodeTest {
14+
id: ID
15+
title: String
16+
}
17+
18+
type Query {
19+
posts: [Post] @http(path: "/posts")
20+
}

src/core/config/transformer/snapshots/tailcall__core__config__transformer__rename_types__test__rename_type.snap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ input InputUser {
1111
username: String
1212
}
1313

14+
union FooBar = InputUser | User
15+
16+
enum TaskStatus {
17+
COMPLETED
18+
PENDING
19+
STARTED
20+
}
21+
1422
type Post {
1523
body: String
1624
id: ID!

src/core/generator/snapshots/tailcall__core__generator__generator__test__should_generate_combined_config.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ input news__NewsInput {
1818
body: String
1919
id: Int
2020
postImage: String
21-
status: news__Status
21+
status: Status
2222
title: String
2323
}
2424

25-
enum news__Status {
25+
enum Status {
2626
DELETED
2727
DRAFT
2828
PUBLISHED
@@ -52,7 +52,7 @@ type News {
5252
body: String
5353
id: Int
5454
postImage: String
55-
status: news__Status
55+
status: Status
5656
title: String
5757
}
5858

@@ -80,11 +80,11 @@ type Post {
8080
type Query {
8181
inCompatibleProperties: InCompatibleProperty @http(path: "/")
8282
news__NewsService__AddNews(news: news__NewsInput!): News @grpc(body: "{{.args.news}}", method: "news.NewsService.AddNews")
83-
news__NewsService__DeleteNews(newsId: news__NewsId!): Empty @grpc(body: "{{.args.newsId}}", method: "news.NewsService.DeleteNews")
83+
news__NewsService__DeleteNews(newsId: Id!): Empty @grpc(body: "{{.args.newsId}}", method: "news.NewsService.DeleteNews")
8484
news__NewsService__EditNews(news: news__NewsInput!): News @grpc(body: "{{.args.news}}", method: "news.NewsService.EditNews")
8585
news__NewsService__GetAllNews: NewsNewsServiceGetMultipleNew @grpc(method: "news.NewsService.GetAllNews")
8686
news__NewsService__GetMultipleNews(multipleNewsId: news__MultipleNewsId!): NewsNewsServiceGetMultipleNew @grpc(body: "{{.args.multipleNewsId}}", method: "news.NewsService.GetMultipleNews")
87-
news__NewsService__GetNews(newsId: news__NewsId!): News @grpc(body: "{{.args.newsId}}", method: "news.NewsService.GetNews")
87+
news__NewsService__GetNews(newsId: Id!): News @grpc(body: "{{.args.newsId}}", method: "news.NewsService.GetNews")
8888
post(id: Int! = 1): Post @http(path: "/posts/{{.args.id}}")
8989
posts: [Post] @http(path: "/posts?_limit=11")
9090
user(id: Int!): User @http(path: "/users/{{.args.id}}")

tests/cli/snapshots/cli_spec__test__generator_spec__tests__cli__fixtures__generator__gen_json_proto_mix_config.md.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ input news__NewsInput {
1818
body: String
1919
id: Int
2020
postImage: String
21-
status: news__Status
21+
status: Status
2222
title: String
2323
}
2424

25-
enum news__Status {
25+
enum Status {
2626
DELETED
2727
DRAFT
2828
PUBLISHED
@@ -51,7 +51,7 @@ type News {
5151
body: String
5252
id: Int
5353
postImage: String
54-
status: news__Status
54+
status: Status
5555
title: String
5656
}
5757

@@ -61,11 +61,11 @@ type NewsNewsServiceGetMultipleNew {
6161

6262
type Query {
6363
news__NewsService__AddNews(news: news__NewsInput!): News @grpc(body: "{{.args.news}}", method: "news.NewsService.AddNews")
64-
news__NewsService__DeleteNews(newsId: news__NewsId!): Empty @grpc(body: "{{.args.newsId}}", method: "news.NewsService.DeleteNews")
64+
news__NewsService__DeleteNews(newsId: Id!): Empty @grpc(body: "{{.args.newsId}}", method: "news.NewsService.DeleteNews")
6565
news__NewsService__EditNews(news: news__NewsInput!): News @grpc(body: "{{.args.news}}", method: "news.NewsService.EditNews")
6666
news__NewsService__GetAllNews: NewsNewsServiceGetMultipleNew @grpc(method: "news.NewsService.GetAllNews")
6767
news__NewsService__GetMultipleNews(multipleNewsId: news__MultipleNewsId!): NewsNewsServiceGetMultipleNew @grpc(body: "{{.args.multipleNewsId}}", method: "news.NewsService.GetMultipleNews")
68-
news__NewsService__GetNews(newsId: news__NewsId!): News @grpc(body: "{{.args.newsId}}", method: "news.NewsService.GetNews")
68+
news__NewsService__GetNews(newsId: Id!): News @grpc(body: "{{.args.newsId}}", method: "news.NewsService.GetNews")
6969
users: [User] @http(path: "/users")
7070
}
7171

0 commit comments

Comments
 (0)