Skip to content

Commit

Permalink
case class schema derivation: inherit namespace from sealed trait (#833)
Browse files Browse the repository at this point in the history
* remove unused parameter

* case classes: inherit namespace from sealed trait

* add default to make it compile with Scala 3
  • Loading branch information
mberndt123 authored May 15, 2024
1 parent be9a4fb commit 01a005a
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ object Records:

def schema[T](ctx: CaseClass[SchemaFor, T]): SchemaFor[T] = {

val annos = Annotations(ctx.annotations)
val naming = Names(ctx.typeInfo, annos, ctx.typeAnnotations)
val annos = Annotations(ctx)
val naming = Names(ctx.typeInfo, annos)
val error = annos.error

val record = Schema.createRecord(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object ValueTypes {
*/
def schema[T](ctx: CaseClass[SchemaFor, T]): Schema =
val annos: Annotations = Annotations(ctx) // taking over @AvroFixed and the like
val names = Names(ctx.typeInfo, annos, ctx.typeAnnotations)
val names = Names(ctx.typeInfo, annos)

// if the class is a value type, then we need to use the schema for the single field inside the type
// in other words, if we have `case class Foo(str: String) extends AnyVal` then this acts just like String.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package com.sksamuel.avro4s.typeutils
import com.sksamuel.avro4s.{AvroAliasable, AvroDoc, AvroDocumentable, AvroErasedName, AvroError, AvroFixed, AvroName, AvroNameable, AvroNamespace, AvroNoDefault, AvroProp, AvroProperty, AvroSortPriority, AvroTransient, AvroUnionPosition}
import magnolia1.{CaseClass, TypeInfo}

class Annotations(annos: Seq[Any]) {
class Annotations(annos: Seq[Any], inheritedAnnos: Seq[Any] = Nil) {
private[this] val allAnnos: Seq[Any] = annos ++ inheritedAnnos

def name: Option[String] = annos.collectFirst {
case t: AvroNameable => t.name
}

def namespace: Option[String] = annos.collectFirst {
def namespace: Option[String] = allAnnos.collectFirst {
case t: AvroNamespace => t.namespace
}

Expand Down Expand Up @@ -60,6 +61,6 @@ class Annotations(annos: Seq[Any]) {
}

object Annotations {
def apply(ctx: CaseClass[_, _]): Annotations = new Annotations(ctx.annotations)
def apply(annos: Seq[Any]): Annotations = new Annotations(annos)
def apply(ctx: CaseClass[_, _]): Annotations = new Annotations(ctx.annotations, ctx.inheritedAnnotations)
def apply(annos: Seq[Any]): Annotations = new Annotations(annos, Nil)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import magnolia1.TypeInfo
* Extracts names and namespaces from a type.
* Takes into consideration provided annotations.
*/
case class Names(typeInfo: TypeInfo, val annos: Annotations, val typeAnnos: Seq[Any] = Nil) {
case class Names(typeInfo: TypeInfo, val annos: Annotations) {

private val defaultNamespace = typeInfo.owner.replaceAll("\\.<local .*?>", "").stripSuffix(".package")

Expand Down Expand Up @@ -62,7 +62,7 @@ case class Names(typeInfo: TypeInfo, val annos: Annotations, val typeAnnos: Seq[
}

object Names {
def apply(info: TypeInfo): Names = Names(info, Annotations(Nil), Nil)
def apply(info: TypeInfo): Names = Names(info, Annotations(Nil))
// def apply[F[_], T](subtype: Subtype[F, T]): NameExtractor = NameExtractor(subtype.typeName, subtype.annotations)
//
// def apply(typeName: TypeName, annos: Seq[Any]): NameExtractor = NameExtractor(TypeInfo(typeName, annos))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.sksamuel.avro4s.schema
import com.sksamuel.avro4s.AvroSchema
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import com.sksamuel.avro4s.AvroNamespace
import com.sksamuel.avro4s.AvroName

class NamespaceSchemaTest extends AnyFunSuite with Matchers {

Expand Down Expand Up @@ -30,6 +32,16 @@ class NamespaceSchemaTest extends AnyFunSuite with Matchers {
val schema = AvroSchema[NamespaceTestFoo]
schema.toString(true) shouldBe expected.toString(true)
}
test("case classes should inherit namespace from parent sealed trait") {
@AvroNamespace("foobar")
@AvroName("Qux")
sealed trait Foo
object Foo {
case class Bla() extends Foo
}
AvroSchema[Foo.Bla].getNamespace() shouldBe "foobar"
AvroSchema[Foo.Bla].getName() shouldBe "Bla"
}
}


Expand Down

0 comments on commit 01a005a

Please sign in to comment.