Skip to content

Commit

Permalink
refactor: make calling the udf source compatible
Browse files Browse the repository at this point in the history
It's annoying to use the Sized class on the call side.
  • Loading branch information
ingarabr committed Aug 25, 2023
1 parent 90fbe2e commit 142cf46
Show file tree
Hide file tree
Showing 6 changed files with 747 additions and 31 deletions.
22 changes: 17 additions & 5 deletions core/src/main/scala/no/nrk/bigquery/UDF.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,34 @@ import no.nrk.bigquery.UDF.UDFId._
import no.nrk.bigquery.syntax._
import shapeless.{Nat, Sized, SizedBuilder, _0}

/** The UDF has an apply method rendering a BQSqlFrag that matches the size of `params`.
*
* ```
* val myUdf =
* UDF.temporary(
* ident"myUdf",
* UDF.Params.of(UDF.Param("foo", BQType.STRING)),
* UDF.Body.SQL(bqfr"(foo)"),
* Some(BQType.STRING)
* )
* bqfr"${myUdf(ident"bar")}" // ok
* bqfr"${myUdf()}" // compile error
* bqfr"${myUdf(ident"bar1", ident"bar")}" // compile error
* ```
*/
sealed trait UDF[+A <: UDFId, N <: Nat] {
def name: A
def params: Sized[Seq[UDF.Param], N]
def returnType: Option[BQType]
def apply(args: Sized[Seq[BQSqlFrag.Magnet], N]): BQSqlFrag.Call =
BQSqlFrag.Call(this, args.unsized.toList.map(_.frag))
}
object UDF {

type Params[N <: Nat] = Sized[IndexedSeq[Param], N]

object Params {
val empty: Sized[IndexedSeq[UDF.Param], _0] = Sized.wrap[IndexedSeq[UDF.Param], _0](IndexedSeq.empty[UDF.Param])
def apply = new SizedBuilder[
IndexedSeq
]() // todo: figure out why we need to explicit call apply. Might be related to the type alias
// todo: figure out why we need to explicit call apply. Might be related to the type alias
def apply = new SizedBuilder[IndexedSeq]()
def of = new SizedBuilder[IndexedSeq]()
}

Expand Down
14 changes: 2 additions & 12 deletions core/src/main/scala/no/nrk/bigquery/internal/BQShowSyntax.scala
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
package no.nrk.bigquery.internal

import no.nrk.bigquery.{BQFill, BQFilledTable, BQShow, BQSqlFrag, UDF}
import no.nrk.bigquery.{BQFill, BQFilledTable, BQShow, BQSqlFrag}
import cats.Foldable
import cats.syntax.all._
import shapeless._0

import java.time.LocalDate

trait BQShowSyntax {
trait BQShowSyntax extends UdfSyntax {

implicit def bqShowInterpolator(sc: StringContext): BQShow.BQShowInterpolator = new BQShow.BQShowInterpolator(sc)
implicit def bqShowOps[A](a: A): BQShowOps[A] = new BQShowOps[A](a)
implicit def bqFragmentsOps[S[_]: Foldable, A](values: S[A]): FragmentsOps[S, A] = new FragmentsOps(values)
implicit def bqFilledTableLocalDateOps(fill: BQFilledTable[LocalDate]): BQFilledTableLocalDateOps =
new BQFilledTableLocalDateOps(fill)

implicit def bqUdfOps(udf: UDF[UDF.UDFId, _0]): UdfOps = new UdfOps(udf)
}

/** Makes it possible to call UDFs with no arguments. Shapeless Sized does not by default have an empty instance and we
* do not want to clutter the api with it.
*/
// todo: consider if we should create apply methods matching the Nat class. Then we do not need to think about the Sized instance
class UdfOps(udf: UDF[UDF.UDFId, _0]) {
def apply(): BQSqlFrag.Call = BQSqlFrag.Call(udf, List.empty)
}

class BQShowOps[A](a: A) {
Expand Down
Loading

0 comments on commit 142cf46

Please sign in to comment.