Skip to content

Commit

Permalink
Improve the implementation of oneOf
Browse files Browse the repository at this point in the history
  • Loading branch information
Victoria-Casasampere-BeeTheData committed Dec 12, 2024
1 parent b7c7ed0 commit 1984c1c
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,73 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
return op;
}

@Override
public OperationsMap postProcessOperationsWithModels(final OperationsMap operationsMap, List<ModelMap> allModels) {
HashMap<String, List<String>> oneOfMapDiscriminator = new HashMap<>();

for (ModelMap mo : allModels) {
CodegenModel cm = mo.getModel();

if (cm.discriminator != null) {
for (String model : cm.oneOf) {
List<String> discriminators = oneOfMapDiscriminator.getOrDefault(model, new ArrayList<>());
discriminators.add(cm.discriminator.getPropertyName());
oneOfMapDiscriminator.put(model, discriminators);
}
}
}

for (ModelMap mo : allModels) {
CodegenModel cm = mo.getModel();

List<String> discriminatorsForModel = oneOfMapDiscriminator.get(cm.getSchemaName());

if (discriminatorsForModel != null) {
for (String discriminator : discriminatorsForModel) {
boolean hasDiscriminatorDefined = false;

for (CodegenProperty var : cm.vars) {
if (var.baseName.equals(discriminator)) {
var.isDiscriminator = true;
hasDiscriminatorDefined = true;
break;
}
}

if (!hasDiscriminatorDefined) {
CodegenProperty property = new CodegenProperty();

// Static attributes
// Only strings are supported by serde for tag field types, so it's the only one we'll deal with
property.openApiType = "string";
property.complexType = "string";
property.dataType = "String";
property.datatypeWithEnum = "String";
property.baseType = "string";
property.required = true;
property.isPrimitiveType = true;
property.isString = true;
property.isDiscriminator = true;

// Attributes based on the discriminator value
property.baseName = discriminator;
property.name = discriminator;
property.nameInCamelCase = camelize(discriminator);
property.nameInPascalCase = property.nameInCamelCase.substring(0, 1).toUpperCase(Locale.ROOT) + property.nameInCamelCase.substring(1);
property.nameInSnakeCase = underscore(discriminator).toUpperCase(Locale.ROOT);
property.getter = String.format(Locale.ROOT, "get%s", property.nameInPascalCase);
property.setter = String.format(Locale.ROOT, "set%s", property.nameInPascalCase);
property.defaultValueWithParam = String.format(Locale.ROOT, " = data.%s;", property.name);

// Attributes based on the model name
property.defaultValue = String.format(Locale.ROOT, "r#\"%s\"#.to_string()", cm.getSchemaName());
property.jsonSchema = String.format(Locale.ROOT, "{ \"default\":\"%s\"; \"type\":\"string\" }", cm.getSchemaName());

cm.vars.add(property);
}
}
}
}

final OperationMap operations = operationsMap.getOperations();
operations.put("classnamePascalCase", camelize(operations.getClassname()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,21 +573,70 @@ impl PartialEq for {{{classname}}} {
self.0.get() == other.0.get()
}
}
{{/anyOf.size}}
{{#oneOf.size}}
/// One of:
#[derive(Debug, Clone, PartialEq, serde::Deserialize)]
{{#discriminator}}
#[serde(tag = "{{{propertyBaseName}}}")]
{{/discriminator}}
{{^discriminator}}
#[serde(untagged)]
{{/discriminator}}
pub enum {{{classname}}} {
{{#oneOf}}
/// - {{{.}}}
{{{.}}}(Box<{{{.}}}>),
{{/oneOf}}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct {{{classname}}}(Box<serde_json::value::RawValue>);
}
impl validator::Validate for {{{classname}}}
{
fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {
std::result::Result::Ok(())
match self {
{{#oneOf}}
Self::{{{.}}}(x) => x.validate(),
{{/oneOf}}
}
}
}
{{#discriminator}}
impl serde::Serialize for {{{classname}}} {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
match self {
{{#oneOf}}
Self::{{{.}}}(x) => {{{.}}}::serialize(x, serializer),
{{/oneOf}}
}
}
}
{{#oneOf}}
impl {{{.}}} {
fn __name_for_{{{propertyBaseName}}}() -> String {
String::from("{{{.}}}")
}
fn __serialize_{{{propertyBaseName}}}<S>(_: &String, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
s.serialize_str(&Self::__name_for_{{{propertyBaseName}}}())
}
}
{{/oneOf}}
{{/discriminator}}
{{#oneOf}}
impl From<{{{.}}}> for {{{classname}}} {
fn from(value: {{{.}}}) -> Self {
Self::{{{.}}}(Box::new(value))
}
}
{{/oneOf}}
/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value
/// as specified in https://swagger.io/docs/specification/serialization/
Expand All @@ -600,11 +649,6 @@ impl std::str::FromStr for {{{classname}}} {
}
}
impl PartialEq for {{{classname}}} {
fn eq(&self, other: &Self) -> bool {
self.0.get() == other.0.get()
}
}
{{/oneOf.size}}
{{^anyOf.size}}
{{^oneOf.size}}
Expand All @@ -613,10 +657,14 @@ impl PartialEq for {{{classname}}} {
pub struct {{{classname}}} {
{{#vars}}
{{#description}}
/// {{{.}}}
/// {{{.}}}
{{/description}}
{{#isDiscriminator}}
#[serde(default = "{{{classname}}}::__name_for_{{{name}}}")]
#[serde(serialize_with = "{{{classname}}}::__serialize_{{{name}}}")]
{{/isDiscriminator}}
{{#isEnum}}
/// Note: inline enums are not fully supported by openapi-generator
/// Note: inline enums are not fully supported by openapi-generator
{{/isEnum}}
#[serde(rename = "{{{baseName}}}")]
{{#hasValidation}}
Expand Down

0 comments on commit 1984c1c

Please sign in to comment.