From 62c294fdc647475b3eef4c6f2a42ed8499aae4ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Fri, 1 Mar 2024 15:02:19 +0100 Subject: [PATCH 1/6] Add transformTransitivelyK --- modules/core/src/smithy4s/schema/Schema.scala | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/modules/core/src/smithy4s/schema/Schema.scala b/modules/core/src/smithy4s/schema/Schema.scala index 7d8dc3ce0..3c5739831 100644 --- a/modules/core/src/smithy4s/schema/Schema.scala +++ b/modules/core/src/smithy4s/schema/Schema.scala @@ -190,6 +190,55 @@ object Schema { def apply[A](fa: Schema[A]): Schema[A] = fa.transformHintsTransitively(f) } + /** + * Transforms this schema, and all the schemas inside it, using the provided function. + */ + def transformTransitivelyK(f: Schema ~> Schema): Schema ~> Schema = new (Schema ~> Schema) { + private val compiler = new TransitiveCompiler(f) + + def apply[A](fa: Schema[A]): Schema[A] = fa.compile(compiler) + } + + // format: on + private final class TransitiveCompiler( + underlying: Schema ~> Schema + ) extends (Schema ~> Schema) { + + def apply[A]( + fa: Schema[A] + ): Schema[A] = fa match { + case e @ EnumerationSchema(_, _, _, _, _) => underlying(e) + case p @ PrimitiveSchema(_, _, _) => underlying(p) + case u @ UnionSchema(_, _, _, _) => + underlying(u.copy(alternatives = u.alternatives.map(handleAlt(_)))) + case BijectionSchema(s, bijection) => + underlying(BijectionSchema(this(s), bijection)) + case LazySchema(suspend) => + underlying(LazySchema(suspend.map(this.apply))) + case RefinementSchema(s, refinement) => + underlying(RefinementSchema(this(s), refinement)) + case c: CollectionSchema[c, a] => + underlying(c.copy(member = this(c.member))) + case m @ MapSchema(_, _, _, _) => + underlying(m.copy(key = this(m.key), value = this(m.value))) + case s @ StructSchema(_, _, _, _) => + underlying(s.copy(fields = s.fields.map(handleField(_)))) + case n @ OptionSchema(_) => + underlying(n.copy(underlying = this(n.underlying))) + } + + private def handleField[S, A]( + field: Field[S, A] + ): Field[S, A] = field.copy(schema = this(field.schema)) + + private def handleAlt[S, A]( + alt: Alt[S, A] + ): Alt[S, A] = alt.copy(schema = this(alt.schema)) + } + + // format: off + + ////////////////////////////////////////////////////////////////////////////////////////////////// // SCHEMA BUILDER ////////////////////////////////////////////////////////////////////////////////////////////////// From c127daf4b87edfc0abe20108a5071b56177c16cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Fri, 1 Mar 2024 15:03:54 +0100 Subject: [PATCH 2/6] add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 898a87d5b..8e65b9b7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.18.11 + +* Added a utility method, `Schema.transformTransitivelyK`, to help in recursively transforming schemas. + # 0.18.10 * Bumps alloy to 0.3.1. This is required as otherwise the `alloy#nullable` hints get filtered out when using SimpleRestJsonBuilder. From 355ea98c9a8688d6aab9e958d941c24d2ebb507a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Fri, 1 Mar 2024 15:20:22 +0100 Subject: [PATCH 3/6] Implement transformHintsTransitively in terms of this, update test --- .../schema/HintsTransformationSpec.scala | 7 ++++- modules/core/src/smithy4s/schema/Schema.scala | 30 +++++++++---------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/modules/bootstrapped/test/src/smithy4s/schema/HintsTransformationSpec.scala b/modules/bootstrapped/test/src/smithy4s/schema/HintsTransformationSpec.scala index 3f794c312..f1ea8e3c5 100644 --- a/modules/bootstrapped/test/src/smithy4s/schema/HintsTransformationSpec.scala +++ b/modules/bootstrapped/test/src/smithy4s/schema/HintsTransformationSpec.scala @@ -214,7 +214,12 @@ class HintsTransformationSpec() extends FunSuite { values: List[EnumValue[E]], total: E => EnumValue[E] ): Count[E] = { e => - count(hints) + count(total(e).hints) + count(hints) + count( + values + .find(_.value == total(e).value) + .getOrElse(sys.error("Unknown enum value")) + .hints + ) } def struct[S]( diff --git a/modules/core/src/smithy4s/schema/Schema.scala b/modules/core/src/smithy4s/schema/Schema.scala index 3c5739831..142cd8301 100644 --- a/modules/core/src/smithy4s/schema/Schema.scala +++ b/modules/core/src/smithy4s/schema/Schema.scala @@ -66,18 +66,20 @@ sealed trait Schema[A]{ case s: OptionSchema[a] => OptionSchema(s.underlying.transformHintsLocally(f)).asInstanceOf[Schema[A]] } - final def transformHintsTransitively(f: Hints => Hints): Schema[A] = this match { - case PrimitiveSchema(shapeId, hints, tag) => PrimitiveSchema(shapeId, f(hints), tag) - case s: CollectionSchema[c, a] => CollectionSchema[c, a](s.shapeId, f(s.hints), s.tag, s.member.transformHintsTransitively(f)).asInstanceOf[Schema[A]] - case s: MapSchema[k, v] => MapSchema(s.shapeId, f(s.hints), s.key.transformHintsTransitively(f), s.value.transformHintsTransitively(f)).asInstanceOf[Schema[A]] - case EnumerationSchema(shapeId, hints, tag, values, total) => EnumerationSchema(shapeId, f(hints), tag, values.map(_.transformHints(f)), total andThen (_.transformHints(f))) - case StructSchema(shapeId, hints, fields, make) => StructSchema(shapeId, f(hints), fields.map(_.transformHintsTransitively(f)), make) - case UnionSchema(shapeId, hints, alternatives, dispatch) => UnionSchema(shapeId, f(hints), alternatives.map(_.transformHintsTransitively(f)), dispatch) - case BijectionSchema(schema, bijection) => BijectionSchema(schema.transformHintsTransitively(f), bijection) - case RefinementSchema(schema, refinement) => RefinementSchema(schema.transformHintsTransitively(f), refinement) - case LazySchema(suspend) => LazySchema(suspend.map(_.transformHintsTransitively(f))) - case s: OptionSchema[a] => OptionSchema(s.underlying.transformHintsTransitively(f)).asInstanceOf[Schema[A]] - } + final def transformHintsTransitively(f: Hints => Hints): Schema[A] = transformTransitivelyK(new (Schema ~> Schema) { + def apply[B](fa: Schema[B]): Schema[B] = { + val base = fa.transformHintsLocally(f) + + base match { + case EnumerationSchema(shapeId, hints, tag, values, total) => + EnumerationSchema(shapeId, hints, tag, values.map(_.transformHints(f)), total) + + case other => other + } + } + }) + + def transformTransitivelyK(f: Schema ~> Schema): Schema[A] = compile(new TransitiveCompiler(f)) final def validated[C](c: C)(implicit constraint: RefinementProvider.Simple[C, A]): Schema[A] = { val hint = Hints.Binding.fromValue(c)(constraint.tag) @@ -194,9 +196,7 @@ object Schema { * Transforms this schema, and all the schemas inside it, using the provided function. */ def transformTransitivelyK(f: Schema ~> Schema): Schema ~> Schema = new (Schema ~> Schema) { - private val compiler = new TransitiveCompiler(f) - - def apply[A](fa: Schema[A]): Schema[A] = fa.compile(compiler) + def apply[A](fa: Schema[A]): Schema[A] = fa.transformTransitivelyK(f) } // format: on From 2e23c986d1e461afb07d2ff268d89e350f0b8a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Fri, 1 Mar 2024 15:21:16 +0100 Subject: [PATCH 4/6] update changelog again --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e65b9b7d..a9cbed6b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 0.18.11 * Added a utility method, `Schema.transformTransitivelyK`, to help in recursively transforming schemas. +In addition, the semantics of `transformHintsTransitively` have been changed: the transformation no longer modifies the hints on the result of the `total` function. # 0.18.10 From 6e07df8cdd13912c3aec56659656c3da3e2611a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Fri, 1 Mar 2024 15:21:59 +0100 Subject: [PATCH 5/6] empty commit, github is drunk From 39606756c2b0b8b0ef3e8002caf6bde3ec9c03e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Fri, 1 Mar 2024 15:35:33 +0100 Subject: [PATCH 6/6] another empty one