From 2f1b2fcdecd1a8175c1c32679363512a7d19ee3c Mon Sep 17 00:00:00 2001 From: vkorchik Date: Sat, 20 Apr 2024 01:43:05 +0200 Subject: [PATCH] Match union position order with enums and with order in 4.x --- .../sksamuel/avro4s/typeutils/Subtypes.scala | 4 +- .../resources/avro_union_position_enum.json | 6 ++ .../resources/avro_union_position_union.json | 32 +++++++ .../schema/AvroSortPrioritySchemaTest.scala | 83 +++++++++---------- .../schema/AvroUnionPositionSchemaTest.scala | 49 +++++++++++ 5 files changed, 130 insertions(+), 44 deletions(-) create mode 100644 avro4s-core/src/test/resources/avro_union_position_enum.json create mode 100644 avro4s-core/src/test/resources/avro_union_position_union.json create mode 100644 avro4s-core/src/test/scala/com/sksamuel/avro4s/schema/AvroUnionPositionSchemaTest.scala diff --git a/avro4s-core/src/main/scala/com/sksamuel/avro4s/typeutils/Subtypes.scala b/avro4s-core/src/main/scala/com/sksamuel/avro4s/typeutils/Subtypes.scala index c16ad7b2..2137ec4c 100644 --- a/avro4s-core/src/main/scala/com/sksamuel/avro4s/typeutils/Subtypes.scala +++ b/avro4s-core/src/main/scala/com/sksamuel/avro4s/typeutils/Subtypes.scala @@ -14,6 +14,6 @@ object SubtypeOrdering extends Ordering[SealedTrait.Subtype[_, _, _]] { val priorityA = annosA.sortPriority.getOrElse(999999F) val priorityB = annosB.sortPriority.getOrElse(999999F) - if (priorityA == priorityB) namesA.fullName.compare(namesB.fullName) else priorityA.compare(priorityB) + if (priorityA == priorityB) namesA.fullName.compare(namesB.fullName) else priorityB.compare(priorityA) } -} \ No newline at end of file +} diff --git a/avro4s-core/src/test/resources/avro_union_position_enum.json b/avro4s-core/src/test/resources/avro_union_position_enum.json new file mode 100644 index 00000000..a6cf3e0c --- /dev/null +++ b/avro4s-core/src/test/resources/avro_union_position_enum.json @@ -0,0 +1,6 @@ +{ + "type": "enum", + "name": "Numeric", + "namespace": "com.sksamuel.avro4s.schema.AvroUnionPositionSchemaTestContext", + "symbols": ["NaturalNumber", "RationalNumber", "RealNumber"] +} diff --git a/avro4s-core/src/test/resources/avro_union_position_union.json b/avro4s-core/src/test/resources/avro_union_position_union.json new file mode 100644 index 00000000..3fad25ad --- /dev/null +++ b/avro4s-core/src/test/resources/avro_union_position_union.json @@ -0,0 +1,32 @@ +{ + "type": "record", + "name": "FightingStyleWrapper", + "namespace": "com.sksamuel.avro4s.schema.AvroUnionPositionSchemaTestContext", + "fields": [ + { + "name": "fightingstyle", + "type": [ + { + "type": "record", + "name": "DefensiveFightingStyle", + "fields": [ + { + "name": "has_armor", + "type": "boolean" + } + ] + }, + { + "type": "record", + "name": "AggressiveFightingStyle", + "fields": [ + { + "name": "agressiveness", + "type": "float" + } + ] + } + ] + } + ] +} diff --git a/avro4s-core/src/test/scala/com/sksamuel/avro4s/schema/AvroSortPrioritySchemaTest.scala b/avro4s-core/src/test/scala/com/sksamuel/avro4s/schema/AvroSortPrioritySchemaTest.scala index 14a722de..2417a2fe 100644 --- a/avro4s-core/src/test/scala/com/sksamuel/avro4s/schema/AvroSortPrioritySchemaTest.scala +++ b/avro4s-core/src/test/scala/com/sksamuel/avro4s/schema/AvroSortPrioritySchemaTest.scala @@ -1,49 +1,48 @@ -//package com.sksamuel.avro4s.schema -// -//import com.sksamuel.avro4s.{AvroSchema, AvroSortPriority} -// -//import org.scalatest.funsuite.AnyFunSuite -//import org.scalatest.matchers.should.Matchers -// -//class AvroSortPrioritySchemaTest extends AnyFunSuite with Matchers { -// -// test("enums should be sorted by descending priority") { -// val expected = new org.apache.avro.Schema.Parser().parse(getClass.getResourceAsStream("/avro_sort_priority_enum.json")) -// val schema = AvroSchema[Numeric] -// schema.toString(true) shouldBe expected.toString(true) -// } -// -// test("unions should be sorted by descending priority") { -// val expected = new org.apache.avro.Schema.Parser().parse(getClass.getResourceAsStream("/avro_sort_priority_union.json")) -// val schema = AvroSchema[FightingStyleWrapper] -// -// schema.toString(true) shouldBe expected.toString(true) -// } -// +package com.sksamuel.avro4s.schema + +import com.sksamuel.avro4s.{AvroSchema, AvroSortPriority} + +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.should.Matchers + +class AvroSortPrioritySchemaTest extends AnyFunSuite with Matchers { + + test("enums should be sorted by descending priority") { + val expected = new org.apache.avro.Schema.Parser().parse(getClass.getResourceAsStream("/avro_sort_priority_enum.json")) + val schema = AvroSchema[Numeric] + schema.toString(true) shouldBe expected.toString(true) + } + + test("unions should be sorted by descending priority") { + val expected = new org.apache.avro.Schema.Parser().parse(getClass.getResourceAsStream("/avro_sort_priority_union.json")) + val schema = AvroSchema[FightingStyleWrapper] + + schema.toString(true) shouldBe expected.toString(true) + } + // test("avrosortpriority should respect union default ordering") { // val expected = new org.apache.avro.Schema.Parser().parse(getClass.getResourceAsStream("/avro_sort_priority_union_with_default.json")) // val schema = AvroSchema[FightingStyleWrapperWithDefault] // // schema.toString(true) shouldBe expected.toString(true) // } -//} -// -// -//sealed trait Numeric -//@AvroSortPriority(1) -//case object RationalNumber extends Numeric -//@AvroSortPriority(0) -//case object RealNumber extends Numeric -//@AvroSortPriority(2) -//case object NaturalNumber extends Numeric -// -// -//case class FightingStyleWrapper(fightingstyle: FightingStyle) +} + + +sealed trait Numeric +@AvroSortPriority(1) +case object RationalNumber extends Numeric +@AvroSortPriority(0) +case object RealNumber extends Numeric +@AvroSortPriority(2) +case object NaturalNumber extends Numeric + + +case class FightingStyleWrapper(fightingstyle: FightingStyle) //case class FightingStyleWrapperWithDefault(fightingstyle: FightingStyle = AggressiveFightingStyle(10)) -// -//sealed trait FightingStyle -//@AvroSortPriority(2) -//case class AggressiveFightingStyle(agressiveness: Float) extends FightingStyle -//@AvroSortPriority(10) -//case class DefensiveFightingStyle(has_armor: Boolean) extends FightingStyle -// + +sealed trait FightingStyle +@AvroSortPriority(2) +case class AggressiveFightingStyle(agressiveness: Float) extends FightingStyle +@AvroSortPriority(10) +case class DefensiveFightingStyle(has_armor: Boolean) extends FightingStyle diff --git a/avro4s-core/src/test/scala/com/sksamuel/avro4s/schema/AvroUnionPositionSchemaTest.scala b/avro4s-core/src/test/scala/com/sksamuel/avro4s/schema/AvroUnionPositionSchemaTest.scala new file mode 100644 index 00000000..3ddf7b06 --- /dev/null +++ b/avro4s-core/src/test/scala/com/sksamuel/avro4s/schema/AvroUnionPositionSchemaTest.scala @@ -0,0 +1,49 @@ +package com.sksamuel.avro4s.schema + +import com.sksamuel.avro4s.{AvroSchema, AvroUnionPosition} + +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.should.Matchers + +class AvroUnionPositionSchemaTest extends AnyFunSuite with Matchers with AvroUnionPositionSchemaTestContext { + + test("enums should be sorted by ascending union position") { + val expected = new org.apache.avro.Schema.Parser().parse(getClass.getResourceAsStream("/avro_union_position_enum.json")) + val schema = AvroSchema[Numeric] + schema.toString(true) shouldBe expected.toString(true) + } + + test("unions should be sorted by ascending union position") { + val expected = new org.apache.avro.Schema.Parser().parse(getClass.getResourceAsStream("/avro_union_position_union.json")) + val schema = AvroSchema[FightingStyleWrapper] + + schema.toString(true) shouldBe expected.toString(true) + } + +// test("avrosortpriority should respect union default ordering") { +// val expected = new org.apache.avro.Schema.Parser().parse(getClass.getResourceAsStream("/avro_sort_priority_union_with_default.json")) +// val schema = AvroSchema[FightingStyleWrapperWithDefault] +// +// schema.toString(true) shouldBe expected.toString(true) +// } +} + +trait AvroUnionPositionSchemaTestContext { + + sealed trait Numeric + @AvroUnionPosition(2) + case object RationalNumber extends Numeric + @AvroUnionPosition(3) + case object RealNumber extends Numeric + @AvroUnionPosition(1) + case object NaturalNumber extends Numeric + + case class FightingStyleWrapper(fightingstyle: FightingStyle) +// case class FightingStyleWrapperWithDefault(fightingstyle: FightingStyle = AggressiveFightingStyle(10)) + + sealed trait FightingStyle + @AvroUnionPosition(2) + case class AggressiveFightingStyle(agressiveness: Float) extends FightingStyle + @AvroUnionPosition(1) + case class DefensiveFightingStyle(has_armor: Boolean) extends FightingStyle +}