Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

case class schema derivation: inherit namespace from sealed trait #833

Merged
merged 3 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading