Skip to content

Commit

Permalink
Merge pull request #32 from GoNZooo/r.empty-functions-for-kotlin-structs
Browse files Browse the repository at this point in the history
feat(kt): add companion `create` function for structs
  • Loading branch information
GoNZooo authored Oct 28, 2022
2 parents faeb152 + c47c193 commit 6aa9647
Show file tree
Hide file tree
Showing 15 changed files with 313 additions and 39 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 2.3.0

### Features

- `Struct.create` function in companion object for all generated structs in
Kotlin output, which set optional fields to `null` by default.

## 2.2.3

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion gotyno-hs.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack

name: gotyno-hs
version: 2.2.3
version: 2.3.0
synopsis: A type definition compiler supporting multiple output languages.
description: Compiles type definitions into F#, TypeScript and Python, with validators, decoders and encoders.
category: Compiler
Expand Down
2 changes: 1 addition & 1 deletion package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: gotyno-hs
version: 2.2.3
version: 2.3.0
synopsis: A type definition compiler supporting multiple output languages.
description: Compiles type definitions into F#, TypeScript and Python, with validators, decoders and encoders.
license: BSD2
Expand Down
57 changes: 55 additions & 2 deletions src/CodeGeneration/Kotlin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,14 @@ outputPlainStruct name fields =
literalCompare _other (StructField _aName (LiteralType _bl)) = LT
literalCompare _a _b = EQ
typeOutput = mconcat ["@Serializable\n", "data class ", nameOf name]
in mconcat [typeOutput, "(\n ", fieldsOutput, "\n) : java.io.Serializable"]
in mconcat
[ typeOutput,
"(\n ",
fieldsOutput,
"\n) : java.io.Serializable {\n",
outputStructCompanion name fields [],
"}"
]

outputGenericStruct :: DefinitionName -> [TypeVariable] -> [StructField] -> Text
outputGenericStruct name typeVariables fields =
Expand All @@ -206,9 +213,55 @@ outputGenericStruct name typeVariables fields =
"(\n ",
fieldsOutput,
"\n",
") : java.io.Serializable"
") : java.io.Serializable {\n",
outputStructCompanion name fields typeVariables,
"}"
]

outputStructCompanion :: DefinitionName -> [StructField] -> [TypeVariable] -> Text
outputStructCompanion name fields typeVariables =
let createOutput =
mconcat
[ " fun ",
typeVariableOutput <> if null typeVariables then "" else " ",
"create",
"(",
createParameterOutput,
"): ",
nameOf name,
typeVariableOutput,
" {\n",
" return ",
nameOf name,
"(",
createArgumentOutput,
")\n",
" }\n"
]
(optionalFields, nonOptionalFields) = List.partition isOptionalField fields
(literalFields, nonLiteralFields) = List.partition isLiteralField nonOptionalFields
typeVariableOutput =
if null typeVariables then "" else joinedTypeVariables
joinedTypeVariables = mconcat ["<", joinTypeVariables typeVariables, ">"]
createParameterOutput =
(nonLiteralFields <> optionalFields <> literalFields)
& fmap outputFieldParameter
& Text.intercalate ", "
outputFieldParameter f
| isOptionalField f =
mconcat [nameOf f, ": ", f ^. structFieldType & outputFieldType, " = null"]
| otherwise = mconcat [nameOf f, ": ", f ^. structFieldType & outputFieldType]
isOptionalField (StructField _ (ComplexType (OptionalType _))) = True
isOptionalField _ = False
isLiteralField (StructField _ (LiteralType _)) = True
isLiteralField _ = False
createArgumentOutput =
fields
& fmap outputFieldArgument
& Text.intercalate ", "
outputFieldArgument f = mconcat [nameOf f, " = ", nameOf f]
in mconcat [" companion object {\n", createOutput, " }\n"]

outputUnion :: DefinitionName -> FieldName -> UnionType -> Text
outputUnion name typeTag unionType =
let caseUnionOutput =
Expand Down
4 changes: 4 additions & 0 deletions src/CodeGeneration/Utilities.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ instance HasName FieldName where
{-# INLINE nameOf #-}
nameOf = (^. unwrap)

instance HasName StructField where
{-# INLINE nameOf #-}
nameOf = (^. structFieldName) >>> nameOf

class HasDefinitionName a where
definitionNameOf :: a -> DefinitionName

Expand Down
56 changes: 49 additions & 7 deletions test/reference-output/basic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ data class Recruiter(
val created: BigInteger,
@get:JsonProperty("type")
val type: String = "Recruiter"
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(Name: String, emails: ArrayList<String?>, created: BigInteger, recruiter: Recruiter? = null, type: String = "Recruiter"): Recruiter {
return Recruiter(type = type, Name = Name, emails = emails, recruiter = recruiter, created = created)
}
}
}

@Serializable
@JsonTypeInfo(
Expand Down Expand Up @@ -65,7 +71,13 @@ sealed class GetSearchesFilter : java.io.Serializable {
data class SearchesParameters(
@get:JsonProperty("filters")
val filters: ArrayList<GetSearchesFilter>
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(filters: ArrayList<GetSearchesFilter>): SearchesParameters {
return SearchesParameters(filters = filters)
}
}
}

enum class StillSize(val data: String) : java.io.Serializable {
@JsonProperty("w92") W92("w92"),
Expand All @@ -83,29 +95,53 @@ data class LogInData(
val username: String,
@get:JsonProperty("password")
val password: String
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(username: String, password: String): LogInData {
return LogInData(username = username, password = password)
}
}
}

@Serializable
data class UserId(
@get:JsonProperty("value")
val value: String
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(value: String): UserId {
return UserId(value = value)
}
}
}

@Serializable
data class Channel(
@get:JsonProperty("name")
val name: String,
@get:JsonProperty("private")
val private: Boolean
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(name: String, private: Boolean): Channel {
return Channel(name = name, private = private)
}
}
}

@Serializable
data class Email(
@get:JsonProperty("value")
val value: String,
@get:JsonProperty("public")
val public: Boolean
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(value: String, public: Boolean): Email {
return Email(value = value, public = public)
}
}
}

@Serializable
@JsonTypeInfo(
Expand Down Expand Up @@ -205,7 +241,13 @@ data class Person(
val recruiter: Recruiter,
@get:JsonProperty("spouse")
val spouse: Maybe<Person>
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(name: String, age: Byte, efficiency: Float, on_vacation: Boolean, hobbies: ArrayList<String>, last_fifteen_comments: ArrayList<String>, recruiter: Recruiter, spouse: Maybe<Person>): Person {
return Person(name = name, age = age, efficiency = efficiency, on_vacation = on_vacation, hobbies = hobbies, last_fifteen_comments = last_fifteen_comments, recruiter = recruiter, spouse = spouse)
}
}
}

@Serializable
@JsonTypeInfo(
Expand Down
8 changes: 7 additions & 1 deletion test/reference-output/basicImport.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ class BasicImport {
data class StructUsingImport(
@get:JsonProperty("field")
val field: BasicStruct.BasicStruct
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(field: BasicStruct.BasicStruct): StructUsingImport {
return StructUsingImport(field = field)
}
}
}

@Serializable
@JsonTypeInfo(
Expand Down
8 changes: 7 additions & 1 deletion test/reference-output/basicOptional.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ data class HasOptionalString(
val optionalArrayField: ArrayList<Int>?,
@get:JsonProperty("arrayOfOptionalField")
val arrayOfOptionalField: ArrayList<Int?>
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(arrayOfOptionalField: ArrayList<Int?>, stringField: String? = null, optionalArrayField: ArrayList<Int>? = null): HasOptionalString {
return HasOptionalString(stringField = stringField, optionalArrayField = optionalArrayField, arrayOfOptionalField = arrayOfOptionalField)
}
}
}

@Serializable
@JsonTypeInfo(
Expand Down
8 changes: 7 additions & 1 deletion test/reference-output/basicStruct.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,11 @@ data class BasicStruct(
val field1: Int,
@get:JsonProperty("field2")
val field2: String
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(field1: Int, field2: String): BasicStruct {
return BasicStruct(field1 = field1, field2 = field2)
}
}
}
}
8 changes: 7 additions & 1 deletion test/reference-output/basicUnion.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ class BasicUnion {
data class PayloadStruct(
@get:JsonProperty("field1")
val field1: Int
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(field1: Int): PayloadStruct {
return PayloadStruct(field1 = field1)
}
}
}

@Serializable
@JsonTypeInfo(
Expand Down
8 changes: 7 additions & 1 deletion test/reference-output/genericStruct.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,11 @@ class GenericStruct {
data class GenericStruct<T>(
@get:JsonProperty("field")
val field: T
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun <T> create(field: T): GenericStruct<T> {
return GenericStruct(field = field)
}
}
}
}
48 changes: 42 additions & 6 deletions test/reference-output/generics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,25 @@ data class UsingGenerics(
val field1: Basic.Maybe<String>,
@get:JsonProperty("field2")
val field2: Basic.Either<String, Int>
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(field1: Basic.Maybe<String>, field2: Basic.Either<String, Int>): UsingGenerics {
return UsingGenerics(field1 = field1, field2 = field2)
}
}
}

@Serializable
data class UsingOwnGenerics<T>(
@get:JsonProperty("field1")
val field1: Basic.Maybe<T>
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun <T> create(field1: Basic.Maybe<T>): UsingOwnGenerics<T> {
return UsingOwnGenerics(field1 = field1)
}
}
}

@Serializable
data class KnownForMovie(
Expand All @@ -45,7 +57,13 @@ data class KnownForMovie(
val overview: String,
@get:JsonProperty("media_type")
val media_type: String = "movie"
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(id: Int, vote_average: Float, overview: String, poster_path: String? = null, title: String? = null, release_date: String? = null, media_type: String = "movie"): KnownForMovie {
return KnownForMovie(media_type = media_type, poster_path = poster_path, id = id, title = title, vote_average = vote_average, release_date = release_date, overview = overview)
}
}
}

@Serializable
data class KnownForShow(
Expand All @@ -63,7 +81,13 @@ data class KnownForShow(
val name: String?,
@get:JsonProperty("media_type")
val media_type: String = "tv"
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(id: Int, vote_average: Float, overview: String, poster_path: String? = null, first_air_date: String? = null, name: String? = null, media_type: String = "tv"): KnownForShow {
return KnownForShow(media_type = media_type, poster_path = poster_path, id = id, vote_average = vote_average, overview = overview, first_air_date = first_air_date, name = name)
}
}
}

@JsonDeserialize(using = KnownFor.Deserializer::class)
@Serializable
Expand Down Expand Up @@ -105,7 +129,13 @@ data class KnownForMovieWithoutTypeTag(
val release_date: String?,
@get:JsonProperty("overview")
val overview: String
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(id: Int, vote_average: Float, overview: String, poster_path: String? = null, title: String? = null, release_date: String? = null): KnownForMovieWithoutTypeTag {
return KnownForMovieWithoutTypeTag(poster_path = poster_path, id = id, title = title, vote_average = vote_average, release_date = release_date, overview = overview)
}
}
}

@Serializable
data class KnownForShowWithoutTypeTag(
Expand All @@ -121,7 +151,13 @@ data class KnownForShowWithoutTypeTag(
val first_air_date: String?,
@get:JsonProperty("name")
val name: String?
) : java.io.Serializable
) : java.io.Serializable {
companion object {
fun create(id: Int, vote_average: Float, overview: String, poster_path: String? = null, first_air_date: String? = null, name: String? = null): KnownForShowWithoutTypeTag {
return KnownForShowWithoutTypeTag(poster_path = poster_path, id = id, vote_average = vote_average, overview = overview, first_air_date = first_air_date, name = name)
}
}
}

@Serializable
@JsonTypeInfo(
Expand Down
Loading

0 comments on commit 6aa9647

Please sign in to comment.