From cfcf3253bdf6b5f33ccb551c8650fca7b10d88f9 Mon Sep 17 00:00:00 2001 From: vbergeron Date: Mon, 16 Oct 2023 11:58:52 +0200 Subject: [PATCH 1/3] Feature: Add iron's RefinedTypeOps support --- .../sttp/iron/codec/iron/TapirCodecIron.scala | 22 ++++++++++++++++++- .../codec/iron/TapirCodecIronTestScala3.scala | 9 ++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/integrations/iron/src/main/scala/sttp/iron/codec/iron/TapirCodecIron.scala b/integrations/iron/src/main/scala/sttp/iron/codec/iron/TapirCodecIron.scala index 032f447fcb..8e97f12858 100644 --- a/integrations/iron/src/main/scala/sttp/iron/codec/iron/TapirCodecIron.scala +++ b/integrations/iron/src/main/scala/sttp/iron/codec/iron/TapirCodecIron.scala @@ -4,6 +4,8 @@ import io.github.iltotore.iron.Constraint import io.github.iltotore.iron.:| import io.github.iltotore.iron.refineEither import io.github.iltotore.iron.refineOption +import io.github.iltotore.iron.RefinedTypeOps +import io.github.iltotore.iron.RefinedTypeOpsImpl import io.github.iltotore.iron.constraint.any.* import io.github.iltotore.iron.constraint.string.* import io.github.iltotore.iron.constraint.collection.* @@ -32,7 +34,7 @@ trait TapirCodecIron extends DescriptionWitness with LowPriorityValidatorForPred ): Schema[Value :| Predicate] = vSchema.validate(validatorTranslation.validator).map[Value :| Predicate](v => v.refineOption[Predicate])(identity) - inline given [Representation, Value, Predicate, CF <: CodecFormat](using + inline given ironTypeCodec[Representation, Value, Predicate, CF <: CodecFormat](using inline tm: Codec[Representation, Value, CF], inline constraint: Constraint[Value, Predicate], inline validatorTranslation: ValidatorForPredicate[Value, Predicate] @@ -47,6 +49,24 @@ trait TapirCodecIron extends DescriptionWitness with LowPriorityValidatorForPred } }(identity) + inline given refinedTypeSchema[T](using mirror: RefinedTypeOps.Mirror[T])(using + inline vSchema: Schema[mirror.BaseType], + inline constraint: Constraint[mirror.BaseType, mirror.ConstraintType], + inline validatorTranslation: ValidatorForPredicate[mirror.BaseType, mirror.ConstraintType] + ): Schema[T] = + val ops = new RefinedTypeOpsImpl[mirror.BaseType, mirror.ConstraintType, T] {} + import ops.* + summon[Schema[mirror.IronType]].map(input => Some(ops(input)))(_.value) + + inline given refinedTypeCodec[R, T, CF <: CodecFormat] (using mirror: RefinedTypeOps.Mirror[T])(using + inline tm: Codec[R, mirror.BaseType, CF], + inline constraint: Constraint[mirror.BaseType, mirror.ConstraintType], + inline validatorTranslation: ValidatorForPredicate[mirror.BaseType, mirror.ConstraintType] + ): Codec[R, T, CF] = + val ops = new RefinedTypeOpsImpl[mirror.BaseType, mirror.ConstraintType, T] {} + import ops.* + summon[Codec[R, mirror.IronType, CF]].map(ops(_))(_.value) + inline given (using inline vSchema: Schema[String], inline constraint: Constraint[String, ValidUUID], diff --git a/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/TapirCodecIronTestScala3.scala b/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/TapirCodecIronTestScala3.scala index 4b57a4faac..6812c1a77e 100644 --- a/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/TapirCodecIronTestScala3.scala +++ b/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/TapirCodecIronTestScala3.scala @@ -18,6 +18,11 @@ import io.github.iltotore.iron.constraint.all.* import sttp.tapir.Validator import sttp.tapir.ValidationError +// Opaque aliases can't be included into class bodies +type RefinedIntConstraint = Interval.ClosedOpen[0, 10] +opaque type RefinedInt <: Int = Int :| RefinedIntConstraint +object RefinedInt extends RefinedTypeOpsImpl[Int, RefinedIntConstraint, RefinedInt] + class TapirCodecIronTestScala3 extends AnyFlatSpec with Matchers { val schema: Schema[Double :| Positive] = summon[Schema[Double :| Positive]] @@ -215,4 +220,8 @@ class TapirCodecIronTestScala3 extends AnyFlatSpec with Matchers { } } + "Instances for opaque refined type" should "correctly derived" in: + summon[Schema[RefinedInt]] + summon[Codec[String, RefinedInt, TextPlain]] + } From 54cd9d8bd75e5350f6afd9189b3c9c84bfbab29d Mon Sep 17 00:00:00 2001 From: vbergeron Date: Mon, 16 Oct 2023 13:13:37 +0200 Subject: [PATCH 2/3] Simplier implem based on iron-circe --- .../sttp/iron/codec/iron/TapirCodecIron.scala | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/integrations/iron/src/main/scala/sttp/iron/codec/iron/TapirCodecIron.scala b/integrations/iron/src/main/scala/sttp/iron/codec/iron/TapirCodecIron.scala index 8e97f12858..aef3a497de 100644 --- a/integrations/iron/src/main/scala/sttp/iron/codec/iron/TapirCodecIron.scala +++ b/integrations/iron/src/main/scala/sttp/iron/codec/iron/TapirCodecIron.scala @@ -49,23 +49,11 @@ trait TapirCodecIron extends DescriptionWitness with LowPriorityValidatorForPred } }(identity) - inline given refinedTypeSchema[T](using mirror: RefinedTypeOps.Mirror[T])(using - inline vSchema: Schema[mirror.BaseType], - inline constraint: Constraint[mirror.BaseType, mirror.ConstraintType], - inline validatorTranslation: ValidatorForPredicate[mirror.BaseType, mirror.ConstraintType] - ): Schema[T] = - val ops = new RefinedTypeOpsImpl[mirror.BaseType, mirror.ConstraintType, T] {} - import ops.* - summon[Schema[mirror.IronType]].map(input => Some(ops(input)))(_.value) - - inline given refinedTypeCodec[R, T, CF <: CodecFormat] (using mirror: RefinedTypeOps.Mirror[T])(using - inline tm: Codec[R, mirror.BaseType, CF], - inline constraint: Constraint[mirror.BaseType, mirror.ConstraintType], - inline validatorTranslation: ValidatorForPredicate[mirror.BaseType, mirror.ConstraintType] - ): Codec[R, T, CF] = - val ops = new RefinedTypeOpsImpl[mirror.BaseType, mirror.ConstraintType, T] {} - import ops.* - summon[Codec[R, mirror.IronType, CF]].map(ops(_))(_.value) + given refinedTypeSchema[T](using m: RefinedTypeOps.Mirror[T], ev: Schema[m.IronType]): Schema[T] = + ev.asInstanceOf[Schema[T]] + + given refinedTypeCodec[R, T, CF <: CodecFormat] (using m: RefinedTypeOps.Mirror[T], ev: Codec[R, m.IronType, CF]): Codec[R, T, CF] = + ev.asInstanceOf[Codec[R, T, CF]] inline given (using inline vSchema: Schema[String], From 95f13088abd067faddea24ec38f9cdb916464d72 Mon Sep 17 00:00:00 2001 From: vbergeron Date: Tue, 17 Oct 2023 11:46:25 +0200 Subject: [PATCH 3/3] fixup! opaque in its own package --- .../test/scala-3/sttp/iron/codec/iron/RefinedInt.scala | 8 ++++++++ .../sttp/iron/codec/iron/TapirCodecIronTestScala3.scala | 7 +------ 2 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 integrations/iron/src/test/scala-3/sttp/iron/codec/iron/RefinedInt.scala diff --git a/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/RefinedInt.scala b/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/RefinedInt.scala new file mode 100644 index 0000000000..232c6037d9 --- /dev/null +++ b/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/RefinedInt.scala @@ -0,0 +1,8 @@ +package sttp.iron.codec.iron + +import io.github.iltotore.iron.* +import io.github.iltotore.iron.constraint.all.* + +type RefinedIntConstraint = Interval.ClosedOpen[0, 10] +opaque type RefinedInt <: Int = Int :| RefinedIntConstraint +object RefinedInt extends RefinedTypeOpsImpl[Int, RefinedIntConstraint, RefinedInt] diff --git a/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/TapirCodecIronTestScala3.scala b/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/TapirCodecIronTestScala3.scala index 6812c1a77e..417cfe68fc 100644 --- a/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/TapirCodecIronTestScala3.scala +++ b/integrations/iron/src/test/scala-3/sttp/iron/codec/iron/TapirCodecIronTestScala3.scala @@ -18,11 +18,6 @@ import io.github.iltotore.iron.constraint.all.* import sttp.tapir.Validator import sttp.tapir.ValidationError -// Opaque aliases can't be included into class bodies -type RefinedIntConstraint = Interval.ClosedOpen[0, 10] -opaque type RefinedInt <: Int = Int :| RefinedIntConstraint -object RefinedInt extends RefinedTypeOpsImpl[Int, RefinedIntConstraint, RefinedInt] - class TapirCodecIronTestScala3 extends AnyFlatSpec with Matchers { val schema: Schema[Double :| Positive] = summon[Schema[Double :| Positive]] @@ -220,7 +215,7 @@ class TapirCodecIronTestScala3 extends AnyFlatSpec with Matchers { } } - "Instances for opaque refined type" should "correctly derived" in: + "Instances for opaque refined type" should "be correctly derived" in: summon[Schema[RefinedInt]] summon[Codec[String, RefinedInt, TextPlain]]