Skip to content

Commit

Permalink
Implemented configurable derivation
Browse files Browse the repository at this point in the history
  • Loading branch information
Георгий Ковалев committed May 2, 2024
1 parent b90f917 commit f7d77eb
Show file tree
Hide file tree
Showing 35 changed files with 2,090 additions and 358 deletions.
Binary file added modules/core/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package tethys.derivation


private [tethys] trait JsonObjectWriterDerivation {

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package tethys.derivation


private [tethys] trait JsonObjectWriterDerivation {

}

This file was deleted.

10 changes: 10 additions & 0 deletions modules/core/src/main/scala-3/tethys/JsonConfig.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tethys

sealed trait JsonConfig[A]:
def discriminateBy[Field](select: A => Field): JsonConfig[A]


object JsonConfig:
@scala.annotation.compileTimeOnly("Config must be an inlined given or provided directly to 'derived'")
def configure[A]: JsonConfig[A] =
throw IllegalStateException("Config must be an inlined given or provided directly to 'derived'")
46 changes: 46 additions & 0 deletions modules/core/src/main/scala-3/tethys/JsonFieldStyle.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package tethys

import java.util.regex.Pattern


enum JsonFieldStyle {
case Capitalize, Uncapitalize, LowerCase, UpperCase

case KebabCase, LowerKebabCase, UpperKebabCase, CapitalizedKebabCase

case SnakeCase, LowerSnakeCase, UpperSnakeCase, CapitalizedSnakeCase
}

private[tethys]
object JsonFieldStyle:
private val regexp1: Pattern = Pattern.compile("([A-Z]+)([A-Z][a-z])")
private val regexp2: Pattern = Pattern.compile("([a-z\\d])([A-Z])")
private val replacement: String = "$1_$2"
private val snakeCase: String => String = splitName(_).mkString("_")
private val kebabcase: String => String = splitName(_).mkString("-")
private val capitalize: String => String = _.capitalize
private val uncapitalize: String => String = (field: String) => field.updated(0, field.charAt(0).toLower)
private val lowercase: String => String = _.toLowerCase()
private val uppercase: String => String = _.toUpperCase()

def applyStyle(string: String, style: JsonFieldStyle): String =
style match
case JsonFieldStyle.Capitalize => capitalize(string)
case JsonFieldStyle.Uncapitalize => uncapitalize(string)
case JsonFieldStyle.LowerCase => lowercase(string)
case JsonFieldStyle.UpperCase => uppercase(string)

case JsonFieldStyle.KebabCase => kebabcase(string)
case JsonFieldStyle.LowerKebabCase => (kebabcase andThen lowercase)(string)
case JsonFieldStyle.UpperKebabCase => (kebabcase andThen uppercase)(string)
case JsonFieldStyle.CapitalizedKebabCase => (kebabcase andThen capitalize)(string)

case JsonFieldStyle.SnakeCase => snakeCase(string)
case JsonFieldStyle.LowerSnakeCase => (snakeCase andThen lowercase)(string)
case JsonFieldStyle.UpperSnakeCase => (snakeCase andThen uppercase)(string)
case JsonFieldStyle.CapitalizedSnakeCase => (snakeCase andThen capitalize)(string)


private def splitName(name: String): List[String] =
val first = JsonFieldStyle.regexp1.matcher(name).replaceAll(JsonFieldStyle.replacement)
JsonFieldStyle.regexp2.matcher(first).replaceAll(JsonFieldStyle.replacement).split("_").toList
21 changes: 21 additions & 0 deletions modules/core/src/main/scala-3/tethys/OrdinalEnumJsonReader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package tethys

import tethys.readers.{FieldName, ReaderError}
import tethys.readers.tokens.TokenIterator

trait OrdinalEnumJsonReader[A] extends JsonReader[A]

object OrdinalEnumJsonReader:
inline def derived[A <: scala.reflect.Enum]: OrdinalEnumJsonReader[A] =
new OrdinalEnumJsonReader[A]:
def read(it: TokenIterator)(implicit fieldName: FieldName): A =
if it.currentToken().isNumberValue then
val res = it.int()
it.next()
try derivation.EnumCompanion.getByOrdinal[A](res)
catch
case ex: NoSuchElementException =>
ReaderError.wrongJson(s"Unknown enum ordinal: $res")
else
ReaderError.wrongJson(s"Expected int value but found: ${it.currentToken()}")

Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package tethys
import tethys.writers.tokens.TokenWriter


trait OrdinalEnumWriter[A] extends JsonWriter[A]
trait OrdinalEnumJsonWriter[A] extends JsonWriter[A]

object OrdinalEnumWriter:
inline def derived[A <: scala.reflect.Enum]: OrdinalEnumWriter[A] =
object OrdinalEnumJsonWriter:
inline def derived[A <: scala.reflect.Enum]: OrdinalEnumJsonWriter[A] =
(value: A, tokenWriter: TokenWriter) => tokenWriter.writeNumber(value.ordinal)

inline def withLabel[A <: scala.reflect.Enum](label: String): JsonObjectWriter[A] =
Expand Down
18 changes: 0 additions & 18 deletions modules/core/src/main/scala-3/tethys/OrdinalEnumReader.scala

This file was deleted.

23 changes: 23 additions & 0 deletions modules/core/src/main/scala-3/tethys/StringEnumJsonReader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tethys

import tethys.readers.{FieldName, ReaderError}
import tethys.readers.tokens.TokenIterator

trait StringEnumJsonReader[A] extends JsonReader[A]

object StringEnumJsonReader:
inline def derived[A <: scala.reflect.Enum]: StringEnumJsonReader[A] =
new StringEnumJsonReader[A]:
def read(it: TokenIterator)(implicit fieldName: FieldName): A =
if it.currentToken().isStringValue then
val res = it.string()
it.next()
try
derivation.EnumCompanion.getByName[A](res)
catch
case ex: NoSuchElementException =>
ReaderError.wrongJson(s"Unknown enum name: $res")
else
ReaderError.wrongJson(s"Expected string value but found: ${it.currentToken()}")


Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package tethys
import tethys.writers.tokens.TokenWriter

trait StringEnumWriter[A] extends JsonWriter[A]
trait StringEnumJsonWriter[A] extends JsonWriter[A]

object StringEnumWriter:
inline def derived[A <: scala.reflect.Enum]: StringEnumWriter[A] =
object StringEnumJsonWriter:
inline def derived[A <: scala.reflect.Enum]: StringEnumJsonWriter[A] =
(value: A, tokenWriter: TokenWriter) => tokenWriter.writeString(value.toString)

inline def withLabel[A <: scala.reflect.Enum](label: String): JsonObjectWriter[A] =
Expand Down
18 changes: 0 additions & 18 deletions modules/core/src/main/scala-3/tethys/StringEnumReader.scala

This file was deleted.

Loading

0 comments on commit f7d77eb

Please sign in to comment.