Skip to content

Commit 6e6bea0

Browse files
committed
fix: wrong typespec generation for all-of with single ref
1 parent a7159f6 commit 6e6bea0

17 files changed

Lines changed: 128 additions & 144 deletions

docs/generators/elixir.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,18 @@ These options may be applied as additional-properties (cli) or configOptions (pl
4545
## LANGUAGE PRIMITIVES
4646

4747
<ul class="column-ul">
48-
<li>AnyType</li>
49-
<li>Atom</li>
50-
<li>Boolean</li>
51-
<li>Decimal</li>
52-
<li>Float</li>
53-
<li>Integer</li>
54-
<li>List</li>
55-
<li>Map</li>
56-
<li>PID</li>
57-
<li>String</li>
58-
<li>Tuple</li>
48+
<li>Date.t</li>
49+
<li>DateTime.t</li>
50+
<li>String.t</li>
5951
<li>any()</li>
52+
<li>binary()</li>
53+
<li>boolean()</li>
54+
<li>float()</li>
55+
<li>integer()</li>
56+
<li>list()</li>
6057
<li>map()</li>
58+
<li>nil</li>
59+
<li>number()</li>
6160
</ul>
6261

6362
## RESERVED WORDS

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

Lines changed: 54 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -180,44 +180,53 @@ public ElixirClientCodegen() {
180180
*/
181181
languageSpecificPrimitives = new HashSet<>(
182182
Arrays.asList(
183-
"Integer",
184-
"Float",
185-
"Decimal",
186-
"Boolean",
187-
"String",
188-
"List",
189-
"Atom",
190-
"Map",
191-
"AnyType",
192-
"Tuple",
193-
"PID",
194-
// This is a workaround, since the DefaultCodeGen uses our elixir TypeSpec
195-
// datetype to evaluate the primitive
183+
"integer()",
184+
"float()",
185+
"number()",
186+
"boolean()",
187+
"String.t",
188+
"Date.t",
189+
"DateTime.t",
190+
"binary()",
191+
"list()",
196192
"map()",
197-
"any()"));
193+
"any()",
194+
"nil"));
198195

199196
// ref:
200197
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
201198
typeMapping = new HashMap<>();
202-
typeMapping.put("integer", "Integer");
203-
typeMapping.put("long", "Integer");
204-
typeMapping.put("number", "Float");
205-
typeMapping.put("float", "Float");
206-
typeMapping.put("double", "Float");
207-
typeMapping.put("string", "String");
208-
typeMapping.put("byte", "Integer");
209-
typeMapping.put("boolean", "Boolean");
210-
typeMapping.put("Date", "Date");
211-
typeMapping.put("DateTime", "DateTime");
212-
typeMapping.put("file", "String");
213-
typeMapping.put("map", "Map");
214-
typeMapping.put("array", "List");
215-
typeMapping.put("list", "List");
216-
typeMapping.put("object", "Map");
217-
typeMapping.put("binary", "String");
218-
typeMapping.put("ByteArray", "String");
219-
typeMapping.put("UUID", "String");
220-
typeMapping.put("URI", "String");
199+
// primitive types
200+
typeMapping.put("string", "String.t");
201+
typeMapping.put("number", "number()");
202+
typeMapping.put("integer", "integer()");
203+
typeMapping.put("boolean", "boolean()");
204+
typeMapping.put("array", "list()");
205+
typeMapping.put("object", "map()");
206+
typeMapping.put("null", "nil");
207+
// string formats
208+
typeMapping.put("byte", "String.t");
209+
typeMapping.put("binary", "binary()");
210+
typeMapping.put("password", "String.t");
211+
typeMapping.put("uuid", "String.t");
212+
typeMapping.put("email", "String.t");
213+
typeMapping.put("uri", "String.t");
214+
typeMapping.put("file", "String.t");
215+
// integer formats
216+
typeMapping.put("int32", "integer()");
217+
typeMapping.put("int64", "integer()");
218+
typeMapping.put("long", "integer()");
219+
// float formats
220+
typeMapping.put("float", "float()");
221+
typeMapping.put("double", "float()");
222+
typeMapping.put("decimal", "float()");
223+
// date-time formats
224+
typeMapping.put("date", "Date.t");
225+
typeMapping.put("date-time", "DateTime.t");
226+
typeMapping.put("DateTime", "DateTime.t");
227+
// other formats
228+
typeMapping.put("ByteArray", "binary()");
229+
typeMapping.put("UUID", "String.t");
221230

222231
cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE,
223232
"The main namespace to use for all classes. e.g. Yay.Pets"));
@@ -570,49 +579,19 @@ public String toOperationId(String operationId) {
570579
*/
571580
@Override
572581
public String getTypeDeclaration(Schema p) {
573-
if (ModelUtils.isAnyType(p)) {
574-
return "any()";
575-
} else if(ModelUtils.isFreeFormObject(p, null)) {
576-
return "%{optional(String.t) => any()}";
577-
} else if (ModelUtils.isArraySchema(p)) {
582+
if (ModelUtils.isArraySchema(p)) {
578583
Schema inner = ModelUtils.getSchemaItems(p);
579584
return "[" + getTypeDeclaration(inner) + "]";
580585
} else if (ModelUtils.isMapSchema(p)) {
581586
Schema inner = ModelUtils.getAdditionalProperties(p);
582587
return "%{optional(String.t) => " + getTypeDeclaration(inner) + "}";
583-
} else if (ModelUtils.isPasswordSchema(p)) {
584-
return "String.t";
585-
} else if (ModelUtils.isEmailSchema(p)) {
586-
return "String.t";
587-
} else if (ModelUtils.isByteArraySchema(p)) {
588-
return "binary()";
589-
} else if (ModelUtils.isUUIDSchema(p)) {
590-
return "String.t";
591-
} else if (ModelUtils.isDateSchema(p)) {
592-
return "Date.t";
593-
} else if (ModelUtils.isDateTimeSchema(p)) {
594-
return "DateTime.t";
595-
} else if (ModelUtils.isObjectSchema(p)) {
596-
return "map()";
597-
} else if (ModelUtils.isIntegerSchema(p)) {
598-
return "integer()";
599-
} else if (ModelUtils.isNumberSchema(p)) {
600-
return "float()";
601-
} else if (ModelUtils.isBinarySchema(p) || ModelUtils.isFileSchema(p)) {
602-
return "String.t";
603-
} else if (ModelUtils.isBooleanSchema(p)) {
604-
return "boolean()";
605588
} else if (!StringUtils.isEmpty(p.get$ref())) {
606-
switch (super.getTypeDeclaration(p)) {
607-
case "String":
608-
return "String.t";
609-
default:
610-
return this.moduleName + ".Model." + super.getTypeDeclaration(p) + ".t";
589+
String refType = super.getTypeDeclaration(p);
590+
if (languageSpecificPrimitives.contains(refType)) {
591+
return refType;
592+
} else {
593+
return this.moduleName + ".Model." + refType + ".t";
611594
}
612-
} else if (ModelUtils.isFileSchema(p)) {
613-
return "String.t";
614-
} else if (ModelUtils.isStringSchema(p)) {
615-
return "String.t";
616595
} else if (p.getType() == null) {
617596
return "any()";
618597
}
@@ -630,14 +609,11 @@ public String getTypeDeclaration(Schema p) {
630609
@Override
631610
public String getSchemaType(Schema p) {
632611
String openAPIType = super.getSchemaType(p);
633-
String type = null;
634612
if (typeMapping.containsKey(openAPIType)) {
635-
type = typeMapping.get(openAPIType);
636-
if (languageSpecificPrimitives.contains(type))
637-
return toModelName(type);
638-
} else
639-
type = openAPIType;
640-
return toModelName(type);
613+
return typeMapping.get(openAPIType);
614+
} else {
615+
return toModelName(openAPIType);
616+
}
641617
}
642618

643619
class ExtendedCodegenResponse extends CodegenResponse {
@@ -784,24 +760,6 @@ public ExtendedCodegenOperation(CodegenOperation o) {
784760
this.operationIdCamelCase = o.operationIdCamelCase;
785761
}
786762

787-
private void translateBaseType(StringBuilder returnEntry, String baseType) {
788-
switch (baseType) {
789-
case "AnyType":
790-
returnEntry.append("any()");
791-
break;
792-
case "Boolean":
793-
returnEntry.append("boolean()");
794-
break;
795-
case "Float":
796-
returnEntry.append("float()");
797-
break;
798-
default:
799-
returnEntry.append(baseType);
800-
returnEntry.append(".t");
801-
break;
802-
}
803-
}
804-
805763
public String typespec() {
806764
StringBuilder sb = new StringBuilder("@spec ");
807765
sb.append(underscore(operationId));
@@ -845,14 +803,11 @@ private String normalizeTypeName(String baseType, boolean isPrimitive) {
845803
if (baseType == null) {
846804
return "nil";
847805
}
848-
if (isPrimitive || "String.t".equals(baseType)) {
806+
if (isPrimitive || languageSpecificPrimitives.contains(baseType)) {
849807
return baseType;
850808
}
851809
if (!baseType.startsWith(moduleName + ".Model.")) {
852-
baseType = moduleName + ".Model." + baseType;
853-
}
854-
if (!baseType.endsWith(".t")) {
855-
baseType += ".t";
810+
baseType = moduleName + ".Model." + baseType + ".t";
856811
}
857812
return baseType;
858813
}

modules/openapi-generator/src/test/resources/3_0/elixir/petstore-with-fake-endpoints-models-for-testing.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,15 @@ paths:
13371337
responses:
13381338
200:
13391339
description: The instance started successfully
1340+
/fake/all-of-with-single-ref:
1341+
get:
1342+
responses:
1343+
200:
1344+
description: Successful operation
1345+
content:
1346+
application/json:
1347+
schema:
1348+
$ref: "#/components/schemas/AllOfWithSingleRef"
13401349
servers:
13411350
- url: "http://{server}.swagger.io:{port}/v2"
13421351
description: petstore server

samples/client/petstore/elixir/lib/openapi_petstore/api/default.ex

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,33 @@ defmodule OpenapiPetstore.Api.Default do
1818
1919
### Returns
2020
21+
- `{:ok, OpenapiPetstore.Model.AllOfWithSingleRef.t}` on success
22+
- `{:error, Tesla.Env.t}` on failure
23+
"""
24+
@spec fake_all_of_with_single_ref_get(Tesla.Env.client, keyword()) :: {:ok, OpenapiPetstore.Model.AllOfWithSingleRef.t} | {:error, Tesla.Env.t}
25+
def fake_all_of_with_single_ref_get(connection, _opts \\ []) do
26+
request =
27+
%{}
28+
|> method(:get)
29+
|> url("/fake/all-of-with-single-ref")
30+
|> Enum.into([])
31+
32+
connection
33+
|> Connection.request(request)
34+
|> evaluate_response([
35+
{200, OpenapiPetstore.Model.AllOfWithSingleRef}
36+
])
37+
end
38+
39+
@doc """
40+
41+
### Parameters
42+
43+
- `connection` (OpenapiPetstore.Connection): Connection to server
44+
- `opts` (keyword): Optional parameters
45+
46+
### Returns
47+
2148
- `{:ok, OpenapiPetstore.Model.FooGetDefaultResponse.t}` on success
2249
- `{:error, Tesla.Env.t}` on failure
2350
"""

samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,14 @@ defmodule OpenapiPetstore.Api.Fake do
180180
181181
- `connection` (OpenapiPetstore.Connection): Connection to server
182182
- `opts` (keyword): Optional parameters
183-
- `:body` (float()): Input number as post body
183+
- `:body` (number()): Input number as post body
184184
185185
### Returns
186186
187-
- `{:ok, float()}` on success
187+
- `{:ok, number()}` on success
188188
- `{:error, Tesla.Env.t}` on failure
189189
"""
190-
@spec fake_outer_number_serialize(Tesla.Env.client, keyword()) :: {:ok, float()} | {:error, Tesla.Env.t}
190+
@spec fake_outer_number_serialize(Tesla.Env.client, keyword()) :: {:ok, number()} | {:error, Tesla.Env.t}
191191
def fake_outer_number_serialize(connection, opts \\ []) do
192192
optional_params = %{
193193
:body => :body
@@ -464,7 +464,7 @@ defmodule OpenapiPetstore.Api.Fake do
464464
### Parameters
465465
466466
- `connection` (OpenapiPetstore.Connection): Connection to server
467-
- `number` (float()): None
467+
- `number` (number()): None
468468
- `double` (float()): None
469469
- `pattern_without_delimiter` (String.t): None
470470
- `byte` (binary()): None
@@ -485,7 +485,7 @@ defmodule OpenapiPetstore.Api.Fake do
485485
- `{:ok, nil}` on success
486486
- `{:error, Tesla.Env.t}` on failure
487487
"""
488-
@spec test_endpoint_parameters(Tesla.Env.client, float(), float(), String.t, binary(), keyword()) :: {:ok, nil} | {:error, Tesla.Env.t}
488+
@spec test_endpoint_parameters(Tesla.Env.client, number(), float(), String.t, binary(), keyword()) :: {:ok, nil} | {:error, Tesla.Env.t}
489489
def test_endpoint_parameters(connection, number, double, pattern_without_delimiter, byte, opts \\ []) do
490490
optional_params = %{
491491
:integer => :form,
@@ -623,7 +623,7 @@ defmodule OpenapiPetstore.Api.Fake do
623623
### Parameters
624624
625625
- `connection` (OpenapiPetstore.Connection): Connection to server
626-
- `body` (%{optional(String.t) => any()}): request body
626+
- `body` (map()): request body
627627
- `opts` (keyword): Optional parameters
628628
629629
### Returns

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ defmodule OpenapiPetstore.Model.AdditionalPropertiesClass do
1717
:map_of_map_property => %{optional(String.t) => %{optional(String.t) => String.t}} | nil
1818
}
1919

20+
alias OpenapiPetstore.Deserializer
21+
2022
def decode(value) do
2123
value
24+
|> Deserializer.deserialize(:map_of_map_property, :map, OpenapiPetstore.Model.Map)
2225
end
2326
end
2427

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ defmodule OpenapiPetstore.Model.ArrayOfArrayOfNumberOnly do
1212
]
1313

1414
@type t :: %__MODULE__{
15-
:ArrayArrayNumber => [[float()]] | nil
15+
:ArrayArrayNumber => [[number()]] | nil
1616
}
1717

1818
def decode(value) do

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ defmodule OpenapiPetstore.Model.ArrayOfNumberOnly do
1212
]
1313

1414
@type t :: %__MODULE__{
15-
:ArrayNumber => [float()] | nil
15+
:ArrayNumber => [number()] | nil
1616
}
1717

1818
def decode(value) do

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ defmodule OpenapiPetstore.Model.FakeBigDecimalMap200Response do
1313
]
1414

1515
@type t :: %__MODULE__{
16-
:someId => float() | nil,
17-
:someMap => %{optional(String.t) => float()} | nil
16+
:someId => number() | nil,
17+
:someMap => %{optional(String.t) => number()} | nil
1818
}
1919

2020
def decode(value) do

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ defmodule OpenapiPetstore.Model.FormatTest do
3030
:integer => integer() | nil,
3131
:int32 => integer() | nil,
3232
:int64 => integer() | nil,
33-
:number => float(),
33+
:number => number(),
3434
:float => float() | nil,
3535
:double => float() | nil,
36-
:decimal => String.t | nil,
36+
:decimal => float() | nil,
3737
:string => String.t | nil,
3838
:byte => binary(),
3939
:binary => String.t | nil,
@@ -45,12 +45,8 @@ defmodule OpenapiPetstore.Model.FormatTest do
4545
:pattern_with_digits_and_delimiter => String.t | nil
4646
}
4747

48-
alias OpenapiPetstore.Deserializer
49-
5048
def decode(value) do
5149
value
52-
|> Deserializer.deserialize(:date, :date, nil)
53-
|> Deserializer.deserialize(:dateTime, :datetime, nil)
5450
end
5551
end
5652

0 commit comments

Comments
 (0)