From 4f240337f945969ad0cf69f9e05faadcc5072d18 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 26 Feb 2025 11:04:44 +0100 Subject: [PATCH 1/2] Upgrade openapi-codegen --- regen_openapi.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/regen_openapi.sh b/regen_openapi.sh index d61c31631..f9b91c331 100755 --- a/regen_openapi.sh +++ b/regen_openapi.sh @@ -2,7 +2,7 @@ set -eo pipefail -OPENAPI_GIT_REV='98dbc5b090a5c8d72fe50962ee04b46fb9d7db20' +OPENAPI_GIT_REV='272125558d6ac4718bdc87b1652e5d4122b69f19' if [ -n "$1" ]; then curl "$1" | python -m json.tool > lib-openapi.json @@ -34,11 +34,6 @@ fi # Remove APIs we may not (yet) want to expose rm rust/src/api/{environment,health}.rs - - # Remove .codegen.json files, its purpose is fulfilled already: - # - The expected git rev of the tool is encoded at the top of this file. - # - The lib-openapi.json used as input is also committed to this repo. - rm rust/src/{api,models}/.codegen.json ) cd $(dirname "$0") From 4c7ac25eae3787a1d3f1f5532a704e6d33f18ef2 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 26 Feb 2025 11:03:56 +0100 Subject: [PATCH 2/2] rust: Update codegen templates to support struct enums --- rust/templates/component_type.rs.jinja | 2 + rust/templates/types/struct.rs.jinja | 48 +-------------------- rust/templates/types/struct_enum.rs.jinja | 38 ++++++++++++++++ rust/templates/types/struct_fields.rs.jinja | 47 ++++++++++++++++++++ 4 files changed, 88 insertions(+), 47 deletions(-) create mode 100644 rust/templates/types/struct_enum.rs.jinja create mode 100644 rust/templates/types/struct_fields.rs.jinja diff --git a/rust/templates/component_type.rs.jinja b/rust/templates/component_type.rs.jinja index cdb2aaf71..0d5a8a8d5 100644 --- a/rust/templates/component_type.rs.jinja +++ b/rust/templates/component_type.rs.jinja @@ -9,6 +9,8 @@ {% include "types/string_enum.rs.jinja" -%} {% elif type.kind == "integer_enum" -%} {% include "types/integer_enum.rs.jinja" -%} +{% elif type.kind == "struct_enum" -%} + {% include "types/struct_enum.rs.jinja" -%} {% else -%} compile_error!("{{ type.kind }} types are not supported by this codegen template"); {% endif %} diff --git a/rust/templates/types/struct.rs.jinja b/rust/templates/types/struct.rs.jinja index 6318c353d..ae57b94f4 100644 --- a/rust/templates/types/struct.rs.jinja +++ b/rust/templates/types/struct.rs.jinja @@ -12,53 +12,7 @@ use super::{ {{ doc_comment }} #[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] pub struct {{ type.name | to_upper_camel_case }} { - {% for field in type.fields %} - {% if field.description is defined -%} - {{ field.description | to_doc_comment(style="rust") }} - {# we currently use String for date-time params, for backwards compat -#} - {# document the format so it's not _that_ awkward -#} - {% if field.type.is_datetime() -%} - /// - /// RFC3339 date string. - {% endif -%} - {% endif -%} - - {% if field.deprecated -%} - #[deprecated] - {% endif -%} - - {% if field.name != field.name | to_snake_case -%} - #[serde(rename = "{{ field.name }}")] - {% endif -%} - - {# - we only have defaults on optional fields now, and the old codegen - was not doing anything with them, so leave them alone here as well, - at least for now - -#} - {# {% if field.default is defined and field.default is not none -%} - #[serde(default = "{{ field.name | to_snake_case }}_default")] - {% endif -%} -#} - {% if field.type.is_datetime() -%} - {% set field_ty = "String" -%} - {% else -%} - {% set field_ty = field.type.to_rust() -%} - {% endif -%} - - {% if not field.required or field.nullable -%} - {# only for patch requests, if the field is both non-required - and nullable, use JsOption -#} - {% if type.name is endingwith "Patch" and field.nullable -%} - {% set field_ty %}JsOption<{{ field_ty }}>{% endset -%} - #[serde(default, skip_serializing_if = "JsOption::is_undefined")] - {% else -%} - {% set field_ty %}Option<{{ field_ty }}>{% endset -%} - #[serde(skip_serializing_if = "Option::is_none")] - {% endif -%} - {% endif -%} - - pub {{ field.name | to_snake_case }}: {{ field_ty }}, - {% endfor %} + {% include "types/struct_fields.rs.jinja" -%} } impl {{ type.name | to_upper_camel_case }} { diff --git a/rust/templates/types/struct_enum.rs.jinja b/rust/templates/types/struct_enum.rs.jinja new file mode 100644 index 000000000..b4a56c981 --- /dev/null +++ b/rust/templates/types/struct_enum.rs.jinja @@ -0,0 +1,38 @@ +use serde::{Deserialize, Serialize}; + +use super::{ + {% for c in referenced_components -%} + {{ c | to_snake_case }}::{{ c | to_upper_camel_case }}, + {% endfor -%} +}; + +{% set type_name = type.name | to_upper_camel_case -%} +{% if type.fields | length > 0 -%} + {% set enum_type_name %}{{ type_name }}{{ type.content_field | to_upper_camel_case }}{% endset -%} + + {{ doc_comment }} + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct {{ type_name }} { + {% include "types/struct_fields.rs.jinja" %} + + #[serde(flatten)] + {% set enum_field_name = type.content_field | to_snake_case %} + {% if type.content_field != enum_field_name -%} + #[serde(rename = "{{ type.content_field }}")] + {% endif -%} + pub {{ enum_field_name }}: {{ enum_type_name }}, + } +{% else -%} + {% set enum_type_name = type_name %} +{% endif %} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(tag = "{{ type.discriminator_field }}", content = "{{ type.content_field }}")] +pub enum {{ enum_type_name }} { + {% for variant in type.variants -%} + {{ variant.name | to_upper_camel_case -}} + {% if variant.schema_ref is defined -%} + ({{ variant.schema_ref | to_upper_camel_case }}) + {%- endif %}, + {% endfor -%} +} diff --git a/rust/templates/types/struct_fields.rs.jinja b/rust/templates/types/struct_fields.rs.jinja new file mode 100644 index 000000000..990c3ed05 --- /dev/null +++ b/rust/templates/types/struct_fields.rs.jinja @@ -0,0 +1,47 @@ +{% for field in type.fields %} + {% if field.description is defined -%} + {{ field.description | to_doc_comment(style="rust") }} + {# we currently use String for date-time params, for backwards compat -#} + {# document the format so it's not _that_ awkward -#} + {% if field.type.is_datetime() -%} + /// + /// RFC3339 date string. + {% endif -%} + {% endif -%} + + {% if field.deprecated -%} + #[deprecated] + {% endif -%} + + {% if field.name != field.name | to_snake_case -%} + #[serde(rename = "{{ field.name }}")] + {% endif -%} + + {# + we only have defaults on optional fields now, and the old codegen + was not doing anything with them, so leave them alone here as well, + at least for now + -#} + {# {% if field.default is defined and field.default is not none -%} + #[serde(default = "{{ field.name | to_snake_case }}_default")] + {% endif -%} -#} + {% if field.type.is_datetime() -%} + {% set field_ty = "String" -%} + {% else -%} + {% set field_ty = field.type.to_rust() -%} + {% endif -%} + + {% if not field.required or field.nullable -%} + {# only for patch requests, if the field is both non-required + and nullable, use JsOption -#} + {% if type.name is endingwith "Patch" and field.nullable -%} + {% set field_ty %}JsOption<{{ field_ty }}>{% endset -%} + #[serde(default, skip_serializing_if = "JsOption::is_undefined")] + {% else -%} + {% set field_ty %}Option<{{ field_ty }}>{% endset -%} + #[serde(skip_serializing_if = "Option::is_none")] + {% endif -%} + {% endif -%} + + pub {{ field.name | to_snake_case }}: {{ field_ty }}, +{% endfor %}