Skip to content

Commit 67b9c95

Browse files
committed
better handling of enums
1 parent 5b3258a commit 67b9c95

11 files changed

Lines changed: 91 additions & 27 deletions

File tree

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,28 @@ public void execute(Template.Fragment fragment, Writer writer) throws IOExceptio
304304
writer.write(text.toUpperCase(Locale.ROOT));
305305
}
306306
});
307+
additionalProperties.put("quoteIfString", new Mustache.Lambda() {
308+
@Override
309+
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
310+
String text = fragment.execute();
311+
if (text != null) {
312+
try {
313+
// Try to parse as a number
314+
Double.parseDouble(text);
315+
// If parsing succeeds, it's a number, so write it as is
316+
writer.write(text);
317+
} catch (NumberFormatException e) {
318+
// Check if it's a boolean
319+
if (text.equals("true") || text.equals("false")) {
320+
writer.write(text);
321+
} else {
322+
// It's not a number or boolean, so it's a string - quote it
323+
writer.write("\"" + text + "\"");
324+
}
325+
}
326+
}
327+
}
328+
});
307329

308330
if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
309331
setModuleName((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
@@ -426,6 +448,12 @@ public CodegenModel fromModel(String name, Schema model) {
426448
for (CodegenProperty field : requiredEctoFields) {
427449
ecm.requiredEctoFields.add(new ExtendedCodegenProperty(field));
428450
}
451+
452+
List<CodegenProperty> ectoEnums = new ArrayList<>(ecm.ectoEnums);
453+
ecm.ectoEnums.clear();
454+
for (CodegenProperty field : ectoEnums) {
455+
ecm.ectoEnums.add(new ExtendedCodegenProperty(field));
456+
}
429457

430458
return ecm;
431459
}
@@ -910,6 +938,7 @@ class ExtendedCodegenModel extends CodegenModel {
910938
public boolean hasImports;
911939
public List<CodegenProperty> ectoFields = new ArrayList<>();
912940
public List<CodegenProperty> ectoEmbeds = new ArrayList<>();
941+
public List<CodegenProperty> ectoEnums = new ArrayList<>();
913942
public List<CodegenProperty> requiredEctoFields = new ArrayList<>();
914943

915944
public ExtendedCodegenModel(CodegenModel cm) {
@@ -971,6 +1000,9 @@ public ExtendedCodegenModel(CodegenModel cm) {
9711000
if (var.required) {
9721001
this.requiredEctoFields.add(var);
9731002
}
1003+
if (var.isEnum || var.isEnumRef) {
1004+
this.ectoEnums.add(var);
1005+
}
9741006
} else {
9751007
this.ectoEmbeds.add(var);
9761008
}
@@ -1083,6 +1115,28 @@ public String ectoType() {
10831115
}
10841116

10851117
private String ectoType(CodegenProperty property) {
1118+
if (property.isEnumRef) {
1119+
List<Object> values = (List<Object>) property.allowableValues.get("values");
1120+
if (!values.isEmpty()) {
1121+
Object firstValue = values.get(0);
1122+
if (firstValue instanceof String) {
1123+
return ":string";
1124+
} else if (firstValue instanceof Integer || firstValue instanceof Long) {
1125+
return ":integer";
1126+
} else if (firstValue instanceof Float || firstValue instanceof Double) {
1127+
return ":float";
1128+
} else if (firstValue instanceof Boolean) {
1129+
return ":boolean";
1130+
} else {
1131+
// Default to string for unknown types
1132+
return ":string";
1133+
}
1134+
} else {
1135+
// No values, default to string
1136+
return ":string";
1137+
}
1138+
}
1139+
10861140
String baseType = property.baseType;
10871141
switch (baseType) {
10881142
case "integer()":

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

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,7 @@
1414
@primary_key false
1515
embedded_schema do
1616
{{#ectoFields}}
17-
{{#isEnum}}
18-
field {{#atom}}{{&baseName}}{{/atom}}, Ecto.Enum, values: [{{#allowableValues}}{{#values}}{{#atom}}{{.}}{{/atom}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}]
19-
{{/isEnum}}
20-
{{^isEnum}}
21-
{{#isEnumRef}}
22-
field {{#atom}}{{&baseName}}{{/atom}}, Ecto.Enum, values: [{{#allowableValues}}{{#values}}{{#atom}}{{.}}{{/atom}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}]
23-
{{/isEnumRef}}
24-
{{^isEnumRef}}
2517
field {{#atom}}{{&baseName}}{{/atom}}, {{{ectoType}}}
26-
{{/isEnumRef}}
27-
{{/isEnum}}
2818
{{/ectoFields}}
2919
{{#ectoEmbeds}}
3020
{{^isArray}}embeds_one{{/isArray}}{{#isArray}}embeds_many{{/isArray}} {{#atom}}{{&baseName}}{{/atom}}, {{&moduleName}}.Model.{{^isArray}}{{{baseType}}}{{/isArray}}{{#isArray}}{{{items.baseType}}}{{/isArray}}
@@ -36,6 +26,9 @@
3626
struct
3727
|> Ecto.Changeset.cast(params, [{{#ectoFields}}{{#atom}}{{&baseName}}{{/atom}}{{^-last}}, {{/-last}}{{/ectoFields}}])
3828
|> Ecto.Changeset.validate_required([{{#requiredEctoFields}}{{#atom}}{{&baseName}}{{/atom}}{{^-last}}, {{/-last}}{{/requiredEctoFields}}])
29+
{{#ectoEnums}}
30+
|> Ecto.Changeset.validate_inclusion({{#atom}}{{&baseName}}{{/atom}}, [{{#allowableValues}}{{#values}}{{#quoteIfString}}{{.}}{{/quoteIfString}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}])
31+
{{/ectoEnums}}
3932
{{#ectoEmbeds}}
4033
|> Ecto.Changeset.cast_embed({{#atom}}{{&baseName}}{{/atom}}{{#required}}, required: true{{/required}})
4134
{{/ectoEmbeds}}

samples/client/petstore/elixir/lib/openapi_petstore/model/all_of_with_single_ref.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ defmodule OpenapiPetstore.Model.AllOfWithSingleRef do
1616
@primary_key false
1717
embedded_schema do
1818
field :username, :string
19-
field :SingleRefType, Ecto.Enum, values: [:admin, :user]
19+
field :SingleRefType, :string
2020
end
2121

2222
@spec changeset(t(), map()) :: Ecto.Changeset.t()
2323
def changeset(%__MODULE__{} = struct, params) do
2424
struct
2525
|> Ecto.Changeset.cast(params, [:username, :SingleRefType])
2626
|> Ecto.Changeset.validate_required([])
27+
|> Ecto.Changeset.validate_inclusion(:SingleRefType, ["admin", "user"])
2728
end
2829
end
2930

samples/client/petstore/elixir/lib/openapi_petstore/model/child_with_nullable.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ defmodule OpenapiPetstore.Model.ChildWithNullable do
1616
@derive {JSON.Encoder, only: [:type, :nullableProperty, :otherProperty]}
1717
@primary_key false
1818
embedded_schema do
19-
field :type, Ecto.Enum, values: [:ChildWithNullable]
19+
field :type, :string
2020
field :nullableProperty, :string
2121
field :otherProperty, :string
2222
end
@@ -26,6 +26,7 @@ defmodule OpenapiPetstore.Model.ChildWithNullable do
2626
struct
2727
|> Ecto.Changeset.cast(params, [:type, :nullableProperty, :otherProperty])
2828
|> Ecto.Changeset.validate_required([])
29+
|> Ecto.Changeset.validate_inclusion(:type, ["ChildWithNullable"])
2930
end
3031
end
3132

samples/client/petstore/elixir/lib/openapi_petstore/model/enum_arrays.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ defmodule OpenapiPetstore.Model.EnumArrays do
1515
@derive {JSON.Encoder, only: [:just_symbol, :array_enum]}
1616
@primary_key false
1717
embedded_schema do
18-
field :just_symbol, Ecto.Enum, values: [:"&gt;&#x3D;", :"$"]
19-
field :array_enum, Ecto.Enum, values: [:fish, :crab]
18+
field :just_symbol, :string
19+
field :array_enum, {:array, :string}
2020
end
2121

2222
@spec changeset(t(), map()) :: Ecto.Changeset.t()
2323
def changeset(%__MODULE__{} = struct, params) do
2424
struct
2525
|> Ecto.Changeset.cast(params, [:just_symbol, :array_enum])
2626
|> Ecto.Changeset.validate_required([])
27+
|> Ecto.Changeset.validate_inclusion(:just_symbol, ["&gt;&#x3D;", "$"])
28+
|> Ecto.Changeset.validate_inclusion(:array_enum, ["fish", "crab"])
2729
end
2830
end
2931

samples/client/petstore/elixir/lib/openapi_petstore/model/enum_test.ex

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,29 @@ defmodule OpenapiPetstore.Model.EnumTest do
2121
@derive {JSON.Encoder, only: [:enum_string, :enum_string_required, :enum_integer, :enum_number, :outerEnum, :outerEnumInteger, :outerEnumDefaultValue, :outerEnumIntegerDefaultValue]}
2222
@primary_key false
2323
embedded_schema do
24-
field :enum_string, Ecto.Enum, values: [:UPPER, :lower, :""]
25-
field :enum_string_required, Ecto.Enum, values: [:UPPER, :lower, :""]
26-
field :enum_integer, Ecto.Enum, values: [:"1", :"-1"]
27-
field :enum_number, Ecto.Enum, values: [:"1.1", :"-1.2"]
28-
field :outerEnum, Ecto.Enum, values: [:placed, :approved, :delivered]
29-
field :outerEnumInteger, Ecto.Enum, values: [:"0", :"1", :"2"]
30-
field :outerEnumDefaultValue, Ecto.Enum, values: [:placed, :approved, :delivered]
31-
field :outerEnumIntegerDefaultValue, Ecto.Enum, values: [:"0", :"1", :"2"]
24+
field :enum_string, :string
25+
field :enum_string_required, :string
26+
field :enum_integer, :integer
27+
field :enum_number, :float
28+
field :outerEnum, :string
29+
field :outerEnumInteger, :integer
30+
field :outerEnumDefaultValue, :string
31+
field :outerEnumIntegerDefaultValue, :integer
3232
end
3333

3434
@spec changeset(t(), map()) :: Ecto.Changeset.t()
3535
def changeset(%__MODULE__{} = struct, params) do
3636
struct
3737
|> Ecto.Changeset.cast(params, [:enum_string, :enum_string_required, :enum_integer, :enum_number, :outerEnum, :outerEnumInteger, :outerEnumDefaultValue, :outerEnumIntegerDefaultValue])
3838
|> Ecto.Changeset.validate_required([:enum_string_required])
39+
|> Ecto.Changeset.validate_inclusion(:enum_string, ["UPPER", "lower", ""])
40+
|> Ecto.Changeset.validate_inclusion(:enum_string_required, ["UPPER", "lower", ""])
41+
|> Ecto.Changeset.validate_inclusion(:enum_integer, [1, -1])
42+
|> Ecto.Changeset.validate_inclusion(:enum_number, [1.1, -1.2])
43+
|> Ecto.Changeset.validate_inclusion(:outerEnum, ["placed", "approved", "delivered"])
44+
|> Ecto.Changeset.validate_inclusion(:outerEnumInteger, [0, 1, 2])
45+
|> Ecto.Changeset.validate_inclusion(:outerEnumDefaultValue, ["placed", "approved", "delivered"])
46+
|> Ecto.Changeset.validate_inclusion(:outerEnumIntegerDefaultValue, [0, 1, 2])
3947
end
4048
end
4149

samples/client/petstore/elixir/lib/openapi_petstore/model/map_test.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ defmodule OpenapiPetstore.Model.MapTest do
1818
@primary_key false
1919
embedded_schema do
2020
field :map_map_of_string, :map
21-
field :map_of_enum_string, Ecto.Enum, values: [:UPPER, :lower]
21+
field :map_of_enum_string, :map
2222
field :direct_map, :map
2323
field :indirect_map, :map
2424
end
@@ -28,6 +28,7 @@ defmodule OpenapiPetstore.Model.MapTest do
2828
struct
2929
|> Ecto.Changeset.cast(params, [:map_map_of_string, :map_of_enum_string, :direct_map, :indirect_map])
3030
|> Ecto.Changeset.validate_required([])
31+
|> Ecto.Changeset.validate_inclusion(:map_of_enum_string, ["UPPER", "lower"])
3132
end
3233
end
3334

samples/client/petstore/elixir/lib/openapi_petstore/model/order.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ defmodule OpenapiPetstore.Model.Order do
2323
field :petId, :integer
2424
field :quantity, :integer
2525
field :shipDate, :utc_datetime
26-
field :status, Ecto.Enum, values: [:placed, :approved, :delivered]
26+
field :status, :string
2727
field :complete, :boolean
2828
end
2929

@@ -32,6 +32,7 @@ defmodule OpenapiPetstore.Model.Order do
3232
struct
3333
|> Ecto.Changeset.cast(params, [:id, :petId, :quantity, :shipDate, :status, :complete])
3434
|> Ecto.Changeset.validate_required([])
35+
|> Ecto.Changeset.validate_inclusion(:status, ["placed", "approved", "delivered"])
3536
end
3637
end
3738

samples/client/petstore/elixir/lib/openapi_petstore/model/outer_object_with_enum_property.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ defmodule OpenapiPetstore.Model.OuterObjectWithEnumProperty do
1414
@derive {JSON.Encoder, only: [:value]}
1515
@primary_key false
1616
embedded_schema do
17-
field :value, Ecto.Enum, values: [:"0", :"1", :"2"]
17+
field :value, :integer
1818
end
1919

2020
@spec changeset(t(), map()) :: Ecto.Changeset.t()
2121
def changeset(%__MODULE__{} = struct, params) do
2222
struct
2323
|> Ecto.Changeset.cast(params, [:value])
2424
|> Ecto.Changeset.validate_required([:value])
25+
|> Ecto.Changeset.validate_inclusion(:value, [0, 1, 2])
2526
end
2627
end
2728

samples/client/petstore/elixir/lib/openapi_petstore/model/parent_with_nullable.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ defmodule OpenapiPetstore.Model.ParentWithNullable do
1515
@derive {JSON.Encoder, only: [:type, :nullableProperty]}
1616
@primary_key false
1717
embedded_schema do
18-
field :type, Ecto.Enum, values: [:ChildWithNullable]
18+
field :type, :string
1919
field :nullableProperty, :string
2020
end
2121

@@ -24,6 +24,7 @@ defmodule OpenapiPetstore.Model.ParentWithNullable do
2424
struct
2525
|> Ecto.Changeset.cast(params, [:type, :nullableProperty])
2626
|> Ecto.Changeset.validate_required([])
27+
|> Ecto.Changeset.validate_inclusion(:type, ["ChildWithNullable"])
2728
end
2829
end
2930

0 commit comments

Comments
 (0)