Skip to content

Commit 2ef197c

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

16 files changed

Lines changed: 169 additions & 144 deletions

File tree

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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,29 @@ paths:
13371337
responses:
13381338
200:
13391339
description: The instance started successfully
1340+
/fake/all-of-with-local-single-ref:
1341+
get:
1342+
tags:
1343+
- fake
1344+
responses:
1345+
200:
1346+
description: Successful operation
1347+
content:
1348+
application/json:
1349+
schema:
1350+
allOf:
1351+
- $ref: "#/components/schemas/Foo"
1352+
/fake/all-of-with-remote-single-ref:
1353+
get:
1354+
tags:
1355+
- fake
1356+
responses:
1357+
200:
1358+
description: Successful operation
1359+
content:
1360+
application/json:
1361+
schema:
1362+
$ref: "#/components/schemas/AllOfWithSingleRef"
13401363
servers:
13411364
- url: "http://{server}.swagger.io:{port}/v2"
13421365
description: petstore server

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

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,60 @@ defmodule OpenapiPetstore.Api.Fake do
99
alias OpenapiPetstore.Connection
1010
import OpenapiPetstore.RequestBuilder
1111

12+
@doc """
13+
14+
### Parameters
15+
16+
- `connection` (OpenapiPetstore.Connection): Connection to server
17+
- `opts` (keyword): Optional parameters
18+
19+
### Returns
20+
21+
- `{:ok, OpenapiPetstore.Model.Foo.t}` on success
22+
- `{:error, Tesla.Env.t}` on failure
23+
"""
24+
@spec fake_all_of_with_local_single_ref_get(Tesla.Env.client, keyword()) :: {:ok, any()} | {:error, Tesla.Env.t}
25+
def fake_all_of_with_local_single_ref_get(connection, _opts \\ []) do
26+
request =
27+
%{}
28+
|> method(:get)
29+
|> url("/fake/all-of-with-local-single-ref")
30+
|> Enum.into([])
31+
32+
connection
33+
|> Connection.request(request)
34+
|> evaluate_response([
35+
{200, OpenapiPetstore.Model.Foo}
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+
48+
- `{:ok, OpenapiPetstore.Model.AllOfWithSingleRef.t}` on success
49+
- `{:error, Tesla.Env.t}` on failure
50+
"""
51+
@spec fake_all_of_with_remote_single_ref_get(Tesla.Env.client, keyword()) :: {:ok, OpenapiPetstore.Model.AllOfWithSingleRef.t} | {:error, Tesla.Env.t}
52+
def fake_all_of_with_remote_single_ref_get(connection, _opts \\ []) do
53+
request =
54+
%{}
55+
|> method(:get)
56+
|> url("/fake/all-of-with-remote-single-ref")
57+
|> Enum.into([])
58+
59+
connection
60+
|> Connection.request(request)
61+
|> evaluate_response([
62+
{200, OpenapiPetstore.Model.AllOfWithSingleRef}
63+
])
64+
end
65+
1266
@doc """
1367
for Java apache and Java native, test toUrlQueryString for maps with BegDecimal keys
1468
@@ -180,14 +234,14 @@ defmodule OpenapiPetstore.Api.Fake do
180234
181235
- `connection` (OpenapiPetstore.Connection): Connection to server
182236
- `opts` (keyword): Optional parameters
183-
- `:body` (float()): Input number as post body
237+
- `:body` (number()): Input number as post body
184238
185239
### Returns
186240
187-
- `{:ok, float()}` on success
241+
- `{:ok, number()}` on success
188242
- `{:error, Tesla.Env.t}` on failure
189243
"""
190-
@spec fake_outer_number_serialize(Tesla.Env.client, keyword()) :: {:ok, float()} | {:error, Tesla.Env.t}
244+
@spec fake_outer_number_serialize(Tesla.Env.client, keyword()) :: {:ok, number()} | {:error, Tesla.Env.t}
191245
def fake_outer_number_serialize(connection, opts \\ []) do
192246
optional_params = %{
193247
:body => :body
@@ -464,7 +518,7 @@ defmodule OpenapiPetstore.Api.Fake do
464518
### Parameters
465519
466520
- `connection` (OpenapiPetstore.Connection): Connection to server
467-
- `number` (float()): None
521+
- `number` (number()): None
468522
- `double` (float()): None
469523
- `pattern_without_delimiter` (String.t): None
470524
- `byte` (binary()): None
@@ -485,7 +539,7 @@ defmodule OpenapiPetstore.Api.Fake do
485539
- `{:ok, nil}` on success
486540
- `{:error, Tesla.Env.t}` on failure
487541
"""
488-
@spec test_endpoint_parameters(Tesla.Env.client, float(), float(), String.t, binary(), keyword()) :: {:ok, nil} | {:error, Tesla.Env.t}
542+
@spec test_endpoint_parameters(Tesla.Env.client, number(), float(), String.t, binary(), keyword()) :: {:ok, nil} | {:error, Tesla.Env.t}
489543
def test_endpoint_parameters(connection, number, double, pattern_without_delimiter, byte, opts \\ []) do
490544
optional_params = %{
491545
:integer => :form,
@@ -623,7 +677,7 @@ defmodule OpenapiPetstore.Api.Fake do
623677
### Parameters
624678
625679
- `connection` (OpenapiPetstore.Connection): Connection to server
626-
- `body` (%{optional(String.t) => any()}): request body
680+
- `body` (map()): request body
627681
- `opts` (keyword): Optional parameters
628682
629683
### 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

0 commit comments

Comments
 (0)