Я узнал, что иерархия универсальных типов scala с другим именем атрибута динамический полиморфизм с экстракторами может решить части моей проблемы.Однако я также узнал, что кошки, котята и бесформенные могут стать путем к чистому решению.К сожалению, я пока не знаком ни с одним из них.Пытаясь построить из приведенного выше примера, я понял, что экстракторов недостаточно.
Как я могу создавать инжекторы?Может даже с бесформенным?И динамически создавать экземпляры подходящих объектов.
Ниже приведен более полный пример использования экстракторов, в котором описаны мои ошибки компиляции:
import org.apache.spark.sql.{Dataset, SparkSession}
sealed trait Db {
def db: String
def table: String
}
case class DataSource(override val db: String,
override val table: String)
extends Db
trait Feed extends BaseConfiguration
trait FooFeedConfiguration extends Feed {
def fooFeed: DataSource
}
trait FeedDataSourceExtractor[F <: Feed] {
def extract(feedDs: F): DataSource
}
implicit val cellFeedEx = new FeedDataSourceExtractor[FooFeedConfiguration] {
override def extract(feedDS: FooFeedConfiguration) = feedDS.fooFeed
}
trait BaseConfiguration {
def applicationName: String
}
trait SparkDatasetProvider[T <: Product, C <: BaseConfiguration] {
def provide(spark: SparkSession, c: C): Dataset[T]
}
def myFunction[T <: Product, F <: Feed, feedProvider <: SparkDatasetProvider[T, F]](spark: SparkSession, c: F)(implicit feedEx: FeedDataSourceExtractor[F]): Dataset[T] = {
val dataSourceWithInterval = feedEx.extract(c)
//FooFeedProvider.provideAndFilter(
feedProvider.provide( // TODO why does this not compile.
spark,
//new FooFeedConfiguration {
new F {
override val applicationName = c.applicationName
override val feed // TODO need some kind of injector
DataSource(dataSourceWithInterval.db, // real code performs some fancy logic here (on other attribute values)
dataSourceWithInterval.table)
}
)
}
final case class FooFeed(foo: Int, bar: String)
object FeedProvider extends SparkDatasetProvider[FooFeed, FooFeedConfiguration] {
override def provide(spark: SparkSession, c: FooFeedConfiguration) = {
import spark.implicits._
spark.sql(s"select * from ${c.fooFeed.db}.${c.fooFeed.table}").as[FooFeed]
}
}
myFunction[FooFeed, FooFeedConfiguration, FeedProvider[FooFeed, FooFeedConfiguration]]()
// cant call FeedProvider
// all these type parameters (duplicated) seem to be not elegant. Is there a better way?