diff --git a/docs/generators/elixir.md b/docs/generators/elixir.md index bc1a7a9beb8..8f7ec5a796c 100644 --- a/docs/generators/elixir.md +++ b/docs/generators/elixir.md @@ -45,19 +45,18 @@ These options may be applied as additional-properties (cli) or configOptions (pl ## LANGUAGE PRIMITIVES ## RESERVED WORDS diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java index 7928a50f3ea..edea3a420a6 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java @@ -180,44 +180,55 @@ public class ElixirClientCodegen extends DefaultCodegen { */ languageSpecificPrimitives = new HashSet<>( Arrays.asList( - "Integer", - "Float", - "Decimal", - "Boolean", - "String", - "List", - "Atom", - "Map", - "AnyType", - "Tuple", - "PID", - // This is a workaround, since the DefaultCodeGen uses our elixir TypeSpec - // datetype to evaluate the primitive + "integer()", + "float()", + "number()", + "boolean()", + "String.t", + "Date.t", + "DateTime.t", + "binary()", + "list()", "map()", - "any()")); + "any()", + "nil")); // ref: // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types typeMapping = new HashMap<>(); - typeMapping.put("integer", "Integer"); - typeMapping.put("long", "Integer"); - typeMapping.put("number", "Float"); - typeMapping.put("float", "Float"); - typeMapping.put("double", "Float"); - typeMapping.put("string", "String"); - typeMapping.put("byte", "Integer"); - typeMapping.put("boolean", "Boolean"); - typeMapping.put("Date", "Date"); - typeMapping.put("DateTime", "DateTime"); - typeMapping.put("file", "String"); - typeMapping.put("map", "Map"); - typeMapping.put("array", "List"); - typeMapping.put("list", "List"); - typeMapping.put("object", "Map"); - typeMapping.put("binary", "String"); - typeMapping.put("ByteArray", "String"); - typeMapping.put("UUID", "String"); - typeMapping.put("URI", "String"); + // primitive types + typeMapping.put("string", "String.t"); + typeMapping.put("number", "number()"); + typeMapping.put("integer", "integer()"); + typeMapping.put("boolean", "boolean()"); + typeMapping.put("array", "list()"); + typeMapping.put("object", "map()"); + typeMapping.put("map", "map()"); + typeMapping.put("null", "nil"); + // string formats + typeMapping.put("byte", "String.t"); + typeMapping.put("binary", "binary()"); + typeMapping.put("password", "String.t"); + typeMapping.put("uuid", "String.t"); + typeMapping.put("email", "String.t"); + typeMapping.put("uri", "String.t"); + typeMapping.put("file", "String.t"); + // integer formats + typeMapping.put("int32", "integer()"); + typeMapping.put("int64", "integer()"); + typeMapping.put("long", "integer()"); + // float formats + typeMapping.put("float", "float()"); + typeMapping.put("double", "float()"); + typeMapping.put("decimal", "float()"); + // date-time formats + typeMapping.put("date", "Date.t"); + typeMapping.put("date-time", "DateTime.t"); + // other + typeMapping.put("ByteArray", "binary()"); + typeMapping.put("DateTime", "DateTime.t"); + typeMapping.put("UUID", "String.t"); + cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, "The main namespace to use for all classes. e.g. Yay.Pets")); @@ -570,49 +581,19 @@ public class ElixirClientCodegen extends DefaultCodegen { */ @Override public String getTypeDeclaration(Schema p) { - if (ModelUtils.isAnyType(p)) { - return "any()"; - } else if(ModelUtils.isFreeFormObject(p, null)) { - return "%{optional(String.t) => any()}"; - } else if (ModelUtils.isArraySchema(p)) { + if (ModelUtils.isArraySchema(p)) { Schema inner = ModelUtils.getSchemaItems(p); return "[" + getTypeDeclaration(inner) + "]"; } else if (ModelUtils.isMapSchema(p)) { Schema inner = ModelUtils.getAdditionalProperties(p); return "%{optional(String.t) => " + getTypeDeclaration(inner) + "}"; - } else if (ModelUtils.isPasswordSchema(p)) { - return "String.t"; - } else if (ModelUtils.isEmailSchema(p)) { - return "String.t"; - } else if (ModelUtils.isByteArraySchema(p)) { - return "binary()"; - } else if (ModelUtils.isUUIDSchema(p)) { - return "String.t"; - } else if (ModelUtils.isDateSchema(p)) { - return "Date.t"; - } else if (ModelUtils.isDateTimeSchema(p)) { - return "DateTime.t"; - } else if (ModelUtils.isObjectSchema(p)) { - return "map()"; - } else if (ModelUtils.isIntegerSchema(p)) { - return "integer()"; - } else if (ModelUtils.isNumberSchema(p)) { - return "float()"; - } else if (ModelUtils.isBinarySchema(p) || ModelUtils.isFileSchema(p)) { - return "String.t"; - } else if (ModelUtils.isBooleanSchema(p)) { - return "boolean()"; } else if (!StringUtils.isEmpty(p.get$ref())) { - switch (super.getTypeDeclaration(p)) { - case "String": - return "String.t"; - default: - return this.moduleName + ".Model." + super.getTypeDeclaration(p) + ".t"; + String refType = super.getTypeDeclaration(p); + if (languageSpecificPrimitives.contains(refType)) { + return refType; + } else { + return this.moduleName + ".Model." + refType + ".t"; } - } else if (ModelUtils.isFileSchema(p)) { - return "String.t"; - } else if (ModelUtils.isStringSchema(p)) { - return "String.t"; } else if (p.getType() == null) { return "any()"; } @@ -630,14 +611,11 @@ public class ElixirClientCodegen extends DefaultCodegen { @Override public String getSchemaType(Schema p) { String openAPIType = super.getSchemaType(p); - String type = null; if (typeMapping.containsKey(openAPIType)) { - type = typeMapping.get(openAPIType); - if (languageSpecificPrimitives.contains(type)) - return toModelName(type); - } else - type = openAPIType; - return toModelName(type); + return typeMapping.get(openAPIType); + } else { + return toModelName(openAPIType); + } } class ExtendedCodegenResponse extends CodegenResponse { @@ -784,24 +762,6 @@ public class ElixirClientCodegen extends DefaultCodegen { this.operationIdCamelCase = o.operationIdCamelCase; } - private void translateBaseType(StringBuilder returnEntry, String baseType) { - switch (baseType) { - case "AnyType": - returnEntry.append("any()"); - break; - case "Boolean": - returnEntry.append("boolean()"); - break; - case "Float": - returnEntry.append("float()"); - break; - default: - returnEntry.append(baseType); - returnEntry.append(".t"); - break; - } - } - public String typespec() { StringBuilder sb = new StringBuilder("@spec "); sb.append(underscore(operationId)); @@ -819,16 +779,10 @@ public class ElixirClientCodegen extends DefaultCodegen { for (CodegenResponse response : this.responses) { ExtendedCodegenResponse exResponse = (ExtendedCodegenResponse) response; StringBuilder returnEntry = new StringBuilder(); - if (exResponse.baseType == null) { - returnEntry.append("nil"); - } else if (exResponse.containerType == null) { // not container (array, map, set) - returnEntry.append(normalizeTypeName(exResponse.dataType, exResponse.primitiveType)); + if (exResponse.schema != null) { + returnEntry.append(getTypeDeclaration((Schema) exResponse.schema)); } else { - if (exResponse.containerType.equals("array") || exResponse.containerType.equals("set")) { - returnEntry.append(exResponse.dataType); - } else if (exResponse.containerType.equals("map")) { - returnEntry.append("map()"); - } + returnEntry.append(normalizeTypeName(exResponse.dataType, exResponse.primitiveType)); } uniqueResponseTypes.add(returnEntry.toString()); } @@ -845,14 +799,11 @@ public class ElixirClientCodegen extends DefaultCodegen { if (baseType == null) { return "nil"; } - if (isPrimitive || "String.t".equals(baseType)) { + if (isPrimitive || languageSpecificPrimitives.contains(baseType)) { return baseType; } if (!baseType.startsWith(moduleName + ".Model.")) { - baseType = moduleName + ".Model." + baseType; - } - if (!baseType.endsWith(".t")) { - baseType += ".t"; + baseType = moduleName + ".Model." + baseType + ".t"; } return baseType; } diff --git a/modules/openapi-generator/src/test/resources/3_0/elixir/petstore-with-fake-endpoints-models-for-testing.yaml b/modules/openapi-generator/src/test/resources/3_0/elixir/petstore-with-fake-endpoints-models-for-testing.yaml index 4c1654d2a2b..b2dd68dfe06 100644 --- a/modules/openapi-generator/src/test/resources/3_0/elixir/petstore-with-fake-endpoints-models-for-testing.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/elixir/petstore-with-fake-endpoints-models-for-testing.yaml @@ -1337,6 +1337,29 @@ paths: responses: 200: description: The instance started successfully + /fake/all-of-with-local-single-ref: + get: + tags: + - fake + responses: + 200: + description: Successful operation + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/Foo" + /fake/all-of-with-remote-single-ref: + get: + tags: + - fake + responses: + 200: + description: Successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/AllOfWithSingleRef" servers: - url: "http://{server}.swagger.io:{port}/v2" description: petstore server diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex b/samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex index 7067b04b079..c5359c24df7 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex @@ -9,6 +9,60 @@ defmodule OpenapiPetstore.Api.Fake do alias OpenapiPetstore.Connection import OpenapiPetstore.RequestBuilder + @doc """ + + ### Parameters + + - `connection` (OpenapiPetstore.Connection): Connection to server + - `opts` (keyword): Optional parameters + + ### Returns + + - `{:ok, OpenapiPetstore.Model.Foo.t}` on success + - `{:error, Tesla.Env.t}` on failure + """ + @spec fake_all_of_with_local_single_ref_get(Tesla.Env.client, keyword()) :: {:ok, any()} | {:error, Tesla.Env.t} + def fake_all_of_with_local_single_ref_get(connection, _opts \\ []) do + request = + %{} + |> method(:get) + |> url("/fake/all-of-with-local-single-ref") + |> Enum.into([]) + + connection + |> Connection.request(request) + |> evaluate_response([ + {200, OpenapiPetstore.Model.Foo} + ]) + end + + @doc """ + + ### Parameters + + - `connection` (OpenapiPetstore.Connection): Connection to server + - `opts` (keyword): Optional parameters + + ### Returns + + - `{:ok, OpenapiPetstore.Model.AllOfWithSingleRef.t}` on success + - `{:error, Tesla.Env.t}` on failure + """ + @spec fake_all_of_with_remote_single_ref_get(Tesla.Env.client, keyword()) :: {:ok, OpenapiPetstore.Model.AllOfWithSingleRef.t} | {:error, Tesla.Env.t} + def fake_all_of_with_remote_single_ref_get(connection, _opts \\ []) do + request = + %{} + |> method(:get) + |> url("/fake/all-of-with-remote-single-ref") + |> Enum.into([]) + + connection + |> Connection.request(request) + |> evaluate_response([ + {200, OpenapiPetstore.Model.AllOfWithSingleRef} + ]) + end + @doc """ for Java apache and Java native, test toUrlQueryString for maps with BegDecimal keys @@ -180,14 +234,14 @@ defmodule OpenapiPetstore.Api.Fake do - `connection` (OpenapiPetstore.Connection): Connection to server - `opts` (keyword): Optional parameters - - `:body` (float()): Input number as post body + - `:body` (number()): Input number as post body ### Returns - - `{:ok, float()}` on success + - `{:ok, number()}` on success - `{:error, Tesla.Env.t}` on failure """ - @spec fake_outer_number_serialize(Tesla.Env.client, keyword()) :: {:ok, float()} | {:error, Tesla.Env.t} + @spec fake_outer_number_serialize(Tesla.Env.client, keyword()) :: {:ok, number()} | {:error, Tesla.Env.t} def fake_outer_number_serialize(connection, opts \\ []) do optional_params = %{ :body => :body @@ -464,7 +518,7 @@ defmodule OpenapiPetstore.Api.Fake do ### Parameters - `connection` (OpenapiPetstore.Connection): Connection to server - - `number` (float()): None + - `number` (number()): None - `double` (float()): None - `pattern_without_delimiter` (String.t): None - `byte` (binary()): None @@ -485,7 +539,7 @@ defmodule OpenapiPetstore.Api.Fake do - `{:ok, nil}` on success - `{:error, Tesla.Env.t}` on failure """ - @spec test_endpoint_parameters(Tesla.Env.client, float(), float(), String.t, binary(), keyword()) :: {:ok, nil} | {:error, Tesla.Env.t} + @spec test_endpoint_parameters(Tesla.Env.client, number(), float(), String.t, binary(), keyword()) :: {:ok, nil} | {:error, Tesla.Env.t} def test_endpoint_parameters(connection, number, double, pattern_without_delimiter, byte, opts \\ []) do optional_params = %{ :integer => :form, @@ -623,7 +677,7 @@ defmodule OpenapiPetstore.Api.Fake do ### Parameters - `connection` (OpenapiPetstore.Connection): Connection to server - - `body` (%{optional(String.t) => any()}): request body + - `body` (map()): request body - `opts` (keyword): Optional parameters ### Returns diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/api/store.ex b/samples/client/petstore/elixir/lib/openapi_petstore/api/store.ex index 5dcce57a5c3..169fba9df01 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/api/store.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/api/store.ex @@ -54,7 +54,7 @@ defmodule OpenapiPetstore.Api.Store do - `{:ok, %{}}` on success - `{:error, Tesla.Env.t}` on failure """ - @spec get_inventory(Tesla.Env.client, keyword()) :: {:ok, map()} | {:error, Tesla.Env.t} + @spec get_inventory(Tesla.Env.client, keyword()) :: {:ok, %{optional(String.t) => integer()}} | {:error, Tesla.Env.t} def get_inventory(connection, _opts \\ []) do request = %{} diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/array_of_array_of_number_only.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/array_of_array_of_number_only.ex index 2c677885ca2..3e1d0c6559b 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/array_of_array_of_number_only.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/array_of_array_of_number_only.ex @@ -12,7 +12,7 @@ defmodule OpenapiPetstore.Model.ArrayOfArrayOfNumberOnly do ] @type t :: %__MODULE__{ - :ArrayArrayNumber => [[float()]] | nil + :ArrayArrayNumber => [[number()]] | nil } def decode(value) do diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/array_of_number_only.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/array_of_number_only.ex index 095cf30a596..c24fce09dae 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/array_of_number_only.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/array_of_number_only.ex @@ -12,7 +12,7 @@ defmodule OpenapiPetstore.Model.ArrayOfNumberOnly do ] @type t :: %__MODULE__{ - :ArrayNumber => [float()] | nil + :ArrayNumber => [number()] | nil } def decode(value) do diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/fake_big_decimal_map_200_response.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/fake_big_decimal_map_200_response.ex index f9e5ef7517c..99b3de06d47 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/fake_big_decimal_map_200_response.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/fake_big_decimal_map_200_response.ex @@ -13,8 +13,8 @@ defmodule OpenapiPetstore.Model.FakeBigDecimalMap200Response do ] @type t :: %__MODULE__{ - :someId => float() | nil, - :someMap => %{optional(String.t) => float()} | nil + :someId => number() | nil, + :someMap => %{optional(String.t) => number()} | nil } def decode(value) do diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/format_test.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/format_test.ex index ef67673e377..fbc8130d89f 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/format_test.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/format_test.ex @@ -30,10 +30,10 @@ defmodule OpenapiPetstore.Model.FormatTest do :integer => integer() | nil, :int32 => integer() | nil, :int64 => integer() | nil, - :number => float(), + :number => number(), :float => float() | nil, :double => float() | nil, - :decimal => String.t | nil, + :decimal => float() | nil, :string => String.t | nil, :byte => binary(), :binary => String.t | nil, @@ -45,12 +45,8 @@ defmodule OpenapiPetstore.Model.FormatTest do :pattern_with_digits_and_delimiter => String.t | nil } - alias OpenapiPetstore.Deserializer - def decode(value) do value - |> Deserializer.deserialize(:date, :date, nil) - |> Deserializer.deserialize(:dateTime, :datetime, nil) end end diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/mixed_properties_and_additional_properties_class.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/mixed_properties_and_additional_properties_class.ex index 89955b8e66e..06948bd0feb 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/mixed_properties_and_additional_properties_class.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/mixed_properties_and_additional_properties_class.ex @@ -23,7 +23,6 @@ defmodule OpenapiPetstore.Model.MixedPropertiesAndAdditionalPropertiesClass do def decode(value) do value - |> Deserializer.deserialize(:dateTime, :datetime, nil) |> Deserializer.deserialize(:map, :map, OpenapiPetstore.Model.Animal) end end diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/nullable_class.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/nullable_class.ex index 28891b8013d..f76320366df 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/nullable_class.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/nullable_class.ex @@ -24,25 +24,21 @@ defmodule OpenapiPetstore.Model.NullableClass do @type t :: %__MODULE__{ :integer_prop => integer() | nil, - :number_prop => float() | nil, + :number_prop => number() | nil, :boolean_prop => boolean() | nil, :string_prop => String.t | nil, :date_prop => Date.t | nil, :datetime_prop => DateTime.t | nil, - :array_nullable_prop => [%{optional(String.t) => any()}] | nil, - :array_and_items_nullable_prop => [%{optional(String.t) => any()}] | nil, - :array_items_nullable => [%{optional(String.t) => any()}] | nil, - :object_nullable_prop => %{optional(String.t) => any()} | nil, - :object_and_items_nullable_prop => %{optional(String.t) => any()} | nil, - :object_items_nullable => %{optional(String.t) => any()} | nil + :array_nullable_prop => [map()] | nil, + :array_and_items_nullable_prop => [map()] | nil, + :array_items_nullable => [map()] | nil, + :object_nullable_prop => %{optional(String.t) => map()} | nil, + :object_and_items_nullable_prop => %{optional(String.t) => map()} | nil, + :object_items_nullable => %{optional(String.t) => map()} | nil } - alias OpenapiPetstore.Deserializer - def decode(value) do value - |> Deserializer.deserialize(:date_prop, :date, nil) - |> Deserializer.deserialize(:datetime_prop, :datetime, nil) end end diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/number_only.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/number_only.ex index 755a4174bb0..353469e79d2 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/number_only.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/number_only.ex @@ -12,7 +12,7 @@ defmodule OpenapiPetstore.Model.NumberOnly do ] @type t :: %__MODULE__{ - :JustNumber => float() | nil + :JustNumber => number() | nil } def decode(value) do diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/object_with_deprecated_fields.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/object_with_deprecated_fields.ex index 17362be72e1..3d34b482722 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/object_with_deprecated_fields.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/object_with_deprecated_fields.ex @@ -16,7 +16,7 @@ defmodule OpenapiPetstore.Model.ObjectWithDeprecatedFields do @type t :: %__MODULE__{ :uuid => String.t | nil, - :id => float() | nil, + :id => number() | nil, :deprecatedRef => OpenapiPetstore.Model.DeprecatedModel.t | nil, :bars => [String.t] | nil } diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/order.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/order.ex index 5bf534749ed..1e3a7ea2ec2 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/order.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/order.ex @@ -25,11 +25,8 @@ defmodule OpenapiPetstore.Model.Order do :complete => boolean() | nil } - alias OpenapiPetstore.Deserializer - def decode(value) do value - |> Deserializer.deserialize(:shipDate, :datetime, nil) end end diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/model/outer_composite.ex b/samples/client/petstore/elixir/lib/openapi_petstore/model/outer_composite.ex index af0b16a5ab4..3e240cf0ba5 100644 --- a/samples/client/petstore/elixir/lib/openapi_petstore/model/outer_composite.ex +++ b/samples/client/petstore/elixir/lib/openapi_petstore/model/outer_composite.ex @@ -14,7 +14,7 @@ defmodule OpenapiPetstore.Model.OuterComposite do ] @type t :: %__MODULE__{ - :my_number => float() | nil, + :my_number => number() | nil, :my_string => String.t | nil, :my_boolean => boolean() | nil }