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

Inject Product super to generated case classes #296

Merged
merged 2 commits into from
Feb 27, 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
11 changes: 10 additions & 1 deletion src/main/scala/com/spotify/scio/AnnotationTypeInjector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package com.spotify.scio

import java.io.File
import java.nio.charset.Charset
import java.nio.file.{Paths, Files as JFiles}
import java.nio.file.{Files as JFiles, Paths}
import com.google.common.base.Charsets
import com.google.common.hash.Hashing
import com.google.common.io.Files
Expand All @@ -34,6 +34,15 @@ import scala.collection.mutable

object AnnotationTypeInjector {
private val Log = Logger.getInstance(classOf[AnnotationTypeInjector])

// case classes implement Product trait
val CaseClassSuper: String = "_root_.scala.Product"
val CaseClassFunctions: Seq[String] = Seq(
"def productArity: _root_.scala.Int = ???",
"def productElement(n: _root_.scala.Int): _root_.scala.Any = ???",
"def canEqual(x: _root_.scala.Any): _root_.scala.Boolean = ???"
)

private val CaseClassArgs = """case\s+class\s+[^(]+\((.*)\).*""".r
private val TypeArg = """[a-zA-Z0-9_$]+\s*:\s*[a-zA-Z0-9._$]+([\[(](.*?)[)\]]+)?""".r
private val AlertEveryMissedXInvocations = 5
Expand Down
26 changes: 11 additions & 15 deletions src/main/scala/com/spotify/scio/AvroTypeInjector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ object AvroTypeInjector {
s"$AvroTNamespace.fromPath",
s"$AvroTNamespace.toSchema"
)
private val CaseClassSuper =

private val HasAvroAnnotationSuper =
"_root_.com.spotify.scio.avro.types.AvroType.HasAvroAnnotation"

private def avroAnnotation(sc: ScClass): Option[String] =
Expand All @@ -44,25 +45,20 @@ final class AvroTypeInjector extends AnnotationTypeInjector {
override def injectFunctions(source: ScTypeDefinition): Seq[String] =
source match {
case c: ScClass if avroAnnotation(c).isDefined =>
val result = for {
cc <- Option(c.containingClass)
qn <- Option(cc.getQualifiedName)
val fields = for {
cc <- Option(c.containingClass).toSeq
qn <- Option(cc.getQualifiedName).toSeq
parent = qn.init
defs <- {
generatedCaseClasses(parent, c)
.find(_.contains(CaseClassSuper))
.map(getApplyPropsSignature)
.map(v => s"def $v = ???")
}
} yield defs

result.toSeq
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt this ever worked. This was returning a

List("def List(p1: Type1, p2: Type2) = ???")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that does not seem helpful...

cls <- generatedCaseClasses(parent, c).find(_.contains(HasAvroAnnotationSuper)).toSeq
v <- getApplyPropsSignature(cls)
} yield s"def $v = ???"
CaseClassFunctions ++ fields
case _ => Seq.empty
}

override def injectSupers(source: ScTypeDefinition): Seq[String] =
source match {
case c: ScClass if avroAnnotation(c).isDefined => Seq(CaseClassSuper)
case c: ScClass if avroAnnotation(c).isDefined => Seq(CaseClassSuper, HasAvroAnnotationSuper)
case _ => Seq.empty
}

Expand All @@ -77,7 +73,7 @@ final class AvroTypeInjector extends AnnotationTypeInjector {
case c: ScClass if avroAnnotation(c).isDefined =>
val (annotated, other) =
generatedCaseClasses(source.getQualifiedName.init, c).partition(
_.contains(CaseClassSuper)
_.contains(HasAvroAnnotationSuper)
)
(c, (annotated.headOption, other))
}
Expand Down
30 changes: 12 additions & 18 deletions src/main/scala/com/spotify/scio/BigQueryTypeInjector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ object BigQueryTypeInjector {
s"$BQTNamespace.toTable"
)

private val CaseClassSuper =
private val HasAnnotationSuper =
"_root_.com.spotify.scio.bigquery.types.BigQueryType.HasAnnotation"

private def bqAnnotation(sc: ScClass): Option[String] =
Expand Down Expand Up @@ -76,14 +76,12 @@ object BigQueryTypeInjector {
annotation match {
case a if a.contains(FromQuery) =>
val simple = """
|def query: _root_.java.lang.String = ???
|def queryRaw: _root_.java.lang.String = ???
|""".stripMargin

bqQuerySignature(c)
.map { params =>
simple + s"""
|def query($params): _root_.java.lang.String = ???
|def queryAsSource($params): _root_.com.spotify.scio.bigquery.Query = ???
|""".stripMargin
}
Expand All @@ -110,25 +108,21 @@ final class BigQueryTypeInjector extends AnnotationTypeInjector {
override def injectFunctions(source: ScTypeDefinition): Seq[String] =
source match {
case c: ScClass if bqAnnotation(c).isDefined =>
val result = for {
cc <- Option(c.containingClass)
qn <- Option(cc.getQualifiedName)
val fields = for {
cc <- Option(c.containingClass).toSeq
qn <- Option(cc.getQualifiedName).toSeq
parent = qn.init
defs <- {
generatedCaseClasses(parent, c)
.find(_.contains(CaseClassSuper))
.map(getApplyPropsSignature)
.map(v => s"def $v = ???")
}
} yield defs

result.toSeq
case _ => Seq.empty
cls <- generatedCaseClasses(parent, c).find(_.contains(HasAnnotationSuper)).toSeq
v <- getApplyPropsSignature(cls)
} yield s"def $v = ???"
CaseClassFunctions ++ fields
case _ =>
Seq.empty
}

override def injectSupers(source: ScTypeDefinition): Seq[String] =
source match {
case c: ScClass if bqAnnotation(c).isDefined => Seq(CaseClassSuper)
case c: ScClass if bqAnnotation(c).isDefined => Seq(CaseClassSuper, HasAnnotationSuper)
case _ => Seq.empty
}

Expand All @@ -143,7 +137,7 @@ final class BigQueryTypeInjector extends AnnotationTypeInjector {
case c: ScClass if bqAnnotation(c).isDefined =>
val (annotated, other) =
generatedCaseClasses(source.getQualifiedName.init, c).partition(
_.contains(CaseClassSuper)
_.contains(HasAnnotationSuper)
)
(c, (annotated.headOption, other))
}
Expand Down