Skip to content

Commit 7327f1b

Browse files
author
Thomas Ville
committed
[rust] support discriminators on existing fields
1 parent 4f9f14a commit 7327f1b

File tree

94 files changed

+2162
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+2162
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
generatorName: rust
2+
outputDir: samples/client/others/rust/reqwest/oneOf-discriminator
3+
library: reqwest
4+
inputSpec: modules/openapi-generator/src/test/resources/3_0/oneOfDiscriminator.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/rust
6+
additionalProperties:
7+
supportAsync: false
8+
packageName: oneof-discriminator-reqwest

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,20 @@ public CodegenModel fromModel(String name, Schema model) {
318318
return mdl;
319319
}
320320

321+
@Override
322+
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
323+
// Collect all models into a single list
324+
List<ModelMap> allModels = new ArrayList<>();
325+
for (ModelsMap models : objs.values()) {
326+
allModels.addAll(models.getModels());
327+
}
328+
329+
// Process oneOf discriminators across all models
330+
postProcessOneOfModels(allModels);
331+
332+
return super.postProcessAllModels(objs);
333+
}
334+
321335
@Override
322336
public ModelsMap postProcessModels(ModelsMap objs) {
323337
for (ModelMap model : objs.getModels()) {
@@ -666,6 +680,66 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
666680
}
667681
}
668682

683+
private void postProcessOneOfModels(List<ModelMap> allModels) {
684+
final HashMap<String, List<String>> oneOfMapDiscriminator = new HashMap<>();
685+
686+
for (ModelMap mo : allModels) {
687+
final CodegenModel cm = mo.getModel();
688+
689+
final CodegenComposedSchemas cs = cm.getComposedSchemas();
690+
691+
if (cs != null) {
692+
final List<CodegenProperty> csOneOf = cs.getOneOf();
693+
694+
if (csOneOf != null) {
695+
for (CodegenProperty model : csOneOf) {
696+
// Generate a valid name for the enum variant.
697+
// Mainly needed for primitive types.
698+
String[] modelParts = model.dataType.replace("<", "Of").replace(">", "").split("::");
699+
model.datatypeWithEnum = StringUtils.camelize(modelParts[modelParts.length - 1]);
700+
701+
// Primitive type is not properly set, this overrides it to guarantee adequate model generation.
702+
if (!model.getDataType().matches(String.format(Locale.ROOT, ".*::%s", model.getDatatypeWithEnum()))) {
703+
model.isPrimitiveType = true;
704+
}
705+
}
706+
707+
cs.setOneOf(csOneOf);
708+
cm.setComposedSchemas(cs);
709+
}
710+
}
711+
712+
if (cm.discriminator != null) {
713+
for (String model : cm.oneOf) {
714+
List<String> discriminators = oneOfMapDiscriminator.getOrDefault(model, new ArrayList<>());
715+
discriminators.add(cm.discriminator.getPropertyBaseName());
716+
oneOfMapDiscriminator.put(model, discriminators);
717+
}
718+
}
719+
}
720+
721+
for (ModelMap mo : allModels) {
722+
final CodegenModel cm = mo.getModel();
723+
724+
for (CodegenProperty var : cm.vars) {
725+
var.isDiscriminator = false;
726+
}
727+
728+
final List<String> discriminatorsForModel = oneOfMapDiscriminator.get(cm.getSchemaName());
729+
730+
if (discriminatorsForModel != null) {
731+
for (String discriminator : discriminatorsForModel) {
732+
for (CodegenProperty var : cm.vars) {
733+
if (var.baseName.equals(discriminator)) {
734+
var.isDiscriminator = true;
735+
break;
736+
}
737+
}
738+
}
739+
}
740+
}
741+
}
742+
669743
@Override
670744
public void postProcessParameter(CodegenParameter parameter) {
671745
super.postProcessParameter(parameter);

modules/openapi-generator/src/main/resources/rust/model.mustache

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ pub struct {{{classname}}} {
131131
{{#isByteArray}}
132132
{{#vendorExtensions.isMandatory}}#[serde_as(as = "serde_with::base64::Base64")]{{/vendorExtensions.isMandatory}}{{^vendorExtensions.isMandatory}}#[serde_as(as = "{{^serdeAsDoubleOption}}Option{{/serdeAsDoubleOption}}{{#serdeAsDoubleOption}}super::DoubleOption{{/serdeAsDoubleOption}}<serde_with::base64::Base64>")]{{/vendorExtensions.isMandatory}}
133133
{{/isByteArray}}
134+
{{#isDiscriminator}}
135+
#[serde(default = "{{{classname}}}::_name_for_{{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}")]
136+
{{/isDiscriminator}}
134137
#[serde(rename = "{{{baseName}}}"{{^required}}{{#isNullable}}, default{{^isByteArray}}, with = "::serde_with::rust::double_option"{{/isByteArray}}{{/isNullable}}{{/required}}{{^required}}, skip_serializing_if = "Option::is_none"{{/required}}{{#required}}{{#isNullable}}, deserialize_with = "Option::deserialize"{{/isNullable}}{{/required}})]
135138
pub {{{name}}}: {{!
136139
### Option Start
@@ -172,6 +175,16 @@ impl {{{classname}}} {
172175
}
173176
}
174177
}
178+
{{#vars}}
179+
{{#isDiscriminator}}
180+
181+
impl {{{classname}}} {
182+
fn _name_for_{{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}() -> String {
183+
{{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}String::from("{{classname}}"){{/defaultValue}}
184+
}
185+
}
186+
{{/isDiscriminator}}
187+
{{/vars}}
175188
{{/oneOf.isEmpty}}
176189
{{^oneOf.isEmpty}}
177190
{{! TODO: add other vars that are not part of the oneOf}}

modules/openapi-generator/src/test/resources/3_0/oneOfDiscriminator.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,29 @@ components:
298298
- $ref: '#/components/schemas/FruitType'
299299
discriminator:
300300
propertyName: fruitType
301+
AppleReqDiscReservedKeyword:
302+
type: object
303+
required:
304+
- seeds
305+
- type
306+
properties:
307+
seeds:
308+
type: integer
309+
type:
310+
type: string
311+
BananaReqDiscReservedKeyword:
312+
type: object
313+
required:
314+
- length
315+
- type
316+
properties:
317+
length:
318+
type: integer
319+
type:
320+
type: string
321+
FruitOneOfDiscReservedKeyword:
322+
oneOf:
323+
- $ref: '#/components/schemas/AppleReqDiscReservedKeyword'
324+
- $ref: '#/components/schemas/BananaReqDiscReservedKeyword'
325+
discriminator:
326+
propertyName: type

samples/client/others/rust/hyper/composed-oneof/src/models/obj_a.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
1313

1414
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
1515
pub struct ObjA {
16+
#[serde(default = "ObjA::_name_for_realtype")]
1617
#[serde(rename = "realtype", skip_serializing_if = "Option::is_none")]
1718
pub realtype: Option<String>,
1819
#[serde(rename = "message", skip_serializing_if = "Option::is_none")]
@@ -28,3 +29,9 @@ impl ObjA {
2829
}
2930
}
3031

32+
impl ObjA {
33+
fn _name_for_realtype() -> String {
34+
String::from("ObjA")
35+
}
36+
}
37+

samples/client/others/rust/hyper/composed-oneof/src/models/obj_b.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
1313

1414
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
1515
pub struct ObjB {
16+
#[serde(default = "ObjB::_name_for_realtype")]
1617
#[serde(rename = "realtype", skip_serializing_if = "Option::is_none")]
1718
pub realtype: Option<String>,
1819
#[serde(rename = "description", skip_serializing_if = "Option::is_none")]
@@ -31,3 +32,9 @@ impl ObjB {
3132
}
3233
}
3334

35+
impl ObjB {
36+
fn _name_for_realtype() -> String {
37+
String::from("ObjB")
38+
}
39+
}
40+

samples/client/others/rust/hyper/composed-oneof/src/models/obj_c.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
1313

1414
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
1515
pub struct ObjC {
16+
#[serde(default = "ObjC::_name_for_realtype")]
1617
#[serde(rename = "realtype", skip_serializing_if = "Option::is_none")]
1718
pub realtype: Option<String>,
1819
#[serde(rename = "state", skip_serializing_if = "Option::is_none")]
@@ -28,3 +29,9 @@ impl ObjC {
2829
}
2930
}
3031

32+
impl ObjC {
33+
fn _name_for_realtype() -> String {
34+
String::from("ObjC")
35+
}
36+
}
37+

samples/client/others/rust/hyper/composed-oneof/src/models/obj_d.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
1313

1414
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
1515
pub struct ObjD {
16+
#[serde(default = "ObjD::_name_for_realtype")]
1617
#[serde(rename = "realtype", skip_serializing_if = "Option::is_none")]
1718
pub realtype: Option<String>,
1819
#[serde(rename = "color", skip_serializing_if = "Option::is_none")]
@@ -28,3 +29,9 @@ impl ObjD {
2829
}
2930
}
3031

32+
impl ObjD {
33+
fn _name_for_realtype() -> String {
34+
String::from("ObjD")
35+
}
36+
}
37+

samples/client/others/rust/hyper/oneOf/src/models/foo.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub struct Foo {
2626
#[serde(rename = "@baseType", skip_serializing_if = "Option::is_none")]
2727
pub at_base_type: Option<String>,
2828
/// When sub-classing, this defines the sub-class Extensible name
29+
#[serde(default = "Foo::_name_for_atType")]
2930
#[serde(rename = "@type")]
3031
pub at_type: String,
3132
#[serde(rename = "fooPropA", skip_serializing_if = "Option::is_none")]
@@ -48,3 +49,9 @@ impl Foo {
4849
}
4950
}
5051

52+
impl Foo {
53+
fn _name_for_atType() -> String {
54+
String::from("Foo")
55+
}
56+
}
57+

samples/client/others/rust/hyper/oneOf/src/models/foo_ref.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub struct FooRef {
2626
#[serde(rename = "@baseType", skip_serializing_if = "Option::is_none")]
2727
pub at_base_type: Option<String>,
2828
/// When sub-classing, this defines the sub-class Extensible name
29+
#[serde(default = "FooRef::_name_for_atType")]
2930
#[serde(rename = "@type")]
3031
pub at_type: String,
3132
/// Name of the related entity.
@@ -53,3 +54,9 @@ impl FooRef {
5354
}
5455
}
5556

57+
impl FooRef {
58+
fn _name_for_atType() -> String {
59+
String::from("FooRef")
60+
}
61+
}
62+

0 commit comments

Comments
 (0)