Skip to content

Commit

Permalink
Upgrade zio-schema and adjust OpenAPI and CSV modules
Browse files Browse the repository at this point in the history
  • Loading branch information
pwliwanow committed Apr 16, 2024
1 parent 2e3e217 commit b38aea0
Show file tree
Hide file tree
Showing 10 changed files with 2,406 additions and 3,079 deletions.
1,424 changes: 868 additions & 556 deletions chopsticks-csv/src/main/scala/dev/chopsticks/csv/CsvDecoder.scala

Large diffs are not rendered by default.

985 changes: 83 additions & 902 deletions chopsticks-csv/src/main/scala/dev/chopsticks/csv/CsvEncoder.scala

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ object CsvDecoderTest {
object CsvDecoderTestName extends OpenApiModel[CsvDecoderTestName] {
implicit override lazy val zioSchema: Schema[CsvDecoderTestName] =
Schema[String]
.validate(Validator.all(Validator.minLength(1), Validator.maxLength(100)))
.validated(Validator.all(Validator.minLength(1), Validator.maxLength(100)))
.mapBoth(CsvDecoderTestName(_), _.value)
}

final case class CsvDecoderTestAddressList(value: List[CsvDecoderTestAddress]) extends AnyVal
object CsvDecoderTestAddressList extends OpenApiModel[CsvDecoderTestAddressList] {
implicit override lazy val zioSchema: Schema[CsvDecoderTestAddressList] =
Schema[List[CsvDecoderTestAddress]]
.validate(Validator.minSize(1))
.validated(Validator.minSize(1))
.mapBoth(CsvDecoderTestAddressList(_), _.value)
}

Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import eu.timepit.refined.types.all.NonNegInt
import eu.timepit.refined.types.numeric.{NonNegLong, PosInt, PosLong}
import eu.timepit.refined.types.string.NonEmptyString
import sttp.tapir.Validator
import zio.schema.{DefaultJavaTimeSchemas, Schema}
import zio.schema.Schema
import zio.schema.internal.SourceLocation
import zio.Chunk

object OpenApiZioSchemas extends DefaultJavaTimeSchemas {
object OpenApiZioSchemas {
implicit class ZioSchemaOps[A](val schema: Schema[A]) extends AnyVal {
def named(name: String): Schema[A] = {
schema.annotate(OpenApiAnnotations.entityName(name))
}
def validate(validator: Validator[A]): Schema[A] = {
def validated(validator: Validator[A]): Schema[A] = {
schema.annotate(OpenApiAnnotations.validate[A](validator))
}
def description(description: String): Schema[A] = {
Expand Down Expand Up @@ -49,32 +49,32 @@ object OpenApiZioSchemas extends DefaultJavaTimeSchemas {

implicit val nonEmptyStringSchema: Schema[NonEmptyString] =
Schema[String]
.validate(Validators.nonEmptyStringValidator)
.validated(Validators.nonEmptyStringValidator)
.transformWithoutAnnotations[NonEmptyString](NonEmptyString.from, _.value)

implicit val posIntSchema: Schema[PosInt] =
Schema[Int]
.validate(Validators.posIntValidator)
.validated(Validators.posIntValidator)
.transformWithoutAnnotations[PosInt](PosInt.from, _.value)

implicit val nonNegIntSchema: Schema[NonNegInt] =
Schema[Int]
.validate(Validators.nonNegIntValidator)
.validated(Validators.nonNegIntValidator)
.transformWithoutAnnotations[NonNegInt](NonNegInt.from, _.value)

implicit val posLongSchema: Schema[PosLong] =
Schema[Long]
.validate(Validators.posLongValidator)
.validated(Validators.posLongValidator)
.transformWithoutAnnotations[PosLong](PosLong.from, _.value)

implicit val nonNegLongSchema: Schema[NonNegLong] =
Schema[Long]
.validate(Validators.nonNegLongValidator)
.validated(Validators.nonNegLongValidator)
.transformWithoutAnnotations[NonNegLong](NonNegLong.from, _.value)

implicit def nonEmptyListSchema[A: Schema]: Schema[NonEmptyList[A]] =
Schema[List[A]]
.validate(Validators.nonEmptyCollectionValidator)
.validated(Validators.nonEmptyCollectionValidator[A, List])
.transformWithoutAnnotations(
xs => {
NonEmptyList.fromList(xs) match {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dev.chopsticks.openapi.common

import dev.chopsticks.openapi.OpenApiParsedAnnotations
import zio.schema.TypeId

final private[chopsticks] case class ConverterCacheKey(entityName: String, annotationsHash: Int)

final private[chopsticks] class ConverterCache[C[_]](
cache: scala.collection.mutable.Map[ConverterCacheKey, C[_] with ConverterCache.Lazy[C[_]]] =
scala.collection.mutable.Map.empty[ConverterCacheKey, C[_] with ConverterCache.Lazy[C[_]]]
) {
private[chopsticks] def convertUsingCache[A](
typeId: TypeId,
annotations: OpenApiParsedAnnotations[A]
)(convert: => C[A])(
initLazy: () => C[A] with ConverterCache.Lazy[C[A]]
): C[A] = {
val entityName = OpenApiConverterUtils.getEntityName(Some(typeId), annotations)
entityName match {
case Some(name) =>
val cacheKey = ConverterCacheKey(name, annotations.hashCode())
cache.get(cacheKey) match {
case Some(value) => value.asInstanceOf[C[A]]
case None =>
val lazyEnc = initLazy()
val _ = cache.addOne(cacheKey -> lazyEnc.asInstanceOf[C[_] with ConverterCache.Lazy[C[_]]])
val result = convert
lazyEnc.set(result)
result
}
case None =>
convert
}
}
}
object ConverterCache {
private[chopsticks] trait Lazy[A] {
private var _value: A = _
final private[ConverterCache] def set(value: A): Unit = _value = value
final private[chopsticks] def get: A =
if (_value == null) throw new RuntimeException(s"${this.getClass.getSimpleName} has not yet been initialized")
else _value
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dev.chopsticks.openapi.common

import dev.chopsticks.openapi.OpenApiParsedAnnotations
import zio.schema.{Schema, TypeId}
import zio.schema.TypeId.Nominal

object OpenApiConverterUtils {
def getEntityName(schema: Schema[_]): Option[String] = {
schema match {
case r: Schema.Record[_] =>
val parsed = OpenApiParsedAnnotations.extractAnnotations(r.annotations)
getEntityName(Some(r.id), parsed)
case r: Schema.Enum[_] =>
val parsed = OpenApiParsedAnnotations.extractAnnotations(r.annotations)
getEntityName(Some(r.id), parsed)
case r: Schema.Lazy[_] =>
getEntityName(r.schema)
case other =>
OpenApiParsedAnnotations.extractAnnotations(other.annotations).entityName
}
}

private[chopsticks] def getCaseEntityName(
schemaCase: Schema.Case[_, _],
parsed: OpenApiParsedAnnotations[_]
): Option[String] = {
getEntityName(schemaCase.schema, parsed)
}

private def getEntityName(schema: Schema[_], parsed: OpenApiParsedAnnotations[_]): Option[String] = {
schema match {
case r: Schema.Record[_] =>
getEntityName(Some(r.id), parsed)
case r: Schema.Lazy[_] =>
getEntityName(r.schema, parsed)
case _ =>
parsed.entityName
}
}

private[chopsticks] def getEntityName(typeId: Option[TypeId], metadata: OpenApiParsedAnnotations[_]) = {
metadata.entityName.orElse {
typeId match {
case Some(Nominal(packageName, objectNames, typeName)) =>
Some(OpenApiSettings.default.getTypeName(packageName, objectNames, typeName))
case _ => None
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dev.chopsticks.openapi.common

import zio.Chunk

trait OpenApiSettings {
def getTypeName(packageName: Chunk[String], objectNames: Chunk[String], typeName: String): String
}
object OpenApiSettings {
val default = new OpenApiSettings {
override def getTypeName(packageName: Chunk[String], objectNames: Chunk[String], typeName: String): String = {
val n1 = objectNames.mkString("_")
if (n1.isEmpty) typeName
else s"${n1}_$typeName"
}
}
}
4 changes: 2 additions & 2 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ object Dependencies {
}

lazy val zioSchemaDeps = {
val zioSchemaOrganization = "dev.chopsticks"
val zioSchemaVersion = "0.1.12"
val zioSchemaOrganization = "dev.zio"
val zioSchemaVersion = "1.1.0"
Seq(
zioSchemaOrganization %% "zio-schema" % zioSchemaVersion,
zioSchemaOrganization %% "zio-schema-json" % zioSchemaVersion,
Expand Down

0 comments on commit b38aea0

Please sign in to comment.