All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.nrk.bigquery.client.http4s.internal.RoutineHelper.scala Maven / Gradle / Ivy

/*
 * Copyright 2020 NRK
 *
 * SPDX-License-Identifier: MIT
 */

package no.nrk.bigquery
package client.http4s.internal

import cats.syntax.all.*
import googleapis.bigquery.*
import no.nrk.bigquery.util.ToSized

object RoutineHelper {
  def fromGoogle(routine: Routine): Either[String, BQPersistentRoutine.Unknown] =
    for {
      ref <- routine.routineReference.toRight("No routine reference defined")
      tpe <- routine.routineType.toRight("No routine type defined")
      converted <- tpe match {
        case RoutineRoutineType.SCALAR_FUNCTION => toUDF(routine, ref)
        case RoutineRoutineType.TABLE_VALUED_FUNCTION => toTVF(routine, ref)
        case x => Left(s"routine type '${x.value}' is not supported")
      }

    } yield converted

  def toGoogle(routine: BQPersistentRoutine.Unknown, existing: Option[Routine]) =
    routine match {
      case TVF(name, _, params, query, schema, description) =>
        val patching = existing.getOrElse(
          Routine(
            routineReference = Some(
              RoutineReference(
                projectId = Some(name.dataset.project.value),
                datasetId = Some(name.dataset.id),
                routineId = Some(name.name.value))),
            language = Some(RoutineLanguage.SQL),
            routineType = Some(RoutineRoutineType.TABLE_VALUED_FUNCTION)
          ))

        patching.copy(
          arguments = Some(
            params.unsized
              .map(p => Argument(name = Some(p.name.value), dataType = p.maybeType.map(SchemaHelper.fromBQType)))
              .toList),
          definitionBody = Some(query.asString),
          returnTableType = Some(SchemaHelper.toTableType(schema)),
          description = description
        )

      case UDF.Persistent(name, params, body, returnType, description) =>
        val (lang, bodyString, imports) = body match {
          case UDF.Body.Sql(bd) => (RoutineLanguage.SQL, bd.asString, None)
          case UDF.Body.Js(bd, imports) => (RoutineLanguage.JAVASCRIPT, bd, Some(imports))
        }
        val patching = existing.getOrElse(
          Routine(
            routineReference = Some(
              RoutineReference(
                projectId = Some(name.dataset.project.value),
                datasetId = Some(name.dataset.id),
                routineId = Some(name.name.value))),
            language = Some(lang),
            routineType = Some(RoutineRoutineType.SCALAR_FUNCTION)
          ))

        patching.copy(
          arguments = Some(
            params.unsized
              .map(p => Argument(name = Some(p.name.value), dataType = p.maybeType.map(SchemaHelper.fromBQType)))
              .toList),
          definitionBody = Some(bodyString),
          importedLibraries = imports,
          returnType = returnType.map(SchemaHelper.fromBQType),
          description = description
        )
    }

  def toUdfId(ref: RoutineReference) =
    (ref.projectId, ref.datasetId, ref.routineId).mapN((a, b, c) =>
      UDF.UDFId.PersistentId(BQDataset.Ref(ProjectId.unsafeFromString(a), b), Ident(c)))

  def toTVFId(ref: RoutineReference) =
    (ref.projectId, ref.datasetId, ref.routineId).mapN((a, b, c) =>
      TVF.TVFId(BQDataset.Ref(ProjectId.unsafeFromString(a), b), Ident(c)))

  def toParam(argument: Argument) =
    (argument.name, argument.dataType).mapN((name, dt) => BQRoutine.Param(Ident(name), SchemaHelper.toBQType(dt)))

  def toUDF(routine: Routine, ref: RoutineReference) =
    for {
      id <- toUdfId(ref).toRight("Not possible to create UDF.UDFId.PersistentId")
      params = routine.arguments.getOrElse(Nil).flatMap(toParam)
      lang <- routine.language.toRight("No language defined")
      body <- lang match {
        case RoutineLanguage.SQL =>
          Right(UDF.Body.Sql(routine.definitionBody.map(BQSqlFrag.Frag.apply).getOrElse(BQSqlFrag.Empty)))
        case RoutineLanguage.JAVASCRIPT =>
          Right(
            UDF.Body.Js(
              routine.definitionBody.getOrElse(""),
              routine.importedLibraries.getOrElse(Nil)
            ))
        case x => Left(s"Unsupported language: '$x'")
      }
    } yield UDF.Persistent(
      id,
      ToSized(params),
      body,
      routine.returnType.flatMap(SchemaHelper.toBQType),
      routine.description
    )

  def toTVF(routine: Routine, ref: RoutineReference) =
    for {
      id <- toTVFId(ref).toRight("Not possible to create TVF.TVFId")
      params = routine.arguments.getOrElse(Nil).flatMap(toParam)
    } yield TVF(
      id,
      BQPartitionType.NotPartitioned,
      ToSized(params),
      routine.definitionBody.map(BQSqlFrag.Frag.apply).getOrElse(BQSqlFrag.Empty),
      routine.returnTableType.flatMap(SchemaHelper.fromTableType).getOrElse(BQSchema.of())
    )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy