cats.data.NonEmptyList Scala Examples

The following examples show how to use cats.data.NonEmptyList. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: PureConfigModule.scala    From scala-server-toolkit   with MIT License 5 votes vote down vote up
package com.avast.sst.pureconfig

import cats.data.NonEmptyList
import cats.effect.Sync
import cats.syntax.either._
import pureconfig.error.{ConfigReaderFailure, ConfigReaderFailures, ConvertFailure}
import pureconfig.{ConfigReader, ConfigSource}

import scala.reflect.ClassTag


  def makeOrRaise[F[_]: Sync, A: ConfigReader: ClassTag](source: ConfigSource): F[A] = Sync[F].delay(source.loadOrThrow[A])

  private def convertFailures(failures: ConfigReaderFailures): NonEmptyList[String] = {
    NonEmptyList(failures.head, failures.tail.toList).map(formatFailure)
  }

  private def formatFailure(configReaderFailure: ConfigReaderFailure): String = {
    configReaderFailure match {
      case convertFailure: ConvertFailure =>
        s"Invalid configuration ${convertFailure.path}: ${convertFailure.description}"
      case configFailure =>
        s"Invalid configuration : ${configFailure.description}"
    }
  }

} 
Example 2
Source File: MySQLSocket.scala    From asyncdb   with Apache License 2.0 5 votes vote down vote up
package io.asyncdb
package netty
package mysql

import cats.syntax.all._
import cats.effect._
import cats.effect.concurrent._
import cats.data.NonEmptyList
import io.netty.bootstrap.Bootstrap
import io.netty.channel.{Channel, ChannelInitializer}
import java.nio.charset.Charset
import protocol.client._
import protocol.server._

case class MySQLSocketConfig(
  bootstrap: Bootstrap,
  username: String,
  password: Option[String],
  database: Option[String],
  charset: Short,
  authMethod: Option[String]
) extends NettySocketConfig

class MySQLSocket[F[_]](
  config: MySQLSocketConfig,
  channelHolder: Deferred[F, Either[Throwable, Channel]],
  ref: MsgRef[F]
)(implicit F: Concurrent[F])
    extends NettySocket[F, Message](config, channelHolder) {

  def connect = {
    open.flatMap(_.read).as(this)
  }

  def disconnect = {
    close.void
  }

  def write(n: Message) = {
    channel.flatMap(_.write(n).to[F]).void
  }

  def read = ref.take.flatMap {
    case OrErr(value) =>
      F.fromEither(value)
    case v => F.pure(v)
  }
}

object MySQLSocket {
  def apply[F[_]: ConcurrentEffect](config: MySQLSocketConfig) = {
    for {
      msgRef   <- MVar[F].empty[Message]
      clientCS <- Deferred[F, Charset]
      initCtx = ChannelContext(
        ChannelState.Handshake.WaitHandshakeInit,
        clientCS
      )
      ctxRef <- Ref[F].of(initCtx)
      decoder = new FrameDecoder[F](config, ctxRef, msgRef)
      encoder = new FrameEncoder(config)
      initHandler = new ChannelInitializer[Channel] {
        override def initChannel(channel: Channel): Unit = {
          channel
            .pipeline()
            .addLast("MySQLFrameDecoder", decoder)
            .addLast("MySQLFrameEncoder", encoder)
        }
      }
      _ = config.bootstrap.handler(initHandler)
      channel <- Deferred[F, Either[Throwable, Channel]]
    } yield new MySQLSocket[F](config, channel, msgRef)
  }
} 
Example 3
Source File: AsOpenApiParam.scala    From typed-schema   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.tschema.swagger
import cats.data.NonEmptyList
import derevo.Derivation
import magnolia.{CaseClass, Magnolia, SealedTrait}

sealed trait AsOpenApiParam[T] {
  def types: Map[String, DescribedType]
  def optional: AsOpenApiParam[Option[T]]
}

object AsOpenApiParam extends AsOpenParamInstances[AsOpenApiParam] with Derivation[AsOpenApiParam] {
  type Typeclass[x] = AsOpenApiParam[x]

  def apply[T](param: AsOpenApiParam[T]): AsOpenApiParam[T] = param

  def combine[T](ctx: CaseClass[Typeclass, T]): Typeclass[T] =
    AsMultiOpenApiParam[T](
      NonEmptyList
        .fromListUnsafe(ctx.parameters.toList)
        .flatMap { param =>
          param.typeclass match {
            case AsSingleOpenApiParam(t, r) => NonEmptyList.of(OpenApiParamField(param.label, t, r))
            case AsMultiOpenApiParam(ps)    => ps
          }
        }
    )

  def generate[T]: Typeclass[T] = macro Magnolia.gen[T]
  def instance[T]: Typeclass[T] = macro Magnolia.gen[T]
}

trait OpenApiParamInfo {
  def typ: SwaggerType
  def required: Boolean
  def types = typ.collectTypes
}
final case class OpenApiParamField(name: String, typ: SwaggerType, required: Boolean) extends OpenApiParamInfo

final case class AsMultiOpenApiParam[T](fields: NonEmptyList[OpenApiParamField]) extends AsOpenApiParam[T] {
  def parts: NonEmptyList[String]              = fields.map(_.name)
  def types                                    = fields.foldLeft(Map.empty[String, DescribedType])(_ ++ _.types)
  def optional: AsMultiOpenApiParam[Option[T]] = AsMultiOpenApiParam(fields.map(_.copy(required = false)))
}
final case class AsSingleOpenApiParam[T](typ: SwaggerType, required: Boolean = true)
    extends AsOpenApiParam[T] with OpenApiParamInfo {
  def optional: AsOpenApiParam[Option[T]] = AsSingleOpenApiParam(typ, required = false)
}

object AsSingleOpenApiParam extends AsOpenParamInstances[AsSingleOpenApiParam]

trait AsOpenParamInstances[TC[x] >: AsSingleOpenApiParam[x]] {
  final implicit def requiredParam[T](implicit typ: SwaggerTypeable[T]): TC[T]                 =
    AsSingleOpenApiParam[T](typ = typ.typ, required = true)
  final implicit def optParam[T](implicit param: AsOpenApiParam[T]): AsOpenApiParam[Option[T]] = param.optional
} 
Example 4
Source File: BackwardsTest.scala    From newts   with Apache License 2.0 5 votes vote down vote up
package newts

import cats._
import cats.data.{NonEmptyList, Writer}
import cats.implicits._
import cats.kernel.laws.discipline.{EqTests, OrderTests}
import cats.laws.discipline.{AlternativeTests, ApplicativeErrorTests, CommutativeApplicativeTests, DistributiveTests, FunctorFilterTests, NonEmptyTraverseTests}
import cats.laws.discipline.arbitrary._
import fixtures.ShowTestClass

class BackwardsTest extends NewtsSuite {

  checkAll("Backwards[Option, Int]", EqTests[Backwards[Option, Int]].eqv)
  checkAll("Backwards[Option, Int]", OrderTests[Backwards[Option, Int]].order)
  checkAll("Backwards[Option, Int]", AlternativeTests[Backwards[Option, ?]].alternative[Int, Int, Int])
  checkAll("Backwards[Option, Int]", CommutativeApplicativeTests[Backwards[Option, ?]].commutativeApplicative[Int, Int, Int])
  checkAll("Backwards[Last, Int]]", DistributiveTests[Backwards[Last, ?]].distributive[Int, Int, Int, Option, Function0])
  checkAll("Backwards[List, Int]", FunctorFilterTests[Backwards[List, ?]].functorFilter[Int, Int, Int])
  checkAll("Backwards[NonEmptyList, Int]", NonEmptyTraverseTests[Backwards[NonEmptyList, ?]].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option])
  checkAll("Backwards[Either[String, ?], Int]", ApplicativeErrorTests[Backwards[Either[String, ?], ?], String].applicativeError[Int, Int, Int])

  test("applies actions in reverse order") {
    val f1 = Writer.tell(List(1)) *> Writer.value(1)
    val f2 = Writer.tell(List(2)) *> Writer.value(2)
    val f3 = Writer.tell(List(3)) *> Writer.value(3)

    val composed = (Backwards(f1), Backwards(f2), Backwards(f3)).mapN(Tuple3.apply).forwards

    composed.value shouldEqual ((1, 2, 3))
    composed.written shouldEqual List(3, 2, 1)
  }

  test("show") {
    Backwards(Option("aString")).show shouldEqual "Backwards(Some(aString))"
    Backwards(List(42, 24)).show shouldEqual "Backwards(List(42, 24))"
    Backwards(Writer("log", new ShowTestClass)).show shouldEqual s"Backwards((log,${ShowTestClass.show}))"
  }
} 
Example 5
Source File: ReverseTest.scala    From newts   with Apache License 2.0 5 votes vote down vote up
package newts

import cats._
import cats.data.{NonEmptyList, Writer}
import cats.implicits._
import cats.kernel.laws.discipline.{EqTests, OrderTests}
import cats.laws.discipline.arbitrary._
import cats.laws.discipline.{AlternativeTests, BimonadTests, CommutativeMonadTests, DistributiveTests, FunctorFilterTests, MonadErrorTests, NonEmptyTraverseTests}
import fixtures.ShowTestClass

class ReverseTest extends NewtsSuite {

  checkAll("Reverse[Option, Int]", EqTests[Reverse[Option, Int]].eqv)
  checkAll("Reverse[Option, Int]", OrderTests[Reverse[Option, Int]].order)
  checkAll("Reverse[Option, Int]", AlternativeTests[Reverse[Option, ?]].alternative[Int, Int, Int])
  checkAll("Reverse[Option, Int]", CommutativeMonadTests[Reverse[Option, ?]].commutativeMonad[Int, Int, Int])
  checkAll("Reverse[Last, Int]]", DistributiveTests[Reverse[Last, ?]].distributive[Int, Int, Int, Option, Function0])
  checkAll("Reverse[List, Int]", FunctorFilterTests[Reverse[List, ?]].functorFilter[Int, Int, Int])
  checkAll("Reverse[NonEmptyList, Int]", BimonadTests[Reverse[NonEmptyList, ?]].bimonad[Int, Int, Int])
  checkAll("Reverse[NonEmptyList, Int]", NonEmptyTraverseTests[Reverse[NonEmptyList, ?]].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option])
  checkAll("Reverse[Either[String, ?], Int]", MonadErrorTests[Reverse[Either[String, ?], ?], String].monadError[Int, Int, Int])

  type RevList[A] = Reverse[List, A]

  test("is folded in reverse order") {
    Reverse(List("a", "b", "c")).foldLeft("")(_ ++ _) shouldBe "cba"
    Reverse(List("a", "b", "c")).foldRight(Eval.now(""))((x, y) => Eval.now(x ++ y.value)).value shouldBe "cba"
  }

  test("is traversed in reverse order") {
    def write(n: Int): Writer[List[Int], Int] = Writer.tell(List(n)) *> Writer.value(n)

    val result: Writer[List[Int], List[Int]] = Reverse(List(1,2,3)).traverse(write).map(_.getReverse)

    result.value shouldEqual List(1,2,3)
    result.written shouldEqual List(3,2,1)
  }

  test("show") {
    Reverse(Option("aString")).show shouldEqual "Reverse(Some(aString))"
    Reverse(List(42, 24)).show shouldEqual "Reverse(List(42, 24))"
    Reverse(Writer("log", new ShowTestClass)).show shouldEqual s"Reverse((log,${ShowTestClass.show}))"
  }
} 
Example 6
Source File: DualTest.scala    From newts   with Apache License 2.0 5 votes vote down vote up
package newts

import cats.Id
import cats.data.NonEmptyList
import cats.kernel.laws.discipline.{EqTests, MonoidTests, SemigroupTests}
import cats.laws.discipline.{DistributiveTests, MonadTests, TraverseTests}
import cats.laws.discipline.arbitrary._
import fixtures.ShowTestClass

class DualTest extends NewtsSuite {

  checkAll("Dual[NonEmptyList[Int]]", SemigroupTests[Dual[NonEmptyList[Int]]].semigroup)
  checkAll("Dual[List[Int]]"        , MonoidTests[Dual[List[Int]]].monoid)
  checkAll("Dual[Int]"              , EqTests[Dual[Int]].eqv)
  checkAll("Dual[Int]"              , MonadTests[Dual].monad[Int, Int, Int])
  checkAll("Dual[Int]"              , TraverseTests[Dual].traverse[Int, Int, Int, Int, Option, Option])
  checkAll("Dual[Int]"              , DistributiveTests[Dual].distributive[Int, Int, Int, Option, Id])

  test("combine"){
    val xs = NonEmptyList.of(1,2)
    val ys = NonEmptyList.of(3,4)

    xs.asDual |+| ys.asDual shouldEqual (ys |+| xs).asDual
  }

  test("show") {
    Dual("aString").show shouldEqual "Dual(aString)"
    Dual(42).show shouldEqual "Dual(42)"
    Dual(new ShowTestClass).show shouldEqual s"Dual(${ShowTestClass.show})"
  }

  test("dual of first is last"){
    val xs = NonEmptyList(1, List(2,3,4,5))

    xs.reduceMap(_.asFirst.asDual).getDual.getFirst shouldEqual 5
  }
} 
Example 7
Source File: CoreSummonSpec.scala    From interop-cats   with Apache License 2.0 5 votes vote down vote up
package zio.interop.test

import cats.data.NonEmptyList
import cats.{ Bifunctor, Monad, MonadError, SemigroupK }
import zio._
import zio.interop.catz.core._
import zio.stream.interop.catz.core._
import zio.stream.{ Stream, ZStream }
import zio.test.Assertion._
import zio.test.{ DefaultRunnableSpec, test, _ }

object CoreSummonSpecextends extends DefaultRunnableSpec {
  override def spec =
    suite("summons from catz.core work with only a cats-core dependency")(
      test("ZIO instances") {
        val monad      = implicitly[Monad[UIO]]
        val monadError = implicitly[MonadError[Task, Throwable]]
        val semigroupK = implicitly[SemigroupK[IO[NonEmptyList[Unit], ?]]]
        val bifunctor  = implicitly[Bifunctor[IO]]

        monad.map(ZIO.unit)(identity)
        monadError.map(ZIO.unit)(identity)
        semigroupK.combineK(ZIO.unit, ZIO.unit)
        bifunctor.leftMap(ZIO.fromOption(None))(identity)

        assert(())(anything)
      },
      test("ZManaged instances") {
        val monad      = implicitly[Monad[ZManaged[Any, Nothing, ?]]]
        val monadError = implicitly[MonadError[Managed[Throwable, ?], Throwable]]
        val semigroupK = implicitly[SemigroupK[Managed[Nothing, ?]]]
        val bifunctor  = implicitly[Bifunctor[Managed]]

        monad.map(ZManaged.unit)(identity)
        monadError.map(ZManaged.unit)(identity)
        semigroupK.combineK(ZManaged.unit, ZManaged.unit)
        bifunctor.leftMap(ZManaged.fail(()))(identity)

        assert(())(anything)
      },
      test("ZStream instances") {
        val monad      = implicitly[Monad[ZStream[Any, Nothing, ?]]]
        val monadError = implicitly[MonadError[Stream[Throwable, ?], Throwable]]
        val semigroupK = implicitly[SemigroupK[Stream[Nothing, ?]]]
        val bifunctor  = implicitly[Bifunctor[Stream]]

        monad.map(ZStream.unit)(identity)
        monadError.map(ZStream.unit)(identity)
        semigroupK.combineK(ZStream.unit, ZStream.unit)
        bifunctor.leftMap(ZStream.fail(()))(identity)

        assert(())(anything)
      }
    )

} 
Example 8
Source File: TapirCodecCats.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.codec.cats

import cats.data.{NonEmptyChain, NonEmptyList, NonEmptySet}
import sttp.tapir.{Schema, SchemaType}
import sttp.tapir._

import scala.collection.immutable.SortedSet

trait TapirCodecCats {

  private def nonEmpty[T, C[X] <: Iterable[X]]: Validator.Primitive[C[T]] = Validator.minSize[T, C](1)

  private def iterableAndNonEmpty[T, C[X] <: Iterable[X]](implicit v: Validator[T]): Validator[C[T]] =
    v.asIterableElements[C].and(nonEmpty)

  implicit def validatorNel[T: Validator]: Validator[NonEmptyList[T]] =
    iterableAndNonEmpty[T, List].contramap(_.toList)

  implicit def validatorNec[T: Validator]: Validator[NonEmptyChain[T]] =
    iterableAndNonEmpty[T, List].contramap(_.toChain.toList)

  implicit def validatorNes[T: Validator]: Validator[NonEmptySet[T]] =
    iterableAndNonEmpty[T, Set].contramap(_.toSortedSet)

  implicit def schemaForNel[T: Schema]: Schema[NonEmptyList[T]] =
    Schema[NonEmptyList[T]](SchemaType.SArray(implicitly[Schema[T]])).copy(isOptional = false)

  implicit def schemaForNec[T: Schema]: Schema[NonEmptyChain[T]] =
    Schema[NonEmptyChain[T]](SchemaType.SArray(implicitly[Schema[T]])).copy(isOptional = false)

  implicit def schemaForNes[T: Schema]: Schema[NonEmptySet[T]] =
    Schema[NonEmptySet[T]](SchemaType.SArray(implicitly[Schema[T]])).copy(isOptional = false)

  implicit def codecForNonEmptyList[L, H, CF <: CodecFormat](implicit c: Codec[L, List[H], CF]): Codec[L, NonEmptyList[H], CF] =
    c.modifySchema(_.copy(isOptional = false))
      .validate(nonEmpty)
      .mapDecode { l => DecodeResult.fromOption(NonEmptyList.fromList(l)) }(_.toList)

  implicit def codecForNonEmptyChain[L, H, CF <: CodecFormat](implicit c: Codec[L, List[H], CF]): Codec[L, NonEmptyChain[H], CF] =
    c.modifySchema(_.copy(isOptional = false))
      .validate(nonEmpty)
      .mapDecode { l => DecodeResult.fromOption(NonEmptyChain.fromSeq(l)) }(_.toNonEmptyList.toList)

  implicit def codecForNonEmptySet[L, H: Ordering, CF <: CodecFormat](implicit c: Codec[L, Set[H], CF]): Codec[L, NonEmptySet[H], CF] =
    c.modifySchema(_.copy(isOptional = false))
      .validate(nonEmpty)
      .mapDecode { set => DecodeResult.fromOption(NonEmptySet.fromSet(SortedSet(set.toSeq: _*))) }(_.toSortedSet)
} 
Example 9
Source File: PlayServerTests.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.server.play

import akka.actor.ActorSystem
import cats.data.NonEmptyList
import cats.effect.{IO, Resource}
import play.api.Mode
import play.api.mvc.{Handler, RequestHeader}
import play.api.routing.Router
import play.api.routing.Router.Routes
import play.core.server.{DefaultAkkaHttpServerComponents, ServerConfig}
import sttp.tapir.Endpoint
import sttp.tapir.server.tests.ServerTests
import sttp.tapir.server.{DecodeFailureHandler, ServerDefaults, ServerEndpoint}
import sttp.tapir.tests.{Port, PortCounter}

import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Await, Future}
import scala.reflect.ClassTag

class PlayServerTests extends ServerTests[Future, Nothing, Router.Routes] {
  override def multipleValueHeaderSupport: Boolean = false
  override def multipartInlineHeaderSupport: Boolean = false
  override def streamingSupport: Boolean = false

  private implicit val actorSystem: ActorSystem = ActorSystem()

  override protected def afterAll(): Unit = {
    Await.result(actorSystem.terminate(), 5.seconds)
    super.afterAll()
  }

  override def pureResult[T](t: T): Future[T] = Future.successful(t)

  override def suspendResult[T](t: => T): Future[T] = Future(t)

  override def route[I, E, O](
      e: ServerEndpoint[I, E, O, Nothing, Future],
      decodeFailureHandler: Option[DecodeFailureHandler]
  ): Routes = {
    implicit val serverOptions: PlayServerOptions =
      PlayServerOptions.default.copy(decodeFailureHandler = decodeFailureHandler.getOrElse(ServerDefaults.decodeFailureHandler))
    e.toRoute
  }

  override def routeRecoverErrors[I, E <: Throwable, O](e: Endpoint[I, E, O, Nothing], fn: I => Future[O])(implicit
      eClassTag: ClassTag[E]
  ): Routes = {
    e.toRouteRecoverErrors(fn)
  }

  override def server(routes: NonEmptyList[Routes], port: Port): Resource[IO, Unit] = {
    val components = new DefaultAkkaHttpServerComponents {
      override lazy val serverConfig: ServerConfig = ServerConfig(port = Some(port), address = "127.0.0.1", mode = Mode.Test)
      override def router: Router =
        Router.from(
          routes.reduce((a: Routes, b: Routes) => {
            val handler: PartialFunction[RequestHeader, Handler] = {
              case request => a.applyOrElse(request, b)
            }

            handler
          })
        )
    }
    val bind = IO {
      components.server
    }
    Resource.make(bind)(s => IO(s.stop())).map(_ => ())
  }

  override val portCounter: PortCounter = new PortCounter(38000)
} 
Example 10
Source File: VertxServerTests.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.server.vertx

import cats.data.NonEmptyList
import cats.effect.{IO, Resource}
import cats.implicits._
import io.vertx.lang.scala.VertxExecutionContext
import io.vertx.scala.core.Vertx
import io.vertx.scala.core.http.HttpServerOptions
import io.vertx.scala.ext.web.{Route, Router}
import org.scalatest.BeforeAndAfterEach
import sttp.tapir._
import sttp.tapir.server.tests.ServerTests
import sttp.tapir.server.{DecodeFailureHandler, ServerDefaults, ServerEndpoint}
import sttp.tapir.tests.{Port, PortCounter}

import scala.concurrent.Future
import scala.reflect.ClassTag

class VertxServerTests extends ServerTests[Future, String, Router => Route] with BeforeAndAfterEach {

  implicit val options: VertxEndpointOptions = VertxEndpointOptions()
    .logWhenHandled(true)
    .logAllDecodeFailures(true)

  override def multipartInlineHeaderSupport: Boolean = false // README: doesn't seem supported but I may be wrong

  protected var vertx: Vertx = _

  override def beforeAll(): Unit = {
    super.beforeAll()
    vertx = Vertx.vertx()
  }

  override def afterAll(): Unit = {
    super.afterAll()
    vertx.close()
  }

  override def pureResult[T](t: T): Future[T] = Future.successful(t)
  override def suspendResult[T](t: => T): Future[T] = Future(t)(VertxExecutionContext(vertx.getOrCreateContext()))

  override def route[I, E, O](
      e: ServerEndpoint[I, E, O, String, Future],
      decodeFailureHandler: Option[DecodeFailureHandler]
  ): Router => Route =
    e.route(options.copy(decodeFailureHandler.getOrElse(ServerDefaults.decodeFailureHandler)))

  override def routeRecoverErrors[I, E <: Throwable, O](e: Endpoint[I, E, O, String], fn: I => Future[O])(implicit
      eClassTag: ClassTag[E]
  ): Router => Route =
    e.routeRecoverErrors(fn)

  override def server(routes: NonEmptyList[Router => Route], port: Port): Resource[IO, Unit] = {
    val router = Router.router(vertx)
    val server = vertx.createHttpServer(HttpServerOptions().setPort(port)).requestHandler(router)
    val listenIO = IO.fromFuture(IO(server.listenFuture(port)))
    routes.toList.foreach(_.apply(router))
    Resource.make(listenIO)(s => IO(s.closeFuture())).void
  }

  override lazy val portCounter: PortCounter = new PortCounter(54000)

} 
Example 11
Source File: AkkaHttpServerTests.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.server.akkahttp

import cats.implicits._
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.server.Directives
import akka.http.scaladsl.server.Directives._
import cats.data.NonEmptyList
import cats.effect.{IO, Resource}
import sttp.client._
import com.typesafe.scalalogging.StrictLogging
import sttp.tapir.{Endpoint, endpoint, stringBody}
import sttp.tapir.server.tests.ServerTests
import sttp.tapir._
import sttp.tapir.server.{DecodeFailureHandler, ServerDefaults, ServerEndpoint}
import sttp.tapir.tests.{Port, PortCounter}

import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
import scala.reflect.ClassTag

class AkkaHttpServerTests extends ServerTests[Future, AkkaStream, Route] with StrictLogging {
  private implicit var actorSystem: ActorSystem = _

  override protected def beforeAll(): Unit = {
    super.beforeAll()
    actorSystem = ActorSystem()
  }

  override protected def afterAll(): Unit = {
    Await.result(actorSystem.terminate(), 5.seconds)
    super.afterAll()
  }

  override def route[I, E, O](
      e: ServerEndpoint[I, E, O, AkkaStream, Future],
      decodeFailureHandler: Option[DecodeFailureHandler] = None
  ): Route = {
    implicit val serverOptions: AkkaHttpServerOptions = AkkaHttpServerOptions.default.copy(
      decodeFailureHandler = decodeFailureHandler.getOrElse(ServerDefaults.decodeFailureHandler)
    )
    e.toRoute
  }

  override def routeRecoverErrors[I, E <: Throwable, O](e: Endpoint[I, E, O, AkkaStream], fn: I => Future[O])(implicit
      eClassTag: ClassTag[E]
  ): Route = {
    e.toRouteRecoverErrors(fn)
  }

  override def server(routes: NonEmptyList[Route], port: Port): Resource[IO, Unit] = {
    val bind = IO.fromFuture(IO(Http().bindAndHandle(routes.toList.reduce(_ ~ _), "localhost", port)))
    Resource.make(bind)(binding => IO.fromFuture(IO(binding.unbind())).void).void
  }

  override def pureResult[T](t: T): Future[T] = Future.successful(t)
  override def suspendResult[T](t: => T): Future[T] = {
    import scala.concurrent.ExecutionContext.Implicits.global
    Future { t }
  }

  override lazy val portCounter: PortCounter = new PortCounter(57000)

  if (testNameFilter.isEmpty) {
    test("endpoint nested in a path directive") {
      val e = endpoint.get.in("test" and "directive").out(stringBody).serverLogic(_ => pureResult("ok".asRight[Unit]))
      val port = portCounter.next()
      val route = Directives.pathPrefix("api")(e.toRoute)
      server(NonEmptyList.of(route), port).use { _ =>
        basicRequest.get(uri"http://localhost:$port/api/test/directive").send().map(_.body shouldBe Right("ok"))
      }.unsafeRunSync
    }
  }
} 
Example 12
Source File: FinatraServerTests.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.server.finatra

import cats.data.NonEmptyList
import cats.effect.{ContextShift, IO, Resource, Timer}
import com.github.ghik.silencer.silent
import com.twitter.finagle.http.Request
import com.twitter.finatra.http.filters.{AccessLoggingFilter, ExceptionMappingFilter}
import com.twitter.finatra.http.{Controller, EmbeddedHttpServer, HttpServer}
import com.twitter.finatra.http.routing.HttpRouter
import com.twitter.util.{Future, FuturePool}
import sttp.tapir.Endpoint
import sttp.tapir.server.{DecodeFailureHandler, ServerDefaults, ServerEndpoint}
import sttp.tapir.server.tests.ServerTests
import sttp.tapir.tests.{Port, PortCounter}

import scala.concurrent.ExecutionContext
import scala.reflect.ClassTag
import scala.concurrent.duration._

class FinatraServerTests extends ServerTests[Future, Nothing, FinatraRoute] {
  override def streamingSupport: Boolean = false

  private val futurePool = FuturePool.unboundedPool

  implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
  implicit val contextShift: ContextShift[IO] = IO.contextShift(ec)
  implicit val timer: Timer[IO] = IO.timer(ec)

  override def pureResult[T](t: T): Future[T] = Future.value(t)

  override def suspendResult[T](t: => T): Future[T] =
    futurePool {
      t
    }

  override def route[I, E, O](
      e: ServerEndpoint[I, E, O, Nothing, Future],
      decodeFailureHandler: Option[DecodeFailureHandler] = None
  ): FinatraRoute = {
    implicit val serverOptions: FinatraServerOptions =
      FinatraServerOptions.default.copy(decodeFailureHandler = decodeFailureHandler.getOrElse(ServerDefaults.decodeFailureHandler))
    e.toRoute
  }

  override def routeRecoverErrors[I, E <: Throwable, O](e: Endpoint[I, E, O, Nothing], fn: I => Future[O])(implicit
      eClassTag: ClassTag[E]
  ): FinatraRoute = {
    e.toRouteRecoverErrors(fn)
  }

  override def server(routes: NonEmptyList[FinatraRoute], port: Port): Resource[IO, Unit] = FinatraServerTests.server(routes, port)

  override lazy val portCounter: PortCounter = new PortCounter(58000)
}

object FinatraServerTests {
  def server(routes: NonEmptyList[FinatraRoute], port: Port)(implicit ioTimer: Timer[IO]): Resource[IO, Unit] = {
    def waitUntilHealthy(s: EmbeddedHttpServer, count: Int): IO[EmbeddedHttpServer] =
      if (s.isHealthy) IO.pure(s)
      else if (count > 1000) IO.raiseError(new IllegalStateException("Server unhealthy"))
      else IO.sleep(10.milliseconds).flatMap(_ => waitUntilHealthy(s, count + 1))

    val bind = IO {
      class TestController extends Controller with TapirController {
        routes.toList.foreach(addTapirRoute)
      }

      class TestServer extends HttpServer {
        @silent("discarded")
        override protected def configureHttp(router: HttpRouter): Unit = {
          router
            .filter[AccessLoggingFilter[Request]]
            .filter[ExceptionMappingFilter[Request]]
            .add(new TestController)
        }
      }

      val server = new EmbeddedHttpServer(
        new TestServer,
        Map(
          "http.port" -> s":$port"
        ),
        // in the default implementation waitForWarmup suspends the thread for 1 second between healthy checks
        // we improve on that by checking every 10ms
        waitForWarmup = false
      )
      server.start()
      server
    }.flatMap(waitUntilHealthy(_, 0))

    Resource
      .make(bind)(httpServer => IO(httpServer.close()))
      .map(_ => ())
  }
} 
Example 13
Source File: FinatraServerCatsTests.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.server.finatra.cats

import cats.data.NonEmptyList
import cats.effect.{ContextShift, IO, Resource, Timer}
import sttp.tapir.Endpoint
import sttp.tapir.server.finatra.{FinatraRoute, FinatraServerOptions, FinatraServerTests}
import sttp.tapir.server.tests.ServerTests
import sttp.tapir.server.{DecodeFailureHandler, ServerDefaults, ServerEndpoint}
import sttp.tapir.tests.{Port, PortCounter}

import scala.concurrent.ExecutionContext
import scala.reflect.ClassTag

class FinatraServerCatsTests extends ServerTests[IO, Nothing, FinatraRoute] {
  override def streamingSupport: Boolean = false

  implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
  implicit val contextShift: ContextShift[IO] = IO.contextShift(ec)
  implicit val timer: Timer[IO] = IO.timer(ec)

  override def pureResult[T](t: T): IO[T] = IO.pure(t)
  override def suspendResult[T](t: => T): IO[T] = IO.apply(t)

  override def route[I, E, O](
      e: ServerEndpoint[I, E, O, Nothing, IO],
      decodeFailureHandler: Option[DecodeFailureHandler] = None
  ): FinatraRoute = {
    implicit val serverOptions: FinatraServerOptions =
      FinatraServerOptions.default.copy(decodeFailureHandler = decodeFailureHandler.getOrElse(ServerDefaults.decodeFailureHandler))
    e.toRoute
  }

  override def routeRecoverErrors[I, E <: Throwable, O](e: Endpoint[I, E, O, Nothing], fn: I => IO[O])(implicit
      eClassTag: ClassTag[E]
  ): FinatraRoute = e.toRouteRecoverErrors(fn)

  override def server(routes: NonEmptyList[FinatraRoute], port: Port): Resource[IO, Unit] = FinatraServerTests.server(routes, port)

  override lazy val portCounter: PortCounter = new PortCounter(59000)
} 
Example 14
Source File: Http4sServerTests.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.server.http4s

import cats.data.{Kleisli, NonEmptyList}
import cats.effect._
import cats.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import org.http4s.{EntityBody, HttpRoutes, Request, Response}
import sttp.tapir.server.tests.ServerTests
import sttp.tapir.Endpoint
import sttp.tapir._
import sttp.client._
import sttp.tapir.server.{DecodeFailureHandler, ServerDefaults, ServerEndpoint}
import sttp.tapir.tests.{Port, PortCounter}

import scala.concurrent.ExecutionContext
import scala.reflect.ClassTag

class Http4sServerTests extends ServerTests[IO, EntityBody[IO], HttpRoutes[IO]] {
  implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
  implicit val contextShift: ContextShift[IO] = IO.contextShift(ec)
  implicit val timer: Timer[IO] = IO.timer(ec)

  override def pureResult[T](t: T): IO[T] = IO.pure(t)
  override def suspendResult[T](t: => T): IO[T] = IO.apply(t)

  override def route[I, E, O](
      e: ServerEndpoint[I, E, O, EntityBody[IO], IO],
      decodeFailureHandler: Option[DecodeFailureHandler] = None
  ): HttpRoutes[IO] = {
    implicit val serverOptions: Http4sServerOptions[IO] = Http4sServerOptions
      .default[IO]
      .copy(
        decodeFailureHandler = decodeFailureHandler.getOrElse(ServerDefaults.decodeFailureHandler)
      )
    e.toRoutes
  }

  override def routeRecoverErrors[I, E <: Throwable, O](e: Endpoint[I, E, O, EntityBody[IO]], fn: I => IO[O])(implicit
      eClassTag: ClassTag[E]
  ): HttpRoutes[IO] = {
    e.toRouteRecoverErrors(fn)
  }

  override def server(routes: NonEmptyList[HttpRoutes[IO]], port: Port): Resource[IO, Unit] = {
    val service: Kleisli[IO, Request[IO], Response[IO]] = routes.reduceK.orNotFound

    BlazeServerBuilder[IO](ExecutionContext.global)
      .bindHttp(port, "localhost")
      .withHttpApp(service)
      .resource
      .void
  }

  override lazy val portCounter: PortCounter = new PortCounter(56000)

  if (testNameFilter.isEmpty) {
    test("should work with a router and routes in a context") {
      val e = endpoint.get.in("test" / "router").out(stringBody).serverLogic(_ => IO.pure("ok".asRight[Unit]))
      val routes = e.toRoutes
      val port = portCounter.next()

      BlazeServerBuilder[IO](ExecutionContext.global)
        .bindHttp(port, "localhost")
        .withHttpApp(Router("/api" -> routes).orNotFound)
        .resource
        .use { _ => basicRequest.get(uri"http://localhost:$port/api/test/router").send().map(_.body shouldBe Right("ok")) }
        .unsafeRunSync()
    }
  }
} 
Example 15
Source File: ConfigSettingsValidator.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.settings.utils

import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._
import com.typesafe.config.{Config, ConfigException}
import com.wavesplatform.transaction.assets.exchange.AssetPair
import net.ceedubs.ficus.Ficus._
import net.ceedubs.ficus.readers.ValueReader

import scala.jdk.CollectionConverters._
import scala.util.Try

object ConfigSettingsValidator {

  type ErrorsListOr[A] = ValidatedNel[String, A]

  def apply(config: Config): ConfigSettingsValidator = new ConfigSettingsValidator(config)

  implicit class ErrorListOrOps[A](validatedValue: ErrorsListOr[A]) {
    def getValueOrThrowErrors: A = validatedValue valueOr (errorsAcc => throw new Exception(errorsAcc.mkString_(", ")))
  }

  object AdhocValidation {
    def validateAssetPairKey(key: String): Validated[String, AssetPair] =
      Validated.fromTry(AssetPair.fromString(key)) leftMap (_ => s"Can't parse asset pair '$key'")
  }
}

class ConfigSettingsValidator(config: Config) {

  import ConfigSettingsValidator.ErrorsListOr

  private def createError[T](settingName: String, errorMsg: String, showError: Boolean = true, showValue: Boolean = true): NonEmptyList[String] = {

    lazy val value = config.getValue(settingName).unwrapped

    lazy val msg = (showValue, showError) match {
      case (true, true)  => s"$value ($errorMsg)"
      case (true, false) => s"$value"
      case (false, true) => s"$errorMsg"
      case _             => ""
    }

    NonEmptyList.one(s"Invalid setting $settingName value: $msg")
  }

  def validate[T: ValueReader](settingName: String, showError: Boolean = false): ErrorsListOr[T] = {
    Validated fromTry Try(config.as[T](settingName)) leftMap (ex => createError(settingName, ex.getMessage, showError))
  }

  def validateByPredicate[T: ValueReader](settingName: String)(predicate: T => Boolean, errorMsg: String): ErrorsListOr[T] = {
    validate[T](settingName, showError = true).ensure(createError(settingName, errorMsg))(predicate)
  }

  def validatePercent(settingName: String): ErrorsListOr[Double] = {
    validateByPredicate[Double](settingName)(p => 0 < p && p <= 100, "required 0 < percent <= 100")
  }

  def validateList[T: ValueReader](settingName: String): ErrorsListOr[List[T]] = {
    config
      .getList(settingName)
      .asScala
      .toList
      .zipWithIndex
      .traverse {
        case (cfg, index) =>
          val elemPath = s"$settingName.$index"
          Validated fromTry Try(cfg.atPath(elemPath).as[T](elemPath)) leftMap (ex => List(ex.getMessage))
      }
      .leftMap(errorsInList => createError(settingName, errorsInList.mkString(", "), showValue = false))
  }

  def validateMap[K, V: ValueReader](settingName: String)(keyValidator: String => Validated[String, K]): ErrorsListOr[Map[K, V]] = {
    config
      .getConfig(settingName)
      .root()
      .entrySet()
      .asScala
      .toList
      .traverse { entry =>
        val elemPath = s"$settingName.${entry.getKey}"
        val k        = keyValidator(entry.getKey).leftMap(List(_))
        val v        = Validated fromTry Try(entry.getValue.atPath(elemPath).as[V](elemPath)) leftMap (ex => List(ex.getMessage))
        k.product(v)
      }
      .map(_.toMap)
      .leftMap(errorsInList => createError(settingName, errorsInList.mkString(", "), showValue = false))
  }

  def validateWithDefault[T: ValueReader](settingName: String, defaultValue: T, showError: Boolean = false): ErrorsListOr[T] = {
    Validated
      .fromTry(Try(config.as[T](settingName)).recover { case _: ConfigException.Missing => defaultValue })
      .leftMap(ex => createError(settingName, ex.getMessage, showError))
  }

  def validateByPredicateWithDefault[T: ValueReader](
      settingName: String)(predicate: T => Boolean, errorMsg: String, defaultValue: T): ErrorsListOr[T] = {
    validateWithDefault[T](settingName, defaultValue, showError = true).ensure(createError(settingName, errorMsg))(predicate)
  }
} 
Example 16
Source File: PureConfigModuleTest.scala    From scala-server-toolkit   with MIT License 5 votes vote down vote up
package com.avast.sst.pureconfig

import cats.data.NonEmptyList
import cats.effect.SyncIO
import org.scalatest.funsuite.AnyFunSuite
import pureconfig.error.ConfigReaderException
import pureconfig.generic.semiauto.deriveReader
import pureconfig.{ConfigReader, ConfigSource}

class PureConfigModuleTest extends AnyFunSuite {

  private val source = ConfigSource.string("""|number = 123
                                              |string = "test"""".stripMargin)

  private case class TestConfig(number: Int, string: String)

  implicit private val configReader: ConfigReader[TestConfig] = deriveReader

  test("Simple configuration loading") {
    assert(PureConfigModule.make[SyncIO, TestConfig](source).unsafeRunSync() === Right(TestConfig(123, "test")))
    assert(
      PureConfigModule.make[SyncIO, TestConfig](ConfigSource.empty).unsafeRunSync() === Left(
        NonEmptyList("Invalid configuration : Key not found: 'number'.", List("Invalid configuration : Key not found: 'string'."))
      )
    )
  }

  test("Configuration loading with exceptions") {
    assert(PureConfigModule.makeOrRaise[SyncIO, TestConfig](source).unsafeRunSync() === TestConfig(123, "test"))
    assertThrows[ConfigReaderException[TestConfig]] {
      PureConfigModule.makeOrRaise[SyncIO, TestConfig](ConfigSource.empty).unsafeRunSync()
    }
  }

} 
Example 17
Source File: KeySchema.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.dynamodb

import cats.data.NonEmptyList
import org.aws4s.core.{AggregateParamRenderer, AggregateParamValidator}

case class KeySchema(elements: NonEmptyList[KeySchemaElement])
    extends DynamoDbAggregateParam(
      KeySchema.name,
      elements.toList,
      AggregateParamValidator.sizeInRangeInclusive(1, 2),
      AggregateParamRenderer.jsonArray,
    )

object KeySchema {
  val name: String = "KeySchema"
} 
Example 18
Source File: CreateTable.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.dynamodb

import cats.data.NonEmptyList
import cats.effect.Effect
import io.circe.{Decoder, Json}
import org.aws4s.Region
import org.aws4s.core.{Command, Param}

private[dynamodb] case class CreateTable[F[_]: Effect](
    region:                Region,
    indices:               NonEmptyList[Index],
    tableName:             TableName,
    provisionedThroughput: ProvisionedThroughput,
) extends DynamoDbCommand[F, CreateTableSuccess] {

  override def action: String = "CreateTable"

  override def params: List[Param[Json]] = {
    val attributeDefinitions = AttributeDefinitions(indices.map(ix => AttributeDefinition(ix.attributeName, ix.attributeType)))
    val keySchema            = KeySchema(indices.map(ix            => KeySchemaElement(ix.attributeName, ix.keyType)))

    List(attributeDefinitions, tableName, keySchema, provisionedThroughput)
  }

  override val validator: Command.Validator[Json] = _ => None
}

case class CreateTableSuccess(tableDescription: TableDescription)

object CreateTableSuccess {
  implicit val decoder: Decoder[CreateTableSuccess] =
    Decoder.forProduct1(TableDescription.name)(CreateTableSuccess.apply)
} 
Example 19
Source File: DynamoDb.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.dynamodb

import cats.data.NonEmptyList
import cats.effect.Effect
import io.circe.Json
import org.aws4s.core.Service
import org.aws4s.{Credentials, Region}
import org.http4s.client.Client
import org.aws4s.core.ExtraEntityDecoderInstances._

case class DynamoDb[F[_]: Effect](client: F[Client[F]], region: Region, credentials: () => Credentials) extends Service[F, Json] {

  def createTable(tableName: TableName, indices: NonEmptyList[Index], provisionedThroughput: ProvisionedThroughput): F[CreateTableSuccess] =
    run {
      CreateTable(region, indices, tableName, provisionedThroughput)
    }

  def deleteTable(tableName: TableName): F[DeleteTableSuccess] =
    run {
      DeleteTable(region, tableName)
    }
} 
Example 20
Source File: AttributeDefinitions.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.dynamodb

import cats.data.NonEmptyList
import org.aws4s.core.{AggregateParamRenderer, AggregateParamValidator}

case class AttributeDefinitions(value: NonEmptyList[AttributeDefinition])
    extends DynamoDbAggregateParam(
      AttributeDefinitions.name,
      value.toList,
      AggregateParamValidator.all,
      AggregateParamRenderer.jsonArray
    )

object AttributeDefinitions {
  val name: String = "AttributeDefinitions"
} 
Example 21
Source File: ResponseContent.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.core

import cats.data.NonEmptyList
import cats.effect.{Effect, Sync}
import io.circe.Json
import org.http4s.{EntityDecoder, MediaRange, Message}
import org.http4s.scalaxml._
import org.http4s.circe._

private[aws4s] sealed trait ResponseContent {
  final def tryParse[A](pf: PartialFunction[ResponseContent, Option[A]]): Option[A] =
    pf.orElse[ResponseContent, Option[A]]({ case _ => None })(this)
}

private[aws4s] case class XmlContent(elem:    scala.xml.Elem) extends ResponseContent
private[aws4s] case class JsonContent(json:   Json) extends ResponseContent
private[aws4s] case class StringContent(text: String) extends ResponseContent
private[aws4s] case object NoContent extends ResponseContent

private[aws4s] object ResponseContent {

  implicit def entityDecoder[F[_]: Effect]: EntityDecoder[F, ResponseContent] =
    EntityDecoder[F, scala.xml.Elem].map(elem => XmlContent(elem)).widen[ResponseContent] orElse
      EntityDecoder[F, Json].map(json         => JsonContent(json)).widen[ResponseContent] orElse
      inclusiveJsonEntityDecoder.map(json     => JsonContent(json)).widen[ResponseContent] orElse
      EntityDecoder[F, String].map(text       => StringContent(text)).widen[ResponseContent] orElse
      EntityDecoder[F, Unit].map(_            => NoContent).widen[ResponseContent]

  private def inclusiveJsonEntityDecoder[F[_]: Sync]: EntityDecoder[F, Json] = {
    val json = jsonDecoder[F]
    val extraMediaRanges = NonEmptyList.of(
      "application/x-amz-json-1.0"
    ) map (mr => MediaRange.parse(mr).getOrElse(throw new RuntimeException(s"Invalid Media Range: $mr")))
    val allMediaRanges = extraMediaRanges concat json.consumes.toList
    EntityDecoder.decodeBy[F, Json](allMediaRanges.head, allMediaRanges.tail: _*)((msg: Message[F]) => json.decode(msg, strict = false))
  }
} 
Example 22
Source File: DynamoDbSmokeTest.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.dynamodb

import cats.data.NonEmptyList
import org.aws4s.Region
import org.aws4s.core.SmokeTest

class DynamoDbSmokeTest extends SmokeTest {

  val dynamodb = DynamoDb(httpClient, Region.`us-east-1`, credentials)

  "Table creation" should "succeed" in {
    val tableName             = TableName("secret_table_fur_mich")
    val indices               = NonEmptyList.of(Index(AttributeName("name"), AttributeType.String, KeyType.Hash))
    val provisionedThroughput = ProvisionedThroughput(WriteCapacityUnits(6), ReadCapacityUnits(6))

    val action = dynamodb.createTable(tableName, indices, provisionedThroughput)

    action.attempt.unsafeToFuture().map {
      case Left(err) =>
        if (err.toString.contains("Table already exists"))
          succeed
        else
          fail(err.toString)
      case Right(cs) => cs shouldEqual CreateTableSuccess(TableDescription(tableName))
    }
  }

  "Table deletion" should "succeed" in {
    val tableName = TableName("secret_table_fur_mich")

    val action = dynamodb.deleteTable(tableName)

    action.attempt.unsafeToFuture().map {
      case Left(err) =>
        if (err.toString.contains("Attempt to change a resource which is still in use"))
          succeed
        else
          fail(err.toString)
      case Right(ds) => ds shouldEqual DeleteTableSuccess(TableDescription(tableName))
    }
  }
} 
Example 23
Source File: utils.scala    From lithium   with Apache License 2.0 5 votes vote down vote up
package com.swissborg.lithium

import akka.cluster.swissborg.EitherValues
import cats.data.{NonEmptyList, NonEmptySet}
import org.scalacheck.Arbitrary
import org.scalacheck.Gen._

import scala.collection.immutable.SortedSet

package object utils extends EitherValues {

  
  def splitIn[A](parts: Int, as: NonEmptySet[A]): Arbitrary[NonEmptyList[NonEmptySet[A]]] =
    Arbitrary {
      if (parts <= 1 || parts > as.length) const(NonEmptyList.of(as))
      else {
        for {
          takeN <- chooseNum(1, as.length - parts + 1) // leave enough `as` to have at least 1 element per part
          newSet = as.toSortedSet.take(takeN.toInt)
          newSets <- splitIn(parts - 1, // parts > takeN
                             NonEmptySet.fromSetUnsafe(as.toSortedSet -- newSet)).arbitrary
        } yield NonEmptySet.fromSetUnsafe(newSet) :: newSets
      }
    }

  def pickNonEmptySubset[A: Ordering](as: NonEmptySet[A]): Arbitrary[NonEmptySet[A]] = Arbitrary {
    atLeastOne(as.toSortedSet).map(seq => NonEmptySet.fromSetUnsafe(SortedSet(seq.toSeq: _*)))
  }
} 
Example 24
Source File: ValidatedUtils.scala    From chimney   with Apache License 2.0 5 votes vote down vote up
package io.scalaland.chimney.cats.utils

import cats.InvariantMonoidal
import cats.data.{NonEmptyChain, NonEmptyList, Validated, ValidatedNec, ValidatedNel}

object ValidatedUtils {

  implicit class OptionOps[T](val opt: Option[T]) extends AnyVal {

    def toValidated[EE[_]: InvariantMonoidal](err: => String): Validated[EE[String], T] = {
      opt match {
        case Some(value) => Validated.Valid(value)
        case None        => Validated.Invalid(InvariantMonoidal[EE].point(err))
      }
    }

    def toValidatedNec(err: => String): ValidatedNec[String, T] =
      toValidated[NonEmptyChain](err)(implicitly)

    def toValidatedNel(err: => String): ValidatedNel[String, T] =
      toValidated[NonEmptyList](err)(implicitly)
  }

  implicit class ValidatedOps[+E, +A](val validated: Validated[E, A]) extends AnyVal {

    def getValid: A = {
      validated.valueOr(_ => throw new NoSuchElementException)
    }
  }
} 
Example 25
Source File: zio.scala    From izanami   with Apache License 2.0 5 votes vote down vote up
package libs.ziohelper
import cats.data.NonEmptyList
import play.api.libs.json.{JsError, JsPath, JsResult, JsSuccess, JsonValidationError}
import domains.errors.{IzanamiErrors, ValidationError}
import zio._
import libs.logs.ZLogger

object JsResults {

  def handleJsError[C <: ZLogger, T](err: Seq[(JsPath, Seq[JsonValidationError])]): ZIO[C, IzanamiErrors, T] =
    ZLogger.error(s"Error parsing json $err") *>
    IO.fail(NonEmptyList.of(ValidationError.error("error.json.parsing")))

  def jsResultToError[C <: ZLogger, T](jsResult: JsResult[T]): ZIO[C, IzanamiErrors, T] =
    fromJsResult(jsResult) { handleJsError }

  def jsResultToHttpResponse[T](jsResult: JsResult[T]) =
    liftJsResult(jsResult)(err => play.api.mvc.Results.BadRequest(ValidationError.fromJsError(err).toJson))

  def liftJsResult[T, E](jsResult: JsResult[T])(onError: Seq[(JsPath, Seq[JsonValidationError])] => E): IO[E, T] =
    jsResult match {
      case JsSuccess(value, _) => IO.succeed(value)
      case JsError(errors)     => IO.fail(onError(errors.toSeq.map(t => t.copy(_2 = t._2.toSeq))))
    }

  def fromJsResult[C <: ZLogger, T, E](
      jsResult: JsResult[T]
  )(onError: Seq[(JsPath, Seq[JsonValidationError])] => ZIO[C, E, T]): ZIO[C, E, T] =
    jsResult match {
      case JsSuccess(value, _) => ZIO.succeed(value)
      case JsError(errors)     => onError(errors.toSeq.map(t => t.copy(_2 = t._2.toSeq)))
    }

} 
Example 26
Source File: json.scala    From izanami   with Apache License 2.0 5 votes vote down vote up
package libs
import cats.data.NonEmptyList
import play.api.libs.json._
import play.api.libs.json.Reads._

object json {

  private def nelReads[A](implicit reads: Reads[A]): Reads[NonEmptyList[A]] = __.read[List[A]].flatMap {
    case h :: t => Reads.pure(NonEmptyList(h, t))
    case _ =>
      Reads[NonEmptyList[A]] { _ =>
        JsError("nonemptylist.expected")
      }
  }
  private def nelWrites[A](implicit writes: Writes[List[A]]): Writes[NonEmptyList[A]] =
    Writes[NonEmptyList[A]] { nel =>
      writes.writes(nel.toList)
    }

  implicit def nelFormat[A](implicit format: Format[A]): Format[NonEmptyList[A]] =
    Format(nelReads[A], nelWrites[A])

} 
Example 27
Source File: AuthInfoSpec.scala    From izanami   with Apache License 2.0 5 votes vote down vote up
package domains

import cats.data.NonEmptyList
import domains.errors.{IzanamiErrors, Unauthorized}
import domains.user.OauthUser
import libs.logs.ZLogger
import test.IzanamiSpec
import zio.{Layer, Runtime, ZEnv, ZLayer}
import domains.auth.AuthInfo

class AuthInfoSpec extends IzanamiSpec {

  def testLayer(admin: Boolean = false): Layer[Throwable, AuthInfo] = AuthInfo.value(
    OauthUser("1",
              "john.doe",
              "[email protected]",
              admin,
              AuthorizedPatterns(AuthorizedPattern("test", PatternRights.R)))
  )

  "AuthInfo" must {
    "is admin" in {

      val authModule: ZLayer[Any, Throwable, AuthInfo with ZLogger] = (testLayer(true) ++ ZLogger.live)

      val res: Either[IzanamiErrors, Unit] =
        Runtime.default.unsafeRun(AuthInfo.isAdmin().either.provideSomeLayer[ZEnv](authModule))
      res must be(Right(()))
    }

    "is not admin" in {
      val authModule: ZLayer[Any, Throwable, AuthInfo with ZLogger] = (testLayer() ++ ZLogger.live)

      val res: Either[IzanamiErrors, Unit] =
        Runtime.default.unsafeRun(AuthInfo.isAdmin().either.provideSomeLayer[ZEnv](authModule))
      res must be(Left(NonEmptyList.of(Unauthorized(None))))
    }
  }
} 
Example 28
Source File: User.scala    From whirlwind-tour-akka-typed   with Apache License 2.0 5 votes vote down vote up
package de.heikoseeberger.wtat

import cats.data.{ NonEmptyList, Validated }
import cats.syntax.apply._
import cats.syntax.either._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.boolean.And
import eu.timepit.refined.char.LetterOrDigit
import eu.timepit.refined.collection.{ Forall, NonEmpty }
import eu.timepit.refined.refineV

object User {

  type Username           = Refined[String, UsernameRefinement]
  type UsernameRefinement = And[NonEmpty, Forall[LetterOrDigit]]

  type Nickname           = Refined[String, NicknameRefinement]
  type NicknameRefinement = NonEmpty

  def apply(username: String, nickname: String): Validated[NonEmptyList[String], User] =
    (validateUsername(username), validateNickname(nickname)).mapN(new User(_, _))

  def validateUsername(username: String): Validated[NonEmptyList[String], Username] =
    refineV[UsernameRefinement](username).toValidatedNel

  def validateNickname(nickname: String): Validated[NonEmptyList[String], Nickname] =
    refineV[NicknameRefinement](nickname).toValidatedNel
}

final case class User(username: User.Username, nickname: User.Nickname) 
Example 29
Source File: HiveSinkConfig.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.sink.config

import java.util.Collections

import cats.data.NonEmptyList
import com.datamountaineer.kcql.{Field, PartitioningStrategy, SchemaEvolution}
import com.landoop.streamreactor.connect.hive._
import com.landoop.streamreactor.connect.hive.formats.{HiveFormat, ParquetHiveFormat}
import com.landoop.streamreactor.connect.hive.kerberos.Kerberos
import com.landoop.streamreactor.connect.hive.sink.evolution.{AddEvolutionPolicy, EvolutionPolicy, IgnoreEvolutionPolicy, StrictEvolutionPolicy}
import com.landoop.streamreactor.connect.hive.sink.partitioning.{DynamicPartitionHandler, PartitionHandler, StrictPartitionHandler}
import com.landoop.streamreactor.connect.hive.sink.staging._

import scala.collection.JavaConverters._

case class HiveSinkConfig(dbName: DatabaseName,
                          filenamePolicy: FilenamePolicy = DefaultFilenamePolicy,
                          stageManager: StageManager = new StageManager(DefaultFilenamePolicy),
                          tableOptions: Set[TableOptions] = Set.empty,
                          kerberos: Option[Kerberos],
                          hadoopConfiguration: HadoopConfiguration)

case class TableOptions(tableName: TableName,
                        topic: Topic,
                        createTable: Boolean = false,
                        overwriteTable: Boolean = false,
                        partitioner: PartitionHandler = new DynamicPartitionHandler(),
                        evolutionPolicy: EvolutionPolicy = IgnoreEvolutionPolicy,
                        projection: Option[NonEmptyList[Field]] = None,
                        // when creating a new table, the table will be partitioned with the fields set below
                        partitions: Seq[PartitionField] = Nil,
                        // the format used when creating a new table, if the table exists
                        // then the format will be derived from the table parameters
                        format: HiveFormat = ParquetHiveFormat,
                        commitPolicy: CommitPolicy = DefaultCommitPolicy(Some(1000 * 1000 * 128), None, None),
                        location: Option[String] = None)

object HiveSinkConfig {

  def fromProps(props: Map[String, String]): HiveSinkConfig = {

    import scala.concurrent.duration._

    val config = HiveSinkConfigDefBuilder(props.asJava)
    val tables = config.getKCQL.map { kcql =>

      val fields = Option(kcql.getFields).getOrElse(Collections.emptyList).asScala.toList
      val projection = if (fields.size == 1 && fields.head.getName == "*") None else NonEmptyList.fromList(fields)

      val flushSize = Option(kcql.getWithFlushSize).filter(_ > 0)
      val flushInterval = Option(kcql.getWithFlushInterval).filter(_ > 0).map(_.seconds)
      val flushCount = Option(kcql.getWithFlushCount).filter(_ > 0)

      // we must have at least one way of committing files
      val finalFlushSize = Some(flushSize.fold(1000L * 1000 * 128)(identity)) //if (flushSize.isEmpty ) Some(1000L * 1000 * 128) else flushSize

      val format: HiveFormat = HiveFormat(Option(kcql.getStoredAs).map(_.toLowerCase).getOrElse("parquet"))

      TableOptions(
        TableName(kcql.getTarget),
        Topic(kcql.getSource),
        kcql.isAutoCreate,
        kcql.getWithOverwrite,
        Option(kcql.getWithPartitioningStrategy).getOrElse(PartitioningStrategy.DYNAMIC) match {
          case PartitioningStrategy.DYNAMIC => new DynamicPartitionHandler()
          case PartitioningStrategy.STRICT => StrictPartitionHandler
        },
        format = format,
        projection = projection,
        evolutionPolicy = Option(kcql.getWithSchemaEvolution).getOrElse(SchemaEvolution.MATCH) match {
          case SchemaEvolution.ADD => AddEvolutionPolicy
          case SchemaEvolution.IGNORE => IgnoreEvolutionPolicy
          case SchemaEvolution.MATCH => StrictEvolutionPolicy
        },
        partitions = Option(kcql.getPartitionBy).map(_.asScala).getOrElse(Nil).map(name => PartitionField(name)).toVector,
        commitPolicy = DefaultCommitPolicy(
          fileSize = finalFlushSize,
          interval = flushInterval,
          fileCount = flushCount
        ),
        location = Option(kcql.getWithTableLocation)
      )
    }

    HiveSinkConfig(
      dbName = DatabaseName(props(SinkConfigSettings.DatabaseNameKey)),
      filenamePolicy = DefaultFilenamePolicy,
      stageManager = new StageManager(DefaultFilenamePolicy),
      tableOptions = tables,
      kerberos = Kerberos.from(config, SinkConfigSettings),
      hadoopConfiguration = HadoopConfiguration.from(config, SinkConfigSettings)
    )
  }
} 
Example 30
Source File: Conf.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.core

import cats.data.NonEmptyList
import gospeak.core.GsConf.{EventConf, ProposalConf}
import gospeak.core.domain.Group
import gospeak.core.domain.messages.Message
import gospeak.libs.scala.Crypto.AesSecretKey
import gospeak.libs.scala.domain.{EmailAddress, EnumBuilder, Mustache, StringEnum}

final case class ApplicationConf(env: ApplicationConf.Env,
                                 baseUrl: String,
                                 aesKey: AesSecretKey,
                                 admins: NonEmptyList[EmailAddress]) {
  def name: String = env match {
    case ApplicationConf.Env.Local => "Gospeak Local"
    case ApplicationConf.Env.Dev => "Gospeak Dev"
    case ApplicationConf.Env.Staging => "Gospeak Staging"
    case ApplicationConf.Env.Prod => "Gospeak"
  }
}

object ApplicationConf {

  sealed trait Env extends StringEnum {
    def value: String = toString

    def isLocal: Boolean = false

    def isDev: Boolean = false

    def isStaging: Boolean = false

    def isProd: Boolean = false
  }

  object Env extends EnumBuilder[Env]("ApplicationConf.Env") {

    final case object Local extends Env {
      override def isLocal: Boolean = true
    }

    final case object Dev extends Env {
      override def isDev: Boolean = true
    }

    final case object Staging extends Env {
      override def isStaging: Boolean = true
    }

    final case object Prod extends Env {
      override def isProd: Boolean = true
    }

    val all: Seq[Env] = Seq(Local, Dev, Staging, Prod)
  }

}

final case class GsConf(event: EventConf, proposal: ProposalConf) {
  def defaultGroupSettings: Group.Settings = Group.Settings(
    accounts = Group.Settings.Accounts(
      meetup = None,
      slack = None),
    // twitter = None,
    // youtube = None),
    event = Group.Settings.Event(
      description = event.description,
      templates = Map()),
    proposal = Group.Settings.Proposal(
      tweet = proposal.tweet),
    actions = Map())
}

object GsConf {

  final case class EventConf(description: Mustache.Markdown[Message.EventInfo])

  final case class ProposalConf(tweet: Mustache.Text[Message.ProposalInfo])

} 
Example 31
Source File: MsgGroup.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.core.domain.messages

import cats.data.NonEmptyList
import gospeak.core.domain.Group
import gospeak.core.domain.utils.SocialAccounts
import gospeak.libs.scala.domain._

final case class MsgGroup(slug: Group.Slug,
                          name: Group.Name,
                          logo: Option[Logo],
                          banner: Option[Banner],
                          contact: Option[EmailAddress],
                          website: Option[Url],
                          description: Markdown,
                          links: SocialAccounts,
                          tags: Seq[Tag],
                          orgas: NonEmptyList[MsgUser.Embed],
                          sponsors: Seq[MsgSponsor.Embed],
                          publicLink: String,
                          orgaLink: String) 
Example 32
Source File: MsgProposal.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.core.domain.messages

import cats.data.NonEmptyList
import gospeak.core.domain.{Proposal, Talk, User}
import gospeak.libs.scala.Extensions._
import gospeak.libs.scala.domain._

import scala.concurrent.duration._

final case class MsgProposal(id: Proposal.Id,
                             title: Talk.Title,
                             duration: FiniteDuration,
                             description: Markdown,
                             speakers: NonEmptyList[MsgUser.Embed],
                             slides: Option[Url.Slides],
                             video: Option[Url.Video],
                             tags: Seq[Tag],
                             publicLink: String,
                             orgaLink: String)

object MsgProposal {

  final case class Embed(id: Proposal.Id,
                         title: Talk.Title,
                         duration: FiniteDuration,
                         description: Markdown,
                         speakers: NonEmptyList[MsgUser.Embed],
                         slides: Option[Url.Slides],
                         video: Option[Url.Video],
                         tags: Seq[Tag],
                         publicLink: String,
                         orgaLink: String)

  object Embed {
    def unknown(id: Proposal.Id): Embed = Embed(
      id = id,
      title = Talk.Title("Unknown talk"),
      duration = 0.minute,
      description = Markdown(""),
      speakers = NonEmptyList.of(MsgUser.Embed.unknown(User.Id.from("00000000-0000-0000-0000-000000000000").get)),
      slides = None,
      video = None,
      tags = Seq(),
      publicLink = "",
      orgaLink = "")
  }

} 
Example 33
Source File: Talk.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.core.domain

import cats.data.NonEmptyList
import gospeak.core.domain.utils._
import gospeak.libs.scala.domain._

import scala.concurrent.duration.FiniteDuration

final case class Talk(id: Talk.Id,
                      slug: Talk.Slug,
                      status: Talk.Status,
                      title: Talk.Title,
                      duration: FiniteDuration,
                      description: Markdown,
                      message: Markdown,
                      speakers: NonEmptyList[User.Id],
                      slides: Option[Url.Slides],
                      video: Option[Url.Video],
                      tags: Seq[Tag],
                      info: Info) {
  def data: Talk.Data = Talk.Data(this)

  def hasSpeaker(user: User.Id): Boolean = speakers.toList.contains(user)

  def speakerUsers(users: Seq[User]): List[User] = speakers.toList.flatMap(id => users.find(_.id == id))

  def users: List[User.Id] = (speakers.toList ++ info.users).distinct
}

object Talk {
  def apply(d: Data,
            status: Status,
            speakers: NonEmptyList[User.Id],
            info: Info): Talk =
    new Talk(Id.generate(), d.slug, status, d.title, d.duration, d.description, d.message, speakers, d.slides, d.video, d.tags, info)

  final class Id private(value: String) extends DataClass(value) with IId

  object Id extends UuidIdBuilder[Id]("Talk.Id", new Id(_))

  final class Slug private(value: String) extends DataClass(value) with ISlug

  object Slug extends SlugBuilder[Slug]("Talk.Slug", new Slug(_))

  final case class Title(value: String) extends AnyVal

  sealed trait Status extends StringEnum {
    def value: String = toString
  }

  object Status extends EnumBuilder[Status]("Talk.Status") {

    case object Public extends Status {
      def description = s"Talk on your speaker public page. Organizers can contact you to perform it."
    }

    case object Private extends Status {
      def description = "Only you can see it, you can propose it to groups but organizers can't search for it."
    }

    case object Archived extends Status {
      def description = "When your talk is not actual anymore. Will be hidden everywhere."
    }

    val all: Seq[Status] = Seq(Public, Private, Archived)
    val current: NonEmptyList[Status] = NonEmptyList.of(Public, Private)
  }

  final case class Data(slug: Talk.Slug,
                        title: Talk.Title,
                        duration: FiniteDuration,
                        description: Markdown,
                        message: Markdown,
                        slides: Option[Url.Slides],
                        video: Option[Url.Video],
                        tags: Seq[Tag])

  object Data {
    def apply(t: Talk): Data = Data(t.slug, t.title, t.duration, t.description, t.message, t.slides, t.video, t.tags)
  }

} 
Example 34
Source File: GenLaws.scala    From cats-scalacheck   with MIT License 5 votes vote down vote up
package org.scalacheck.cats.laws


import cats.laws.discipline._
import cats.kernel.laws.discipline._
import cats.data.NonEmptyList
import cats.tests.CatsSuite
import org.scalacheck.Gen
import org.scalacheck.cats.ScalaCheckSetup
import org.scalacheck.cats.instances.GenInstances._

class GenLaws extends CatsSuite with ScalaCheckSetup {
  // Tests Alternative
  checkAll("Gen", AlternativeTests[Gen].alternative[Int, Int, Int])
  // Tests Monad
  checkAll("Gen", MonadTests[Gen].monad[Int, Int, Int])
  // Tests FunctorFilter
  checkAll("Gen.FunctorFilterLaws", FunctorFilterTests[Gen].functorFilter[Int, Int, Int])

  // Tests Monoid for Inner Given Monoid
  checkAll("Gen[String]", MonoidTests[Gen[String]].monoid)
  // Tests Low Priority Semigroup
  checkAll("Gen[NonEmptyList[Int]]", SemigroupTests[Gen[NonEmptyList[Int]]].semigroup)
} 
Example 35
Source File: DispatchingMediaTypedEncoderSpec.scala    From cosmos   with Apache License 2.0 5 votes vote down vote up
package com.mesosphere.cosmos.finch

import cats.data.NonEmptyList
import com.mesosphere.http.CompoundMediaType
import com.mesosphere.http.MediaType
import io.circe.Encoder
import io.circe.Json
import io.circe.syntax._
import org.scalatest.FreeSpec

final class DispatchingMediaTypedEncoderSpec extends FreeSpec {

  import DispatchingMediaTypedEncoderSpec._

  "encoderFor(MediaType) should" - {

    "return the first encoder with a media type compatible with the argument" in {
      val Some(mediaTypedEncoder) = ThreeElementEncoder(CompoundMediaType(MediaType("foo", "bar")))
      assertResult(Json.fromInt(1))(mediaTypedEncoder.encoder(()))
      assertResult(NonEmptyList.of(MediaType("foo", "bar")))(mediaTypedEncoder.mediaTypes)
    }

    "indicate failure if no compatible encoder is found" - {

      "because there are no encoders" in {
        val dispatchingEncoder = DispatchingMediaTypedEncoder(Set.empty[MediaTypedEncoder[String]])
        assertResult(None)(dispatchingEncoder(CompoundMediaType(TestingMediaTypes.applicationJson)))
      }

      "because there are only incompatible encoders" in {
        assertResult(None)(ThreeElementEncoder(CompoundMediaType(TestingMediaTypes.applicationJson)))
      }

    }

  }

  "mediaTypes should return the media types of each of the encoders" - {
    "zero elements" in {
      assertResult(Set.empty)(DispatchingMediaTypedEncoder(Set.empty[MediaTypedEncoder[String]]).mediaTypes)
    }

    "three elements" in {
      val expected = Set(MediaType("foo", "foo"), MediaType("foo", "bar"), MediaType("foo", "baz"))
      assertResult(expected)(ThreeElementEncoder.mediaTypes)
    }
  }

}

object DispatchingMediaTypedEncoderSpec {

  val ThreeElementEncoder: DispatchingMediaTypedEncoder[Unit] = DispatchingMediaTypedEncoder(Set(
    MediaTypedEncoder(Encoder.instance[Unit](_ => 0.asJson), MediaType("foo", "foo")),
    MediaTypedEncoder(Encoder.instance[Unit](_ => 1.asJson), MediaType("foo", "bar")),
    MediaTypedEncoder(Encoder.instance[Unit](_ => 2.asJson), MediaType("foo", "baz"))
  ))

} 
Example 36
Source File: MediaTypedEncoder.scala    From cosmos   with Apache License 2.0 5 votes vote down vote up
package com.mesosphere.cosmos.finch

import cats.data.NonEmptyList
import com.mesosphere.http.MediaType
import io.circe.Encoder
import io.circe.Json


trait MediaTypedEncoder[A] {
  /// Describes the JSON encoder associated with this type.
  val encoder: Encoder[A]

  /// Enumerate all of the possible media types for this type.
  val mediaTypes: NonEmptyList[MediaType]

  /// Returns the specific media type based on the value of the type.
  def mediaType(a: A): MediaType

  def apply(a: A): (Json, MediaType) = (encoder(a), mediaType(a))
}

final class SimpleMediaTypedEncoder[A](
  val encoder: Encoder[A],
  mediaTypeForA: MediaType
) extends MediaTypedEncoder[A] {
  val mediaTypes = NonEmptyList.of(mediaTypeForA)
  def mediaType(a: A): MediaType = mediaTypeForA
}

object MediaTypedEncoder {

  def apply[A](mediaType: MediaType)(implicit encoder: Encoder[A]): MediaTypedEncoder[A] = {
    MediaTypedEncoder(encoder, mediaType)
  }

  def apply[A](encoder: Encoder[A], mediaType: MediaType): MediaTypedEncoder[A] = {
    new SimpleMediaTypedEncoder(encoder, mediaType)
  }

} 
Example 37
Source File: MediaTypedDecoder.scala    From cosmos   with Apache License 2.0 5 votes vote down vote up
package com.mesosphere.cosmos.finch

import cats.data.NonEmptyList
import com.mesosphere.cosmos.circe.Decoders.convertToCosmosError
import com.mesosphere.cosmos.error.UnsupportedContentType
import com.mesosphere.error.Result
import com.mesosphere.http.MediaType
import io.circe.Decoder
import io.circe.HCursor
import scala.reflect.ClassTag


trait MediaTypedDecoder[A] {
  val mediaTypes: NonEmptyList[MediaType]
  val decoder: Decoder[A]

  def apply(cursor: HCursor, mediaType: MediaType): Result[A]
}

final class SimpleMediaTypedDecoder[A](
  val mediaTypes: NonEmptyList[MediaType],
  val decoder: Decoder[A]
)(
  implicit classTag: ClassTag[A]
) extends MediaTypedDecoder[A] {

  def apply(cursor: HCursor, mediaType: MediaType): Result[A] = {
    if (mediaTypes.exists(current => MediaType.compatible(current, mediaType))) {
      convertToCosmosError(decoder(cursor), cursor.value.noSpaces)
    } else {
      Left(
        UnsupportedContentType(
          mediaTypes.toList,
          Some(mediaType.show)
        )
      )
    }
  }
}

object MediaTypedDecoder {
  def apply[A](
    mediaTypes: NonEmptyList[MediaType]
  )(
    implicit decoder: Decoder[A],
    classTag: ClassTag[A]
  ): MediaTypedDecoder[A] = {
    new SimpleMediaTypedDecoder(mediaTypes, decoder)
  }

  def apply[A](
    mediaType: MediaType
  )(
    implicit decoder: Decoder[A],
    classTag: ClassTag[A]
  ): MediaTypedDecoder[A] = {
    MediaTypedDecoder(NonEmptyList.of(mediaType))
  }

} 
Example 38
Source File: PetRepositoryInMemoryInterpreter.scala    From scala-pet-store   with Apache License 2.0 5 votes vote down vote up
package io.github.pauljamescleary.petstore
package infrastructure.repository.inmemory

import scala.collection.concurrent.TrieMap
import scala.util.Random

import cats._
import cats.data.NonEmptyList
import cats.implicits._
import domain.pets.{Pet, PetRepositoryAlgebra, PetStatus}

class PetRepositoryInMemoryInterpreter[F[_]: Applicative] extends PetRepositoryAlgebra[F] {
  private val cache = new TrieMap[Long, Pet]

  private val random = new Random

  def create(pet: Pet): F[Pet] = {
    val id = random.nextLong
    val toSave = pet.copy(id = id.some)
    cache += (id -> pet.copy(id = id.some))
    toSave.pure[F]
  }

  def update(pet: Pet): F[Option[Pet]] = pet.id.traverse { id =>
    cache.update(id, pet)
    pet.pure[F]
  }

  def get(id: Long): F[Option[Pet]] = cache.get(id).pure[F]

  def delete(id: Long): F[Option[Pet]] = cache.remove(id).pure[F]

  def findByNameAndCategory(name: String, category: String): F[Set[Pet]] =
    cache.values
      .filter(p => p.name == name && p.category == category)
      .toSet
      .pure[F]

  def list(pageSize: Int, offset: Int): F[List[Pet]] =
    cache.values.toList.sortBy(_.name).slice(offset, offset + pageSize).pure[F]

  def findByStatus(statuses: NonEmptyList[PetStatus]): F[List[Pet]] =
    cache.values.filter(p => statuses.exists(_ == p.status)).toList.pure[F]

  def findByTag(tags: NonEmptyList[String]): F[List[Pet]] = {
    val tagSet = tags.toNes
    cache.values.filter(_.tags.exists(tagSet.contains(_))).toList.pure[F]
  }
}

object PetRepositoryInMemoryInterpreter {
  def apply[F[_]: Applicative]() = new PetRepositoryInMemoryInterpreter[F]()
} 
Example 39
Source File: PetQueryTypeCheckSpec.scala    From scala-pet-store   with Apache License 2.0 5 votes vote down vote up
package io.github.pauljamescleary.petstore
package infrastructure.repository.doobie

import cats.data.NonEmptyList
import cats.effect.IO
import cats.syntax.applicative._
import doobie.scalatest.IOChecker
import doobie.util.transactor.Transactor
import org.scalatest.funsuite.AnyFunSuite
import PetStoreArbitraries.pet
import org.scalatest.matchers.should.Matchers

class PetQueryTypeCheckSpec extends AnyFunSuite with Matchers with IOChecker {
  override val transactor: Transactor[IO] = testTransactor

  import PetSQL._

  test("Typecheck pet queries") {
    pet.arbitrary.sample.map { p =>
      check(selectByStatus(p.status.pure[NonEmptyList]))
      check(insert(p))
      p.id.foreach(id => check(PetSQL.update(p, id)))
    }

    check(selectTagLikeString("example".pure[NonEmptyList]))
    check(select(1L))
    check(selectAll)
    check(delete(1L))
    check(selectByNameAndCategory("name", "category"))
  }
} 
Example 40
Source File: TestCaseCollections.scala    From protoless   with Apache License 2.0 5 votes vote down vote up
package io.protoless.tests.samples

import cats.data.NonEmptyList
import io.protoless.tag._

case class TestCaseCollections(
  d: Seq[Double],
  f: List[Float],
  i: collection.immutable.Seq[Int],
  l: Array[Long],
  ui: scala.collection.Traversable[Int @@ Unsigned],
  ul: scala.collection.Iterable[Long @@ Unsigned],
  si: Stream[Int @@ Signed],
  sl: Vector[Long @@ Signed],
  fi: NonEmptyList[Int @@ Fixed]
)

object TestCaseCollections extends TestCase[TestCaseCollections] {

  override val source: TestCaseCollections = TestCaseCollections(
    d = Seq(1d, 2d),
    f = List(1f, 2f),
    i = scala.collection.immutable.Seq(1, 2),
    l = Array(1L, 2L),
    ui = Seq(unsigned(1), unsigned(2)),
    ul = Seq(unsigned(1L), unsigned(2L)),
    si = Seq(signed(1), signed(2)).toStream,
    sl = Seq(signed(1L), signed(2L)).toVector,
    fi = NonEmptyList.of(fixed(Int.MaxValue))
  )

  override val protobuf: ProtoSerializable = ProtoSerializable(Schemas.Repeated.newBuilder()
    .addDoubleField(source.d(0)).addDoubleField(source.d(1))
    .addFloatField(source.f(0)).addFloatField(source.f(1))
    .addInt32Field(source.i(0)).addInt32Field(source.i(1))
    .addInt64Field(source.l(0)).addInt64Field(source.l(1))
    .addUint32Field(source.ui.toList(0)).addUint32Field(source.ui.toList(1))
    .addUint64Field(source.ul.toList(0)).addUint64Field(source.ul.toList(1))
    .addSint32Field(source.si(0)).addSint32Field(source.si(1))
    .addSint64Field(source.sl(0)).addSint64Field(source.sl(1))
    .addFixed32Field(source.fi.head)
    .build())
} 
Example 41
Source File: Tasks.scala    From sbt-guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail
package sbt

import _root_.sbt.{FeedbackProvidedException, WatchSource}
import cats.data.NonEmptyList
import cats.implicits._
import cats.~>
import com.twilio.guardrail.{Args => ArgsImpl}
import scala.io.AnsiColor
import scala.meta._
import _root_.io.swagger.parser.SwaggerParserExtension

class CodegenFailedException extends FeedbackProvidedException

object Tasks {
  def guardrailTask(
    runner: Map[String,cats.data.NonEmptyList[com.twilio.guardrail.Args]] => com.twilio.guardrail.Target[List[java.nio.file.Path]]
  )(tasks: List[Types.Args], sourceDir: java.io.File): Seq[java.io.File] = {
    // swagger-parser uses SPI to find extensions on the classpath (by default, only the OAPI2 -> OAPI3 converter)
    // See https://github.com/swagger-api/swagger-parser#extensions
    // That being said, Scala's classloader seems to have some issues finding SPI resources:
    // - https://github.com/scala/bug/issues/10247
    // - https://github.com/meetup/sbt-openapi/blob/363fa14/src/main/scala/com/meetup/sbtopenapi/Plugin.scala#L64-L71
    // As a result, we temporarily overwrite Scala's classloader to whichever one loaded swagger-parser, in the hopes
    // that it'll pick up the rest of the SPI classes.
    val oldClassLoader = Thread.currentThread().getContextClassLoader()
    Thread.currentThread().setContextClassLoader(classOf[SwaggerParserExtension].getClassLoader)

    val preppedTasks: Map[String, NonEmptyList[ArgsImpl]] = tasks.foldLeft(Map.empty[String, NonEmptyList[ArgsImpl]]) { case (acc, (language, args)) =>
      val prepped = args.copy(outputPath=Some(sourceDir.getPath))
      acc.updated(language, acc.get(language).fold(NonEmptyList.one(prepped))(_ :+ prepped))
    }

    val  =
      runner
        .apply(preppedTasks)
        .fold[List[java.nio.file.Path]]({
          case MissingArg(args, Error.ArgName(arg)) =>
            println(s"${AnsiColor.RED}Missing argument:${AnsiColor.RESET} ${AnsiColor.BOLD}${arg}${AnsiColor.RESET} (In block ${args})")
            throw new CodegenFailedException()
          case NoArgsSpecified =>
            List.empty
          case NoFramework =>
            println(s"${AnsiColor.RED}No framework specified${AnsiColor.RESET}")
            throw new CodegenFailedException()
          case PrintHelp =>
            List.empty
          case UnknownArguments(args) =>
            println(s"${AnsiColor.RED}Unknown arguments: ${args.mkString(" ")}${AnsiColor.RESET}")
            throw new CodegenFailedException()
          case UnparseableArgument(name, message) =>
            println(s"${AnsiColor.RED}Unparseable argument ${name}: ${message}${AnsiColor.RESET}")
            throw new CodegenFailedException()
          case UnknownFramework(name) =>
            println(s"${AnsiColor.RED}Unknown framework specified: ${name}${AnsiColor.RESET}")
            throw new CodegenFailedException()
          case RuntimeFailure(message) =>
            println(s"${AnsiColor.RED}Error:${AnsiColor.RESET}${message}")
            throw new CodegenFailedException()
          case UserError(message) =>
            println(s"${AnsiColor.RED}Error:${AnsiColor.RESET}${message}")
            throw new CodegenFailedException()
          case MissingModule(section) =>
            println(s"${AnsiColor.RED}Error: Missing module ${section}${AnsiColor.RESET}")
            throw new CodegenFailedException()
          case ModuleConflict(section) =>
            println(s"${AnsiColor.RED}Error: Too many modules specified for ${section}${AnsiColor.RESET}")
            throw new CodegenFailedException()
          case UnconsumedModules(modules) =>
            println(s"${AnsiColor.RED}Error: Unconsumed modules: ${modules.mkString(", ")}${AnsiColor.RESET}")
            throw new CodegenFailedException()
        }, identity)
        //.runEmpty

    Thread.currentThread().setContextClassLoader(oldClassLoader)
    paths.map(_.toFile).distinct
  }

  def watchSources(tasks: List[Types.Args]): Seq[WatchSource] = {
    tasks.flatMap(_._2.specPath.map(new java.io.File(_)).map(WatchSource(_))).toSeq
  }
} 
Example 42
Source File: domain.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive

import cats.Show
import cats.data.NonEmptyList
import org.apache.hadoop.fs.Path
import org.apache.kafka.common.{TopicPartition => KafkaTopicPartition}
import org.apache.kafka.connect.data.Schema

case class Topic(value: String) {
  require(value != null && value.trim.nonEmpty)
}

case class Offset(value: Long) {
  require(value >= 0)
}

case class TopicPartition(topic: Topic, partition: Int) {
  def withOffset(offset: Offset): TopicPartitionOffset = TopicPartitionOffset(topic, partition, offset)
  def toKafka = new KafkaTopicPartition(topic.value, partition)
}

case class TopicPartitionOffset(topic: Topic, partition: Int, offset: Offset) {
  def toTopicPartition = TopicPartition(topic, partition)
}

case class DatabaseName(value: String) {
  require(value != null && value.trim.nonEmpty)
}

case class TableName(value: String) {
  require(value != null && value.trim.nonEmpty)
}

// contains all the partition keys for a particular table
case class PartitionPlan(tableName: TableName, keys: NonEmptyList[PartitionKey])

// contains a partition key, which you can think of as like a partition column name
case class PartitionKey(value: String)

// defines a partition key field
case class PartitionField(name: String, schema: Schema = Schema.STRING_SCHEMA, comment: Option[String] = None) {
  require(name != null && name.trim.nonEmpty)
}

// contains a single partition in a table, that is one set of unique values, one per partition key
case class Partition(entries: NonEmptyList[(PartitionKey, String)], location: Option[Path])

case class Serde(serializationLib: String, inputFormat: String, outputFormat: String, params: Map[String, String])

// generates the default hive metatstore location string for a partition
object DefaultPartitionLocation extends Show[Partition] {
  override def show(t: Partition): String = {
    t.entries.map { case (key, value) => key.value + "=" + value }.toList.mkString("/")
  }
} 
Example 43
Source File: OpenApiFactory.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.libs.openapi

import cats.data.NonEmptyList
import gospeak.libs.scala.Extensions._
import gospeak.libs.openapi.JsonUtils._
import gospeak.libs.openapi.error.OpenApiError.ErrorMessage
import gospeak.libs.openapi.error.{OpenApiError, OpenApiErrors}
import gospeak.libs.openapi.models._
import gospeak.libs.openapi.models.utils._
import play.api.libs.json._

object OpenApiFactory {
  def parseJson(json: JsValue): Either[OpenApiErrors, OpenApi] = {
    import Formats._
    json.validate[OpenApi].fold(
      errors => Left(OpenApiErrors(errors.map(formatError))),
      openApi => Right(openApi)
    )
  }

  def toJson(openApi: OpenApi): JsValue = {
    import Formats._
    Json.toJson(openApi)
  }

  object Formats {
    // `lazy` is useful for recursive types: the sub-type needs the super-type but it's not defined yet. If not lazy, you got a NullPointerException
    private val fString: Format[String] = Format((json: JsValue) => json.validate[String], (o: String) => JsString(o))
    implicit lazy val fTODO: Format[TODO] = Format((_: JsValue) => JsSuccess(TODO()), (_: TODO) => JsNull)
    implicit lazy val fMarkdown: Format[Markdown] = fString.imap(Markdown)(_.value)
    implicit lazy val fUrl: Format[Url] = fString.validate(Url.from)(_.value)
    implicit lazy val fEmail: Format[Email] = fString.validate(Email.from)(_.value)
    implicit lazy val fVersion: Format[Version] = fString.validate(Version.from)(_.format)
    implicit lazy val fJs: Format[Js] = Format(js => JsSuccess(Js(js.toString, js.getClass.getSimpleName)), a => Json.parse(a.value))

    implicit lazy val fReference: Format[Reference] = fString.validate(Reference.from)(_.value)
    implicit lazy val fInfoContact: Format[Info.Contact] = Json.format[Info.Contact]
    implicit lazy val fInfoLicense: Format[Info.License] = Json.format[Info.License]
    implicit lazy val fInfo: Format[Info] = Json.format[Info]
    implicit lazy val fExternalDoc: Format[ExternalDoc] = Json.format[ExternalDoc]
    implicit lazy val fServerVariable: Format[Server.Variable] = Json.format[Server.Variable]
    implicit lazy val fServer: Format[Server] = Json.format[Server]
    implicit lazy val fTag: Format[Tag] = Json.format[Tag]
    implicit lazy val fSchemaString: Format[Schema.StringVal] = Json.format[Schema.StringVal].hint(Schema.hintAttr, Schema.StringVal.hint)
    implicit lazy val fSchemaInteger: Format[Schema.IntegerVal] = Json.format[Schema.IntegerVal].hint(Schema.hintAttr, Schema.IntegerVal.hint)
    implicit lazy val fSchemaNumber: Format[Schema.NumberVal] = Json.format[Schema.NumberVal].hint(Schema.hintAttr, Schema.NumberVal.hint)
    implicit lazy val fSchemaBoolean: Format[Schema.BooleanVal] = Json.format[Schema.BooleanVal].hint(Schema.hintAttr, Schema.BooleanVal.hint)
    implicit lazy val fSchemaArray: Format[Schema.ArrayVal] = Json.format[Schema.ArrayVal].hint(Schema.hintAttr, Schema.ArrayVal.hint)
    implicit lazy val fSchemaObject: Format[Schema.ObjectVal] = Json.format[Schema.ObjectVal].hint(Schema.hintAttr, Schema.ObjectVal.hint)
    implicit lazy val fSchemaReference: Format[Schema.ReferenceVal] = Json.format[Schema.ReferenceVal]
    implicit lazy val fSchemaCombination: Format[Schema.CombinationVal] = Json.format[Schema.CombinationVal]
    implicit lazy val fSchema: Format[Schema] = Format[Schema](
      (json: JsValue) => (json \ Schema.hintAttr).asOpt[String] match {
        case Some(Schema.StringVal.hint) => fSchemaString.reads(json)
        case Some(Schema.IntegerVal.hint) => fSchemaInteger.reads(json)
        case Some(Schema.NumberVal.hint) => fSchemaNumber.reads(json)
        case Some(Schema.BooleanVal.hint) => fSchemaBoolean.reads(json)
        case Some(Schema.ArrayVal.hint) => fSchemaArray.reads(json)
        case Some(Schema.ObjectVal.hint) => fSchemaObject.reads(json)
        case Some(value) => JsError(Seq(OpenApiError.unknownHint(value, Schema.hintAttr).atPath(Schema.hintAttr).toJson))
        case None if (json \ Schema.ReferenceVal.hintAttr).asOpt[String].isDefined => fSchemaReference.reads(json)
        case None => fSchemaCombination.reads(json)
      },
      {
        case s: Schema.StringVal => fSchemaString.writes(s)
        case s: Schema.IntegerVal => fSchemaInteger.writes(s)
        case s: Schema.NumberVal => fSchemaNumber.writes(s)
        case s: Schema.BooleanVal => fSchemaBoolean.writes(s)
        case s: Schema.ArrayVal => fSchemaArray.writes(s)
        case s: Schema.ObjectVal => fSchemaObject.writes(s)
        case s: Schema.ReferenceVal => fSchemaReference.writes(s)
        case s: Schema.CombinationVal => fSchemaCombination.writes(s)
      })
    implicit lazy val fSchemas: Format[Schemas] = implicitly[Format[Map[String, Schema]]].imap(Schemas(_))(_.value)
    implicit lazy val fParameterLocation: Format[Parameter.Location] = fString.validate(Parameter.Location.from)(_.value)
    implicit lazy val fParameter: Format[Parameter] = Json.format[Parameter]
    implicit lazy val fComponents: Format[Components] = Json.format[Components]
    implicit lazy val fHeader: Format[Header] = Json.format[Header]
    implicit lazy val fMediaType: Format[MediaType] = Json.format[MediaType]
    implicit lazy val fLink: Format[Link] = Json.format[Link]
    implicit lazy val fResponse: Format[Response] = Json.format[Response]
    implicit lazy val fRequestBody: Format[RequestBody] = Json.format[RequestBody]
    implicit lazy val fPathItemOperation: Format[PathItem.Operation] = Json.format[PathItem.Operation]
    implicit lazy val fPathItem: Format[PathItem] = Json.format[PathItem]
    implicit lazy val fPaths: Format[Map[Path, PathItem]] = implicitly[Format[Map[String, PathItem]]].validate(
      _.map { case (k, v) => Path.from(k).map(p => (p, v)) }.sequence.map(_.toMap))(
      _.map { case (k, v) => (k.value, v) })
    implicit lazy val fOpenApi: Format[OpenApi] = Json.format[OpenApi].verify(_.getErrors)
  }

  private def formatError(errs: (JsPath, Seq[JsonValidationError])): OpenApiError =
    OpenApiError(
      path = errs._1.path.map(_.toJsonString),
      errors = errs._2.map(err => ErrorMessage(err.message, err.args.map(_.toString).toList)).toNel.getOrElse(NonEmptyList.of(ErrorMessage.noMessage())))

} 
Example 44
Source File: ProjectionMapper.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.sink.mapper

import cats.data.NonEmptyList
import com.datamountaineer.kcql.Field
import com.landoop.streamreactor.connect.hive.StructMapper
import org.apache.kafka.connect.data.{SchemaBuilder, Struct}


class ProjectionMapper(projection: NonEmptyList[Field]) extends StructMapper {

  override def map(input: Struct): Struct = {
    // the compatible output schema built from projected fields with aliases applied
    val builder = projection.foldLeft(SchemaBuilder.struct) { (builder, kcqlField) =>
      Option(input.schema.field(kcqlField.getName)).fold(sys.error(s"Missing field $kcqlField")) { field =>
        builder.field(kcqlField.getAlias, field.schema)
      }
    }
    val schema = builder.build()
    projection.foldLeft(new Struct(schema)) { (struct, field) =>
      struct.put(field.getAlias, input.get(field.getName))
    }
  }
} 
Example 45
Source File: HiveSourceConfig.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.source.config

import java.util.Collections

import cats.data.NonEmptyList
import com.landoop.streamreactor.connect.hive.{DatabaseName, HadoopConfiguration, TableName, Topic}
import com.landoop.streamreactor.connect.hive.kerberos.Kerberos

import scala.collection.JavaConverters._

case class ProjectionField(name: String, alias: String)

case class HiveSourceConfig(dbName: DatabaseName,
                            kerberos: Option[Kerberos],
                            hadoopConfiguration: HadoopConfiguration,
                            tableOptions: Set[SourceTableOptions] = Set.empty,
                            pollSize: Int = 1024)

case class SourceTableOptions(
  tableName: TableName,
  topic: Topic,
  projection: Option[NonEmptyList[ProjectionField]] = None,
  limit: Int = Int.MaxValue
)

object HiveSourceConfig {

  def fromProps(props: Map[String, String]): HiveSourceConfig = {

    val config = HiveSourceConfigDefBuilder(props.asJava)
    val tables = config.getKCQL.map { kcql =>
      val fields = Option(kcql.getFields)
        .getOrElse(Collections.emptyList)
        .asScala
        .toList
        .map { field =>
          ProjectionField(field.getName, field.getAlias)
        }

      val projection = fields match {
        case Nil                              => None
        case ProjectionField("*", "*") :: Nil => None
        case _                                => NonEmptyList.fromList(fields)
      }

      SourceTableOptions(
        TableName(kcql.getSource),
        Topic(kcql.getTarget),
        projection,
        limit = if (kcql.getLimit < 1) Int.MaxValue else kcql.getLimit
      )
    }

    HiveSourceConfig(
      dbName = DatabaseName(props(HiveSourceConfigConstants.DatabaseNameKey)),
      tableOptions = tables,
      kerberos = Kerberos.from(config, HiveSourceConfigConstants),
      hadoopConfiguration =
        HadoopConfiguration.from(config, HiveSourceConfigConstants),
      pollSize = props
        .getOrElse(HiveSourceConfigConstants.PollSizeKey, 1024)
        .toString
        .toInt
    )
  }
} 
Example 46
Source File: ProjectionMapper.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.source.mapper

import cats.data.NonEmptyList
import com.landoop.streamreactor.connect.hive.StructMapper
import com.landoop.streamreactor.connect.hive.source.config.ProjectionField
import org.apache.kafka.connect.data.{SchemaBuilder, Struct}

class ProjectionMapper(projection: NonEmptyList[ProjectionField]) extends StructMapper {

  override def map(input: Struct): Struct = {
    val builder = projection.foldLeft(SchemaBuilder.struct) { (builder, projectionField) =>
      Option(input.schema.field(projectionField.name))
        .fold(sys.error(s"Projection field ${projectionField.name} cannot be found in input")) { field =>
          builder.field(projectionField.alias, field.schema)
        }
    }
    val schema = builder.build()
    projection.foldLeft(new Struct(schema)) { (struct, field) =>
      struct.put(field.alias, input.get(field.name))
    }
  }
} 
Example 47
Source File: DropPartitionValuesMapperTest.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.sink.mapper

import cats.data.NonEmptyList
import com.landoop.streamreactor.connect.hive.{PartitionKey, PartitionPlan, TableName}
import org.apache.kafka.connect.data.{SchemaBuilder, Struct}
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

import scala.collection.JavaConverters._

class DropPartitionValuesMapperTest extends AnyFunSuite with Matchers {

  test("strip partition values") {

    val schema = SchemaBuilder.struct()
      .field("a", SchemaBuilder.string().required().build())
      .field("p", SchemaBuilder.string().required().build())
      .field("q", SchemaBuilder.string().required().build())
      .field("z", SchemaBuilder.string().required().build())
      .build()

    val plan = PartitionPlan(TableName("foo"), NonEmptyList.of(PartitionKey("p"), PartitionKey("q")))
    val struct = new Struct(schema).put("a", "a").put("p", "p").put("q", "q").put("z", "z")
    val output = new DropPartitionValuesMapper(plan).map(struct)
    output.schema().fields().asScala.map(_.name) shouldBe Seq("a", "z")
  }

  test("handle partition field is missing in input") {

    val schema = SchemaBuilder.struct()
      .field("a", SchemaBuilder.string().required().build())
      .field("q", SchemaBuilder.string().required().build())
      .field("z", SchemaBuilder.string().required().build())
      .build()


    val plan = PartitionPlan(TableName("foo"), NonEmptyList.of(PartitionKey("p"), PartitionKey("q")))
    val struct = new Struct(schema).put("a", "a").put("q", "q").put("z", "z")
    val output = new DropPartitionValuesMapper(plan).map(struct)
    output.schema().fields().asScala.map(_.name) shouldBe Seq("a", "z")
  }
} 
Example 48
Source File: domain.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive

import cats.Show
import cats.data.NonEmptyList
import org.apache.hadoop.fs.Path
import org.apache.kafka.common.{TopicPartition => KafkaTopicPartition}
import org.apache.kafka.connect.data.Schema

case class Topic(value: String) {
  require(value != null && value.trim.nonEmpty)
}

case class Offset(value: Long) {
  require(value >= 0)
}

case class TopicPartition(topic: Topic, partition: Int) {
  def withOffset(offset: Offset): TopicPartitionOffset = TopicPartitionOffset(topic, partition, offset)
  def toKafka = new KafkaTopicPartition(topic.value, partition)
}

case class TopicPartitionOffset(topic: Topic, partition: Int, offset: Offset) {
  def toTopicPartition = TopicPartition(topic, partition)
}

case class DatabaseName(value: String) {
  require(value != null && value.trim.nonEmpty)
}

case class TableName(value: String) {
  require(value != null && value.trim.nonEmpty)
}

// contains all the partition keys for a particular table
case class PartitionPlan(tableName: TableName, keys: NonEmptyList[PartitionKey])

// contains a partition key, which you can think of as like a partition column name
case class PartitionKey(value: String)

// defines a partition key field
case class PartitionField(name: String, schema: Schema = Schema.STRING_SCHEMA, comment: Option[String] = None) {
  require(name != null && name.trim.nonEmpty)
}

// contains a single partition in a table, that is one set of unique values, one per partition key
case class Partition(entries: NonEmptyList[(PartitionKey, String)], location: Option[Path])

case class Serde(serializationLib: String, inputFormat: String, outputFormat: String, params: Map[String, String])

// generates the default hive metatstore location string for a partition
object DefaultPartitionLocation extends Show[Partition] {
  override def show(t: Partition): String = {
    t.entries.map { case (key, value) => key.value + "=" + value }.toList.mkString("/")
  }
} 
Example 49
Source File: HiveSinkConfig.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.sink.config

import java.util.Collections

import cats.data.NonEmptyList
import com.datamountaineer.kcql.{Field, PartitioningStrategy, SchemaEvolution}
import com.landoop.streamreactor.connect.hive._
import com.landoop.streamreactor.connect.hive.formats.{HiveFormat, ParquetHiveFormat}
import com.landoop.streamreactor.connect.hive.kerberos.Kerberos
import com.landoop.streamreactor.connect.hive.sink.evolution.{AddEvolutionPolicy, EvolutionPolicy, IgnoreEvolutionPolicy, StrictEvolutionPolicy}
import com.landoop.streamreactor.connect.hive.sink.partitioning.{DynamicPartitionHandler, PartitionHandler, StrictPartitionHandler}
import com.landoop.streamreactor.connect.hive.sink.staging._

import scala.collection.JavaConverters._

case class HiveSinkConfig(dbName: DatabaseName,
                          filenamePolicy: FilenamePolicy = DefaultFilenamePolicy,
                          stageManager: StageManager = new StageManager(DefaultFilenamePolicy),
                          tableOptions: Set[TableOptions] = Set.empty,
                          kerberos: Option[Kerberos],
                          hadoopConfiguration: HadoopConfiguration)

case class TableOptions(tableName: TableName,
                        topic: Topic,
                        createTable: Boolean = false,
                        overwriteTable: Boolean = false,
                        partitioner: PartitionHandler = new DynamicPartitionHandler(),
                        evolutionPolicy: EvolutionPolicy = IgnoreEvolutionPolicy,
                        projection: Option[NonEmptyList[Field]] = None,
                        // when creating a new table, the table will be partitioned with the fields set below
                        partitions: Seq[PartitionField] = Nil,
                        // the format used when creating a new table, if the table exists
                        // then the format will be derived from the table parameters
                        format: HiveFormat = ParquetHiveFormat,
                        commitPolicy: CommitPolicy = DefaultCommitPolicy(Some(1000 * 1000 * 128), None, None),
                        location: Option[String] = None)

object HiveSinkConfig {

  def fromProps(props: Map[String, String]): HiveSinkConfig = {

    import scala.concurrent.duration._

    val config = HiveSinkConfigDefBuilder(props.asJava)
    val tables = config.getKCQL.map { kcql =>

      val fields = Option(kcql.getFields).getOrElse(Collections.emptyList).asScala.toList
      val projection = if (fields.size == 1 && fields.head.getName == "*") None else NonEmptyList.fromList(fields)

      val flushSize = Option(kcql.getWithFlushSize).filter(_ > 0)
      val flushInterval = Option(kcql.getWithFlushInterval).filter(_ > 0).map(_.seconds)
      val flushCount = Option(kcql.getWithFlushCount).filter(_ > 0)

      // we must have at least one way of committing files
      val finalFlushSize = Some(flushSize.fold(1000L * 1000 * 128)(identity)) //if (flushSize.isEmpty ) Some(1000L * 1000 * 128) else flushSize

      val format: HiveFormat = HiveFormat(Option(kcql.getStoredAs).map(_.toLowerCase).getOrElse("parquet"))

      TableOptions(
        TableName(kcql.getTarget),
        Topic(kcql.getSource),
        kcql.isAutoCreate,
        kcql.getWithOverwrite,
        Option(kcql.getWithPartitioningStrategy).getOrElse(PartitioningStrategy.DYNAMIC) match {
          case PartitioningStrategy.DYNAMIC => new DynamicPartitionHandler()
          case PartitioningStrategy.STRICT => StrictPartitionHandler
        },
        format = format,
        projection = projection,
        evolutionPolicy = Option(kcql.getWithSchemaEvolution).getOrElse(SchemaEvolution.MATCH) match {
          case SchemaEvolution.ADD => AddEvolutionPolicy
          case SchemaEvolution.IGNORE => IgnoreEvolutionPolicy
          case SchemaEvolution.MATCH => StrictEvolutionPolicy
        },
        partitions = Option(kcql.getPartitionBy).map(_.asScala).getOrElse(Nil).map(name => PartitionField(name)).toVector,
        commitPolicy = DefaultCommitPolicy(
          fileSize = finalFlushSize,
          interval = flushInterval,
          fileCount = flushCount
        ),
        location = Option(kcql.getWithTableLocation)
      )
    }

    HiveSinkConfig(
      dbName = DatabaseName(props(SinkConfigSettings.DatabaseNameKey)),
      filenamePolicy = DefaultFilenamePolicy,
      stageManager = new StageManager(DefaultFilenamePolicy),
      tableOptions = tables,
      kerberos = Kerberos.from(config, SinkConfigSettings),
      hadoopConfiguration = HadoopConfiguration.from(config, SinkConfigSettings)
    )
  }
} 
Example 50
Source File: ProjectionMapper.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.sink.mapper

import cats.data.NonEmptyList
import com.datamountaineer.kcql.Field
import com.landoop.streamreactor.connect.hive.StructMapper
import org.apache.kafka.connect.data.{SchemaBuilder, Struct}


class ProjectionMapper(projection: NonEmptyList[Field]) extends StructMapper {

  override def map(input: Struct): Struct = {
    // the compatible output schema built from projected fields with aliases applied
    val builder = projection.foldLeft(SchemaBuilder.struct) { (builder, kcqlField) =>
      Option(input.schema.field(kcqlField.getName)).fold(sys.error(s"Missing field $kcqlField")) { field =>
        builder.field(kcqlField.getAlias, field.schema)
      }
    }
    val schema = builder.build()
    projection.foldLeft(new Struct(schema)) { (struct, field) =>
      struct.put(field.getAlias, input.get(field.getName))
    }
  }
} 
Example 51
Source File: HiveSourceConfig.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.source.config

import java.util.Collections

import cats.data.NonEmptyList
import com.landoop.streamreactor.connect.hive.{DatabaseName, HadoopConfiguration, TableName, Topic}
import com.landoop.streamreactor.connect.hive.kerberos.Kerberos

import scala.collection.JavaConverters._

case class ProjectionField(name: String, alias: String)

case class HiveSourceConfig(dbName: DatabaseName,
                            kerberos: Option[Kerberos],
                            hadoopConfiguration: HadoopConfiguration,
                            tableOptions: Set[SourceTableOptions] = Set.empty,
                            pollSize: Int = 1024)

case class SourceTableOptions(
  tableName: TableName,
  topic: Topic,
  projection: Option[NonEmptyList[ProjectionField]] = None,
  limit: Int = Int.MaxValue
)

object HiveSourceConfig {

  def fromProps(props: Map[String, String]): HiveSourceConfig = {

    val config = HiveSourceConfigDefBuilder(props.asJava)
    val tables = config.getKCQL.map { kcql =>
      val fields = Option(kcql.getFields)
        .getOrElse(Collections.emptyList)
        .asScala
        .toList
        .map { field =>
          ProjectionField(field.getName, field.getAlias)
        }

      val projection = fields match {
        case Nil                              => None
        case ProjectionField("*", "*") :: Nil => None
        case _                                => NonEmptyList.fromList(fields)
      }

      SourceTableOptions(
        TableName(kcql.getSource),
        Topic(kcql.getTarget),
        projection,
        limit = if (kcql.getLimit < 1) Int.MaxValue else kcql.getLimit
      )
    }

    HiveSourceConfig(
      dbName = DatabaseName(props(HiveSourceConfigConstants.DatabaseNameKey)),
      tableOptions = tables,
      kerberos = Kerberos.from(config, HiveSourceConfigConstants),
      hadoopConfiguration =
        HadoopConfiguration.from(config, HiveSourceConfigConstants),
      pollSize = props
        .getOrElse(HiveSourceConfigConstants.PollSizeKey, 1024)
        .toString
        .toInt
    )
  }
} 
Example 52
Source File: ProjectionMapper.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.source.mapper

import cats.data.NonEmptyList
import com.landoop.streamreactor.connect.hive.StructMapper
import com.landoop.streamreactor.connect.hive.source.config.ProjectionField
import org.apache.kafka.connect.data.{SchemaBuilder, Struct}

class ProjectionMapper(projection: NonEmptyList[ProjectionField]) extends StructMapper {

  override def map(input: Struct): Struct = {
    val builder = projection.foldLeft(SchemaBuilder.struct) { (builder, projectionField) =>
      Option(input.schema.field(projectionField.name))
        .fold(sys.error(s"Projection field ${projectionField.name} cannot be found in input")) { field =>
          builder.field(projectionField.alias, field.schema)
        }
    }
    val schema = builder.build()
    projection.foldLeft(new Struct(schema)) { (struct, field) =>
      struct.put(field.alias, input.get(field.name))
    }
  }
} 
Example 53
Source File: DropPartitionValuesMapperTest.scala    From stream-reactor   with Apache License 2.0 5 votes vote down vote up
package com.landoop.streamreactor.connect.hive.sink.mapper

import cats.data.NonEmptyList
import com.landoop.streamreactor.connect.hive.{PartitionKey, PartitionPlan, TableName}
import org.apache.kafka.connect.data.{SchemaBuilder, Struct}
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

import scala.collection.JavaConverters._

class DropPartitionValuesMapperTest extends AnyFunSuite with Matchers {

  test("strip partition values") {

    val schema = SchemaBuilder.struct()
      .field("a", SchemaBuilder.string().required().build())
      .field("p", SchemaBuilder.string().required().build())
      .field("q", SchemaBuilder.string().required().build())
      .field("z", SchemaBuilder.string().required().build())
      .build()

    val plan = PartitionPlan(TableName("foo"), NonEmptyList.of(PartitionKey("p"), PartitionKey("q")))
    val struct = new Struct(schema).put("a", "a").put("p", "p").put("q", "q").put("z", "z")
    val output = new DropPartitionValuesMapper(plan).map(struct)
    output.schema().fields().asScala.map(_.name) shouldBe Seq("a", "z")
  }

  test("handle partition field is missing in input") {

    val schema = SchemaBuilder.struct()
      .field("a", SchemaBuilder.string().required().build())
      .field("q", SchemaBuilder.string().required().build())
      .field("z", SchemaBuilder.string().required().build())
      .build()


    val plan = PartitionPlan(TableName("foo"), NonEmptyList.of(PartitionKey("p"), PartitionKey("q")))
    val struct = new Struct(schema).put("a", "a").put("q", "q").put("z", "z")
    val output = new DropPartitionValuesMapper(plan).map(struct)
    output.schema().fields().asScala.map(_.name) shouldBe Seq("a", "z")
  }
} 
Example 54
Source File: InvokeScriptTxValidator.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.transaction.validation.impl

import cats.data.NonEmptyList
import cats.data.Validated.{Invalid, Valid}
import cats.implicits._
import com.wavesplatform.lang.v1.compiler.Terms.FUNCTION_CALL
import com.wavesplatform.lang.v1.{ContractLimits, FunctionHeader}
import com.wavesplatform.protobuf.transaction.PBTransactions
import com.wavesplatform.transaction.TxValidationError.{GenericError, NonPositiveAmount, TooBigArray}
import com.wavesplatform.transaction.smart.InvokeScriptTransaction
import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment
import com.wavesplatform.transaction.validation.{TxValidator, ValidatedNV, ValidatedV}
import com.wavesplatform.utils._

import scala.util.Try

object InvokeScriptTxValidator extends TxValidator[InvokeScriptTransaction] {
  override def validate(tx: InvokeScriptTransaction): ValidatedV[InvokeScriptTransaction] = {
    import tx._

    def checkAmounts(payments: Seq[Payment]): ValidatedNV = {
      val invalid = payments.filter(_.amount <= 0)
      if (invalid.nonEmpty)
        Invalid(NonEmptyList.fromListUnsafe(invalid.toList).map(p => NonPositiveAmount(p.amount, p.assetId.fold("Waves")(_.toString))))
      else Valid(())
    }

    def checkLength =
      if (tx.isProtobufVersion)
        PBTransactions
          .toPBInvokeScriptData(tx.dAppAddressOrAlias, tx.funcCallOpt, tx.payments)
          .toByteArray
          .length <= ContractLimits.MaxInvokeScriptSizeInBytes
      else tx.bytes().length <= ContractLimits.MaxInvokeScriptSizeInBytes

    val callableNameSize =
      funcCallOpt match {
        case Some(FUNCTION_CALL(FunctionHeader.User(internalName, _), _)) => internalName.utf8Bytes.length
        case _ => 0
      }

    V.seq(tx)(
      V.addressChainId(dAppAddressOrAlias, chainId),
      V.cond(
        funcCallOpt.isEmpty || funcCallOpt.get.args.size <= ContractLimits.MaxInvokeScriptArgs,
        GenericError(s"InvokeScript can't have more than ${ContractLimits.MaxInvokeScriptArgs} arguments")
      ),
      V.cond(
        callableNameSize <= ContractLimits.MaxDeclarationNameInBytes,
        GenericError(s"Callable function name size = $callableNameSize bytes must be less than ${ContractLimits.MaxDeclarationNameInBytes}")
      ),
      checkAmounts(payments),
      V.fee(fee),
      Try(checkLength)
        .toEither
        .leftMap(err => GenericError(err.getMessage))
        .filterOrElse(identity, TooBigArray)
        .toValidatedNel
        .map(_ => ())
    )
  }
} 
Example 55
Source File: MiningConstraint.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.mining

import cats.data.NonEmptyList
import com.wavesplatform.state.{Blockchain, Diff}
import com.wavesplatform.transaction.Transaction

trait MiningConstraint {
  def isFull: Boolean
  def isOverfilled: Boolean
  def put(blockchain: Blockchain, x: Transaction, diff: Diff): MiningConstraint
}

object MiningConstraint {
  case object Unlimited extends MiningConstraint {
    override def isFull: Boolean                                                           = false
    override def isOverfilled: Boolean                                                     = false
    override def put(blockchain: Blockchain, x: Transaction, diff: Diff): MiningConstraint = this
  }
}

case class OneDimensionalMiningConstraint(rest: Long, estimator: TxEstimators.Fn, description: String) extends MiningConstraint {
  override def isFull: Boolean = {
    rest < estimator.minEstimate
  }
  override def isOverfilled: Boolean = {
    rest < 0
  }
  override def put(blockchain: Blockchain, x: Transaction, diff: Diff): OneDimensionalMiningConstraint = put(estimator(blockchain, x, diff))
  private def put(x: Long): OneDimensionalMiningConstraint = {
    copy(rest = this.rest - x)
  }

  override def toString: String = {
    s"MiningConstraint(${if (description.isEmpty) "???" else description}, rest = $rest, estimator = $estimator)"
  }
}

case class MultiDimensionalMiningConstraint(constraints: NonEmptyList[MiningConstraint]) extends MiningConstraint {
  override def isFull: Boolean       = constraints.exists(_.isFull)
  override def isOverfilled: Boolean = constraints.exists(_.isOverfilled)
  override def put(blockchain: Blockchain, x: Transaction, diff: Diff): MultiDimensionalMiningConstraint =
    MultiDimensionalMiningConstraint(constraints.map(_.put(blockchain, x, diff)))
}

object MultiDimensionalMiningConstraint {
  val unlimited = MultiDimensionalMiningConstraint(NonEmptyList.of(MiningConstraint.Unlimited))

  def apply(constraint1: MiningConstraint, constraint2: MiningConstraint): MultiDimensionalMiningConstraint =
    MultiDimensionalMiningConstraint(NonEmptyList.of(constraint1, constraint2))

  def formatOverfilledConstraints(currRest: MultiDimensionalMiningConstraint, updatedRest: MultiDimensionalMiningConstraint): Iterator[String] = {
    if (currRest.constraints.length == updatedRest.constraints.length) {
      (for ((curr, upd) <- currRest.constraints.toList.iterator.zip(updatedRest.constraints.toList.iterator) if upd.isOverfilled)
        yield (curr, upd) match {
          case (OneDimensionalMiningConstraint(rest, _, description), OneDimensionalMiningConstraint(newRest, _, _)) =>
            Iterator.single(s"$description($rest -> $newRest)")

          case (m: MultiDimensionalMiningConstraint, m1: MultiDimensionalMiningConstraint) =>
            Iterator.empty ++ formatOverfilledConstraints(m, m1)

          case _ =>
            Iterator.single(s"$curr -> $upd")
        }).flatten
    } else {
      updatedRest.constraints.toList.iterator
        .filter(_.isOverfilled)
        .map(_.toString)
    }
  }
} 
Example 56
Source File: MiningConstraints.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.mining

import cats.data.NonEmptyList
import com.wavesplatform.block.Block
import com.wavesplatform.features.BlockchainFeatures
import com.wavesplatform.settings.MinerSettings
import com.wavesplatform.state.Blockchain

case class MiningConstraints(total: MiningConstraint, keyBlock: MiningConstraint, micro: MiningConstraint)

object MiningConstraints {
  val MaxScriptRunsInBlock = 100
  val MaxScriptsComplexityInBlock = 1000000
  val ClassicAmountOfTxsInBlock = 100
  val MaxTxsSizeInBytes = 1 * 1024 * 1024 // 1 megabyte

  def apply(blockchain: Blockchain, height: Int, minerSettings: Option[MinerSettings] = None): MiningConstraints = {
    val activatedFeatures     = blockchain.activatedFeaturesAt(height)
    val isNgEnabled           = activatedFeatures.contains(BlockchainFeatures.NG.id)
    val isMassTransferEnabled = activatedFeatures.contains(BlockchainFeatures.MassTransfer.id)
    val isScriptEnabled       = activatedFeatures.contains(BlockchainFeatures.SmartAccounts.id)
    val isDAppsEnabled        = activatedFeatures.contains(BlockchainFeatures.Ride4DApps.id)

    val total: MiningConstraint =
      if (isMassTransferEnabled) OneDimensionalMiningConstraint(MaxTxsSizeInBytes, TxEstimators.sizeInBytes, "MaxTxsSizeInBytes")
      else {
        val maxTxs = if (isNgEnabled) Block.MaxTransactionsPerBlockVer3 else ClassicAmountOfTxsInBlock
        OneDimensionalMiningConstraint(maxTxs, TxEstimators.one, "MaxTxs")
      }

    new MiningConstraints(
      total =
        if (isDAppsEnabled)
          MultiDimensionalMiningConstraint(
            NonEmptyList
              .of(OneDimensionalMiningConstraint(MaxScriptsComplexityInBlock, TxEstimators.scriptsComplexity, "MaxScriptsComplexityInBlock"), total))
        else if (isScriptEnabled)
          MultiDimensionalMiningConstraint(
            NonEmptyList.of(OneDimensionalMiningConstraint(MaxScriptRunsInBlock, TxEstimators.scriptRunNumber, "MaxScriptRunsInBlock"), total))
        else total,
      keyBlock =
        if (isNgEnabled) OneDimensionalMiningConstraint(0, TxEstimators.one, "MaxTxsInKeyBlock")
        else OneDimensionalMiningConstraint(ClassicAmountOfTxsInBlock, TxEstimators.one, "MaxTxsInKeyBlock"),
      micro =
        if (isNgEnabled && minerSettings.isDefined)
          OneDimensionalMiningConstraint(minerSettings.get.maxTransactionsInMicroBlock, TxEstimators.one, "MaxTxsInMicroBlock")
        else MiningConstraint.Unlimited
    )
  }
} 
Example 57
Source File: Types.scala    From daml   with Apache License 2.0 5 votes vote down vote up
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.extractor.services

import cats.data.NonEmptyList
import cats.implicits._

import doobie._
import io.circe._
import io.circe.parser._

import org.postgresql.util.PGobject

trait Types {
  implicit val jsonGet: Get[Json] =
    Get.Advanced.other[PGobject](NonEmptyList.of("jsonb")).tmap[Json] { o =>
      parse(o.getValue).leftMap[Json](throw _).merge
    }

  case class ContractResult(
      event_id: String,
      archived_by_event_id: Option[String],
      contract_id: String,
      transaction_id: String,
      archived_by_transaction_id: Option[String],
      is_root_event: Boolean,
      package_id: String,
      template: String,
      create_arguments: Json,
      stakeholders: Json
  )

  case class TransactionResult(
      transaction_id: String,
      seq: Int,
      workflow_id: String,
      effective_at: java.sql.Timestamp,
      extracted_at: java.sql.Timestamp,
      ledger_offset: String
  )

  case class ExerciseResult(
      event_id: String,
      transaction_id: String,
      is_root_event: Boolean,
      contract_id: String,
      package_id: String,
      template: String,
      choice: String,
      choice_argument: Json,
      acting_parties: Json,
      consuming: Boolean,
      witness_parties: Json,
      child_event_ids: Json
  )
}

object Types extends Types 
Example 58
Source File: Consensus.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.consensus

import cats.data.NonEmptyList
import jbok.core.consensus.Consensus._
import jbok.core.ledger.TypedBlock.{ExecutedBlock, MinedBlock}
import jbok.core.models.{Block, BlockHeader}


trait Consensus[F[_]] {
  def prepareHeader(parentOpt: Option[Block]): F[BlockHeader]

  def mine(executed: ExecutedBlock[F]): F[MinedBlock]

  def verify(block: Block): F[Unit]

  def run(block: Block): F[Result]

  def resolveBranch(headers: List[BlockHeader]): F[BranchResult]
}

object Consensus {
  sealed trait Result
  final case class Forward(blocks: List[Block])                         extends Result
  final case class Fork(oldBranch: List[Block], newBranch: List[Block]) extends Result
  final case class Stash(block: Block)                                  extends Result
  final case class Discard(reason: Throwable)                           extends Result

  sealed trait BranchResult
  final case class BetterBranch(newBranch: NonEmptyList[BlockHeader]) extends BranchResult
  final case object NoChainSwitch                                     extends BranchResult
  final case object InvalidBranch                                     extends BranchResult
} 
Example 59
Source File: SimulatePlanApp.scala    From Scala-Programming-Projects   with MIT License 5 votes vote down vote up
package retcalc

import cats.data.Validated._
import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._
import retcalc.RetCalcError.{InvalidArgument, InvalidNumber, RetCalcResult}

object SimulatePlanApp extends App {
  strMain(args) match {
    case Invalid(err) =>
      println(err)
      sys.exit(1)

    case Valid(result) =>
      println(result)
      sys.exit(0)
  }

  def parseInt(name: String, value: String): RetCalcResult[Int] =
    Validated
      .catchOnly[NumberFormatException](value.toInt)
      .leftMap(_ => NonEmptyList.of(InvalidNumber(name, value)))

  def parseParams(args: Array[String]): RetCalcResult[RetCalcParams] =
    (
      parseInt("nbOfYearsRetired", args(2)),
      parseInt("netIncome", args(3)),
      parseInt("currentExpenses", args(4)),
      parseInt("initialCapital", args(5))
    ).mapN { case (nbOfYearsRetired, netIncome, currentExpenses, initialCapital) =>
      RetCalcParams(
        nbOfMonthsInRetirement = nbOfYearsRetired * 12,
        netIncome = netIncome,
        currentExpenses = currentExpenses,
        initialCapital = initialCapital)
    }

  def parseFromUntil(fromUntil: String): RetCalcResult[(String, String)] = {
    val array = fromUntil.split(",")
    if (array.length != 2)
      InvalidArgument(name = "fromUntil", value = fromUntil, expectedFormat = "from,until"
      ).invalidNel
    else
      (array(0), array(1)).validNel
  }

  def strSimulatePlan(returns: Returns, nbOfYearsSaving: Int, params: RetCalcParams)
  : RetCalcResult[String] = {
    RetCalc.simulatePlan(
      returns = returns,
      params = params,
      nbOfMonthsSavings = nbOfYearsSaving * 12
    ).map {
      case (capitalAtRetirement, capitalAfterDeath) =>
        val nbOfYearsInRetirement = params.nbOfMonthsInRetirement / 12
        s"""
           |Capital after $nbOfYearsSaving years of savings:    ${capitalAtRetirement.round}
           |Capital after $nbOfYearsInRetirement years in retirement: ${capitalAfterDeath.round}
           |""".stripMargin
    }.toValidatedNel
  }


  def strMain(args: Array[String]): Validated[String, String] = {
    if (args.length != 6)
      """Usage:
        |simulatePlan from,until nbOfYearsSaving nbOfYearsRetired netIncome currentExpenses initialCapital
        |
        |Example:
        |simulatePlan 1952.09,2017.09 25 40 3000 2000 10000
        |""".stripMargin.invalid
    else {
      val allReturns = Returns.fromEquityAndInflationData(
        equities = EquityData.fromResource("sp500.tsv"),
        inflations = InflationData.fromResource("cpi.tsv"))

      val vFromUntil = parseFromUntil(args(0))
      val vNbOfYearsSaving = parseInt("nbOfYearsSaving", args(1))
      val vParams = parseParams(args)

      (vFromUntil, vNbOfYearsSaving, vParams)
        .tupled
        .andThen { case ((from, until), nbOfYearsSaving, params) =>
          strSimulatePlan(allReturns.fromUntil(from, until), nbOfYearsSaving, params)
        }
        .leftMap(nel => nel.map(_.message).toList.mkString("\n"))
    }
  }
}

case class SimulatePlanArgs(fromMonth: String,
                            untilMonth: String,
                            retCalcParams: RetCalcParams,
                            nbOfMonthsSavings: Int) 
Example 60
Source File: syntax.scala    From refined   with MIT License 5 votes vote down vote up
package eu.timepit.refined.cats

import cats.data.{NonEmptyList, ValidatedNec, ValidatedNel}
import cats.syntax.either._
import eu.timepit.refined.api.RefinedTypeOps
import eu.timepit.refined.types.numeric.PosInt

object syntax extends CatsRefinedTypeOpsSyntax with CatsNonEmptyListSyntax

trait CatsRefinedTypeOpsSyntax {
  implicit class CatsRefinedTypeOps[FTP, T](rtOps: RefinedTypeOps[FTP, T]) {
    def validate(t: T): ValidatedNel[String, FTP] =
      validateNel(t)

    def validateNec(t: T): ValidatedNec[String, FTP] =
      rtOps.from(t).toValidatedNec

    def validateNel(t: T): ValidatedNel[String, FTP] =
      rtOps.from(t).toValidatedNel
  }
}

trait CatsNonEmptyListSyntax {
  implicit class CatsNonEmptyListRefinedOps[A](nel: NonEmptyList[A]) {
    def refinedSize: PosInt = PosInt.unsafeFrom(nel.size)
  }
} 
Example 61
Source File: WsOrdersUpdate.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.api.ws.protocol

import cats.data.NonEmptyList
import cats.syntax.option._
import com.wavesplatform.dex.api.ws.entities.WsFullOrder
import com.wavesplatform.dex.domain.model.Denormalization
import com.wavesplatform.dex.error.ErrorFormatterContext
import com.wavesplatform.dex.model.AcceptedOrder
import com.wavesplatform.dex.model.Events.{OrderCanceled, OrderExecuted}
import play.api.libs.functional.syntax._
import play.api.libs.json._

case class WsOrdersUpdate(orders: NonEmptyList[WsFullOrder], timestamp: Long = System.currentTimeMillis) extends WsServerMessage {
  override val tpe: String = WsOrdersUpdate.tpe

  def append(other: WsOrdersUpdate): WsOrdersUpdate = copy(
    orders = other.orders ::: orders,
    timestamp = other.timestamp
  )
}

object WsOrdersUpdate {

  val tpe = "osu"

  def from(x: OrderCanceled)(implicit efc: ErrorFormatterContext): WsOrdersUpdate = WsOrdersUpdate(
    NonEmptyList.one(WsFullOrder.from(x))
  )

  def from(x: OrderExecuted, ts: Long)(implicit efc: ErrorFormatterContext): WsOrdersUpdate = {
    val ao1       = x.counterRemaining
    val assetPair = ao1.order.assetPair

    val amountAssetDecimals = efc.assetDecimals(assetPair.amountAsset)
    val priceAssetDecimals  = efc.assetDecimals(assetPair.priceAsset)

    def denormalizeAmount(value: Long): Double = Denormalization.denormalizeAmountAndFee(value, amountAssetDecimals).toDouble
    def denormalizePrice(value: Long): Double  = Denormalization.denormalizePrice(value, amountAssetDecimals, priceAssetDecimals).toDouble

    def from(ao: AcceptedOrder): WsFullOrder =
      WsFullOrder.from(
        ao,
        x,
        denormalizeAmount,
        denormalizePrice,
        Denormalization.denormalizeAmountAndFee(_, efc.assetDecimals(ao.feeAsset)).toDouble
      )

    WsOrdersUpdate(NonEmptyList.of(ao1, x.submittedRemaining).map(from), timestamp = ts)
  }

  def wsUnapply(arg: WsOrdersUpdate): Option[(String, Long, NonEmptyList[WsFullOrder])] = (arg.tpe, arg.timestamp, arg.orders).some

  implicit def nonEmptyListFormat[T: Format]: Format[NonEmptyList[T]] = Format(
    Reads.list[T].flatMap { xs =>
      NonEmptyList.fromList(xs).fold[Reads[NonEmptyList[T]]](Reads.failed("The list is empty"))(Reads.pure(_))
    },
    Writes.list[T].contramap(_.toList)
  )

  implicit val wsOrdersUpdateFormat: Format[WsOrdersUpdate] = (
    (__ \ "T").format[String] and
      (__ \ "_").format[Long] and
      (__ \ "o").format(nonEmptyListFormat[WsFullOrder])
  )(
    (_, ts, orders) => WsOrdersUpdate(orders, ts),
    unlift(WsOrdersUpdate.wsUnapply)
  )
} 
Example 62
Source File: OrderRestrictionsSettings.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.settings

import cats.data.NonEmptyList
import cats.syntax.apply._
import com.wavesplatform.dex.settings.utils.ConfigSettingsValidator
import com.wavesplatform.dex.settings.utils.ConfigSettingsValidator.{ErrorsListOr, _}
import net.ceedubs.ficus.Ficus._
import net.ceedubs.ficus.readers.ValueReader

case class OrderRestrictionsSettings(stepAmount: Double, minAmount: Double, maxAmount: Double, stepPrice: Double, minPrice: Double, maxPrice: Double)

object OrderRestrictionsSettings {

  val Default =
    OrderRestrictionsSettings(
      stepAmount = 0.00000001,
      minAmount = 0.00000001,
      maxAmount = 1000000000,
      stepPrice = 0.00000001,
      minPrice = 0.00000001,
      maxPrice = 1000000
    )

  implicit val orderRestrictionsSettingsReader: ValueReader[OrderRestrictionsSettings] = { (cfg, path) =>
    val cfgValidator = ConfigSettingsValidator(cfg)

    def validateSizeMinMax(stepSettingName: String,
                           minSettingName: String,
                           maxSettingName: String,
                           stepDefaultValue: Double,
                           minDefaultValue: Double,
                           maxDefaultValue: Double): ErrorsListOr[(Double, Double, Double)] = {

      def validateSetting(settingName: String, defaultValue: Double): ErrorsListOr[Double] =
        cfgValidator.validateByPredicateWithDefault[Double](settingName)(_ > 0, s"required 0 < value", defaultValue)

      (
        validateSetting(stepSettingName, stepDefaultValue),
        validateSetting(minSettingName, minDefaultValue),
        validateSetting(maxSettingName, maxDefaultValue)
      ).mapN(Tuple3.apply)
        .ensure(NonEmptyList(s"Required $minSettingName < $maxSettingName", Nil)) { case (_, min, max) => min < max }
    }

    (
      validateSizeMinMax(s"$path.step-amount", s"$path.min-amount", s"$path.max-amount", Default.stepAmount, Default.minAmount, Default.maxAmount),
      validateSizeMinMax(s"$path.step-price", s"$path.min-price", s"$path.max-price", Default.stepPrice, Default.minPrice, Default.maxPrice),
    ) mapN {
      case ((stepAmount, minAmount, maxAmount), (stepPrice, minPrice, maxPrice)) =>
        OrderRestrictionsSettings(stepAmount, minAmount, maxAmount, stepPrice, minPrice, maxPrice)
    } getValueOrThrowErrors
  }
} 
Example 63
Source File: MatchingRulesCache.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.caches

import java.util.concurrent.ConcurrentHashMap

import cats.data.NonEmptyList
import com.wavesplatform.dex.domain.asset.{Asset, AssetPair}
import com.wavesplatform.dex.domain.utils.ScorexLogging
import com.wavesplatform.dex.settings.{DenormalizedMatchingRule, MatcherSettings, MatchingRule}

import scala.util.Try
import scala.util.control.NonFatal

class MatchingRulesCache(matcherSettings: MatcherSettings) extends ScorexLogging {

  private val allMatchingRules    = new ConcurrentHashMap[AssetPair, NonEmptyList[DenormalizedMatchingRule]]
  private val currentMatchingRule = new ConcurrentHashMap[AssetPair, DenormalizedMatchingRule]

  def getMatchingRules(assetPair: AssetPair, assetDecimals: Asset => Int): NonEmptyList[DenormalizedMatchingRule] = {
    allMatchingRules.computeIfAbsent(
      assetPair,
      _ => DenormalizedMatchingRule.getDenormalizedMatchingRules(matcherSettings, assetDecimals, assetPair)
    )
  }

  // DEX-488 TODO remove after found a reason of NPE
  def getDenormalizedRuleForNextOrder(assetPair: AssetPair, currentOffset: Long, assetDecimals: Asset => Int): DenormalizedMatchingRule = {

    lazy val defaultRule = DenormalizedMatchingRule.getDefaultRule(assetPair, assetDecimals)

    val result =
      Try {
        getMatchingRules(assetPair, assetDecimals).foldLeft(defaultRule) { case (acc, mr) => if (mr.startOffset <= (currentOffset + 1)) mr else acc }
      }.recover { case NonFatal(e) => log.error(s"Can't get a denormalized rule for a next order", e); defaultRule }
        .getOrElse(defaultRule)

    result.copy(tickSize = result.tickSize max defaultRule.tickSize)
  }

  def getNormalizedRuleForNextOrder(assetPair: AssetPair, currentOffset: Long, assetDecimals: Asset => Int): MatchingRule = {
    getDenormalizedRuleForNextOrder(assetPair, currentOffset, assetDecimals).normalize(assetPair, assetDecimals)
  }

  def updateCurrentMatchingRule(assetPair: AssetPair, denormalizedMatchingRule: DenormalizedMatchingRule): Unit = {
    currentMatchingRule.put(assetPair, denormalizedMatchingRule)
  }

  def setCurrentMatchingRuleForNewOrderBook(assetPair: AssetPair, currentOffset: Long, assetDecimals: Asset => Int): Unit = {
    updateCurrentMatchingRule(assetPair, getDenormalizedRuleForNextOrder(assetPair, currentOffset, assetDecimals))
  }
} 
Example 64
Source File: HealthReporter.scala    From sup   with Apache License 2.0 5 votes vote down vote up
package sup.data

import cats.data.NonEmptyList
import cats.implicits._
import cats.Apply
import cats.Functor
import cats.NonEmptyParallel
import cats.NonEmptyTraverse
import cats.Parallel
import cats.Reducible
import sup._

object HealthReporter {

  
  def parWrapChecks[F[_]: NonEmptyParallel: Functor, G[_]: NonEmptyTraverse, H[_]: Reducible](
    checks: G[HealthCheck[F, H]]
  ): HealthReporter[F, G, H] = HealthCheck.liftF {

    Parallel.parNonEmptyTraverse(checks)(_.check).map(fromResults[G, H])
  }

  def fromResults[G[_]: Reducible: Functor, H[_]: Reducible](
    results: G[HealthResult[H]]
  ): HealthResult[Report[G, H, ?]] =
    HealthResult(Report.fromResults[G, H, Health](results.map(_.value)))
} 
Example 65
Source File: PathGroup.scala    From docless   with MIT License 5 votes vote down vote up
package com.timeout.docless.swagger

import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.instances.all._
import cats.syntax.eq._
import cats.syntax.foldable._
import cats.syntax.monoid._
import cats.{Eq, Monoid}
import com.timeout.docless.schema.JsonSchema.{Definition, TypeRef}

trait PathGroup {
  def params: List[OperationParameter] = Nil

  def definitions: List[Definition]

  def paths: List[Path]
}

object PathGroup {
  val Empty = PathGroup(Nil, Nil, Nil)

  def aggregate(
      info: Info,
      groups: List[PathGroup],
      securitySchemes: List[SecurityScheme] = Nil
  ): ValidatedNel[SchemaError, APISchema] = {
    val g          = groups.combineAll
    val allDefs    = g.definitions
    val definedIds = allDefs.map(_.id).toSet
    val securityDefinitions = SecurityDefinitions(securitySchemes: _*)

    def isDefined(ctx: RefWithContext): Boolean =
      allDefs.exists(_.id === ctx.ref.id)

    val missingDefinitions =
      allDefs.foldMap { d =>
        d.relatedRefs.collect {
          case r @ TypeRef(id, _) if !definedIds.exists(_ === id) =>
            SchemaError.missingDefinition(RefWithContext.definition(r, d))
        }
      }

    val errors =
      g.paths
        .foldMap(_.refs.filterNot(isDefined))
        .map(SchemaError.missingDefinition)
        .toList ++ missingDefinitions

    if (errors.nonEmpty)
      Validated.invalid[NonEmptyList[SchemaError], APISchema](
        NonEmptyList.fromListUnsafe(errors)
      )
    else
      Validated.valid {
        APISchema(
          info = info,
          host = "http://example.com/",
          basePath = "/",
          parameters = OperationParameters(g.params),
          paths = Paths(g.paths),
          schemes = Set(Scheme.Http),
          consumes = Set("application/json"),
          produces = Set("application/json"),
          securityDefinitions = securityDefinitions
        ).defining(g.definitions: _*)
      }
  }

  def apply(ps: List[Path],
            defs: List[Definition],
            _params: List[OperationParameter]): PathGroup =
    new PathGroup {

      override val paths       = ps
      override val definitions = defs
      override val params      = _params
    }

  implicit val pgEq: Eq[PathGroup] = Eq.fromUniversalEquals

  implicit def pgMonoid: Monoid[PathGroup] = new Monoid[PathGroup] {
    override def empty: PathGroup = Empty

    override def combine(x: PathGroup, y: PathGroup): PathGroup =
      PathGroup(
        x.paths |+| y.paths,
        x.definitions |+| y.definitions,
        x.params |+| y.params
      )
  }

} 
Example 66
Source File: PathGroupTest.scala    From docless   with MIT License 5 votes vote down vote up
package com.timeout.docless.swagger

import org.scalatest.{FreeSpec, Inside, Matchers}
import cats.data.NonEmptyList
import cats.data.Validated
import SchemaError._
import com.timeout.docless.schema.JsonSchema
import com.timeout.docless.schema.JsonSchema._
import com.timeout.docless.swagger.Method._

class PathGroupTest extends FreeSpec with Matchers {
  "PathGroup" - {
    val petstore = PetstoreSchema()
    val pet      = PetstoreSchema.Schemas.pet

    val paths     = Path("/example") :: petstore.paths.get.toList
    val defs      = petstore.definitions.get.toList
    val defsNoPet = defs.filterNot(_.id === pet.id)
    val params    = petstore.parameters.get.toList

    val group1          = PathGroup(paths, defs, params)
    val group2          = PathGroup(List(Path("/extra")), Nil, Nil)
    val groupMissingErr = PathGroup(paths, defsNoPet, params)

    def err(path: String, m: Method, f: Definition => Ref): SchemaError =
      missingDefinition(RefWithContext.response(f(pet.definition), m, path))

    "aggregate" - {
      "when some top level definitions are missing" - {
        "returns the missing refs" in {
          PathGroup.aggregate(petstore.info, List(groupMissingErr)) should ===(
            Validated.invalid[NonEmptyList[SchemaError], APISchema](
              NonEmptyList.of(
                err("/pets", Get, ArrayRef.apply),
                err("/pets", Post, TypeRef.apply),
                err("/pets/{id}", Get, TypeRef.apply),
                err("/pets/{id}", Delete, TypeRef.apply)
              )
            )
          )
        }
      }
      "when some nested definitions are missing" - {
        val info = Info("example")
        case class Nested(name: String)
        case class TopLevel(nested: Nested)

        val schema = JsonSchema.deriveFor[TopLevel]
        val nested = schema.relatedDefinitions.head

        val paths = List(
          "/example".Post(
            Operation('_, "...")
              .withParams(BodyParameter(schema = Some(schema.asRef)))
          )
        )

        val withNested    = PathGroup(paths, schema.definitions.toList, Nil)
        val withoutNested = PathGroup(paths, List(schema.definition), Nil)

        "returns the missing refs" in {
          PathGroup.aggregate(info, List(withNested)).isValid shouldBe true
          PathGroup.aggregate(info, List(withoutNested)) should ===(
            Validated.invalid[NonEmptyList[SchemaError], APISchema](
              NonEmptyList.of(
                MissingDefinition(
                  RefWithContext.definition(nested.asRef, schema.definition)
                )
              )
            )
          )
        }
      }
      "when no definition is missing" - {
        "returns a valid api schema" in new Inside {
          inside(PathGroup.aggregate(petstore.info, List(group1, group2))) {
            case Validated.Valid(schema) =>
              schema.info should ===(petstore.info)
              schema.paths.get should ===(group1.paths ++ group2.paths)
              schema.definitions.get should ===(
                group1.definitions ++ group2.definitions
              )
              schema.parameters.get should ===(group1.params ++ group2.params)
          }
        }
      }
    }
  }
} 
Example 67
Source File: FailuresSpec.scala    From roc   with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
package roc
package postgresql

import cats.data.NonEmptyList
import org.scalacheck.Prop.forAll
import org.scalacheck.Gen
import org.specs2._
import roc.postgresql.failures._

final class FailuresSpec extends Specification with ScalaCheck { def is = s2"""

  Failure
    ReadyForQueryDecodingFailure should have correct message         $readyForQueryDecodingFailure
    UnknownAuthenticationFailure should have correct message         $unknownAuthRequestFailure
    UnsupportedAuthenticationFailure should have correct message     $unsupportedAuthFailure
    PostgresqlStateMachineFailure should have correct message        $postgresqlStateMachineFailure
    UnknownPostgresqlMessageTypeFailure should have correct message  $unknownPostgresqlMessageTypeFailure
    PostgresqlMessageDecodingFailure must have a correct error message   $postgresqlMessageDecodingFailure
                                                                         """

  val readyForQueryDecodingFailure = forAll { c: Char =>
    val msg = s"Received unexpected Char $c from Postgres Server."
    val error = new ReadyForQueryDecodingFailure(c)
    error.getMessage must_== msg
  }

  val unknownAuthRequestFailure = forAll { n: Int =>
    val expectedMessage = s"Unknown Authentication Request Type: $n"
    val error           = new UnknownAuthenticationRequestFailure(n)
    error.getMessage must_== expectedMessage
  }

  val unsupportedAuthFailure = forAll { s: String =>
    val expectedMessage =
      s"Unsupported Authentication Failure. $s authentication is not supported."
    val error           = new UnsupportedAuthenticationFailure(s)
    error.getMessage must_== expectedMessage
  }
  
  val postgresqlStateMachineFailure = forAll { (s1: String, s2: String) =>
    val expectedMessage = s"State Transition from $s1 -> $s2 is undefined."
    val error           = new PostgresqlStateMachineFailure(s1, s2)
    error.getMessage must_== expectedMessage
  }
  
  val unknownPostgresqlMessageTypeFailure = forAll { c: Char =>
    val expectedMessage = s"Unknown Postgresql MessageType '$c'."
    val error           = new UnknownPostgresqlMessageTypeFailure(c)
    error.getMessage must_== expectedMessage
  }

  val postgresqlMessageDecodingFailure = forAll(genNELErrorResponse) { nel: NonEmptyList[String] =>
    val error = new PostgresqlMessageDecodingFailure(nel)
    val expectedMessage = nel.foldLeft("")(_ + _)
    expectedMessage must_== error.getMessage
  }

  private lazy val genErrorResponseString: Gen[String] = Gen.oneOf(
    "Required Severity Level was not present.",
    "Required SQLSTATE Code was not present.",
    "Required Message was not present."
  )
  private lazy val genNELErrorResponse: Gen[NonEmptyList[String]] = for {
    string  <-  genErrorResponseString
  } yield NonEmptyList.of(string)

} 
Example 68
Source File: CatsIntegrationSpec.scala    From octopus   with Apache License 2.0 5 votes vote down vote up
package octopus.cats

import cats.data.{NonEmptyList, Validated}
import octopus.example.domain._
import octopus.syntax._
import octopus.{Fixtures, ValidationError}
import org.scalatest.matchers.must.Matchers
import org.scalatest.wordspec.AnyWordSpec

class CatsIntegrationSpec
  extends AnyWordSpec with Matchers with Fixtures {

  "Cats Integration" should {

    "support ValidatedNel" when {

      "Valid scenario" in {
        1.validate.toValidatedNel mustBe Validated.Valid(1)
        userId_Valid.validate.toValidatedNel mustBe Validated.Valid(userId_Valid)
        user_Valid.validate.toValidatedNel mustBe Validated.Valid(user_Valid)
      }

      "Invalid scenario" in {

        userId_Invalid.validate.toValidatedNel mustBe Validated.Invalid(
          NonEmptyList.of(ValidationError(UserId.Err_MustBePositive))
        )

        user_Invalid1.validate.toValidatedNel.leftMap(_.map(_.toPair)) mustBe Validated.Invalid(
          NonEmptyList.of(
            "id" -> UserId.Err_MustBePositive,
            "email" -> Email.Err_MustContainAt,
            "email" -> Email.Err_MustContainDotAfterAt,
            "address.postalCode" -> PostalCode.Err_MustBeLengthOf5,
            "address.postalCode" -> PostalCode.Err_MustContainOnlyDigits,
            "address.city" -> Address.Err_MustNotBeEmpty,
            "address.street" -> Address.Err_MustNotBeEmpty
          )
        )
      }
    }

    "support Validated" when {

      "Valid scenario" in {
        1.validate.toValidated mustBe Validated.Valid(1)
        userId_Valid.validate.toValidated mustBe Validated.Valid(userId_Valid)
        user_Valid.validate.toValidated mustBe Validated.Valid(user_Valid)
      }

      "Invalid scenario" in {

        userId_Invalid.validate.toValidated mustBe Validated.Invalid(
          List(ValidationError(UserId.Err_MustBePositive))
        )

        user_Invalid1.validate.toValidated.leftMap(_.map(_.toPair)) mustBe Validated.Invalid(
          List(
            "id" -> UserId.Err_MustBePositive,
            "email" -> Email.Err_MustContainAt,
            "email" -> Email.Err_MustContainDotAfterAt,
            "address.postalCode" -> PostalCode.Err_MustBeLengthOf5,
            "address.postalCode" -> PostalCode.Err_MustContainOnlyDigits,
            "address.city" -> Address.Err_MustNotBeEmpty,
            "address.street" -> Address.Err_MustNotBeEmpty
          )
        )
      }
    }
  }

} 
Example 69
Source File: Bootstrap.scala    From hydra   with Apache License 2.0 5 votes vote down vote up
package hydra.ingest.modules

import java.time.Instant

import cats.data.NonEmptyList
import cats.effect.Sync
import cats.implicits._
import cats.{Monad, MonadError}
import hydra.core.marshallers.History
import hydra.ingest.app.AppConfig.V2MetadataTopicConfig
import hydra.kafka.model._
import hydra.kafka.programs.CreateTopicProgram
import hydra.kafka.util.KafkaUtils.TopicDetails

final class Bootstrap[F[_]: MonadError[*[_], Throwable]] private (
    createTopicProgram: CreateTopicProgram[F],
    cfg: V2MetadataTopicConfig
) {

  def bootstrapAll: F[Unit] =
    for {
      _ <- bootstrapMetadataTopic
    } yield ()

  private def bootstrapMetadataTopic: F[Unit] =
    if (cfg.createOnStartup) {
      TopicMetadataV2.getSchemas[F].flatMap { schemas =>
        createTopicProgram.createTopic(
          cfg.topicName,
          TopicMetadataV2Request(
            schemas,
            StreamTypeV2.Entity,
            false,
            InternalUseOnly,
            NonEmptyList.of(cfg.contactMethod),
            Instant.now,
            List.empty,
            Some(
              "This is the topic that Hydra uses to keep track of metadata for topics."
            )
          ),
          TopicDetails(cfg.numPartitions, cfg.replicationFactor)
        )
      }
    } else {
      Monad[F].unit
    }

}

object Bootstrap {

  def make[F[_]: Sync](
      createTopicProgram: CreateTopicProgram[F],
      v2MetadataTopicConfig: V2MetadataTopicConfig
  ): F[Bootstrap[F]] = Sync[F].delay {
    new Bootstrap[F](createTopicProgram, v2MetadataTopicConfig)
  }
} 
Example 70
Source File: MetadataAlgebraSpec.scala    From hydra   with Apache License 2.0 5 votes vote down vote up
package hydra.kafka.algebras

import java.time.Instant

import cats.data.NonEmptyList
import cats.effect.{Concurrent, ContextShift, IO, Sync, Timer}
import cats.implicits._
import hydra.avro.registry.SchemaRegistry
import hydra.core.marshallers.History
import hydra.kafka.algebras.MetadataAlgebra.TopicMetadataContainer
import hydra.kafka.model.ContactMethod.Slack
import hydra.kafka.model.TopicMetadataV2Request.Subject
import hydra.kafka.model.{Public, StreamTypeV2, TopicMetadataV2, TopicMetadataV2Key, TopicMetadataV2Request, TopicMetadataV2Value}
import io.chrisdavenport.log4cats.SelfAwareStructuredLogger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import org.apache.avro.generic.GenericRecord
import org.scalatest.Assertion
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike
import retry.RetryPolicies._
import retry.syntax.all._
import retry.{RetryPolicy, _}

import scala.concurrent.ExecutionContext
import scala.concurrent.duration._

class MetadataAlgebraSpec extends AnyWordSpecLike with Matchers {

  implicit private val contextShift: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
  private implicit val concurrentEffect: Concurrent[IO] = IO.ioConcurrentEffect

  private implicit val policy: RetryPolicy[IO] = limitRetries[IO](5) |+| exponentialBackoff[IO](500.milliseconds)
  private implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global)
  private implicit def noop[A]: (A, RetryDetails) => IO[Unit] = retry.noop[IO, A]

  implicit private def unsafeLogger[F[_]: Sync]: SelfAwareStructuredLogger[F] =
    Slf4jLogger.getLogger[F]

  private implicit class RetryAndAssert[A](boolIO: IO[A]) {
    def retryIfFalse(check: A => Boolean): IO[Assertion] =
      boolIO.map(check).retryingM(identity, policy, noop).map(assert(_))
  }


  private val metadataTopicName = "_internal.metadataTopic"
  private val consumerGroup = "Consumer Group"

  (for {
    kafkaClient <- KafkaClientAlgebra.test[IO]
    schemaRegistry <- SchemaRegistry.test[IO]
    metadata <- MetadataAlgebra.make(metadataTopicName, consumerGroup, kafkaClient, schemaRegistry, consumeMetadataEnabled = true)
  } yield {
    runTests(metadata, kafkaClient)
  }).unsafeRunSync()

  private def runTests(metadataAlgebra: MetadataAlgebra[IO], kafkaClientAlgebra: KafkaClientAlgebra[IO]): Unit = {
    "MetadataAlgebraSpec" should {

      "retrieve none for non-existant topic" in {
        val subject = Subject.createValidated("Non-existantTopic").get
        metadataAlgebra.getMetadataFor(subject).unsafeRunSync() shouldBe None
      }

      "retrieve metadata" in {
        val subject = Subject.createValidated("subject1").get
        val (genericRecordsIO, key, value) = getMetadataGenericRecords(subject)

        (for {
          record <- genericRecordsIO
          _ <- kafkaClientAlgebra.publishMessage(record, metadataTopicName)
          _ <- metadataAlgebra.getMetadataFor(subject).retryIfFalse(_.isDefined)
          metadata <- metadataAlgebra.getMetadataFor(subject)
        } yield metadata shouldBe Some(TopicMetadataContainer(key, value, None, None))).unsafeRunSync()
      }

      "retrieve all metadata" in {
        val subject = Subject.createValidated("subject2").get
        val (genericRecordsIO, key, value) = getMetadataGenericRecords(subject)
        (for {
          record <- genericRecordsIO
          _ <- kafkaClientAlgebra.publishMessage(record, metadataTopicName)
          _ <- metadataAlgebra.getMetadataFor(subject).retryIfFalse(_.isDefined)
          allMetadata <- metadataAlgebra.getAllMetadata
        } yield allMetadata should have length 2).unsafeRunSync()
      }
    }
  }

  private def getMetadataGenericRecords(subject: Subject): (IO[(GenericRecord, Option[GenericRecord])], TopicMetadataV2Key, TopicMetadataV2Value) = {
    val key = TopicMetadataV2Key(subject)
    val value = TopicMetadataV2Value(
        StreamTypeV2.Entity,
        deprecated = false,
        Public,
        NonEmptyList.one(Slack.create("#channel").get),
        Instant.now,
        List(),
        None)
    (TopicMetadataV2.encode[IO](key, Some(value)), key, value)
  }
} 
Example 71
Source File: AccessTokenFetcher.scala    From tsec   with MIT License 5 votes vote down vote up
package tsec.oauth2.provider

import cats.implicits._
import java.net.URLDecoder
import cats.data.NonEmptyList

final case class FetchResult(token: String, params: Map[String, String])

sealed trait AccessTokenFetcher {
  def matches(request: ProtectedResourceRequest): Boolean
  def fetch(request: ProtectedResourceRequest): Either[InvalidRequest, FetchResult]
}

object AccessTokenFetcher {
  object RequestParameter extends AccessTokenFetcher {

    override def matches(request: ProtectedResourceRequest): Boolean =
      request.oauthToken.isDefined || request.accessToken.isDefined

    override def fetch(request: ProtectedResourceRequest): Either[InvalidRequest, FetchResult] = {
      val t      = request.oauthToken orElse (request.accessToken)
      val params = request.params.filter { case (_, v) => !v.isEmpty } map { case (k, v) => (k, v.head) }
      t.map(s => FetchResult(s, params - ("oauth_token", "access_token")))
        .toRight(InvalidRequest("missing access token"))
    }
  }

  object AuthHeader extends AccessTokenFetcher {
    val RegexpAuthorization = """^\s*(OAuth|Bearer)\s+([^\s\,]*)""".r
    val RegexpTrim          = """^\s*,\s*""".r
    val RegexpDivComma      = """,\s*""".r

    override def matches(request: ProtectedResourceRequest): Boolean =
      request.header("Authorization").exists { header =>
        RegexpAuthorization.findFirstMatchIn(header).isDefined
      }

    override def fetch(request: ProtectedResourceRequest): Either[InvalidRequest, FetchResult] =
      for {
        header  <- request.header("authorization").toRight(InvalidRequest("Missing authorization header"))
        matcher <- RegexpAuthorization.findFirstMatchIn(header).toRight(InvalidRequest("invalid Authorization header"))
        token = matcher.group(2)
        end   = matcher.end
        params <- if (header.length != end) {
          val trimmedHeader = RegexpTrim.replaceFirstIn(header.substring(end), "")
          val pairs = RegexpDivComma.split(trimmedHeader).map { exp =>
            val (key, value) = exp.split("=", 2) match {
              case Array(k, v) => (k, v.replaceFirst("^\"", ""))
              case Array(k)    => (k, "")
            }

            val v = Either.catchNonFatal(URLDecoder.decode(value.replaceFirst("\"$", ""), "UTF-8"))
            v.map(vv => (key, vv)).leftMap(t => NonEmptyList.one(t.getMessage))
          }

          pairs.toList.parSequence.map(x => Map(x: _*)).leftMap(x => InvalidRequest(x.toList.mkString(",")))
        } else {
          Right(Map.empty[String, String])
        }
      } yield FetchResult(token, params)
  }
} 
Example 72
Source File: JWSMacHeader.scala    From tsec   with MIT License 5 votes vote down vote up
package tsec.jws.mac

import cats.data.NonEmptyList
import cats.syntax.either._
import io.circe._
import io.circe.syntax._
import tsec.common._
import tsec.jws.JWSSerializer
import tsec.jws.header.JWSHeader
import tsec.jwt
import tsec.jwt.algorithms.JWTMacAlgo
import tsec.jwt.header.JWTtyp


  implicit def decoder[A: JWTMacAlgo]: Decoder[JWSMacHeader[A]] = new Decoder[JWSMacHeader[A]] {
    def apply(c: HCursor): Either[DecodingFailure, JWSMacHeader[A]] =
      c.downField("alg")
        .as[String]
        .map(JWTMacAlgo.fromString[A]) match {
        case Right(opt) =>
          opt match {
            case Some(_) =>
              for {
                t     <- c.downField("typ").as[Option[JWTtyp]]
                cType <- c.downField("cty").as[Option[String]]
                crit  <- c.downField("crit").as[Option[NonEmptyList[String]]]
              } yield
                new JWSMacHeader[A](
                  `type` = t,
                  contentType = cType,
                  critical = crit
                ) {}
            case None =>
              Left(DecodingFailure("No algorithm found", Nil))
          }

        case Left(d) => Left(d)
      }
  }

  implicit def genSerializer[A: JWTMacAlgo](
      implicit d: Decoder[JWSMacHeader[A]],
      e: Encoder[JWSMacHeader[A]]
  ): JWSSerializer[JWSMacHeader[A]] =
    new JWSSerializer[JWSMacHeader[A]] {
      def serializeToUtf8(body: JWSMacHeader[A]): Array[Byte] = jwt.JWTPrinter.print(body.asJson).utf8Bytes

      def fromUtf8Bytes(array: Array[Byte]): Either[Error, JWSMacHeader[A]] =
        io.circe.parser.decode[JWSMacHeader[A]](array.toUtf8String)
    }
} 
Example 73
Source File: ValidationError.scala    From circe-json-schema   with Apache License 2.0 5 votes vote down vote up
package io.circe.schema

import cats.data.NonEmptyList
import org.everit.json.schema.ValidationException
import scala.collection.mutable.Builder

sealed abstract class ValidationError(
  val keyword: String,
  val location: String,
  val schemaLocation: Option[String]
) extends Exception {
  final override def fillInStackTrace(): Throwable = this
}

object ValidationError {
  def apply(
    keyword: String,
    message: String,
    location: String,
    schemaLocation: Option[String] = None
  ): ValidationError =
    new ValidationError(keyword, location, schemaLocation) {
      final override def getMessage: String = message
    }

  private[this] def fromEveritOne(e: ValidationException): ValidationError =
    apply(e.getKeyword, e.getMessage, e.getPointerToViolation, Option(e.getSchemaLocation))

  private[this] def fromEveritRecursive(
    e: ValidationException,
    builder: Builder[ValidationError, List[ValidationError]]
  ): Unit = {
    val nested = e.getCausingExceptions
    val iter = nested.iterator

    while (iter.hasNext) {
      builder += fromEveritOne(iter.next)
    }

    val iterRecursive = nested.iterator

    while (iterRecursive.hasNext) {
      fromEveritRecursive(iterRecursive.next, builder)
    }
  }

  private[schema] def fromEverit(e: ValidationException): NonEmptyList[ValidationError] = {
    val builder = List.newBuilder[ValidationError]
    fromEveritRecursive(e, builder)
    NonEmptyList(fromEveritOne(e), builder.result)
  }
} 
Example 74
Source File: Optimize.scala    From skeuomorph   with Apache License 2.0 5 votes vote down vote up
package higherkindness.skeuomorph.mu

import cats.data.NonEmptyList
import higherkindness.skeuomorph.mu.MuF._
import higherkindness.droste._


  def knownCoproductTypesTrans[T](implicit B: Basis[MuF, T]): Trans[MuF, MuF, T] =
    Trans {
      case TCoproduct(NonEmptyList(x, List(y))) =>
        (B.coalgebra(x), B.coalgebra(y)) match {
          case (_, TNull()) => TOption[T](x)
          case (TNull(), _) => TOption[T](y)
          case _            => TEither[T](x, y)
        }
      case other => other
    }

  def knownCoproductTypes[T: Basis[MuF, ?]]: T => T = scheme.cata(knownCoproductTypesTrans.algebra)
} 
Example 75
Source File: ConnectionsEndpoint.scala    From temperature-machine   with Apache License 2.0 5 votes vote down vote up
package bad.robot.temperature.server

import java.net.InetAddress
import java.time.Clock

import bad.robot.temperature.IpAddress._
import bad.robot.temperature._
import cats.data.NonEmptyList
import cats.effect.IO
import cats.implicits._
import org.http4s._
import org.http4s.dsl.io._

object ConnectionsEndpoint {

  private implicit val encoder = jsonEncoder[List[Connection]]

  def apply(connections: Connections, ipAddresses: => NonEmptyList[Option[InetAddress]] = currentIpAddress)(implicit clock: Clock) = HttpService[IO] {
    case GET -> Root / "connections" => {
      Ok(connections.all).map(_.putHeaders(xForwardedHost(ipAddresses)))
    }

    case GET -> Root / "connections" / "active" / "within" / LongVar(period) / "mins" => {
      Ok(connections.allWithin(period)).map(_.putHeaders(xForwardedHost(ipAddresses)))
    }
  }

  private def xForwardedHost(ipAddresses: NonEmptyList[Option[InetAddress]]): Header = {
    Header("X-Forwarded-Host", ipAddresses.map(_.fold("unknown")(_.getHostAddress)).mkString_("", ", ", ""))
  }

} 
Example 76
Source File: BasicAuthentication.scala    From endpoints4s   with MIT License 5 votes vote down vote up
package endpoints4s.http4s.server

import cats.data.NonEmptyList
import cats.syntax.functor._
import endpoints4s.{Tupler, Valid}
import endpoints4s.algebra.BasicAuthentication.Credentials
import endpoints4s.algebra.Documentation
import org.http4s
import org.http4s.headers.{Authorization, `WWW-Authenticate`}
import org.http4s.{BasicCredentials, Challenge}


trait BasicAuthentication
    extends EndpointsWithCustomErrors
    with endpoints4s.algebra.BasicAuthentication {

  private val unauthorizedRequestResponse = http4s
    .Response[Effect](Unauthorized)
    .withHeaders(
      `WWW-Authenticate`(
        NonEmptyList.of(Challenge("Basic", "Realm", Map("charset" -> "UTF-8")))
      )
    )

  private[endpoints4s] def basicAuthenticationHeader: RequestHeaders[Option[Credentials]] =
    headers =>
      Valid(
        headers
          .get(Authorization)
          .flatMap { authHeader =>
            authHeader.credentials match {
              case BasicCredentials(username, password) =>
                Some(Credentials(username, password))
              case _ => None
            }
          }
      )

  def authenticatedRequest[U, E, H, UE, HC, Out](
      method: Method,
      url: Url[U],
      entity: RequestEntity[E],
      headers: RequestHeaders[H],
      requestDocs: Documentation = None
  )(implicit
      tuplerUE: Tupler.Aux[U, E, UE],
      tuplerHC: Tupler.Aux[H, Credentials, HC],
      tuplerUEHC: Tupler.Aux[UE, HC, Out]
  ): Request[Out] =
    extractUrlAndHeaders(method, url, headers ++ basicAuthenticationHeader) {
      case (_, (_, None)) =>
        _ => Effect.pure(Left(unauthorizedRequestResponse))
      case (u, (h, Some(credentials))) =>
        http4sRequest =>
          entity(http4sRequest)
            .map(
              _.map(e => tuplerUEHC(tuplerUE(u, e), tuplerHC(h, credentials)))
            )
    }

} 
Example 77
Source File: package.scala    From hammock   with MIT License 5 votes vote down vote up
import cats._
import cats.data.{EitherK, NonEmptyList}
import cats.free.Free
import cats.effect.Sync
import contextual._

package object hammock {

  import hammock.marshalling._
  import hammock.InterpTrans

  type HammockF[A] = EitherK[HttpF, MarshallF, A]

  implicit class HttpRequestIOSyntax[A](fa: Free[HttpF, A]) {
    def exec[F[_]: Sync](implicit interp: InterpTrans[F]): F[A] =
      fa foldMap interp.trans
  }

  implicit class HammockFSyntax[A](fa: Free[HammockF, A]) {
    def exec[F[_]: Sync](implicit NT: HammockF ~> F): F[A] =
      fa foldMap NT
  }

  implicit class AsSyntaxOnHttpF[F[_], A](fa: Free[F, HttpResponse])(
      implicit
      H: InjectK[HttpF, F]) {
    def as[B](implicit D: Decoder[B], M: MarshallC[EitherK[F, MarshallF, *]]): Free[EitherK[F, MarshallF, *], B] =
      fa.inject[EitherK[F, MarshallF, *]] flatMap { response =>
        M.unmarshall(response.entity)
      }
  }

  implicit def hammockNT[F[_]: Sync](
      implicit H: InterpTrans[F],
      M: MarshallF ~> F
  ): HammockF ~> F = H.trans or M

  object UriContext extends Context

  object UriInterpolator extends Interpolator {
    type Output      = Uri
    type ContextType = UriContext.type
    type Input       = String
    def contextualize(interpolation: StaticInterpolation) = {
      interpolation.parts.foldLeft(List.empty[ContextType]) {
        case (contexts, Hole(_, _)) => UriContext :: contexts
        case (contexts, _)          => contexts
      }
    }

    def evaluate(interpolation: RuntimeInterpolation): Uri = {
      val substituted = interpolation.literals
        .zipAll(interpolation.substitutions, "", "")
        .flatMap(x => List(x._1, x._2))
        .mkString("")
      Uri.fromString(substituted).right.get
    }

  }

  implicit val embedString = UriInterpolator.embed[String](Case(UriContext, UriContext) { x =>
    x
  })

  
  implicit class UriQueryParamsBuilder(val self: NonEmptyList[(String, String)]) extends AnyVal {
    def &(param: (String, String)): NonEmptyList[(String, String)] = param :: self
  }
  implicit class UriQueryInitBuilder(val self: (String, String)) extends AnyVal {
    def &(param: (String, String)): NonEmptyList[(String, String)] = NonEmptyList(self, param :: Nil)
  }
} 
Example 78
Source File: UriProps.scala    From hammock   with MIT License 5 votes vote down vote up
package hammock

import atto._
import Atto._
import cats.Foldable
import cats.data.NonEmptyList
import cats.implicits._
import org.scalacheck._
import org.scalacheck.Prop._
import org.scalacheck.Gen

object UriProps extends Properties("Uri") {
  import Uri._
  import TestInstances._

  property("authority roudtrip") = forAll(authorityArbitrary.arbitrary) { auth: Authority =>
    Uri.Authority.parse.parseOnly(auth.show).either === Right(auth)
  }

  property("uri roudtrip") = forAll(uriArbitrary.arbitrary) { uri: Uri =>
    Uri.unsafeParse(uri.show) === uri
  }

  property("/ appends to the path") = forAll(uriArbitrary.arbitrary, nonEmptyAlphanumString) { (uri: Uri, toAppend: String) =>
    (uri / toAppend).path === uri.path ++ "/" ++ toAppend
  }

  property("param method appends parameter to the query") = forAll(uriArbitrary.arbitrary, nonEmptyAlphanumString, nonEmptyAlphanumString) { (uri: Uri, key: String, value: String) =>
    val query = uri.param(key, value).query
    query.contains(key) && query(key) === value
  }

  property("string interpolation") = forAll(nonEmptyAlphanumString, nonEmptyAlphanumString, nonEmptyAlphanumString) { (url: String, key1: String, value1: String) =>
    val substituedUri = uri"https://${url}?${key1}=${value1}&other=query"
    substituedUri.query.contains(key1) && substituedUri.query(key1) === value1
    substituedUri.show == s"https://${url}?${key1}=${value1}&other=query"
  }

  property("params method appends multiple parameters to the query") = forAll(uriArbitrary.arbitrary, Gen.listOf(nonEmptyStringPair)) { (uri, pairs) =>
    val query = uri.params(pairs: _*).query
    Foldable[List].foldLeft(pairs.map(pair => query.contains(pair._1)), true)(_ && _)
  }

  property("? method should do the same as 'params'") = forAll(uriArbitrary.arbitrary, Gen.nonEmptyListOf(nonEmptyStringPair)) { (uri, pairs) =>
    val result = uri ? NonEmptyList.fromListUnsafe(pairs)
    result === uri.copy(query = uri.query ++ pairs)
  }


} 
Example 79
Source File: StreamingParserSpec.scala    From cormorant   with MIT License 5 votes vote down vote up
package io.chrisdavenport.cormorant
package fs2

import cats.data.NonEmptyList
import cats.effect._
import cats.effect.testing.specs2.CatsIO
import _root_.fs2.Stream
import io.chrisdavenport.cormorant._
// import io.chrisdavenport.cormorant.implicits._
// import scala.concurrent.duration._
import java.io.ByteArrayInputStream
import java.io.InputStream

class StreamingParserSpec extends CormorantSpec with CatsIO {

  def ruinDelims(str: String) = augmentString(str).flatMap {
    case '\n' => "\r\n"
    case c => c.toString
  }

  "Streaming Parser" should {
    // https://github.com/ChristopherDavenport/cormorant/pull/84
    "parse a known value that did not work with streaming" in {
      val x = """First Name,Last Name,Email
Larry,Bordowitz,[email protected]
Anonymous,Hippopotamus,[email protected]"""
      val source = IO.pure(new ByteArrayInputStream(ruinDelims(x).getBytes): InputStream)
      Stream.resource(Blocker[IO]).flatMap{blocker => 
        _root_.fs2.io.readInputStream(
          source,
          chunkSize = 4,
          blocker
        )
      }
        .through(_root_.fs2.text.utf8Decode)
        .through(parseComplete[IO])
        .compile
        .toVector
        .map{ v => 
          val header = CSV.Headers(NonEmptyList.of(CSV.Header("First Name"), CSV.Header("Last Name"), CSV.Header("Email")))
          val row1 = CSV.Row(NonEmptyList.of(CSV.Field("Larry"), CSV.Field("Bordowitz"), CSV.Field("[email protected]")))
          val row2 = CSV.Row(NonEmptyList.of(CSV.Field("Anonymous"), CSV.Field("Hippopotamus"), CSV.Field("[email protected]")))
          Vector(
            (header, row1),
            (header, row2)
          ) must_=== v
        }
    }
  }

  

} 
Example 80
Source File: writelabelled.scala    From cormorant   with MIT License 5 votes vote down vote up
package io.chrisdavenport.cormorant.generic.internal

import io.chrisdavenport.cormorant._
import shapeless._
import shapeless.labelled._
import cats.implicits._
import cats.data.NonEmptyList

trait LabelledWriteProofs
  extends LowPriorityLabelledWriteProofs {

  
  implicit def deriveByNameHListPut[K <: Symbol, H, T <: HList](
      implicit witness: Witness.Aux[K],
      P: Put[H],
      labelledWrite: Lazy[LabelledWrite[T]]
  ): LabelledWrite[FieldType[K, H] :: T] =
    new LabelledWrite[FieldType[K, H] :: T] {
      def headers: CSV.Headers = {
        CSV.Headers(
          NonEmptyList.one(CSV.Header(witness.value.name)) <+>
          labelledWrite.value.headers.l
        )
      }
      def write(a: FieldType[K, H] :: T): CSV.Row =
        CSV.Row(P.put(a.head) :: labelledWrite.value.write(a.tail).l)
    }
}

private[internal] trait LowPriorityLabelledWriteProofs1
  extends LowPriorityLabelledWriteProofs2 {
  implicit def deriveByLabelledWrite2[K, H, T <: HList](
    implicit P: LabelledWrite[H],
    labelledWrite: Lazy[LabelledWrite[T]]
  ): LabelledWrite[FieldType[K, H] :: T] =
    new LabelledWrite[FieldType[K, H]:: T] {
      def headers: CSV.Headers = {
        CSV.Headers(
          P.headers.l <+>
          labelledWrite.value.headers.l
        )
      }
      def write(a: FieldType[K, H] :: T): CSV.Row = {
        CSV.Row(P.write(a.head).l.concatNel(labelledWrite.value.write(a.tail).l))
      }
    }
}

private[internal] trait LowPriorityLabelledWriteProofs2 {
  implicit def labelledWriteHNilGet[K, H](
    implicit W: LabelledWrite[H]
  ): LabelledWrite[FieldType[K, H] :: HNil] = 
    new LabelledWrite[FieldType[K, H] :: HNil] {
      def headers: CSV.Headers =
        W.headers
      def write(a: FieldType[K, H] :: HNil): CSV.Row = 
        W.write(a.head)
    }
  
} 
Example 81
Source File: read.scala    From cormorant   with MIT License 5 votes vote down vote up
package io.chrisdavenport.cormorant.generic.internal

import io.chrisdavenport.cormorant._
import shapeless._
import cats.implicits._
import cats.data.NonEmptyList

trait ReadProofs extends LowPriorityReadProofs {

  implicit def readHNil[H](implicit G: Get[H]): Read[H :: HNil] = new Read[H :: HNil] {
    def readPartial(a: CSV.Row): Either[Error.DecodeFailure, Either[(CSV.Row, H :: HNil), H :: HNil]] = a match {
      case CSV.Row(NonEmptyList(f, Nil)) => 
        G.get(f).map(h => h :: HNil).map(Either.right)
      case CSV.Row(NonEmptyList(f, rest)) => 
        NonEmptyList.fromList(rest) match {
          case Some(nel) => 
            G.get(f).map(h => h :: HNil)
              .map(h => Either.left((CSV.Row(nel), h)))
          case None =>
            Either.left(Error.DecodeFailure.single(s"Unexpected Input: Did Not Expect - $a"))
        }
    }
  }

  implicit def hlistRead[H, T <: HList](
      implicit G: Get[H],
      R: Lazy[Read[T]]
  ): Read[H :: T] = new Read[H :: T] {
    def readPartial(a: CSV.Row): Either[Error.DecodeFailure, Either[(CSV.Row, H :: T), H :: T]] = a match {
      case CSV.Row(NonEmptyList(h, t)) =>
        (
          G.get(h),
          NonEmptyList.fromList(t)
          .fold(
            Either.left[Error.DecodeFailure, Either[(CSV.Row, T), T]](Error.DecodeFailure.single("Unexpected End Of Input"))
          )(nel =>
            R.value.readPartial(CSV.Row(nel))
          )
        ).parMapN{
          case (h, Left((row, t))) => Either.left((row, h :: t))
          case (h, Right(t)) => Either.right(h :: t)
        }
    }
  }
}

private[internal] trait LowPriorityReadProofs{
  implicit def hlistRead2[H, T <: HList](
    implicit RH: Lazy[Read[H]],
    RT: Lazy[Read[T]]
  ): Read[H :: T] = new Read[H :: T]{
    def readPartial(a: CSV.Row): Either[Error.DecodeFailure,Either[(CSV.Row, H :: T),H :: T]] = 
      RH.value.readPartial(a).flatMap{
        case Left((row, h)) => RT.value.readPartial(row).map{
          case Left((row, t)) => Left((row, h :: t))
          case Right(t) => Right(h:: t)
        }
        case Right(value) => 
          Either.left(Error.DecodeFailure.single(s"Incomplete Output - $value only"))
      }
  }
} 
Example 82
Source File: Error.scala    From cormorant   with MIT License 5 votes vote down vote up
package io.chrisdavenport.cormorant

import cats.data.NonEmptyList
import cats.Semigroup

import cats.implicits._

sealed trait Error extends Exception {
  final override def fillInStackTrace(): Throwable = this
  final override def getMessage: String = toString
  override def toString: String = this match {
    case Error.DecodeFailure(failure) => s"DecodeFailure($failure)"
    case Error.ParseFailure(reason) => s"ParseFailure($reason)"
    case Error.PrintFailure(reason) => s"PrintFailure($reason)"
  }
}
object Error {
  final case class ParseFailure(reason: String) extends Error
  object ParseFailure {
    def invalidInput(input: String): ParseFailure =
      ParseFailure(s"Invalid Input: Received $input")
  }

  final case class DecodeFailure(failure: NonEmptyList[String]) extends Error
  object DecodeFailure {
    def single(reason: String): DecodeFailure = DecodeFailure(NonEmptyList.of(reason))
    implicit val decodeFailureSemigroup: Semigroup[DecodeFailure] = {
      new Semigroup[DecodeFailure] {
        def combine(x: DecodeFailure, y: DecodeFailure): DecodeFailure =
          DecodeFailure(x.failure |+| y.failure)
      }
    }
  }

  final case class PrintFailure(reason: String) extends Error
} 
Example 83
Source File: Json.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.bitbucketserver.http4s

import cats.data.NonEmptyList
import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder}
import io.circe.{Decoder, Encoder}
import org.http4s.Uri
import org.scalasteward.core.git.Sha1
import org.scalasteward.core.vcs.data.PullRequestState

object Json {
  case class Page[A](values: List[A])

  case class Repo(id: Int, name: String, forkable: Boolean, project: Project, links: Links)

  case class Project(key: String)

  type Links = Map[String, NonEmptyList[Link]]

  case class Link(href: Uri, name: Option[String])

  case class PR(title: String, state: PullRequestState, links: Links)

  case class NewPR(
      title: String,
      description: String,
      state: PullRequestState,
      open: Boolean,
      closed: Boolean,
      fromRef: Ref,
      toRef: Ref,
      locked: Boolean,
      reviewers: List[Reviewer]
  )

  case class Ref(id: String, repository: Repository)

  case class Repository(slug: String, project: Project)

  case class Condition(reviewers: List[DefaultReviewer])

  case class DefaultReviewer(name: String)

  case class Reviewer(user: User)

  case class User(name: String)

  case class Branches(values: NonEmptyList[Branch])

  case class Branch(id: String, latestCommit: Sha1)

  implicit def pageDecode[A: Decoder]: Decoder[Page[A]] = deriveDecoder
  implicit val repoDecode: Decoder[Repo] = deriveDecoder
  implicit val projectDecode: Decoder[Project] = deriveDecoder
  implicit val linkDecoder: Decoder[Link] = deriveDecoder
  implicit val uriDecoder: Decoder[Uri] = Decoder.decodeString.map(Uri.unsafeFromString)
  implicit val prDecoder: Decoder[PR] = deriveDecoder
  implicit val reviewerDecoder: Decoder[Reviewer] = deriveDecoder
  implicit val userDecoder: Decoder[User] = deriveDecoder
  implicit val defaultReviewerDecoder: Decoder[DefaultReviewer] = deriveDecoder
  implicit val conditionDecoder: Decoder[Condition] = deriveDecoder
  implicit val branchDecoder: Decoder[Branch] = deriveDecoder
  implicit val branchesDecoder: Decoder[Branches] = deriveDecoder

  implicit val encodeNewPR: Encoder[NewPR] = deriveEncoder
  implicit val encodeRef: Encoder[Ref] = deriveEncoder
  implicit val encodeRepository: Encoder[Repository] = deriveEncoder
  implicit val encodeProject: Encoder[Project] = deriveEncoder
  implicit val encodeReviewer: Encoder[Reviewer] = deriveEncoder
  implicit val encodeUser: Encoder[User] = deriveEncoder
} 
Example 84
Source File: Implicits.scala    From openlaw-core   with Apache License 2.0 5 votes vote down vote up
package org.adridadou.openlaw.result

import cats.implicits._
import cats.data.NonEmptyList

import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.language.implicitConversions
import scala.util.{Try, Failure => TFailure, Success => TSuccess}

object Implicits {

  implicit class RichNonEmptyList[T](val nel: NonEmptyList[T]) extends AnyVal {
    def mkString: String = mkString(", ")
    def mkString(sep: String): String = nel.toList.mkString(sep)
  }

  implicit class RichTry[T](val t: Try[T]) extends AnyVal {
    def toResult: Result[T] = t match {
      case TSuccess(v)            => Success(v)
      case TFailure(e: Exception) => Failure(e)

      // don't try to handle Error instances
      case TFailure(t) => throw t
    }
  }

  implicit class RichEither[T](val either: Either[String, T]) extends AnyVal {
    def toResult: Result[T] = either.left.map(FailureMessage(_))
  }

  implicit class RichFuture[T](val future: Future[T]) extends AnyVal {
    def getResult(timeout: Duration): Result[T] =
      attempt(Await.result(future, timeout))
  }

  implicit class RichResult[T](val result: Result[T]) extends AnyVal {
    def addCause(cause: Failure[T]): ResultNel[T] = result match {
      case Success(_)     => cause.toResultNel
      case Left(original) => FailureNel(original, cause.value)
    }
    def addFailure[U >: T](cause: FailureCause): ResultNel[U] = result match {
      case s @ Success(_) => s.toResultNel
      case Left(original) => FailureNel(cause, original)
    }
    def addMessageToFailure[U >: T](message: String): ResultNel[U] =
      result match {
        case s @ Success(_) => s.toResultNel
        case Left(original) => FailureNel(FailureMessage(message), original)
      }
    def convert(pf: PartialFunction[Exception, Exception]): Result[T] =
      result.left.map {
        case FailureException(e, _) if pf.isDefinedAt(e) =>
          FailureException(pf(e))
        case f => f
      }
    def recoverMerge(f: FailureCause => T): T =
      result.fold(failure => f(failure), success => success)
    def recoverWith(pf: PartialFunction[FailureCause, Result[T]]): Result[T] =
      result.leftFlatMap { error =>
        if (pf.isDefinedAt(error)) {
          pf(error)
        } else {
          result
        }
      }
    def toResultNel: ResultNel[T] = result.toValidatedNel
    def toFuture: Future[T] = result match {
      case Success(value) => Future.successful(value)
      case Failure(e, _)  => Future.failed(e)
    }
    def getOrThrow(): T = result.valueOr(_.throwException())
  }

  implicit class RichOption[T](val option: Option[T]) extends AnyVal {
    def toResult(message: String): Result[T] =
      option.map(x => Success(x)).getOrElse(Failure(message))
  }

  implicit class RichResultNel[T](val result: ResultNel[T]) extends AnyVal {
    def toUnit: ResultNel[Unit] = result.map(_ => ())
    def toResult: Result[T] = result.toEither.leftMap {
      case NonEmptyList(x, Seq()) => x
      case nel                    => FailureException(MultipleCauseException(nel))
    }
  }

  implicit def exception2Result[A](e: Exception): Result[A] = Failure[A](e)
  implicit def unitResultConversion[T](wrapped: Result[T]): Result[Unit] =
    wrapped.map(_ => ())
  implicit def failureCause2Exception[T](wrapped: FailureCause): Exception =
    wrapped.e
} 
Example 85
Source File: FailureCause.scala    From openlaw-core   with Apache License 2.0 5 votes vote down vote up
package org.adridadou.openlaw.result

import cats.data.NonEmptyList
import Implicits.RichNonEmptyList

final case class MultipleCauseException(causes: NonEmptyList[FailureCause])
    extends java.lang.RuntimeException(causes.map(_.message).mkString)

trait FailureCause {
  def e: Exception
  def id: String
  def throwException[T](): T = throw e
  def message: String = Option(e.getMessage).getOrElse("")
}

object FailureCause {
  def unapply(result: Result[_]): Option[FailureCause] = result.swap.toOption
}

final case class FailureException(
    override val e: Exception,
    idOpt: Option[String] = None
) extends FailureCause {
  override val id = idOpt.getOrElse(message)
}

final case class FailureMessage(
    override val message: String,
    idOpt: Option[String] = None
) extends FailureCause {
  override val e = new RuntimeException(message)
  override val id = idOpt.getOrElse(message)
} 
Example 86
Source File: package.scala    From openlaw-core   with Apache License 2.0 5 votes vote down vote up
package org.adridadou.openlaw

import result.Implicits.RichResult
import cats.data.Validated._
import cats.data.{NonEmptyList, ValidatedNel}
import cats.data.NonEmptyList.{of, one}
import cats.implicits._
import org.adridadou.openlaw.result.Implicits.RichTry
import scala.util.Try
import scala.util.control.NonFatal

package object result {

  type ResultNel[+A] = ValidatedNel[FailureCause, A]

  type Result[+A] = Either[FailureCause, A]
  type Failure[Nothing] = Left[FailureCause, Nothing]
  type Success[+A] = Right[FailureCause, A]

  def attempt[A](f: => A): Result[A] = Try(f).toResult

  def handleFatalErrors(t: Throwable): Result[Nothing] = t match {
    case NonFatal(e: Exception) => Failure(e)
    case e                      => throw e
  }
}

package result {

  object Success {
    def unit: Result[Unit] = Success(())
    def apply[A](a: A): Result[A] = Right(a)
    def unapply[A](result: Result[A]): Option[A] = result.toOption
  }

  object ResultNel {
    def apply[A](nel: NonEmptyList[Result[A]]): ResultNel[NonEmptyList[A]] =
      nel.map(_.toResultNel).sequence
    def apply[A](nel: List[Result[A]]): ResultNel[List[A]] =
      nel.map(_.toResultNel).sequence
  }

  object FailureNel {
    def apply[A](e: FailureCause): ResultNel[A] =
      Invalid[NonEmptyList[FailureCause]](one(e))
    def apply[A](head: FailureCause, tail: FailureCause*): ResultNel[A] =
      Invalid[NonEmptyList[FailureCause]](of(head, tail: _*))
  }

  object Failure {
    def apply[A](f: FailureCause): Result[A] = Left(f)
    def apply[A](): Result[A] = apply(new RuntimeException)
    def apply[A](e: Exception): Result[A] = apply(FailureException(e))
    def apply[A](e: Exception, id: String): Result[A] =
      apply(FailureException(e, Some(id)))
    def apply[A](message: String): Result[A] = apply(FailureMessage(message))
    def apply[A](message: String, id: String): Result[A] =
      apply(FailureMessage(message, Some(id)))
    def apply[A](es: NonEmptyList[Exception]): ResultNel[A] =
      Invalid(es.map(FailureException(_)))
    // implicits are necessary here to disambiguate arguments after erasure
    def apply[A](
        es: NonEmptyList[(Exception, String)]
    )(implicit i: DummyImplicit): ResultNel[A] =
      Invalid(es.map { case (e, id) => FailureException(e, Some(id)) })
    def apply[A](
        messages: NonEmptyList[String]
    )(implicit i: DummyImplicit, i2: DummyImplicit): ResultNel[A] =
      Invalid(messages.map(FailureMessage(_)))
    def apply[A](messages: NonEmptyList[(String, String)])(
        implicit i: DummyImplicit,
        i2: DummyImplicit,
        i3: DummyImplicit
    ): ResultNel[A] =
      Invalid(messages.map { case (m, id) => FailureMessage(m, Some(id)) })
    def unapply(result: Result[_]): Option[(Exception, String)] =
      result.swap.toOption.map { f =>
        (f.e, f.id)
      }
  }
} 
Example 87
Source File: MonixAutoAckConsumer.scala    From fs2-rabbit   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.fs2rabbit.examples

import cats.data.NonEmptyList
import cats.effect._
import cats.syntax.functor._
import dev.profunktor.fs2rabbit.config.{Fs2RabbitConfig, Fs2RabbitNodeConfig}
import dev.profunktor.fs2rabbit.interpreter.RabbitClient
import dev.profunktor.fs2rabbit.resiliency.ResilientStream
import monix.eval.{Task, TaskApp}
import java.util.concurrent.Executors

object MonixAutoAckConsumer extends TaskApp {

  private val config: Fs2RabbitConfig = Fs2RabbitConfig(
    virtualHost = "/",
    nodes = NonEmptyList.one(
      Fs2RabbitNodeConfig(
        host = "127.0.0.1",
        port = 5672
      )
    ),
    username = Some("guest"),
    password = Some("guest"),
    ssl = false,
    connectionTimeout = 3,
    requeueOnNack = false,
    requeueOnReject = false,
    internalQueueSize = Some(500),
    automaticRecovery = true
  )

  val blockerResource =
    Resource
      .make(Task(Executors.newCachedThreadPool()))(es => Task(es.shutdown()))
      .map(Blocker.liftExecutorService)

  override def run(args: List[String]): Task[ExitCode] =
    blockerResource.use { blocker =>
      RabbitClient[Task](config, blocker).flatMap { client =>
        ResilientStream
          .runF(new AutoAckConsumerDemo[Task](client).program)
          .as(ExitCode.Success)
      }
    }

} 
Example 88
Source File: IOAckerConsumer.scala    From fs2-rabbit   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.fs2rabbit.examples

import java.util.concurrent.Executors

import cats.data.NonEmptyList
import cats.effect._
import cats.syntax.functor._
import dev.profunktor.fs2rabbit.config.{Fs2RabbitConfig, Fs2RabbitNodeConfig}
import dev.profunktor.fs2rabbit.interpreter.RabbitClient
import dev.profunktor.fs2rabbit.resiliency.ResilientStream

object IOAckerConsumer extends IOApp {

  private val config: Fs2RabbitConfig = Fs2RabbitConfig(
    virtualHost = "/",
    nodes = NonEmptyList.one(Fs2RabbitNodeConfig(host = "127.0.0.1", port = 5672)),
    username = Some("guest"),
    password = Some("guest"),
    ssl = false,
    connectionTimeout = 3,
    requeueOnNack = false,
    requeueOnReject = false,
    internalQueueSize = Some(500),
    automaticRecovery = true
  )

  val blockerResource =
    Resource
      .make(IO(Executors.newCachedThreadPool()))(es => IO(es.shutdown()))
      .map(Blocker.liftExecutorService)

  override def run(args: List[String]): IO[ExitCode] =
    blockerResource.use { blocker =>
      RabbitClient[IO](config, blocker).flatMap { client =>
        ResilientStream
          .runF(new AckerConsumerDemo[IO](client).program)
          .as(ExitCode.Success)
      }
    }
} 
Example 89
Source File: Connection.scala    From fs2-rabbit   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.fs2rabbit.algebra

import cats.data.NonEmptyList
import cats.effect.{Resource, Sync}
import cats.implicits._
import com.rabbitmq.client.{Address, ConnectionFactory, DefaultSaslConfig, SaslConfig}
import dev.profunktor.fs2rabbit.config.Fs2RabbitConfig
import dev.profunktor.fs2rabbit.effects.Log
import dev.profunktor.fs2rabbit.javaConversion._
import dev.profunktor.fs2rabbit.model.{AMQPChannel, AMQPConnection, RabbitChannel, RabbitConnection}
import javax.net.ssl.SSLContext

object ConnectionResource {
  type ConnectionResource[F[_]] = Connection[Resource[F, ?]]
  def make[F[_]: Sync: Log](
      conf: Fs2RabbitConfig,
      sslCtx: Option[SSLContext] = None,
      // Unlike SSLContext, SaslConfig is not optional because it is always set
      // by the underlying Java library, even if the user doesn't set it.
      saslConf: SaslConfig = DefaultSaslConfig.PLAIN
  ): F[Connection[Resource[F, ?]]] =
    Sync[F].delay {
      new Connection[Resource[F, ?]] {

        private[fs2rabbit] def mkConnectionFactory: F[(ConnectionFactory, NonEmptyList[Address])] =
          Sync[F].delay {
            val factory   = new ConnectionFactory()
            val firstNode = conf.nodes.head
            factory.setHost(firstNode.host)
            factory.setPort(firstNode.port)
            factory.setVirtualHost(conf.virtualHost)
            factory.setConnectionTimeout(conf.connectionTimeout)
            factory.setAutomaticRecoveryEnabled(conf.automaticRecovery)
            if (conf.ssl) {
              sslCtx.fold(factory.useSslProtocol())(factory.useSslProtocol)
            }
            factory.setSaslConfig(saslConf)
            conf.username.foreach(factory.setUsername)
            conf.password.foreach(factory.setPassword)
            val addresses = conf.nodes.map(node => new Address(node.host, node.port))
            (factory, addresses)
          }

        private[fs2rabbit] def acquireChannel(connection: AMQPConnection): F[AMQPChannel] =
          Sync[F]
            .delay(connection.value.createChannel)
            .flatTap(c => Log[F].info(s"Acquired channel: $c"))
            .map(RabbitChannel)

        private[fs2rabbit] val acquireConnection: F[AMQPConnection] =
          mkConnectionFactory.flatMap {
            case (factory, addresses) =>
              Sync[F]
                .delay(factory.newConnection(addresses.toList.asJava))
                .flatTap(c => Log[F].info(s"Acquired connection: $c"))
                .map(RabbitConnection)
          }

        override def createConnection: Resource[F, AMQPConnection] =
          Resource.make(acquireConnection) {
            case RabbitConnection(conn) =>
              Log[F].info(s"Releasing connection: $conn previously acquired.") *>
                Sync[F].delay {
                  if (conn.isOpen) conn.close()
                }
          }

        override def createChannel(connection: AMQPConnection): Resource[F, AMQPChannel] =
          Resource.make(acquireChannel(connection)) {
            case RabbitChannel(channel) =>
              Sync[F].delay {
                if (channel.isOpen) channel.close()
              }
          }
      }
    }
}

trait Connection[F[_]] {
  def createConnection: F[AMQPConnection]
  def createChannel(connection: AMQPConnection): F[AMQPChannel]
} 
Example 90
Source File: Fs2RabbitConfig.scala    From fs2-rabbit   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.fs2rabbit.config

import cats.data.NonEmptyList

case class Fs2RabbitNodeConfig(
    host: String,
    port: Int
)

case class Fs2RabbitConfig(
    nodes: NonEmptyList[Fs2RabbitNodeConfig],
    virtualHost: String,
    connectionTimeout: Int,
    ssl: Boolean,
    username: Option[String],
    password: Option[String],
    requeueOnNack: Boolean,
    requeueOnReject: Boolean,
    internalQueueSize: Option[Int],
    automaticRecovery: Boolean
)

object Fs2RabbitConfig {
  def apply(
      host: String,
      port: Int,
      virtualHost: String,
      connectionTimeout: Int,
      ssl: Boolean,
      username: Option[String],
      password: Option[String],
      requeueOnNack: Boolean,
      requeueOnReject: Boolean,
      internalQueueSize: Option[Int],
      automaticRecovery: Boolean = true
  ): Fs2RabbitConfig = Fs2RabbitConfig(
    nodes = NonEmptyList.one(Fs2RabbitNodeConfig(host, port)),
    virtualHost = virtualHost,
    connectionTimeout = connectionTimeout,
    ssl = ssl,
    username = username,
    password = password,
    requeueOnNack = requeueOnNack,
    requeueOnReject = requeueOnReject,
    internalQueueSize = internalQueueSize,
    automaticRecovery = automaticRecovery
  )
} 
Example 91
Source File: FtsWork.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.joex.fts

import cats.data.{Kleisli, NonEmptyList}
import cats.effect._
import cats.implicits._
import cats.{ApplicativeError, FlatMap, Semigroup}

import docspell.common._
import docspell.ftsclient._
import docspell.joex.Config
import docspell.joex.scheduler.Context
import docspell.store.queries.{QAttachment, QItem}

object FtsWork {
  def apply[F[_]](f: FtsContext[F] => F[Unit]): FtsWork[F] =
    Kleisli(f)

  def all[F[_]: FlatMap](
      m0: FtsWork[F],
      mn: FtsWork[F]*
  ): FtsWork[F] =
    NonEmptyList.of(m0, mn: _*).reduce(semigroup[F])

  implicit def semigroup[F[_]: FlatMap]: Semigroup[FtsWork[F]] =
    Semigroup.instance((mt1, mt2) => mt1.flatMap(_ => mt2))

  // some tasks

  def log[F[_]](f: Logger[F] => F[Unit]): FtsWork[F] =
    FtsWork(ctx => f(ctx.logger))

  def initialize[F[_]]: FtsWork[F] =
    FtsWork(_.fts.initialize)

  def clearIndex[F[_]](coll: Option[Ident]): FtsWork[F] =
    coll match {
      case Some(cid) =>
        FtsWork(ctx => ctx.fts.clear(ctx.logger, cid))
      case None =>
        FtsWork(ctx => ctx.fts.clearAll(ctx.logger))
    }

  def insertAll[F[_]: Effect](coll: Option[Ident]): FtsWork[F] =
    FtsWork
      .all(
        FtsWork(ctx =>
          ctx.fts.indexData(
            ctx.logger,
            ctx.store
              .transact(
                QAttachment
                  .allAttachmentMetaAndName(coll, ctx.cfg.migration.indexAllChunk)
              )
              .map(caa =>
                TextData
                  .attachment(
                    caa.item,
                    caa.id,
                    caa.collective,
                    caa.lang,
                    caa.name,
                    caa.content
                  )
              )
          )
        ),
        FtsWork(ctx =>
          ctx.fts.indexData(
            ctx.logger,
            ctx.store
              .transact(QItem.allNameAndNotes(coll, ctx.cfg.migration.indexAllChunk * 5))
              .map(nn => TextData.item(nn.id, nn.collective, Option(nn.name), nn.notes))
          )
        )
      )

  object syntax {
    implicit final class FtsWorkOps[F[_]](mt: FtsWork[F]) {
      def ++(mn: FtsWork[F])(implicit ev: FlatMap[F]): FtsWork[F] =
        all(mt, mn)

      def recoverWith(
          other: FtsWork[F]
      )(implicit ev: ApplicativeError[F, Throwable]): FtsWork[F] =
        Kleisli(ctx => mt.run(ctx).onError({ case _ => other.run(ctx) }))

      def forContext(
          cfg: Config.FullTextSearch,
          fts: FtsClient[F]
      ): Kleisli[F, Context[F, _], Unit] =
        mt.local(ctx => FtsContext(cfg, fts, ctx))
    }
  }
} 
Example 92
Source File: Domain.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.analysis.contact

import cats.data.NonEmptyList

import docspell.common.LenientUri

case class Domain(labels: NonEmptyList[String], tld: String) {

  def asString: String =
    labels.toList.mkString(".") + tld

  def toPrimaryDomain: Domain =
    if (labels.tail.isEmpty) this
    else Domain(NonEmptyList.of(labels.last), tld)
}

object Domain {

  def domainFromUri(uri: String): Either[String, Domain] =
    LenientUri
      .parse(if (uri.contains("://")) uri else s"http://$uri")
      .flatMap(uri => uri.authority.toRight("Uri has no authoriry part"))
      .flatMap(auth => parse(auth))

  def parse(str: String): Either[String, Domain] =
    Tld
      .findTld(str)
      .map(tld => (str.dropRight(tld.length), tld))
      .map({
        case (names, tld) =>
          names.split('.').toList match {
            case Nil => Left(s"Not a domain: $str")
            case segs
                if segs.forall(label =>
                  label.trim.nonEmpty && label
                    .forall(c => c.isLetter || c.isDigit || c == '-')
                ) =>
              Right(Domain(NonEmptyList.fromListUnsafe(segs), tld))
            case _ => Left(s"Not a domain: $str")
          }
      })
      .getOrElse(Left(s"Not a domain $str"))

  def isDomain(str: String): Boolean =
    parse(str).isRight
} 
Example 93
Source File: MetaProposal.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.common

import java.time.LocalDate

import cats.data.NonEmptyList
import cats.implicits._
import cats.kernel.Order

import docspell.common.MetaProposal.Candidate
import docspell.common._

import io.circe._
import io.circe.generic.semiauto._


  def flatten(s: NonEmptyList[Candidate]): NonEmptyList[Candidate] = {
    def mergeInto(
        res: NonEmptyList[Candidate],
        el: Candidate
    ): NonEmptyList[Candidate] = {
      val l = res.map(c =>
        if (c.ref.id == el.ref.id) c.copy(origin = c.origin ++ el.origin) else c
      )
      if (l == res) l :+ el
      else l
    }
    val init = NonEmptyList.of(s.head)
    s.tail.foldLeft(init)(mergeInto)
  }

  implicit val jsonDecoder: Decoder[MetaProposal] =
    deriveDecoder[MetaProposal]
  implicit val jsonEncoder: Encoder[MetaProposal] =
    deriveEncoder[MetaProposal]

} 
Example 94
Source File: ItemState.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.common

import cats.data.NonEmptyList

import io.circe.{Decoder, Encoder}

sealed trait ItemState { self: Product =>

  final def name: String =
    productPrefix.toLowerCase

  def isValid: Boolean =
    ItemState.validStates.exists(_ == this)

  def isInvalid: Boolean =
    ItemState.invalidStates.exists(_ == this)
}

object ItemState {

  case object Premature  extends ItemState
  case object Processing extends ItemState
  case object Created    extends ItemState
  case object Confirmed  extends ItemState

  def fromString(str: String): Either[String, ItemState] =
    str.toLowerCase match {
      case "premature"  => Right(Premature)
      case "processing" => Right(Processing)
      case "created"    => Right(Created)
      case "confirmed"  => Right(Confirmed)
      case _            => Left(s"Invalid item state: $str")
    }

  val validStates: NonEmptyList[ItemState] =
    NonEmptyList.of(Created, Confirmed)

  val invalidStates: NonEmptyList[ItemState] =
    NonEmptyList.of(Premature, Processing)

  def unsafe(str: String): ItemState =
    fromString(str).fold(sys.error, identity)

  implicit val jsonDecoder: Decoder[ItemState] =
    Decoder.decodeString.emap(fromString)
  implicit val jsonEncoder: Encoder[ItemState] =
    Encoder.encodeString.contramap(_.name)
} 
Example 95
Source File: MetaProposalList.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.common

import cats.data.NonEmptyList
import cats.kernel.Monoid

import docspell.common.MetaProposal.Candidate

import io.circe._
import io.circe.generic.semiauto._


  def flatten(ml: Seq[MetaProposalList]): MetaProposalList = {
    val init: Map[MetaProposalType, MetaProposal] = Map.empty

    def updateMap(
        map: Map[MetaProposalType, MetaProposal],
        mp: MetaProposal
    ): Map[MetaProposalType, MetaProposal] =
      map.get(mp.proposalType) match {
        case Some(mp0) => map.updated(mp.proposalType, mp0.addIdRef(mp.values.toList))
        case None      => map.updated(mp.proposalType, mp)
      }

    val merged = ml.foldLeft(init)((map, el) => el.proposals.foldLeft(map)(updateMap))

    fromMap(merged)
  }

  implicit val jsonEncoder: Encoder[MetaProposalList] =
    deriveEncoder[MetaProposalList]
  implicit val jsonDecoder: Decoder[MetaProposalList] =
    deriveDecoder[MetaProposalList]

  implicit val metaProposalListMonoid: Monoid[MetaProposalList] =
    Monoid.instance(empty, (m0, m1) => flatten(Seq(m0, m1)))
} 
Example 96
Source File: MetaProposalListTest.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.common

import minitest._
import cats.data.NonEmptyList
import docspell.common.MetaProposal.Candidate

object MetaProposalListTest extends SimpleTestSuite {

  test("flatten retains order of candidates") {
    val cand1 = Candidate(IdRef(Ident.unsafe("123"), "name"), Set.empty)
    val mpl1 = MetaProposalList.of(
      MetaProposal(
        MetaProposalType.CorrOrg,
        NonEmptyList.of(cand1)
      )
    )
    val cand2 = Candidate(IdRef(Ident.unsafe("456"), "name"), Set.empty)
    val mpl2 = MetaProposalList.of(
      MetaProposal(
        MetaProposalType.CorrOrg,
        NonEmptyList.of(cand2)
      )
    )

    val candidates1 = MetaProposalList
      .flatten(Seq(mpl1, mpl2))
      .find(MetaProposalType.CorrOrg)
      .get
      .values
    assertEquals(candidates1.head, cand1)
    assertEquals(candidates1.tail.head, cand2)

    val candidates2 = MetaProposalList
      .flatten(Seq(mpl2, mpl1))
      .find(MetaProposalType.CorrOrg)
      .get
      .values
    assertEquals(candidates2.head, cand2)
    assertEquals(candidates2.tail.head, cand1)
  }

  test("sort by weights") {
    val cand1 = Candidate(IdRef(Ident.unsafe("123"), "name"), Set.empty, Some(0.1))
    val cand2 = Candidate(IdRef(Ident.unsafe("456"), "name"), Set.empty, Some(0.05))
    val mpl = MetaProposalList
      .of(
        MetaProposal(MetaProposalType.CorrOrg, NonEmptyList.of(cand1)),
        MetaProposal(MetaProposalType.CorrOrg, NonEmptyList.of(cand2))
      )
      .sortByWeights

    val candidates = mpl.find(MetaProposalType.CorrOrg).get.values
    assertEquals(candidates.head, cand2)
    assertEquals(candidates.tail.head, cand1)
  }

  test("sort by weights: unset is last") {
    val cand1 = Candidate(IdRef(Ident.unsafe("123"), "name"), Set.empty, Some(0.1))
    val cand2 = Candidate(IdRef(Ident.unsafe("456"), "name"), Set.empty)
    val mpl = MetaProposalList
      .of(
        MetaProposal(MetaProposalType.CorrOrg, NonEmptyList.of(cand1)),
        MetaProposal(MetaProposalType.CorrOrg, NonEmptyList.of(cand2))
      )
      .sortByWeights

    val candidates = mpl.find(MetaProposalType.CorrOrg).get.values
    assertEquals(candidates.head, cand1)
    assertEquals(candidates.tail.head, cand2)
  }
} 
Example 97
Source File: CodeGenWrite.scala    From bosatsu   with Apache License 2.0 5 votes vote down vote up
package org.bykn.bosatsu

import cats.data.NonEmptyList
import cats.effect.IO
import java.nio.file.Path
import java.io.PrintWriter
import org.typelevel.paiges.Doc

object CodeGenWrite {
  @annotation.tailrec
  final def toPath(root: Path, pn: PackageName): Path =
    pn.parts match {
      case NonEmptyList(h, Nil) => root.resolve(h).resolve("Values.java")
      case NonEmptyList(h0, h1 :: tail) =>
        toPath(root.resolve(h0), PackageName(NonEmptyList(h1, tail)))
    }

  def writeDoc(p: Path, d: Doc): IO[Unit] =
    IO {
      Option(p.getParent).foreach(_.toFile.mkdirs)
      val pw = new PrintWriter(p.toFile, "UTF-8")
      try d.renderStream(80).foreach(pw.print(_))
      finally {
        pw.close
      }
    }
} 
Example 98
Source File: TypeRefConverter.scala    From bosatsu   with Apache License 2.0 5 votes vote down vote up
package org.bykn.bosatsu

import cats.Applicative
import cats.data.NonEmptyList
import cats.implicits._
import org.bykn.bosatsu.rankn.Type
import org.bykn.bosatsu.Identifier.Constructor

object TypeRefConverter {
  
  def apply[F[_]: Applicative](t: TypeRef)(nameToType: Constructor => F[Type.Const]): F[Type] = {
    def toType(t: TypeRef): F[Type] = apply(t)(nameToType)

    import Type._
    import TypeRef._

    t match {
      case TypeVar(v) => Applicative[F].pure(TyVar(Type.Var.Bound(v)))
      case TypeName(n) => nameToType(n.ident).map(TyConst(_))
      case TypeArrow(a, b) => (toType(a), toType(b)).mapN(Fun(_, _))
      case TypeApply(a, bs) =>
        @annotation.tailrec
        def toType1(fn: Type, args: NonEmptyList[Type]): Type =
          args match {
            case NonEmptyList(a0, Nil) => TyApply(fn,a0)
            case NonEmptyList(a0, a1 :: as) =>
              toType1(TyApply(fn, a0), NonEmptyList(a1, as))
          }
        (toType(a), bs.traverse(toType)).mapN(toType1(_, _))
      case TypeLambda(pars0, TypeLambda(pars1, e)) =>
        // we normalize to lifting all the foralls to the outside
        toType(TypeLambda(pars0 ::: pars1, e))
      case TypeLambda(pars, e) =>
        toType(e).map { te =>
          Type.forAll(pars.map { case TypeVar(v) => Type.Var.Bound(v) }.toList, te)
        }
      case TypeTuple(ts) =>
        ts.traverse(toType).map(Type.Tuple(_))
    }
  }
} 
Example 99
Source File: PackageName.scala    From bosatsu   with Apache License 2.0 5 votes vote down vote up
package org.bykn.bosatsu

import cats.Order
import cats.data.NonEmptyList
import cats.implicits._
import fastparse.all._
import org.typelevel.paiges.{Doc, Document}
import Parser.upperIdent

case class PackageName(parts: NonEmptyList[String]) {
  lazy val asString: String = parts.toList.mkString("/")
}

object PackageName {

  def parts(first: String, rest: String*): PackageName =
    PackageName(NonEmptyList.of(first, rest :_*))

  implicit val document: Document[PackageName] =
    Document.instance[PackageName] { pn => Doc.text(pn.asString) }

  implicit val parser: P[PackageName] =
    P(upperIdent ~ ("/" ~ upperIdent).rep()).map { case (head, tail) =>
      PackageName(NonEmptyList(head, tail.toList))
    }

  def parse(s: String): Option[PackageName] =
    parser.parse(s) match {
      case Parsed.Success(pn, idx) if idx == s.length => Some(pn)
      case _ => None
    }

  implicit val order: Order[PackageName] =
    Order[NonEmptyList[String]].contramap[PackageName](_.parts)

  implicit val packageNameOrdering: Ordering[PackageName] =
    order.toOrdering

  val PredefName: PackageName =
    PackageName(NonEmptyList.of("Bosatsu", "Predef"))
} 
Example 100
Source File: Import.scala    From bosatsu   with Apache License 2.0 5 votes vote down vote up
package org.bykn.bosatsu

import cats.{Foldable, Functor}
import cats.data.NonEmptyList
import cats.implicits._
import fastparse.all._
import org.typelevel.paiges.{Doc, Document}

import Parser.{spaces, maybeSpace, Combinators}

sealed abstract class ImportedName[+T] {
  def originalName: Identifier
  def localName: Identifier
  def tag: T
  def isRenamed: Boolean = originalName != localName

  def map[U](fn: T => U): ImportedName[U] =
    this match {
      case [email protected](n, t) =>
        ImportedName.OriginalName(n, fn(t))
      case [email protected](o, l, t) =>
        ImportedName.Renamed(o, l, fn(t))
    }

  def traverse[F[_], U](fn: T => F[U])(implicit F: Functor[F]): F[ImportedName[U]] =
    this match {
      case [email protected](n, t) =>
        F.map(fn(t))(ImportedName.OriginalName(n, _))
      case [email protected](o, l, t) =>
        F.map(fn(t))(ImportedName.Renamed(o, l, _))
    }
}

object ImportedName {
  case class OriginalName[T](originalName: Identifier, tag: T) extends ImportedName[T] {
    def localName = originalName
  }
  case class Renamed[T](originalName: Identifier, localName: Identifier, tag: T) extends ImportedName[T]

  implicit val document: Document[ImportedName[Unit]] =
    Document.instance[ImportedName[Unit]] {
      case ImportedName.OriginalName(nm, _) => Document[Identifier].document(nm)
      case ImportedName.Renamed(from, to, _) =>
        Document[Identifier].document(from) + Doc.text(" as ") +
          Document[Identifier].document(to)
    }

  val parser: P[ImportedName[Unit]] = {
    def basedOn(of: P[Identifier]): P[ImportedName[Unit]] =
      P(of ~ (spaces ~ "as" ~ spaces ~/ of).?).map {
        case (from, Some(to)) => ImportedName.Renamed(from, to, ())
        case (orig, None) => ImportedName.OriginalName(orig, ())
      }

    basedOn(Identifier.bindableParser) | basedOn(Identifier.consParser)
  }
}

case class Import[A, B](pack: A, items: NonEmptyList[ImportedName[B]])

object Import {
  implicit val document: Document[Import[PackageName, Unit]] =
    Document.instance[Import[PackageName, Unit]] { case Import(pname, items) =>
      Doc.text("import ") + Document[PackageName].document(pname) + Doc.space +
        // TODO: use paiges to pack this in nicely using .group or something
        Doc.char('[') + Doc.intercalate(Doc.text(", "), items.toList.map(Document[ImportedName[Unit]].document _)) + Doc.char(']')
    }

  val parser: P[Import[PackageName, Unit]] = {
    P("import" ~ spaces ~/ PackageName.parser ~ maybeSpace ~
      ImportedName.parser.nonEmptyListSyntax).map { case (pname, imported) =>
        Import(pname, imported)
      }
  }

  
case class ImportMap[A, B](toMap: Map[Identifier, (A, ImportedName[B])]) {
  def apply(name: Identifier): Option[(A, ImportedName[B])] =
    toMap.get(name)

  def +(that: (A, ImportedName[B])): ImportMap[A, B] =
    ImportMap(toMap.updated(that._2.localName, that))
}

object ImportMap {
  def empty[A, B]: ImportMap[A, B] = ImportMap(Map.empty)
  // Return the list of collisions in local names along with a map
  // with the last name overwriting the import
  def fromImports[A, B](is: List[Import[A, B]]): (List[(A, ImportedName[B])], ImportMap[A, B]) =
    is.iterator
      .flatMap { case Import(p, is) => is.toList.iterator.map((p, _)) }
      .foldLeft((List.empty[(A, ImportedName[B])], ImportMap.empty[A, B])) {
        case ((dups, imap), pim@(pack, im)) =>
          val dups1 = imap(im.localName) match {
            case Some(nm) => nm :: dups
            case None => dups
          }

          (dups1, imap + pim)
        }
} 
Example 101
Source File: Tree.scala    From bosatsu   with Apache License 2.0 5 votes vote down vote up
package org.bykn.bosatsu.graph

import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._

case class Tree[+A](item: A, children: List[Tree[A]])

object Tree {

  def neighborsFn[A](t: Tree[A]): A => List[A] = {
    def toMap(t: Tree[A]): Map[A, Tree[A]] =
      Map(t.item -> t) ++ (t.children.flatMap(toMap(_)))

    val mapToTree: Map[A, Tree[A]] = toMap(t)


    { a: A => mapToTree.get(a).fold(List.empty[A])(_.children.map(_.item)) }
  }

  
  def dagToTree[A](node: A)(nfn: A => List[A]): ValidatedNel[NonEmptyList[A], Tree[A]] = {
    def treeOf(path: NonEmptyList[A], visited: Set[A]): ValidatedNel[NonEmptyList[A], Tree[A]] = {
      val children = nfn(path.head)
      def assumeValid(children: List[A]): ValidatedNel[NonEmptyList[A], Tree[A]] =
        children.traverse { a =>
          // we grow the path out here
          treeOf(a :: path, visited + a)
        }
        .map(Tree(path.head, _))

      NonEmptyList.fromList(children.filter(visited)) match {
        case Some(loops) =>
          val paths = loops.map(_ :: path)
          val invalid = Validated.invalid(paths)
          // also search all the valid cases
          invalid *> assumeValid(children.filterNot(visited))
        case None => assumeValid(children)
      }
    }
    treeOf(NonEmptyList(node, Nil), Set(node))
      .leftMap { nelnel =>
        // remove depulicate paths
        val withSet = nelnel.map { nel => (nel, nel.toList.toSet) }
        distinctBy(withSet)(_._2).map(_._1)
      }
  }

  def distinctBy[A, B](nel: NonEmptyList[A])(fn: A => B): NonEmptyList[A] = {
    @annotation.tailrec
    def remove(seen: Set[B], items: List[A], acc: List[A]): List[A] =
      items match {
        case Nil => acc.reverse
        case h :: t =>
          val b = fn(h)
          if (seen(b)) remove(seen, t, acc)
          else remove(seen + b, t, h :: acc)
      }

    NonEmptyList(nel.head, remove(Set(fn(nel.head)), nel.tail, Nil))
  }

  def distinctBy[A, B](nel: List[A])(fn: A => B): List[A] =
    NonEmptyList.fromList(nel) match {
      case None => Nil
      case Some(nel) => distinctBy(nel)(fn).toList
    }
} 
Example 102
Source File: DefStatement.scala    From bosatsu   with Apache License 2.0 5 votes vote down vote up
package org.bykn.bosatsu

import Parser.{ Combinators, maybeSpace, spaces }
import cats.Applicative
import cats.data.NonEmptyList
import cats.implicits._
import fastparse.all._
import org.bykn.fastparse_cats.StringInstances._
import org.typelevel.paiges.{ Doc, Document }

import Identifier.{Bindable, Constructor}

case class DefStatement[A, B](
  name: Bindable,
  args: List[A],
  retType: Option[TypeRef], result: B) {

  
    def parser[A, B](argParser: P[A], resultTParser: P[B]): P[DefStatement[A, B]] = {
      val args = argParser.parensLines1
      val result = P("->" ~/ maybeSpace ~ TypeRef.parser).?
      P("def" ~ spaces ~/ Identifier.bindableParser ~ args.? ~ maybeSpace ~
        result ~ maybeSpace ~ ":" ~/ resultTParser)
        .map {
          case (name, optArgs, resType, res) =>
            val args = optArgs match {
              case None => Nil
              case Some(ne) => ne.toList
            }
            DefStatement(name, args, resType, res)
        }
    }
} 
Example 103
Source File: ValidationExtension.scala    From franklin   with Apache License 2.0 5 votes vote down vote up
package com.azavea.franklin.extensions.validation

import cats.data.NonEmptyList
import cats.data.Validated.{Invalid, Valid}
import cats.kernel.Semigroup
import com.azavea.stac4s.extensions.ItemAssetExtension
import com.azavea.stac4s.extensions.{ExtensionResult, ItemExtension, LinkExtension}
import eu.timepit.refined.types.string.NonEmptyString
import io.circe._
import io.circe.refined._
import io.circe.syntax._

final case class ValidationExtension(
    attemptedExtensions: NonEmptyList[NonEmptyString],
    errors: List[NonEmptyString]
)

object ValidationExtension {

  implicit val decValidationExtension: Decoder[ValidationExtension] = Decoder.forProduct2(
    "validation:attemptedExtensions",
    "validation:errors"
  )((extensions: NonEmptyList[NonEmptyString], errors: List[NonEmptyString]) =>
    ValidationExtension(extensions, errors)
  )

  implicit val encValidationExtension: Encoder.AsObject[ValidationExtension] = Encoder
    .AsObject[Map[String, Json]]
    .contramapObject((validationExtensionFields: ValidationExtension) =>
      Map(
        "validation:attemptedExtensions" -> validationExtensionFields.attemptedExtensions.asJson,
        "validation:errors"              -> validationExtensionFields.errors.asJson
      )
    )

  implicit val validationExtensionItemExtension: ItemExtension[ValidationExtension] =
    ItemExtension.instance

  implicit val validationExtensionLinkExtension: LinkExtension[ValidationExtension] =
    LinkExtension.instance

  implicit val validationExtensionAssetExtension: ItemAssetExtension[ValidationExtension] =
    ItemAssetExtension.instance

  implicit val semigroupValidationExtension: Semigroup[ValidationExtension] =
    new Semigroup[ValidationExtension] {

      def combine(x: ValidationExtension, y: ValidationExtension): ValidationExtension = {
        ValidationExtension(
          x.attemptedExtensions.concat(y.attemptedExtensions.toList),
          x.errors ++ y.errors
        )
      }
    }

  def success(name: NonEmptyString) = ValidationExtension(
    NonEmptyList.of(name),
    Nil
  )

  def failure(name: NonEmptyString, errors: List[DecodingFailure]) =
    ValidationExtension(NonEmptyList.of(name), errors map { (err: DecodingFailure) =>
      NonEmptyString.from(CursorOp.opsToPath(err.history))
    } collect {
      case Right(v) => v
    })

  def fromResult[T](result: ExtensionResult[T], name: NonEmptyString) = result match {
    case Invalid(errs) =>
      failure(name, errs collect {
        case e: DecodingFailure => e
      })
    case Valid(_) =>
      success(name)
  }
} 
Example 104
Source File: MergeDeps.scala    From bazel-deps   with MIT License 5 votes vote down vote up
package com.github.johnynek.bazel_deps

import cats.data.{ NonEmptyList, Validated, ValidatedNel }
import cats.Foldable
import cats.implicits._
import io.circe.jawn.JawnParser
import java.io.{ File, PrintWriter }
import scala.util.{ Failure, Success }
import java.nio.file.Path

object MergeDeps {
  private def load(f: Path): ValidatedNel[String, Model] =
    FormatDeps.readModel(f.toFile) match {
      case Right(m) => Validated.valid(m)
      case Left(err) => Validated.invalidNel(err)
    }

  def fail(errs: NonEmptyList[String]): Nothing = {
    errs.toList.foreach(System.err.println)
    System.exit(1)
    sys.error("unreachable")
  }

  def apply(models: NonEmptyList[Path], out: Option[Path]): Unit = {

    type A[T] = ValidatedNel[String, T]
    val mod = models.traverse[A, Model](load).toEither.right.flatMap {
      Model.combine(_)
    }

    mod match {
      case Left(errs) => fail(errs)
      case Right(m) =>
        val stream = m.toDoc.renderStream(100)
        out match {
          case None => stream.foreach(System.out.print)
          case Some(path) =>
            val pw = new PrintWriter(path.toFile)
            stream.foreach(pw.print(_))
            pw.flush
            pw.close
        }
      }
  }

  def addDep(model: Path, lang: Language, coords: NonEmptyList[MavenCoordinate]): Unit =
    load(model) match {
      case Validated.Invalid(errs) => fail(errs)
      case Validated.Valid(m) =>
        val realLang = m.getOptions.replaceLang(lang)
        val deps = coords.map(realLang.unmangle(_).toDependencies(realLang))

        def combine(d1: Dependencies, d2: Dependencies): Either[NonEmptyList[String], Dependencies] =
          Dependencies.combine(m.getOptions.getVersionConflictPolicy, d1, d2).toEither

        type E[T] = Either[NonEmptyList[String], T]
        Foldable[NonEmptyList].foldM[E, Dependencies, Dependencies](deps, m.dependencies)(combine) match {
          case Left(errs) => fail(errs)
          case Right(resDep) =>
            val stream = m.copy(dependencies = resDep).toDoc.renderStream(100)
            val pw = new PrintWriter(model.toFile)
            stream.foreach(pw.print(_))
            pw.flush
            pw.close
        }
  }
} 
Example 105
Source File: errors.scala    From cron4s   with Apache License 2.0 5 votes vote down vote up
package cron4s

import cats.Show
import cats.data.NonEmptyList
import cats.syntax.show._


sealed abstract class Error(description: String) extends Exception(description)

object Error {
  implicit val errorShow: Show[Error] = Show.show(_.getMessage)
}

final case class ParseFailed(msg: String, found: String, position: Int)
    extends Error(s"$msg at position $position but found '$found'")

sealed trait ValidationError
object ValidationError {
  implicit val validationErrorShow: Show[ValidationError] = Show.show {
    case e: InvalidField            => e.show
    case e: InvalidFieldCombination => e.show
  }
}

final case class InvalidCron(reason: NonEmptyList[ValidationError])
    extends Error(reason.toList.map(_.show).mkString(", "))

final case class InvalidField(field: CronField, msg: String) extends ValidationError
object InvalidField {
  implicit val invalidFieldShow: Show[InvalidField] = Show.show { err =>
    s"${err.field}: ${err.msg}"
  }
}

final case class InvalidFieldCombination(msg: String) extends ValidationError
object InvalidFieldCombination {
  implicit val invalidFieldCombinationShow: Show[InvalidFieldCombination] =
    Show.show(_.msg)
} 
Example 106
Source File: package.scala    From cron4s   with Apache License 2.0 5 votes vote down vote up
package cron4s

import cats.data.NonEmptyList


package object validation {
  def validateCron(expr: CronExpr): Either[InvalidCron, CronExpr] = {
    val dayFieldError = validateDayFields(expr)
    val fieldErrors   = expr.raw.map(ops.validate).toList.flatten

    val allErrors =
      dayFieldError.fold[List[ValidationError]](fieldErrors)(_ :: fieldErrors)

    NonEmptyList
      .fromList(allErrors)
      .map(errs => Left(InvalidCron(errs)))
      .getOrElse(Right(expr))
  }

  private def validateDayFields(expr: CronExpr) = {
    val dayOfMonth = expr.field[CronField.DayOfMonth].toString
    val dayOfWeek  = expr.field[CronField.DayOfWeek].toString

    if (dayOfMonth == dayOfWeek) {
      Some(
        InvalidFieldCombination(
          s"Fields ${CronField.DayOfMonth} and ${CronField.DayOfWeek} can't both have the expression: $dayOfMonth"
        )
      )
    } else if ((dayOfMonth != "?" && dayOfWeek == "?") || (dayOfMonth == "?" && dayOfWeek != "?")) {
      None
    } else
      Some(
        InvalidFieldCombination(
          s"Either ${CronField.DayOfMonth} and ${CronField.DayOfWeek} must have a ? expression"
        )
      )
  }
} 
Example 107
Source File: RawSource.scala    From coursier   with Apache License 2.0 5 votes vote down vote up
package coursier.install

import argonaut.{DecodeJson, EncodeJson, Parse}
import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._
import coursier.parse.RepositoryParser
import dataclass.data


@data class RawSource(
  repositories: List[String],
  channel: String,
  id: String
) {
  def source: ValidatedNel[String, Source] = {

    import RawAppDescriptor.validationNelToCats

    val repositoriesV = validationNelToCats(RepositoryParser.repositories(repositories))

    val channelV = Validated.fromEither(
      Channel.parse(channel)
        .left.map(NonEmptyList.one)
    )

    (repositoriesV, channelV).mapN {
      (repositories, channel) =>
        Source(
          repositories,
          channel,
          id
        )
    }
  }
  def repr: String =
    RawSource.encoder.encode(this).nospaces
}

object RawSource {

  import argonaut.ArgonautShapeless._

  implicit val encoder = EncodeJson.of[RawSource]
  implicit val decoder = DecodeJson.of[RawSource]

  def parse(input: String): Either[String, RawSource] =
    Parse.decodeEither(input)(decoder)

} 
Example 108
Source File: RepositoryParams.scala    From coursier   with Apache License 2.0 5 votes vote down vote up
package coursier.cli.params

import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.Files

import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._
import coursier.{Repositories, moduleString}
import coursier.cli.install.SharedChannelParams
import coursier.cli.options.RepositoryOptions
import coursier.core.Repository
import coursier.install.Channel
import coursier.ivy.IvyRepository
import coursier.maven.MavenRepository
import coursier.parse.RepositoryParser

final case class RepositoryParams(
  repositories: Seq[Repository],
  channels: SharedChannelParams
)

object RepositoryParams {

  def apply(options: RepositoryOptions, hasSbtPlugins: Boolean = false): ValidatedNel[String, RepositoryParams] = {

    val repositoriesV = Validated.fromEither(
      RepositoryParser.repositories(options.repository)
        .either
        .left
        .map {
          case h :: t => NonEmptyList(h, t)
        }
    )

    val channelsV = SharedChannelParams(options.channelOptions)

    (repositoriesV, channelsV).mapN {
      (repos0, channels) =>

        // preprend defaults
        val defaults =
          if (options.noDefault) Nil
          else {
            val extra =
              if (hasSbtPlugins) Seq(Repositories.sbtPlugin("releases"))
              else Nil
            coursier.Resolve.defaultRepositories ++ extra
          }
        var repos = defaults ++ repos0

        // take sbtPluginHack into account
        repos = repos.map {
          case m: MavenRepository => m.withSbtAttrStub(options.sbtPluginHack)
          case other => other
        }

        // take dropInfoAttr into account
        if (options.dropInfoAttr)
          repos = repos.map {
            case m: IvyRepository => m.withDropInfoAttributes(true)
            case other => other
          }

        RepositoryParams(
          repos,
          channels
        )
    }
  }
} 
Example 109
Source File: SinglePackageParams.scala    From coursier   with Apache License 2.0 5 votes vote down vote up
package coursier.cli.publish.params

import java.nio.file.{Files, Path, Paths}

import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._
import coursier.cli.publish.options.SinglePackageOptions
import coursier.core.{Classifier, Extension}

final case class SinglePackageParams(
  jarOpt: Option[Path],
  pomOpt: Option[Path],
  artifacts: Seq[(Classifier, Extension, Path)],
  `package`: Boolean
)

object SinglePackageParams {

  private def q = "\""

  def apply(options: SinglePackageOptions): ValidatedNel[String, SinglePackageParams] = {

    // FIXME This does some I/O (not reflected in return type)

    def fileExtensionV(path: String): ValidatedNel[String, (Path, String)] =
      fileV(path).withEither(_.flatMap { p =>
        val name = p.getFileName.toString
        val idx = name.lastIndexOf('.')
        if (idx < 0)
          Left(NonEmptyList.one(s"$path has no extension, specify one by passing it with classifier:extension:$path"))
        else {
          val ext = name.drop(idx + 1)
          if (ext.isEmpty)
            Left(NonEmptyList.one(s"$path extension is empty, specify one by passing it with classifier:extension:$path"))
          else
            Right((p, ext))
        }
      })

    def fileV(path: String): ValidatedNel[String, Path] = {
      val p = Paths.get(path)
      if (!Files.exists(p))
        Validated.invalidNel(s"not found: $path")
      else if (!Files.isRegularFile(p))
        Validated.invalidNel(s"not a regular file: $path")
      else
        Validated.validNel(p)
    }

    def fileOptV(pathOpt: Option[String]): ValidatedNel[String, Option[Path]] =
      pathOpt match {
        case None =>
          Validated.validNel(None)
        case Some(path) =>
          fileV(path).map(Some(_))
      }

    val jarOptV = fileOptV(options.jar)
    val pomOptV = fileOptV(options.pom)

    val artifactsV = options.artifact.traverse { s =>
      s.split(":", 3) match {
        case Array(strClassifier, strExtension, path) =>
          fileV(path).map((Classifier(strClassifier), Extension(strExtension), _))
        case Array(strClassifier, path) =>
          fileExtensionV(path).map {
            case (p, ext) =>
              (Classifier(strClassifier), Extension(ext), p)
          }
        case _ =>
          Validated.invalidNel(s"Malformed artifact argument: $s (expected: ${q}classifier:/path/to/artifact$q)")
      }
    }

    val packageV = options.`package` match {
      case Some(true) =>
        Validated.validNel(true)
      case Some(false) =>
        if (options.jar.nonEmpty || options.pom.nonEmpty || options.artifact.nonEmpty)
          Validated.invalidNel("Cannot specify --package=false along with --pom or --jar or --artifact")
        else
          Validated.validNel(false)
      case None =>
        val p = options.jar.nonEmpty || options.pom.nonEmpty || options.artifact.nonEmpty
        Validated.validNel(p)
    }

    (jarOptV, pomOptV, artifactsV, packageV).mapN {
      (jarOpt, pomOpt, artifacts, package0) =>
        SinglePackageParams(
          jarOpt,
          pomOpt,
          artifacts,
          package0
        )
    }
  }
} 
Example 110
Source File: InstallParams.scala    From coursier   with Apache License 2.0 5 votes vote down vote up
package coursier.cli.install

import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.Files

import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._
import coursier.cli.jvm.SharedJavaParams
import coursier.cli.params.{CacheParams, EnvParams, OutputParams}
import coursier.install.Channel

final case class InstallParams(
  cache: CacheParams,
  output: OutputParams,
  shared: SharedInstallParams,
  sharedChannel: SharedChannelParams,
  sharedJava: SharedJavaParams,
  env: EnvParams,
  addChannels: Seq[Channel],
  installChannels: Seq[String],
  force: Boolean
) {
  lazy val channels: Seq[Channel] =
    (sharedChannel.channels ++ addChannels).distinct
}

object InstallParams {

  def apply(options: InstallOptions, anyArg: Boolean): ValidatedNel[String, InstallParams] = {

    val cacheParamsV = options.cacheOptions.params(None)
    val outputV = OutputParams(options.outputOptions)

    val sharedV = SharedInstallParams(options.sharedInstallOptions)

    val sharedChannelV = SharedChannelParams(options.sharedChannelOptions)
    val sharedJavaV = SharedJavaParams(options.sharedJavaOptions)

    val envV = EnvParams(options.envOptions)

    val addChannelsV = options.addChannel.traverse { s =>
      val e = Channel.parse(s)
        .left.map(NonEmptyList.one)
        .map(c => (s, c))
      Validated.fromEither(e)
    }

    val force = options.force

    val checkNeedsChannelsV =
      if (anyArg && sharedChannelV.toOption.exists(_.channels.isEmpty) && addChannelsV.toOption.exists(_.isEmpty))
        Validated.invalidNel(s"Error: no channels specified")
      else
        Validated.validNel(())

    val flags = Seq(
      options.addChannel.nonEmpty,
      envV.toOption.fold(false)(_.anyFlag)
    )
    val flagsV =
      if (flags.count(identity) > 1)
        Validated.invalidNel("Error: can only specify one of --add-channel, --env, --setup.")
      else
        Validated.validNel(())

    val checkArgsV =
      if (anyArg && flags.exists(identity))
        Validated.invalidNel(s"Error: unexpected arguments passed along --add-channel, --env, or --setup.")
      else
        Validated.validNel(())

    (cacheParamsV, outputV, sharedV, sharedChannelV, sharedJavaV, envV, addChannelsV, checkNeedsChannelsV, flagsV, checkArgsV).mapN {
      (cacheParams, output, shared, sharedChannel, sharedJava, env, addChannels, _, _, _) =>
        InstallParams(
          cacheParams,
          output,
          shared,
          sharedChannel,
          sharedJava,
          env,
          addChannels.map(_._2),
          addChannels.map(_._1),
          force
        )
    }
  }
} 
Example 111
Source File: SharedChannelParams.scala    From coursier   with Apache License 2.0 5 votes vote down vote up
package coursier.cli.install

import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.Files

import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._
import coursier.install.Channel
import coursier.install.Channels

final case class SharedChannelParams(
  channels: Seq[Channel]
)

object SharedChannelParams {
  def apply(options: SharedChannelOptions): ValidatedNel[String, SharedChannelParams] = {

    val channelsV = options
      .channel
      .traverse { s =>
        val e = Channel.parse(s)
          .left.map(NonEmptyList.one)
        Validated.fromEither(e)
      }

    val defaultChannels =
      if (options.defaultChannels) Channels.defaultChannels
      else Nil

    val contribChannels =
      if (options.contrib) Channels.contribChannels
      else Nil

    val fileChannelsV =
      if (options.fileChannels) {
        val configDir = coursier.paths.CoursierPaths.configDirectory()
        val channelDir = new File(configDir, "channels")
        val files = Option(channelDir.listFiles())
          .getOrElse(Array.empty[File])
          .filter(f => !f.getName.startsWith("."))
        val rawChannels = files.toList.flatMap { f =>
          val b = Files.readAllBytes(f.toPath)
          val s = new String(b, StandardCharsets.UTF_8)
          s.linesIterator.map(_.trim).filter(_.nonEmpty).toSeq
        }
        rawChannels.traverse { s =>
          val e = Channel.parse(s)
            .left.map(NonEmptyList.one)
          Validated.fromEither(e)
        }
      } else
        Validated.validNel(Nil)

    (channelsV, fileChannelsV).mapN {
      (channels, fileChannels) =>
        SharedChannelParams(
          (channels ++ fileChannels ++ defaultChannels ++ contribChannels).distinct
        )
    }
  }
} 
Example 112
Source File: SharedInstallParams.scala    From coursier   with Apache License 2.0 5 votes vote down vote up
package coursier.cli.install

import java.nio.file.{Path, Paths}

import caseapp.Tag
import cats.data.{NonEmptyList, Validated, ValidatedNel}
import cats.implicits._
import coursier.cache.{Cache, CacheLogger}
import coursier.cli.params.OutputParams
import coursier.core.Repository
import coursier.install.{GraalvmParams, InstallDir}
import coursier.parse.RepositoryParser
import coursier.util.Task

final case class SharedInstallParams(
  repositories: Seq[Repository],
  dir: Path,
  graalvmParamsOpt: Option[GraalvmParams] = None,
  onlyPrebuilt: Boolean,
  platformOpt: Option[String],
  preferPrebuilt: Boolean
) {

  def installDir(cache: Cache[Task]): InstallDir =
    InstallDir(dir, cache)
      .withGraalvmParamsOpt(graalvmParamsOpt)
      .withCoursierRepositories(repositories)
      .withOnlyPrebuilt(onlyPrebuilt)
      .withPlatform(platformOpt)
      .withPreferPrebuilt(preferPrebuilt)
}

object SharedInstallParams {

  lazy val defaultDir = InstallDir.defaultDir

  private[install] implicit def validationNelToCats[L, R](v: coursier.util.ValidationNel[L, R]): ValidatedNel[L, R] =
    v.either match {
      case Left(h :: t) => Validated.invalid(NonEmptyList.of(h, t: _*))
      case Right(r) => Validated.validNel(r)
    }

  def apply(options: SharedInstallOptions): ValidatedNel[String, SharedInstallParams] = {

    val repositoriesV = validationNelToCats(RepositoryParser.repositories(options.repository))

    val defaultRepositories =
      if (options.defaultRepositories)
        coursier.Resolve.defaultRepositories
      else
        Nil

    val dir = options.installDir.filter(_.nonEmpty) match {
      case Some(d) => Paths.get(d)
      case None => defaultDir
    }

    val graalvmParams = GraalvmParams(
      options.graalvmDefaultVersion.filter(_.nonEmpty),
      options.graalvmOption
    )

    val onlyPrebuilt = options.onlyPrebuilt

    val platformOpt = options.installPlatform.orElse(InstallDir.platform())

    val preferPrebuilt = options.installPreferPrebuilt

    repositoriesV.map { repositories =>
      SharedInstallParams(
        defaultRepositories ++ repositories,
        dir,
        Some(graalvmParams),
        onlyPrebuilt,
        platformOpt,
        preferPrebuilt
      )
    }
  }
} 
Example 113
Source File: BookingEventSerializer.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.serialization

import aecor.data.Enriched
import aecor.journal.postgres.PostgresEventJournal
import aecor.journal.postgres.PostgresEventJournal.Serializer.TypeHint
import cats.data.NonEmptyList
import enumeratum.EnumEntry
import ru.pavkin.booking.booking.entity._
import ru.pavkin.booking.booking.protobuf.msg
import enumeratum._
import cats.syntax.either._

import scala.collection.immutable

object BookingEventSerializer
    extends PostgresEventJournal.Serializer[Enriched[EventMetadata, BookingEvent]] {

  sealed trait Hint extends EnumEntry
  object Hint extends Enum[Hint] {
    case object AA extends Hint
    case object AB extends Hint
    case object AC extends Hint
    case object AD extends Hint
    case object AE extends Hint
    case object AF extends Hint
    case object AG extends Hint
    def values: immutable.IndexedSeq[Hint] = findValues
  }

  import Hint._

  def serialize(a: Enriched[EventMetadata, BookingEvent]): (TypeHint, Array[Byte]) = a match {
    case Enriched(m, BookingPlaced(clientId, concertId, seats)) =>
      AA.entryName -> msg.BookingPlaced(clientId, concertId, seats.toList, m.timestamp).toByteArray
    case Enriched(m, BookingConfirmed(tickets, expiresAt)) =>
      AB.entryName -> msg.BookingConfirmed(tickets.toList, expiresAt, m.timestamp).toByteArray
    case Enriched(m, BookingDenied(reason)) =>
      AC.entryName -> msg.BookingDenied(reason, m.timestamp).toByteArray
    case Enriched(m, BookingCancelled(reason)) =>
      AD.entryName -> msg.BookingCancelled(reason, m.timestamp).toByteArray
    case Enriched(m, BookingExpired) =>
      AE.entryName -> msg.BookingExpired(m.timestamp).toByteArray
    case Enriched(m, BookingPaid(paymentId)) =>
      AF.entryName -> msg.BookingPaid(paymentId, m.timestamp).toByteArray
    case Enriched(m, BookingSettled) =>
      AG.entryName -> msg.BookingSettled(m.timestamp).toByteArray
  }

  def deserialize(typeHint: TypeHint,
                  bytes: Array[Byte]): Either[Throwable, Enriched[EventMetadata, BookingEvent]] =
    Either.catchNonFatal(Hint.withName(typeHint) match {

      case Hint.AA =>
        val raw = msg.BookingPlaced.parseFrom(bytes)
        Enriched(
          EventMetadata(raw.timestamp),
          BookingPlaced(raw.clientId, raw.concertId, NonEmptyList.fromListUnsafe(raw.seats.toList))
        )

      case Hint.AB =>
        val raw = msg.BookingConfirmed.parseFrom(bytes)
        Enriched(
          EventMetadata(raw.timestamp),
          BookingConfirmed(NonEmptyList.fromListUnsafe(raw.tickets.toList), raw.expiresAt)
        )

      case Hint.AC =>
        val raw = msg.BookingDenied.parseFrom(bytes)
        Enriched(EventMetadata(raw.timestamp), BookingDenied(raw.reason))

      case Hint.AD =>
        val raw = msg.BookingCancelled.parseFrom(bytes)
        Enriched(EventMetadata(raw.timestamp), BookingCancelled(raw.reason))

      case Hint.AE =>
        val raw = msg.BookingExpired.parseFrom(bytes)
        Enriched(EventMetadata(raw.timestamp), BookingExpired)

      case Hint.AF =>
        val raw = msg.BookingPaid.parseFrom(bytes)
        Enriched(EventMetadata(raw.timestamp), BookingPaid(raw.paymentId))

      case Hint.AG =>
        val raw = msg.BookingSettled.parseFrom(bytes)
        Enriched(EventMetadata(raw.timestamp), BookingSettled)

    })
} 
Example 114
Source File: BookingState.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.entity

import java.time.Instant

import aecor.data.Folded
import cats.data.NonEmptyList
import ru.pavkin.booking.common.models._
import aecor.data.Folded.syntax._

case class BookingState(clientId: ClientId,
                        concertId: ConcertId,
                        seats: NonEmptyList[Seat],
                        tickets: Option[NonEmptyList[Ticket]],
                        status: BookingStatus,
                        expiresAt: Option[Instant],
                        paymentId: Option[PaymentId]) {

  def handleEvent(e: BookingEvent): Folded[BookingState] = e match {
    case _: BookingPlaced => impossible
    case e: BookingConfirmed =>
      copy(tickets = Some(e.tickets), expiresAt = e.expiresAt, status = BookingStatus.Confirmed).next
    case _: BookingDenied | _: BookingCancelled => copy(status = BookingStatus.Canceled).next
    case BookingExpired                         => copy(status = BookingStatus.Canceled).next
    case e: BookingPaid                         => copy(paymentId = Some(e.paymentId)).next
    case BookingSettled                         => copy(status = BookingStatus.Settled).next
  }

}

object BookingState {

  def init(e: BookingEvent): Folded[BookingState] = e match {
    case e: BookingPlaced =>
      BookingState(
        e.clientId,
        e.concertId,
        e.seats,
        None,
        BookingStatus.AwaitingConfirmation,
        None,
        None
      ).next
    case _ => impossible
  }
} 
Example 115
Source File: EventsourcedBookingWithoutExpiration.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.entity

import java.time.Instant

import aecor.MonadActionReject
import aecor.data._
import cats.Monad
import cats.data.EitherT._
import cats.data.NonEmptyList
import cats.syntax.all._
import ru.pavkin.booking.common.models.BookingStatus._
import ru.pavkin.booking.common.models._

// Just an example, isn't uses
class EventsourcedBookingWithoutExpiration[F[_]](
  implicit F: MonadActionReject[F, Option[BookingState], BookingEvent, BookingCommandRejection]
) extends Booking[F] {

  import F._

  val ignore: F[Unit] = unit

  def place(client: ClientId, concert: ConcertId, seats: NonEmptyList[Seat]): F[Unit] =
    read.flatMap {
      case Some(_) => reject(BookingAlreadyExists)
      case None =>
        if (seats.distinct =!= seats) reject(DuplicateSeats)
        else if (seats.size > 10) reject(TooManySeats)
        else append(BookingPlaced(client, concert, seats))
    }

  def confirm(tickets: NonEmptyList[Ticket], expiresAt: Option[Instant]): F[Unit] =
    status.flatMap {
      case AwaitingConfirmation =>
        append(BookingConfirmed(tickets, null)) >>
          whenA(tickets.foldMap(_.price).amount <= 0)(append(BookingSettled))

      case Confirmed | Settled => ignore
      case Denied              => reject(BookingIsDenied)
      case Canceled            => reject(BookingIsAlreadyCanceled)
    }

  def expire: F[Unit] = ???

  def deny(reason: String): F[Unit] =
    status.flatMap {
      case AwaitingConfirmation =>
        append(BookingDenied(reason))
      case Denied              => ignore
      case Confirmed | Settled => reject(BookingIsAlreadyConfirmed)
      case Canceled            => reject(BookingIsAlreadyCanceled)
    }

  def cancel(reason: String): F[Unit] =
    status.flatMap {
      case AwaitingConfirmation | Confirmed =>
        append(BookingCancelled(reason))
      case Canceled | Denied => ignore
      case Settled           => reject(BookingIsAlreadySettled)
    }

  def receivePayment(paymentId: PaymentId): F[Unit] =
    status.flatMap {
      case AwaitingConfirmation        => reject(BookingIsNotConfirmed)
      case Canceled | Denied | Settled => reject(BookingIsAlreadySettled)
      case Confirmed                   => append(BookingPaid(paymentId)) >> append(BookingSettled)
    }

  def status: F[BookingStatus] = read.flatMap {
    case Some(s) => pure(s.status)
    case _       => reject(BookingNotFound)
  }

  def tickets: F[Option[NonEmptyList[Ticket]]] = read.map(_.flatMap(_.tickets))
}

object EventsourcedBookingWithoutExpiration {

  def behavior[F[_]: Monad]: EventsourcedBehavior[
    EitherK[Booking, BookingCommandRejection, ?[_]],
    F,
    Option[BookingState],
    BookingEvent
  ] =
    EventsourcedBehavior
      .optionalRejectable(
        new EventsourcedBookingWithoutExpiration(),
        BookingState.init,
        _.handleEvent(_)
      )
} 
Example 116
Source File: BookingEvent.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.entity

import java.time.Instant

import cats.data.NonEmptyList
import ru.pavkin.booking.common.models._

sealed trait BookingEvent extends Product with Serializable

case class BookingPlaced(clientId: ClientId, concertId: ConcertId, seats: NonEmptyList[Seat])
    extends BookingEvent
case class BookingConfirmed(tickets: NonEmptyList[Ticket], expiresAt: Option[Instant])
    extends BookingEvent
case class BookingDenied(reason: String) extends BookingEvent
case class BookingCancelled(reason: String) extends BookingEvent
case object BookingExpired extends BookingEvent
case class BookingPaid(paymentId: PaymentId) extends BookingEvent
case object BookingSettled extends BookingEvent 
Example 117
Source File: Booking.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.entity

import java.time.Instant

import aecor.macros.boopickleWireProtocol
import cats.data.NonEmptyList
import cats.tagless.autoFunctorK
import ru.pavkin.booking.common.models._
import boopickle.Default._
import BookingWireCodecs._

@autoFunctorK(false)
@boopickleWireProtocol
trait Booking[F[_]] {

  def place(client: ClientId, concert: ConcertId, seats: NonEmptyList[Seat]): F[Unit]
  def confirm(tickets: NonEmptyList[Ticket], expiresAt: Option[Instant]): F[Unit]
  def deny(reason: String): F[Unit]
  def cancel(reason: String): F[Unit]
  def receivePayment(paymentId: PaymentId): F[Unit]
  def expire: F[Unit]
  def status: F[BookingStatus]
}

object Booking 
Example 118
Source File: StubConfirmationService.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.service

import java.time.temporal.ChronoUnit
import java.time.{ Duration, Instant }
import java.util.concurrent.TimeUnit

import cats.Monad
import cats.data.NonEmptyList
import cats.effect.{ Clock, Sync }
import cats.effect.concurrent.Ref
import cats.implicits._
import ru.pavkin.booking.booking.service.TicketReservationService._
import ru.pavkin.booking.booking.service.StubConfirmationService.ConcertState
import ru.pavkin.booking.common.models._

class StubConfirmationService[F[_]: Monad](clock: Clock[F],
                                           state: Ref[F, Map[ConcertId, ConcertState]])
    extends TicketReservationService[F] {

  val expireAfter: Duration = Duration.of(6, ChronoUnit.HOURS)

  def reserve(bookingId: BookingKey,
           concertId: ConcertId,
           seats: NonEmptyList[Seat]): F[Either[ReservationFailure, Reservation]] =
    clock
      .realTime(TimeUnit.MILLISECONDS)
      .map(Instant.ofEpochMilli)
      .flatMap(
        now =>
          state.modify[Either[ReservationFailure, Reservation]](
            concerts =>
              concerts.get(concertId) match {
                case None => concerts -> Left(UnknownSeats)
                case Some(concertState) =>
                  concertState
                    .book(bookingId, seats)
                    .fold(e => concerts -> Left(e), {
                      case (c, t) =>
                        concerts.updated(concertId, c) -> Right(
                          Reservation(t, Some(now.plus(expireAfter)))
                        )
                    })

            }
        )
      )

  def release(bookingId: BookingKey): F[Either[ReleaseFailure, Unit]] =
    state.modify[Either[ReleaseFailure, Unit]](
      concerts =>
        Either
          .fromOption(concerts.find(_._2.bookedSeats.contains(bookingId)), UnknownBooking)
          .flatMap {
            case (concertId, concertState) =>
              concertState.release(bookingId).map(concertId -> _)
          } match {
          case Left(value)                  => concerts -> Left(value)
          case Right((concertId, newState)) => concerts.updated(concertId, newState) -> Right(())
      }
    )
}

object StubConfirmationService {

  def apply[F[_]: Sync](clock: Clock[F],
                        initial: Map[ConcertId, ConcertState]): F[StubConfirmationService[F]] =
    Ref.of(initial).map(new StubConfirmationService(clock, _))

  case class ConcertState(prices: Map[Seat, Money],
                          availableSeats: Set[Seat],
                          bookedSeats: Map[BookingKey, NonEmptyList[Seat]]) {

    def book(
      bookingId: BookingKey,
      seats: NonEmptyList[Seat]
    ): Either[ReservationFailure, (ConcertState, NonEmptyList[Ticket])] =
      if (bookedSeats.contains(bookingId)) Left(SeatsAlreadyBooked)
      else if (!seats.forall(availableSeats)) Left(SeatsAlreadyBooked)
      else if (!seats.forall(prices.contains)) Left(UnknownSeats)
      else
        Right(
          copy(
            availableSeats = availableSeats.diff(seats.toList.toSet),
            bookedSeats = bookedSeats.updated(bookingId, seats)
          ) -> seats.map(s => Ticket(s, prices(s)))
        )

    def release(bookingId: BookingKey): Either[ReleaseFailure, ConcertState] =
      bookedSeats.get(bookingId) match {
        case Some(booked) =>
          Right(
            copy(
              availableSeats = availableSeats ++ booked.toList.toSet,
              bookedSeats = bookedSeats - bookingId
            )
          )
        case None => Left(UnknownBooking)
      }
  }

} 
Example 119
Source File: TicketReservationService.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.service

import java.time.Instant

import cats.data.NonEmptyList
import ru.pavkin.booking.booking.service.TicketReservationService.{
  Reservation,
  ReservationFailure,
  ReleaseFailure
}
import ru.pavkin.booking.common.models.{ BookingKey, ConcertId, Seat, Ticket }

trait TicketReservationService[F[_]] {

  def reserve(bookingId: BookingKey,
              concertId: ConcertId,
              seats: NonEmptyList[Seat]): F[Either[ReservationFailure, Reservation]]

  def release(bookingId: BookingKey): F[Either[ReleaseFailure, Unit]]
}

object TicketReservationService {

  case class Reservation(tickets: NonEmptyList[Ticket], expiresAt: Option[Instant])

  sealed trait ReservationFailure
  case object SeatsAlreadyBooked extends ReservationFailure
  case object UnknownSeats extends ReservationFailure
  case object DuplicateSeats extends ReservationFailure

  sealed trait ReleaseFailure
  case object UnknownBooking extends ReleaseFailure
} 
Example 120
Source File: BookingEndpoint.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking.booking.endpoint

import java.util.UUID

import cats.data.NonEmptyList
import cats.effect.Sync
import cats.implicits._
import ru.pavkin.booking.booking.booking.Bookings
import ru.pavkin.booking.booking.entity.{ BookingCommandRejection, BookingNotFound }
import ru.pavkin.booking.booking.view.{ BookingView, BookingViewRepository }
import ru.pavkin.booking.common.models.{ BookingKey, ClientId, ConcertId, Seat }

trait BookingEndpoint[F[_]] {
  def placeBooking(client: ClientId,
                   concertId: ConcertId,
                   seats: NonEmptyList[Seat]): F[Either[BookingCommandRejection, Unit]]

  def cancelBooking(clientId: ClientId,
                    bookingId: BookingKey,
                    reason: String): F[Either[BookingCommandRejection, Unit]]

  def clientBookings(client: ClientId): F[List[BookingView]]

}

final class DefaultBookingEndpoint[F[_]](
  bookings: Bookings[F],
  bookingsView: BookingViewRepository[F]
)(implicit F: Sync[F])
    extends BookingEndpoint[F] {

  def placeBooking(client: ClientId,
                   concertId: ConcertId,
                   seats: NonEmptyList[Seat]): F[Either[BookingCommandRejection, Unit]] =
    for {
      id <- Sync[F].delay(UUID.randomUUID())
      result <- bookings(BookingKey(id.toString)).place(client, concertId, seats)
    } yield result

  def cancelBooking(clientId: ClientId,
                    bookingId: BookingKey,
                    reason: String): F[Either[BookingCommandRejection, Unit]] =
    bookingsView.get(bookingId).flatMap {
      case None                               => F.pure(Left(BookingNotFound))
      case Some(b) if b.clientId =!= clientId => F.pure(Left(BookingNotFound))
      case Some(_)                            => bookings(bookingId).cancel(reason)
    }

  def clientBookings(client: ClientId): F[List[BookingView]] =
    bookingsView.byClient(client)
} 
Example 121
Source File: KafkaWirings.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking

import aecor.data.{ Committable, ConsumerId }
import cats.data.NonEmptyList
import cats.effect._
import fs2.kafka.{ AutoOffsetReset, ConsumerSettings, _ }
import org.apache.kafka.common.serialization.StringDeserializer
import ru.pavkin.payment.event.PaymentReceived
import ru.pavkin.payment.kafka.PaymentReceivedEventDeserializer

import scala.concurrent.ExecutionContext

final class KafkaWirings[F[_]](
  val paymentReceivedEventStream: ConsumerId => fs2.Stream[F, Committable[F, PaymentReceived]]
)

object KafkaWirings {

  def apply[F[_]: ConcurrentEffect: ContextShift: Timer]: KafkaWirings[F] = {

    def paymentReceivedEventStream(
      consumerId: ConsumerId
    ): fs2.Stream[F, Committable[F, PaymentReceived]] =
      for {
        executionContext <- consumerExecutionContextStream[F]
        settings = bookingPaymentProcessSourceSettings(executionContext).withGroupId(
          consumerId.value
        )
        consumer <- consumerStream[F].using(settings)
        _ <- consumer.subscribe(paymentReceivedTopic)
        stream <- consumer.stream.map(
                   m => Committable(m.committableOffset.commit, m.record.value())
                 )
      } yield stream

    new KafkaWirings[F](paymentReceivedEventStream)
  }

  def bookingPaymentProcessSourceSettings(
    ec: ExecutionContext
  ): ConsumerSettings[String, PaymentReceived] =
    ConsumerSettings(
      keyDeserializer = new StringDeserializer,
      valueDeserializer = new PaymentReceivedEventDeserializer,
      executionContext = ec
    ).withAutoOffsetReset(AutoOffsetReset.Earliest).withBootstrapServers("0.0.0.0:9092")

  val paymentReceivedTopic: NonEmptyList[String] = NonEmptyList.one("PaymentReceived")
} 
Example 122
Source File: HostnamePlatform.scala    From ip4s   with Apache License 2.0 5 votes vote down vote up
package com.comcast.ip4s

import java.net.{InetAddress, UnknownHostException}

import cats.data.NonEmptyList
import cats.effect.Sync

private[ip4s] trait HostnamePlatform { self: Hostname =>

  
  def resolveAll[F[_]: Sync]: F[Option[NonEmptyList[IpAddress]]] =
    Sync[F].delay {
      try {
        val addrs = InetAddress.getAllByName(self.toString)
        NonEmptyList.fromList(addrs.toList.flatMap(addr => IpAddress.fromBytes(addr.getAddress)))
      } catch {
        case _: UnknownHostException => None
      }
    }
} 
Example 123
Source File: DiffCatsInstances.scala    From diffx   with Apache License 2.0 5 votes vote down vote up
package com.softwaremill.diffx.cats

import cats.data.{NonEmptyChain, NonEmptyList, NonEmptySet, NonEmptyVector}
import com.softwaremill.diffx.{Derived, Diff}
import com.softwaremill.diffx.Diff._

trait DiffCatsInstances {
  implicit def diffNel[T: Diff]: Derived[Diff[NonEmptyList[T]]] =
    Derived(Diff[List[T]].contramap[NonEmptyList[T]](_.toList))

  implicit def diffNec[T: Diff]: Derived[Diff[NonEmptyChain[T]]] =
    Derived(Diff[List[T]].contramap[NonEmptyChain[T]](_.toChain.toList))

  implicit def diffNes[T: Diff]: Derived[Diff[NonEmptySet[T]]] =
    Derived(Diff[Set[T]].contramap[NonEmptySet[T]](_.toSortedSet))

  implicit def diffNev[T: Diff]: Derived[Diff[NonEmptyVector[T]]] =
    Derived(Diff[List[T]].contramap[NonEmptyVector[T]](_.toVector.toList))
} 
Example 124
Source File: SwaggerTerms.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail
package terms

import cats.Monad
import cats.data.NonEmptyList
import com.twilio.guardrail.core.{ Mappish, Tracker }
import com.twilio.guardrail.languages.LA
import io.swagger.v3.oas.models._
import io.swagger.v3.oas.models.media.{ ArraySchema, Schema }
import io.swagger.v3.oas.models.parameters.{ Parameter, RequestBody }
import io.swagger.v3.oas.models.responses.ApiResponse
import io.swagger.v3.oas.models.security.{ SecurityScheme => SwSecurityScheme }

abstract class SwaggerLogAdapter[F[_]] {
  def schemaToString(value: Schema[_]): String = "    " + value.toString().linesIterator.filterNot(_.contains(": null")).mkString("\n    ")
  def function[A](name: String): F[A] => F[A]
  def push(name: String): F[Unit]
  def pop: F[Unit]
  def debug(message: String): F[Unit]
  def info(message: String): F[Unit]
  def warning(message: String): F[Unit]
  def error(message: String): F[Unit]
}

abstract class SwaggerTerms[L <: LA, F[_]] {
  def MonadF: Monad[F]

  def extractCommonRequestBodies(components: Option[Components]): F[Map[String, RequestBody]]
  def extractOperations(
      paths: Tracker[Mappish[List, String, PathItem]],
      commonRequestBodies: Map[String, RequestBody],
      globalSecurityRequirements: Option[SecurityRequirements]
  ): F[List[RouteMeta]]
  def extractApiKeySecurityScheme(schemeName: String, securityScheme: SwSecurityScheme, tpe: Option[L#Type]): F[ApiKeySecurityScheme[L]]
  def extractHttpSecurityScheme(schemeName: String, securityScheme: SwSecurityScheme, tpe: Option[L#Type]): F[HttpSecurityScheme[L]]
  def extractOpenIdConnectSecurityScheme(schemeName: String, securityScheme: SwSecurityScheme, tpe: Option[L#Type]): F[OpenIdConnectSecurityScheme[L]]
  def extractOAuth2SecurityScheme(schemeName: String, securityScheme: SwSecurityScheme, tpe: Option[L#Type]): F[OAuth2SecurityScheme[L]]
  def getClassName(operation: Tracker[Operation], vendorPrefixes: List[String]): F[List[String]]
  def getParameterName(parameter: Parameter): F[String]
  def getBodyParameterSchema(parameter: Tracker[Parameter]): F[Tracker[Schema[_]]]
  def getHeaderParameterType(parameter: Tracker[Parameter]): F[Tracker[String]]
  def getPathParameterType(parameter: Tracker[Parameter]): F[Tracker[String]]
  def getQueryParameterType(parameter: Tracker[Parameter]): F[Tracker[String]]
  def getCookieParameterType(parameter: Tracker[Parameter]): F[Tracker[String]]
  def getFormParameterType(parameter: Tracker[Parameter]): F[Tracker[String]]
  def getRefParameterRef(parameter: Tracker[Parameter]): F[Tracker[String]]
  def getSerializableParameterType(parameter: Tracker[Parameter]): F[Tracker[String]]
  def fallbackParameterHandler(parameter: Tracker[Parameter]): F[SwaggerUtil.ResolvedType[L]]
  def getOperationId(operation: Tracker[Operation]): F[String]
  def getResponses(operationId: String, operation: Tracker[Operation]): F[NonEmptyList[(String, Tracker[ApiResponse])]]
  def getSimpleRef(ref: Tracker[Option[Schema[_]]]): F[String]
  def getItems(arr: Tracker[ArraySchema]): F[Tracker[Schema[_]]]
  def getType(model: Tracker[Schema[_]]): F[Tracker[String]]
  def fallbackPropertyTypeHandler(prop: Tracker[Schema[_]]): F[L#Type]
  def resolveType(name: String, protocolElems: List[StrictProtocolElems[L]]): F[StrictProtocolElems[L]]
  def fallbackResolveElems(lazyElems: List[LazyProtocolElems[L]]): F[List[StrictProtocolElems[L]]]
  def log: SwaggerLogAdapter[F]
} 
Example 125
Source File: CoreTerms.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail
package terms

import cats.Monad
import cats.data.NonEmptyList
import com.twilio.guardrail.languages.LA
import com.twilio.guardrail.generators.Framework

abstract class CoreTerms[L <: LA, F[_]] {
  def MonadF: Monad[F]
  def getDefaultFramework: F[Option[String]]
  def extractGenerator(context: Context, defaultFramework: Option[String]): F[Framework[L, Target]]
  def parseArgs(args: Array[String]): F[List[Args]]
  def validateArgs(parsed: List[Args]): F[NonEmptyList[Args]]
  def processArgSet(targetInterpreter: Framework[L, Target])(args: Args): F[ReadSwagger[Target[List[WriteTree]]]]
  def copy(
      newMonadF: Monad[F] = MonadF,
      newGetDefaultFramework: F[Option[String]] = getDefaultFramework,
      newExtractGenerator: (Context, Option[String]) => F[Framework[L, Target]] = extractGenerator _,
      newParseArgs: Array[String] => F[List[Args]] = parseArgs _,
      newValidateArgs: List[Args] => F[NonEmptyList[Args]] = validateArgs _,
      newProcessArgSet: Framework[L, Target] => Args => F[ReadSwagger[Target[List[WriteTree]]]] = processArgSet _
  ) = new CoreTerms[L, F] {
    def MonadF                                                               = newMonadF
    def getDefaultFramework                                                  = newGetDefaultFramework
    def extractGenerator(context: Context, defaultFramework: Option[String]) = newExtractGenerator(context, defaultFramework)
    def parseArgs(args: Array[String])                                       = newParseArgs(args)
    def validateArgs(parsed: List[Args])                                     = newValidateArgs(parsed)
    def processArgSet(targetInterpreter: Framework[L, Target])(args: Args)   = newProcessArgSet(targetInterpreter)(args)
  }
}
object CoreTerms {
  implicit def coreTerm[L <: LA, F[_]](implicit ev: CoreTerms[L, F]): CoreTerms[L, F] = ev
} 
Example 126
Source File: ClientGenerator.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail

import cats.data.NonEmptyList
import cats.implicits._
import com.twilio.guardrail.languages.LA
import com.twilio.guardrail.protocol.terms.client.ClientTerms
import com.twilio.guardrail.protocol.terms.Responses
import com.twilio.guardrail.terms.framework.FrameworkTerms
import com.twilio.guardrail.terms.{ LanguageTerms, RouteMeta, SecurityScheme, SwaggerTerms }
import java.net.URI

case class Clients[L <: LA](clients: List[Client[L]], supportDefinitions: List[SupportDefinition[L]])
case class Client[L <: LA](
    pkg: List[String],
    clientName: String,
    imports: List[L#Import],
    staticDefns: StaticDefns[L],
    client: NonEmptyList[Either[L#Trait, L#ClassDefinition]],
    responseDefinitions: List[L#Definition]
)
case class RenderedClientOperation[L <: LA](
    clientOperation: L#Definition,
    supportDefinitions: List[L#Definition]
)

object ClientGenerator {
  def fromSwagger[L <: LA, F[_]](context: Context, frameworkImports: List[L#Import])(
      serverUrls: Option[NonEmptyList[URI]],
      basePath: Option[String],
      groupedRoutes: List[(List[String], List[RouteMeta])]
  )(
      protocolElems: List[StrictProtocolElems[L]],
      securitySchemes: Map[String, SecurityScheme[L]]
  )(implicit C: ClientTerms[L, F], Fw: FrameworkTerms[L, F], Sc: LanguageTerms[L, F], Sw: SwaggerTerms[L, F]): F[Clients[L]] = {
    import C._
    import Sw._
    import Sc._
    for {
      clientImports      <- getImports(context.tracing)
      clientExtraImports <- getExtraImports(context.tracing)
      supportDefinitions <- generateSupportDefinitions(context.tracing, securitySchemes)
      clients <- groupedRoutes.traverse({
        case (className, unsortedRoutes) =>
          val routes = unsortedRoutes.sortBy(r => (r.path.unwrapTracker, r.method))
          for {
            clientName <- formatTypeName(className.lastOption.getOrElse(""), Some("Client"))
            responseClientPair <- routes.traverse {
              case route @ RouteMeta(path, method, operation, securityRequirements) =>
                for {
                  operationId         <- getOperationId(operation)
                  responses           <- Responses.getResponses[L, F](operationId, operation, protocolElems)
                  responseClsName     <- formatTypeName(operationId, Some("Response"))
                  responseDefinitions <- generateResponseDefinitions(responseClsName, responses, protocolElems)
                  parameters          <- route.getParameters[L, F](protocolElems)
                  methodName          <- formatMethodName(operationId)
                  clientOp            <- generateClientOperation(className, responseClsName, context.tracing, securitySchemes, parameters)(route, methodName, responses)
                } yield (responseDefinitions, clientOp)
            }
            (responseDefinitions, clientOperations) = responseClientPair.unzip
            tracingName                             = Option(className.mkString("-")).filterNot(_.isEmpty)
            ctorArgs    <- clientClsArgs(tracingName, serverUrls, context.tracing)
            staticDefns <- buildStaticDefns(clientName, tracingName, serverUrls, ctorArgs, context.tracing)
            client <- buildClient(
              clientName,
              tracingName,
              serverUrls,
              basePath,
              ctorArgs,
              clientOperations.map(_.clientOperation),
              clientOperations.flatMap(_.supportDefinitions),
              context.tracing
            )
          } yield {
            Client[L](className, clientName, (clientImports ++ frameworkImports ++ clientExtraImports), staticDefns, client, responseDefinitions.flatten)
          }
      })
    } yield Clients[L](clients, supportDefinitions)
  }
} 
Example 127
Source File: Scala.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail.generators.syntax

import cats.data.NonEmptyList
import com.twilio.guardrail.{ StaticDefns, SwaggerUtil, Target }
import com.twilio.guardrail.core.Tracker
import com.twilio.guardrail.generators.{ LanguageParameter, RawParameterName, RawParameterType }
import com.twilio.guardrail.languages.ScalaLanguage
import com.twilio.guardrail.generators.operations.TracingLabelFormatter
import scala.meta._

object Scala {
  implicit class RichRawParameterName(parameter: RawParameterName) {
    import _root_.scala.meta._
    def toLit: Lit.String = Lit.String(parameter.value)
  }

  implicit class ScalaTracingLabel(value: TracingLabelFormatter) {
    def toLit: Lit.String = Lit.String(s"${value.context}:${value.operationId}")
  }

  implicit class RichLanguageParameter(value: LanguageParameter.type) {
    import _root_.scala.meta._
    import com.twilio.guardrail.languages.ScalaLanguage
    def fromParam(param: Term.Param, rawType: Option[String] = Some("string"), rawFormat: Option[String] = None): LanguageParameter[ScalaLanguage] =
      param match {
        case param @ Term.Param(_, name, decltype, _) =>
          val tpe: Type = decltype
            .flatMap({
              case tpe @ t"Option[$_]" => Some(tpe)
              case Type.ByName(tpe)    => Some(tpe)
              case tpe @ Type.Name(_)  => Some(tpe)
              case _                   => None
            })
            .getOrElse(t"Nothing")
          new LanguageParameter[ScalaLanguage](
            None,
            param,
            Term.Name(name.value),
            RawParameterName(name.value),
            tpe,
            RawParameterType(rawType, rawFormat),
            true,
            None,
            false
          )
      }
  }

  implicit class ExtendedUnzip[T1, T2, T3, T4, T5, T6, T7, T8](xs: NonEmptyList[(T1, T2, T3, T4, T5, T6, T7, T8)]) {
    def unzip8: (List[T1], List[T2], List[T3], List[T4], List[T5], List[T6], List[T7], List[T8]) =
      xs.foldLeft(
        (List.empty[T1], List.empty[T2], List.empty[T3], List.empty[T4], List.empty[T5], List.empty[T6], List.empty[T7], List.empty[T8])
      ) {
        case ((v1a, v2a, v3a, v4a, v5a, v6a, v7a, v8a), (v1, v2, v3, v4, v5, v6, v7, v8)) =>
          (v1a :+ v1, v2a :+ v2, v3a :+ v3, v4a :+ v4, v5a :+ v5, v6a :+ v6, v7a :+ v7, v8a :+ v8)
      }
  }

  val GENERATED_CODE_COMMENT: String =
    s"""
       |""".stripMargin

  def companionForStaticDefns(staticDefns: StaticDefns[ScalaLanguage]): Defn.Object =
    q"""
    object ${Term.Name(staticDefns.className)} {
      ..${staticDefns.extraImports}
      ..${staticDefns.definitions}
    }
    """

  def generateUrlPathParams(path: Tracker[String], pathArgs: List[LanguageParameter[ScalaLanguage]]): Target[Term] =
    SwaggerUtil.paths.generateUrlPathParams[ScalaLanguage](
      path,
      pathArgs,
      Lit.String(_),
      name => q"Formatter.addPath(${name})",
      q"host + basePath",
      (a, b) => q"${a} + ${b}"
    )
} 
Example 128
Source File: package.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail.generators

import cats.data.NonEmptyList
import java.util.Locale
import java.util.regex.Matcher.quoteReplacement
import io.swagger.v3.oas.models.{ Operation, PathItem }
import io.swagger.v3.oas.models.media.Schema
import io.swagger.v3.oas.models.parameters.Parameter
import scala.collection.IterableLike
import scala.collection.generic.CanBuildFrom
import scala.language.implicitConversions

package syntax {
  class RichNotNullShower[A](value: A) {
    def showNotNull: String = showNotNullIndented(0)
    def showNotNullIndented(indent: Int): String =
      ("  " * indent) + value.toString().linesIterator.filterNot(_.contains(": null")).mkString("\n" + ("  " * indent))
  }

  class RichCollection[A, Repr](xs: IterableLike[A, Repr]) {
    def distinctBy[B, That](f: A => B)(implicit cbf: CanBuildFrom[Repr, A, That]): That = {
      val builder = cbf(xs.repr)
      val i       = xs.iterator
      var set     = Set[B]()
      while (i.hasNext) {
        val o = i.next
        val b = f(o)
        if (!set(b)) {
          set += b
          builder += o
        }
      }
      builder.result
    }
  }
}

package object syntax {
  val GENERATED_CODE_COMMENT_LINES: List[String] = List(
    "This file was generated by Guardrail (https://github.com/twilio/guardrail).",
    "Modifications will be overwritten; instead edit the OpenAPI/Swagger spec file."
  )

  
  private val SPLIT_DELIMITERS = "[-_\\s\\.]+".r
  private val BOUNDARY_SPLITTERS = List(
    "([^A-Z])([A-Z])".r,
    "([A-Z]+)([A-Z][a-z]+)".r
  )

  implicit class RichString(private val s: String) extends AnyVal {
    private def splitParts(s: String): List[String] =
      BOUNDARY_SPLITTERS
        .foldLeft(SPLIT_DELIMITERS.split(s))(
          (last, splitter) => last.flatMap(part => splitter.replaceAllIn(part, m => quoteReplacement(m.group(1) + "-" + m.group(2))).split("-"))
        )
        .map(_.toLowerCase(Locale.US))
        .toList

    def toPascalCase: String = splitParts(s).map(_.capitalize).mkString

    def toCamelCase: String =
      NonEmptyList
        .fromList(splitParts(s))
        .fold("")(
          parts => parts.head + parts.tail.map(_.capitalize).mkString
        )

    def toSnakeCase: String = splitParts(s).mkString("_")

    def toDashedCase: String = splitParts(s).mkString("-")

    def uncapitalized: String =
      if (s.nonEmpty) {
        val inUnPacked              = s.toCharArray
        val lowercaseFirstCharacter = Character.toLowerCase(inUnPacked(0))
        new String(lowercaseFirstCharacter +: inUnPacked.tail)
      } else s

  }

  implicit def RichSchema: Schema[_] => RichNotNullShower[Schema[_]]    = new RichNotNullShower[Schema[_]](_)
  implicit def RichOperation: Operation => RichNotNullShower[Operation] = new RichNotNullShower[Operation](_)
  implicit def RichPathItem: PathItem => RichNotNullShower[PathItem]    = new RichNotNullShower[PathItem](_)
  implicit def RichParameter: Parameter => RichNotNullShower[Parameter] = new RichNotNullShower[Parameter](_)

  implicit def toRichCollection[A, Repr](xs: IterableLike[A, Repr]): RichCollection[A, Repr] = new RichCollection(xs)
} 
Example 129
Source File: AkkaHttpHelper.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail.generators.Scala

import cats.data.NonEmptyList
import cats.implicits._
import com.twilio.guardrail.Target
import com.twilio.guardrail.core.Tracker
import com.twilio.guardrail.protocol.terms.{ ApplicationJson, ContentType, TextPlain }
import scala.meta._

object AkkaHttpHelper {
  def generateDecoder(tpe: Type, consumes: Tracker[NonEmptyList[ContentType]]): Target[(Term, Type)] = {
    val baseType = tpe match {
      case t"Option[$x]" => x
      case x             => x
    }

    for {
      unmarshallers <- consumes.indexedDistribute.toList.flatTraverse {
        case Tracker(_, ApplicationJson)   => Target.pure(List(q"structuredJsonEntityUnmarshaller"))
        case Tracker(_, TextPlain)         => Target.pure(List(q"stringyJsonEntityUnmarshaller"))
        case Tracker(history, contentType) => Target.log.warning(s"Unable to generate decoder for ${contentType} (${history})").map(_ => List.empty[Term.Name])
      }
      unmarshaller <- unmarshallers match {
        case Nil      => Target.raiseUserError(s"No decoders available (${consumes.showHistory})")
        case x :: Nil => Target.pure(x)
        case xs       => Target.pure(q"Unmarshaller.firstOf(..${xs})")
      }
    } yield {
      val decoder = q""" {
        ${unmarshaller}.flatMap(_ => _ => json => io.circe.Decoder[${baseType}].decodeJson(json).fold(FastFuture.failed, FastFuture.successful))
      }
      """
      (decoder, baseType)
    }
  }
} 
Example 130
Source File: SpringMvcClientGenerator.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail.generators.Java

import com.twilio.guardrail.Target
import com.twilio.guardrail.languages.JavaLanguage
import com.twilio.guardrail.protocol.terms.client._
import cats.data.NonEmptyList
import com.twilio.guardrail.generators.LanguageParameters
import com.twilio.guardrail.protocol.terms.Responses
import com.twilio.guardrail.terms.{ RouteMeta, SecurityScheme }
import com.twilio.guardrail.StrictProtocolElems
import java.net.URI

object SpringMvcClientGenerator {

  object ClientTermInterp extends ClientTerms[JavaLanguage, Target] {
    def MonadF = Target.targetInstances
    def generateClientOperation(
        className: List[String],
        responseClsName: String,
        tracing: Boolean,
        securitySchemes: Map[String, SecurityScheme[JavaLanguage]],
        parameters: LanguageParameters[JavaLanguage]
    )(
        route: RouteMeta,
        methodName: String,
        responses: Responses[JavaLanguage]
    ) =
      Target.raiseUserError("spring client generation is not currently supported")
    def getImports(tracing: Boolean) =
      Target.raiseUserError("spring client generation is not currently supported")
    def getExtraImports(tracing: Boolean) =
      Target.raiseUserError("spring client generation is not currently supported")
    def clientClsArgs(
        tracingName: Option[String],
        serverUrls: Option[NonEmptyList[URI]],
        tracing: Boolean
    ) =
      Target.raiseUserError("spring client generation is not currently supported")
    def generateResponseDefinitions(
        responseClsName: String,
        responses: Responses[JavaLanguage],
        protocolElems: List[StrictProtocolElems[JavaLanguage]]
    ) =
      Target.raiseUserError("spring client generation is not currently supported")
    def generateSupportDefinitions(
        tracing: Boolean,
        securitySchemes: Map[String, SecurityScheme[JavaLanguage]]
    ) =
      Target.raiseUserError("spring client generation is not currently supported")
    def buildStaticDefns(
        clientName: String,
        tracingName: Option[String],
        serverUrls: Option[NonEmptyList[URI]],
        ctorArgs: List[List[com.github.javaparser.ast.body.Parameter]],
        tracing: Boolean
    ) =
      Target.raiseUserError("spring client generation is not currently supported")
    def buildClient(
        clientName: String,
        tracingName: Option[String],
        serverUrls: Option[NonEmptyList[URI]],
        basePath: Option[String],
        ctorArgs: List[List[com.github.javaparser.ast.body.Parameter]],
        clientCalls: List[com.github.javaparser.ast.body.BodyDeclaration[_ <: com.github.javaparser.ast.body.BodyDeclaration[_]]],
        supportDefinitions: List[com.github.javaparser.ast.body.BodyDeclaration[_ <: com.github.javaparser.ast.body.BodyDeclaration[_]]],
        tracing: Boolean
    ) =
      Target.raiseUserError("spring client generation is not currently supported")
  }
} 
Example 131
Source File: DropwizardHelpers.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail.generators.Java

import cats.data.NonEmptyList
import cats.syntax.foldable._
import com.github.javaparser.ast.`type`.Type
import com.twilio.guardrail.core.Tracker
import com.twilio.guardrail.generators.LanguageParameters
import com.twilio.guardrail.generators.syntax.Java._
import com.twilio.guardrail.languages.JavaLanguage
import com.twilio.guardrail.protocol.terms._
import io.swagger.v3.oas.models.Operation

object DropwizardHelpers {
  private val CONSUMES_PRIORITY = NonEmptyList.of(ApplicationJson, TextPlain, OctetStream)
  private val PRODUCES_PRIORITY = NonEmptyList.of(ApplicationJson, TextPlain, OctetStream)

  def getBestConsumes(operation: Tracker[Operation], contentTypes: List[ContentType], parameters: LanguageParameters[JavaLanguage]): Option[ContentType] =
    if (parameters.formParams.nonEmpty) {
      if (parameters.formParams.exists(_.isFile) || contentTypes.contains(MultipartFormData)) {
        Some(MultipartFormData)
      } else {
        Some(UrlencodedFormData)
      }
    } else {
      parameters.bodyParams.map({ bodyParam =>
        CONSUMES_PRIORITY
          .collectFirstSome(ct => contentTypes.find(_ == ct))
          .orElse(contentTypes.collectFirst({ case tc: TextContent => tc }))
          .orElse(contentTypes.collectFirst({ case bc: BinaryContent => bc }))
          .getOrElse({
            val fallback =
              if (bodyParam.argType.isPrimitiveType || bodyParam.argType.isNamed("String")) TextPlain
              else ApplicationJson
            println(s"WARNING: no supported body param type at ${operation.showHistory}; falling back to $fallback")
            fallback
          })
      })
    }

  def getBestProduces(operationId: String, contentTypes: List[ContentType], response: Response[JavaLanguage]): Option[ContentType] =
    response.value
      .map(_._1)
      .flatMap({ valueType: Type =>
        PRODUCES_PRIORITY
          .collectFirstSome(ct => contentTypes.find(_ == ct))
          .orElse(contentTypes.collectFirst({ case tc: TextContent => tc }))
          .orElse(contentTypes.collectFirst({ case bc: BinaryContent => bc }))
          .orElse({
            val fallback = if (valueType.isNamed("String")) TextPlain else ApplicationJson
            println(
              s"WARNING: no supported body param type for operation '$operationId', response code ${response.statusCode}; falling back to ${fallback.value}"
            )
            Option(fallback)
          })
      })
} 
Example 132
Source File: JavaModule.scala    From guardrail   with MIT License 5 votes vote down vote up
package com.twilio.guardrail
package generators

import com.twilio.guardrail.languages.JavaLanguage
import com.twilio.guardrail.generators.Java.JacksonGenerator
import com.twilio.guardrail.generators.Java.AsyncHttpClientClientGenerator
import com.twilio.guardrail.generators.Java.DropwizardGenerator
import com.twilio.guardrail.generators.Java.SpringMvcGenerator
import com.twilio.guardrail.generators.Java.DropwizardServerGenerator
import com.twilio.guardrail.generators.Java.SpringMvcServerGenerator
import cats.data.NonEmptyList

import com.twilio.guardrail.protocol.terms.protocol.{ ArrayProtocolTerms, EnumProtocolTerms, ModelProtocolTerms, PolyProtocolTerms, ProtocolSupportTerms }
import com.twilio.guardrail.protocol.terms.client.ClientTerms
import com.twilio.guardrail.protocol.terms.server.ServerTerms
import com.twilio.guardrail.terms.{ LanguageTerms, SwaggerTerms }
import com.twilio.guardrail.terms.framework.FrameworkTerms

object JavaModule extends AbstractModule[JavaLanguage] {
  def jackson: (
      ProtocolSupportTerms[JavaLanguage, Target],
      ModelProtocolTerms[JavaLanguage, Target],
      EnumProtocolTerms[JavaLanguage, Target],
      ArrayProtocolTerms[JavaLanguage, Target],
      PolyProtocolTerms[JavaLanguage, Target]
  ) = (
    JacksonGenerator.ProtocolSupportTermInterp,
    JacksonGenerator.ModelProtocolTermInterp,
    JacksonGenerator.EnumProtocolTermInterp,
    JacksonGenerator.ArrayProtocolTermInterp,
    JacksonGenerator.PolyProtocolTermInterp
  )

  def dropwizard: (
      ServerTerms[JavaLanguage, Target],
      FrameworkTerms[JavaLanguage, Target]
  ) = (DropwizardServerGenerator.ServerTermInterp, DropwizardGenerator.FrameworkInterp)
  def spring: (
      ServerTerms[JavaLanguage, Target],
      FrameworkTerms[JavaLanguage, Target]
  )                                                      = (SpringMvcServerGenerator.ServerTermInterp, SpringMvcGenerator.FrameworkInterp)
  def asyncHttpClient: ClientTerms[JavaLanguage, Target] = AsyncHttpClientClientGenerator.ClientTermInterp

  def extract(modules: NonEmptyList[String]): Target[Framework[JavaLanguage, Target]] =
    (for {
      (protocol, model, enum, array, poly) <- popModule("json", ("jackson", jackson))
      client                               <- popModule("client", ("async-http-client", asyncHttpClient))
      (server, framework)                  <- popModule("server", ("dropwizard", dropwizard), ("spring-mvc", spring))
    } yield new Framework[JavaLanguage, Target] {
      def ArrayProtocolInterp: ArrayProtocolTerms[JavaLanguage, Target]     = array
      def ClientInterp: ClientTerms[JavaLanguage, Target]                   = client
      def EnumProtocolInterp: EnumProtocolTerms[JavaLanguage, Target]       = enum
      def FrameworkInterp: FrameworkTerms[JavaLanguage, Target]             = framework
      def ModelProtocolInterp: ModelProtocolTerms[JavaLanguage, Target]     = model
      def PolyProtocolInterp: PolyProtocolTerms[JavaLanguage, Target]       = poly
      def ProtocolSupportInterp: ProtocolSupportTerms[JavaLanguage, Target] = protocol
      def ServerInterp: ServerTerms[JavaLanguage, Target]                   = server
      def SwaggerInterp: SwaggerTerms[JavaLanguage, Target]                 = SwaggerGenerator[JavaLanguage]
      def LanguageInterp: LanguageTerms[JavaLanguage, Target]               = JavaGenerator.JavaInterp
    }).runA(modules.toList.toSet)
} 
Example 133
Source File: ConfigReaderInstances.scala    From DataQuality   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.agilelab.dataquality.common.instances

import cats.data.Validated.{Invalid, Valid}
import cats.data.{NonEmptyList, ValidatedNel}
import cats.implicits._
import com.agilelab.dataquality.common.enumerations.DBTypes
import com.agilelab.dataquality.common.models.DatabaseCommon
import com.agilelab.dataquality.common.parsers.ConfigReader
import com.agilelab.dataquality.common.parsers.DQConfig.AllErrorsOr
import com.typesafe.config.Config

import scala.util.{Failure, Success, Try}

object ConfigReaderInstances {

  private def parseString(str: String)(implicit conf: Config): AllErrorsOr[String] = {
    Try(conf.getString(str)) match {
      case Success(v) => Valid(v)
      case Failure(_) => Invalid(NonEmptyList.one(s"Field $str is missing"))
    }
  }

  private def parseStringEnumerated(str: String, enum: Set[String])(implicit conf: Config): AllErrorsOr[String] = {
    Try(conf.getString(str)) match {
      case Success(v) if enum.contains(v) => Valid(v)
      case Success(v) => Invalid(NonEmptyList.one(s"Unsupported value of $str: $v"))
      case Failure(_) => Invalid(NonEmptyList.one(s"Field $str is missing"))
    }
  }

  implicit val databaseReader: ConfigReader[DatabaseCommon] =
    new ConfigReader[DatabaseCommon] {
      def read(conf: Config, enums: Set[String]*): AllErrorsOr[DatabaseCommon] = {
        val id: AllErrorsOr[String] = parseString("id")(conf)
        val subtype: AllErrorsOr[String] = parseStringEnumerated("subtype", DBTypes.names)(conf)

        Try(conf.getConfig("config")) match {
          case Success(innerConf) =>
            val host: AllErrorsOr[String] = parseString("host")(innerConf)

            val port: AllErrorsOr[Option[Int]] = Valid(Try(innerConf.getString("port").toInt).toOption)
            val service: AllErrorsOr[Option[String]] = Valid(Try(innerConf.getString("service")).toOption)
            val user: AllErrorsOr[Option[String]] = Valid(Try(innerConf.getString("user")).toOption)
            val password: AllErrorsOr[Option[String]] = Valid(Try(innerConf.getString("password")).toOption)
            val schema: AllErrorsOr[Option[String]] = Valid(Try(innerConf.getString("schema")).toOption)

            (id, subtype, host, port, service, user, password, schema).mapN(DatabaseCommon.apply _)
          case Failure(_) => Invalid(NonEmptyList.one("Inner config is missing"))
        }
      }
    }

//  implicit val sourceReader: ConfigReader[SourceCommon] =
//    new ConfigReader[SourceCommon] {
//      override def read(value: Config): AllErrorsOr[SourceCommon] = ???
//    }
} 
Example 134
Source File: TestMessageQueue.scala    From vinyldns   with Apache License 2.0 5 votes vote down vote up
package vinyldns.api.engine
import cats.data.NonEmptyList
import cats.effect.IO
import vinyldns.core.domain.record.RecordSetChange
import vinyldns.core.domain.zone.ZoneCommand
import vinyldns.core.health.HealthCheck.HealthCheck
import vinyldns.core.queue.{CommandMessage, MessageCount, MessageQueue, SendBatchResult}
import vinyldns.core.health.HealthCheck._

import scala.concurrent.duration.FiniteDuration

object TestMessageQueue extends MessageQueue {
  override def receive(count: MessageCount): IO[List[CommandMessage]] = IO(List())

  override def requeue(message: CommandMessage): IO[Unit] = IO.unit

  override def remove(message: CommandMessage): IO[Unit] = IO.unit

  override def changeMessageTimeout(message: CommandMessage, duration: FiniteDuration): IO[Unit] =
    IO.unit

  override def sendBatch[A <: ZoneCommand](messages: NonEmptyList[A]): IO[SendBatchResult[A]] = {
    val partition = messages.toList.partition {
      case bad: RecordSetChange if bad.recordSet.name == "bad" => false
      case _ => true
    }
    IO {
      SendBatchResult(partition._1, partition._2.map((new RuntimeException("BOO"), _)))
    }
  }

  override def send[A <: ZoneCommand](command: A): IO[Unit] = IO.unit

  override def healthCheck(): HealthCheck = IO.unit.attempt.asHealthCheck(TestMessageQueue.getClass)
} 
Example 135
Source File: ValidatedMatchersSpec.scala    From cats-scalatest   with Apache License 2.0 5 votes vote down vote up
package cats.scalatest

import cats.data.Validated.{Invalid, Valid}
import cats.data.{NonEmptyList, ValidatedNel}

class ValidatedMatchersSpec extends TestBase with ValidatedMatchers {
  "ValidatedMatchers" should {
    val simpleFailureNel: ValidatedNel[String, Nothing] = Invalid(NonEmptyList.of(thisRecord, thisTobacconist))

    "Match one specific element in an Invalid NEL" in {
      simpleFailureNel should haveInvalid(thisRecord)
    }

    "Match multiple specific elements in an Invalid NEL" in {
      simpleFailureNel should (haveInvalid(thisRecord).and(haveInvalid(thisTobacconist)))
    }

    "Match a specific element of a single Invalid" in {
      Invalid(thisRecord) should beInvalid(thisRecord)
    }

    "Test whether a Validated instance is a Invalid w/o specific element value" in {
      Invalid(thisTobacconist) should be(invalid)
    }

    "By negating 'invalid', test whether a Validated instance is a Valid" in {
      Valid(hovercraft) should not be (invalid)
    }

    "Test whether a Validated instance is a Valid" in {
      Valid(hovercraft) should be(valid)
    }

    "By negating 'valid', test whether a Validated instance is an invalid" in {
      Invalid(thisTobacconist) should not be (valid)
    }

    "Match a specific element of a single Valid" in {
      Valid(hovercraft) should beValid(hovercraft)
    }

    "Match one specific type in an Invalid NEL" in {
      simpleFailureNel should haveAnInvalid[String]

      val nel: ValidatedNel[String, Nothing] = Invalid(NonEmptyList.of("test"))
      nel should haveAnInvalid[String]
      nel should haveAnInvalid[Any]
      nel shouldNot haveAnInvalid[Int]

      val nel2: ValidatedNel[Nothing, Unit] = Valid(())
      nel2 shouldNot haveAnInvalid[String]
      nel2 shouldNot haveAnInvalid[Unit]
    }
  }
} 
Example 136
Source File: NonEmptyListScalaTestInstancesSpec.scala    From cats-scalatest   with Apache License 2.0 5 votes vote down vote up
package cats.scalatest

import org.scalatest.exceptions.TestFailedException
import org.scalatest.enablers.Collecting
import org.scalatest.LoneElement._
import org.scalatest.Inspectors._
import cats.data.NonEmptyList

class NonEmptyListScalaTestInstancesSpec extends TestBase {
  import NonEmptyListScalaTestInstances._

  "loneElement" should {
    "apply an assertion when there is a single element" in {
      val nel: NonEmptyList[Int] = NonEmptyList.one(10)
      nel.loneElement should be <= 10
    }

    "should throw TestFailedException if the NonEmptyList has more elements" in {
      val nel: NonEmptyList[Int] = NonEmptyList.of(10, 16)
      val caught =
        intercept[TestFailedException] {
          nel.loneElement should ===(thisRecord)
        }
      if (isJVM)
        caught.failedCodeLineNumber.value should equal(thisLineNumber - 3)
      caught.failedCodeFileName.value should be("NonEmptyListScalaTestInstancesSpec.scala")
    }
  }

  "inspectors" should {
    "state something about all elements" in {
      val nel: NonEmptyList[Int] = NonEmptyList.of(1, 2, 3, 4, 5)
      forAll(nel)(_ should be > 0)
    }
  }

  "sizeOf" should {
    "return the size of the collection" in {
      val nel: NonEmptyList[Int] = NonEmptyList.of(1, 2)
      implicitly[Collecting[Int, NonEmptyList[Int]]].sizeOf(nel) shouldBe 2
    }
  }
} 
Example 137
Source File: pure.scala    From kittens   with Apache License 2.0 5 votes vote down vote up
package cats
package derived

import alleycats.Pure
import cats.data.NonEmptyList
import cats.instances.all._
import cats.laws.discipline.SerializableTests
import shapeless.test.illTyped

class PureSuite extends KittensSuite {
  import PureSuite._
  import TestDefns._

  def testPure(context: String)(
    implicit lOption: Pure[LOption],
    pList: Pure[PList],
    caseClassWOption: Pure[CaseClassWOption],
    nelOption: Pure[NelOption],
    interleaved: Pure[Interleaved],
    boxColor: Pure[BoxColor]
  ): Unit = {
    test(s"$context.Pure[LOption]")(assert(lOption.pure(42) == Some(42) :: Nil))
    test(s"$context.Pure[PList]")(assert(pList.pure("Scala") == ("Scala" :: Nil, "Scala" :: Nil)))
    test(s"$context.Pure[CaseClassWOption]")(assert(caseClassWOption.pure(3.14) == CaseClassWOption(Some(3.14))))
    test(s"$context.Pure[NelOption]")(assert(nelOption.pure(42) == NonEmptyList.of(Some(42))))
    test(s"$context.Pure[Interleaved]")(assert(interleaved.pure('x') == Interleaved(0, 'x', 0, 'x' :: Nil, "")))
    test(s"$context.Pure respects existing instances")(assert(boxColor.pure(()) == Box(Color(255, 255, 255))))
    checkAll(s"$context.Pure is Serializable", SerializableTests.serializable(Pure[Interleaved]))
  }

  {
    import auto.pure._
    testPure("auto")
    illTyped("Pure[IList]")
    illTyped("Pure[Snoc]")
  }

  {
    import cached.pure._
    testPure("cached")
    illTyped("Pure[IList]")
    illTyped("Pure[Snoc]")
  }

  {
    import semiInstances._
    testPure("semiauto")
    illTyped("semiauto.pure[IList]")
    illTyped("semiauto.pure[Snoc]")
  }
}

object PureSuite {
  import TestDefns._

  type LOption[A] = List[Option[A]]
  type PList[A] = (List[A], List[A])
  type NelOption[A] = NonEmptyList[Option[A]]
  type BoxColor[A] = Box[Color[A]]

  object semiInstances {
    implicit val lOption: Pure[LOption] = semiauto.pure
    implicit val pList: Pure[PList] = semiauto.pure
    implicit val caseClassWOption: Pure[CaseClassWOption] = semiauto.pure
    implicit val nelOption: Pure[NelOption] = semiauto.pure
    implicit val interleaved: Pure[Interleaved] = semiauto.pure
    implicit val boxColor: Pure[BoxColor] = semiauto.pure
  }

  final case class Color[A](r: Int, g: Int, b: Int)
  object Color {

    implicit val pure: Pure[Color] = new Pure[Color] {
      def pure[A](value: A) = Color(255, 255, 255)
    }
  }
} 
Example 138
Source File: emptyk.scala    From kittens   with Apache License 2.0 5 votes vote down vote up
package cats.derived

import alleycats.{EmptyK, Pure}
import alleycats.std.all._
import cats.data.NonEmptyList
import cats.laws.discipline.SerializableTests
import cats.instances.all._
import shapeless.test.illTyped

class EmptyKSuite extends KittensSuite {
  import EmptyKSuite._
  import TestDefns._

  def testEmptyK(context: String)(
    implicit lOption: EmptyK[LOption],
    pList: EmptyK[PList],
    caseClassWOption: EmptyK[CaseClassWOption],
    nelOption: EmptyK[NelOption],
    boxColor: EmptyK[BoxColor]
  ): Unit = {
    test(s"$context.EmptyK[LOption]")(assert(lOption.empty == Nil))
    test(s"$context.EmptyK[PList]")(assert(pList.empty == (Nil, Nil)))
    test(s"$context.EmptyK[CaseClassWOption]")(assert(caseClassWOption.empty == CaseClassWOption(None)))
    test(s"$context.EmptyK[NelOption]")(assert(nelOption.empty == NonEmptyList.of(None)))
    test(s"$context.EmptyK respects existing instances")(assert(boxColor.empty == Box(Color(255, 255, 255))))
    checkAll(s"$context.EmptyK is Serializable", SerializableTests.serializable(EmptyK[PList]))
  }

  implicit val pureBox: Pure[Box] = new Pure[Box] {
    def pure[A](a: A) = Box(a)
  }

  {
    import auto.emptyK._
    testEmptyK("auto")
    illTyped("EmptyK[IList]")
    illTyped("EmptyK[Snoc]")
  }

  {
    import cached.emptyK._
    testEmptyK("cached")
    illTyped("EmptyK[IList]")
    illTyped("EmptyK[Snoc]")
  }

  {
    import semiInstances._
    testEmptyK("semiauto")
    illTyped("semiauto.emptyK[IList]")
    illTyped("semiauto.emptyK[Snoc]")
  }
}

object EmptyKSuite {
  import TestDefns._

  type LOption[A] = List[Option[A]]
  type PList[A] = (List[A], List[A])
  type NelOption[A] = NonEmptyList[Option[A]]
  type BoxColor[A] = Box[Color[A]]

  object semiInstances {
    implicit val lOption: EmptyK[LOption] = semiauto.emptyK
    implicit val pList: EmptyK[PList] = semiauto.emptyK
    implicit val caseClassWOption: EmptyK[CaseClassWOption] = semiauto.emptyK
    implicit val nelOption: EmptyK[NelOption] = semiauto.emptyK
    implicit val boxColor: EmptyK[BoxColor] = semiauto.emptyK
  }

  final case class Color[A](r: Int, g: Int, b: Int)
  object Color {

    implicit val emptyK: EmptyK[Color] = new EmptyK[Color] {
      def empty[A] = Color(255, 255, 255)
    }
  }
} 
Example 139
Source File: nonEmptyTraverse.scala    From kittens   with Apache License 2.0 5 votes vote down vote up
package cats.derived

import cats.NonEmptyTraverse
import cats.data.{NonEmptyList, NonEmptyVector, OneAnd}
import cats.instances.all._
import cats.laws.discipline.arbitrary._
import cats.laws.discipline.{NonEmptyTraverseTests, SerializableTests}

class NonEmptyTraverseSuite extends KittensSuite {
  import NonEmptyTraverseSuite._
  import TestDefns._
  import TestEqInstances._

  def testReducible(context: String)(
    implicit iCons: NonEmptyTraverse[ICons],
    tree: NonEmptyTraverse[Tree],
    nelSCons: NonEmptyTraverse[NelSCons],
    nelAndOne: NonEmptyTraverse[NelAndOne],
    listAndNel: NonEmptyTraverse[ListAndNel],
    interleaved: NonEmptyTraverse[Interleaved]
  ): Unit = {

    checkAll(
      s"$context.NonEmptyTraverse[ICons]",
      NonEmptyTraverseTests[ICons].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]
    )

    checkAll(
      s"$context.NonEmptyTraverse[Tree]",
      NonEmptyTraverseTests[Tree].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]
    )

    checkAll(
      s"$context.NonEmptyTraverse[NelSCons]",
      NonEmptyTraverseTests[NelSCons].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]
    )

    checkAll(
      s"$context.NonEmptyTraverse[NelAndOne]",
      NonEmptyTraverseTests[NelAndOne].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]
    )

    checkAll(
      s"$context.NonEmptyTraverse[ListAndNel]",
      NonEmptyTraverseTests[ListAndNel].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]
    )

    checkAll(
      s"$context.NonEmptyTraverse[Interleaved]",
      NonEmptyTraverseTests[Interleaved].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option]
    )

    checkAll(
      s"$context.NonEmptyTraverse is Serializable",
      SerializableTests.serializable(NonEmptyTraverse[Tree])
    )

    val n = 10000
    val largeIList = ICons(0, IList.fromSeq(1 until n))
    val largeSnoc: NelSCons[Int] = NonEmptyList.one(SCons(Snoc.fromSeq(1 until n), 0))

    test(s"$context.Traverse.nonEmptyTraverse is stack safe") {
      val actualIList = largeIList.nonEmptyTraverse(i => Option(i + 1)).map(IList.toList)
      val actualSnoc = largeSnoc.nonEmptyTraverse(i => Option(i + 1)).map(_.toList.flatMap(Snoc.toList))
      assert(actualIList.isDefined)
      assert(actualSnoc.isDefined)
    }
  }

  {
    import auto.nonEmptyTraverse._
    testReducible("auto")
  }

  {
    import cached.nonEmptyTraverse._
    testReducible("cached")
  }

  {
    import semiInstances._
    testReducible("semiauto")
  }
}

object NonEmptyTraverseSuite {
  import TestDefns._

  type NelSCons[A] = NonEmptyList[SCons[A]]
  type NelAndOne[A] = NonEmptyList[OneAnd[List, A]]
  type ListAndNel[A] = (List[A], NonEmptyList[A])

  object semiInstances {
    implicit val iCons: NonEmptyTraverse[ICons] = semiauto.nonEmptyTraverse
    implicit val tree: NonEmptyTraverse[Tree] = semiauto.nonEmptyTraverse
    implicit val nelSCons: NonEmptyTraverse[NelSCons] = semiauto.nonEmptyTraverse
    implicit val nelAndOne: NonEmptyTraverse[NelAndOne] = semiauto.nonEmptyTraverse
    implicit val listAndNel: NonEmptyTraverse[ListAndNel] = semiauto.nonEmptyTraverse
    implicit val interleaved: NonEmptyTraverse[Interleaved] = semiauto.nonEmptyTraverse
  }
} 
Example 140
Source File: JobDetailsRequest.scala    From mist   with Apache License 2.0 5 votes vote down vote up
package io.hydrosphere.mist.master

import cats.data.NonEmptyList
import java.io.File

sealed trait FilterClause

object FilterClause {
  case class ByFunctionId(id: String) extends FilterClause
  case class ByWorkerId(id: String) extends FilterClause
  case class ByStatuses(statuses: NonEmptyList[JobDetails.Status]) extends FilterClause
}

case class JobDetailsRequest(
  limit: Int,
  offset: Int,
  filters: Seq[FilterClause]
) { self =>

  def withFilter(f: FilterClause): JobDetailsRequest = copy(filters = f +: filters)
  def withOptFilter(optF: Option[FilterClause]): JobDetailsRequest = 
    optF.fold(self)(f => self.withFilter(f))
}

object JobDetailsRequest {
  def apply(limit: Int, offset: Int): JobDetailsRequest = JobDetailsRequest(limit, offset, Seq.empty)
}

case class JobDetailsResponse(
  jobs: Seq[JobDetails],
  total: Int
) 
Example 141
Source File: JobRequestSql.scala    From mist   with Apache License 2.0 5 votes vote down vote up
package io.hydrosphere.mist.master.store

import cats.data.NonEmptyList
import doobie.{Fragment, Fragments}
import doobie.implicits._
import io.hydrosphere.mist.master.FilterClause.{ByFunctionId, ByStatuses, ByWorkerId}
import io.hydrosphere.mist.master.{JobDetails, JobDetailsRecord, JobDetailsRequest}

class H2JobRequestSql extends JobRequestSql {
  override def update(jobDetails: JobDetails): Fragment = {
    val r: JobDetailsRecord = JobDetailsRecord(jobDetails)
    sql"""
      merge into job_details
      (
        path, class_name, namespace, parameters,
        external_id, function, action, source,
        job_id, start_time, end_time, job_result,
        status, worker_id, create_time
      ) key(job_id)
      values
      (
        ${r.path}, ${r.className}, ${r.namespace}, ${r.parameters},
        ${r.externalId}, ${r.function}, ${r.action}, ${r.source},
        ${r.jobId}, ${r.startTime}, ${r.endTime}, ${r.jobResult},
        ${r.status}, ${r.workerId}, ${r.createTime}
      )"""
  }
}

class PgJobRequestSql extends JobRequestSql {
  override def update(jobDetails: JobDetails): Fragment = {
    val r: JobDetailsRecord = JobDetailsRecord(jobDetails)
    sql"""
      insert into job_details
      (
        path, class_name, namespace, parameters,
        external_id, function, action, source,
        job_id, start_time, end_time, job_result,
        status, worker_id, create_time
      ) values
      (
        ${r.path}, ${r.className}, ${r.namespace}, ${r.parameters},
        ${r.externalId}, ${r.function}, ${r.action}, ${r.source},
        ${r.jobId}, ${r.startTime}, ${r.endTime}, ${r.jobResult},
        ${r.status}, ${r.workerId}, ${r.createTime}
      ) on conflict (job_id) do update set
        path = ${r.path},
        class_name = ${r.className},
        namespace = ${r.namespace},
        parameters = ${r.parameters},
        external_id = ${r.externalId},
        function = ${r.function},
        action = ${r.action},
        source = ${r.source},
        start_time = ${r.startTime},
        end_time = ${r.endTime},
        job_result = ${r.jobResult},
        status = ${r.status},
        worker_id = ${r.workerId},
        create_time = ${r.createTime}
    """
  }

}

object JobRequestSql {
  def apply(jdbcUrl: String): JobRequestSql = {
    jdbcUrl match {
      case s if s.startsWith("jdbc:h2") => new H2JobRequestSql()
      case s if s.startsWith("jdbc:postgresql") => new PgJobRequestSql()
      case _ =>
        throw new RuntimeException(s"Can't work with jdbc $jdbcUrl. Supported databses are PostgreSQL and H2");
    }
  }
}

trait JobRequestSql {

//  def flyDbMigrationPath: String

  
  def generateSqlByJobDetailsRequest(req: JobDetailsRequest): Fragment = {
    val filters =
      if (req.filters.isEmpty) sql"" else {
        fr"where" ++ req.filters.map {
          case ByFunctionId(id) => fr"function = $id"
          case ByStatuses(statuses) => Fragments.in(fr"status", statuses.map(_.toString))
          case ByWorkerId(id) => fr"worker_id = $id"
        }.reduce((a, b) => a ++ fr"and" ++ b)
      }
    val limit = fr"limit ${req.limit} offset ${req.offset}"
    val order = fr"order by create_time desc"
    beginSql ++ filters ++ order ++ limit
  }
} 
Example 142
Source File: JobRequestsSqlSpec.scala    From mist   with Apache License 2.0 5 votes vote down vote up
package io.hydrosphere.mist.master.store

import io.hydrosphere.mist.master.FilterClause.{ByFunctionId, ByStatuses, ByWorkerId}
import io.hydrosphere.mist.master.JobDetails.Status._
import io.hydrosphere.mist.master.{JobDetails, JobDetailsRequest}
import org.scalatest.{FunSpec, Matchers}
import doobie.implicits._
import io.hydrosphere.mist.core.CommonData.{Action, JobParams}
import io.hydrosphere.mist.master.JobDetails.Source
import mist.api.data.JsMap
import cats.data.NonEmptyList

class JobRequestsSqlSpec extends FunSpec with Matchers{

  describe("h2 sql") {
    test(new H2JobRequestSql)
  }
  
  describe("postgres sql") {
    test(new PgJobRequestSql)
  }
  
  def test(jobRequestSql: JobRequestSql): Unit = {
    it("select(*)") {
      val sql = jobRequestSql.generateSqlByJobDetailsRequest(JobDetailsRequest(0, 0))
      sql.toString() shouldEqual sql"select * from job_details order by create_time desc limit ? offset ? ".toString()
    }

    it("filter by function") {
      val sql = jobRequestSql.generateSqlByJobDetailsRequest(JobDetailsRequest(0, 0).withFilter(ByFunctionId("ID")))
      sql.toString() shouldEqual sql"select * from job_details where function = ? order by create_time desc limit ? offset ? ".toString()
    }

    it("filter by worker") {
      val sql = jobRequestSql.generateSqlByJobDetailsRequest(JobDetailsRequest(0, 0).withFilter(ByWorkerId("ID")))
      sql.toString() shouldEqual sql"select * from job_details where worker_id = ? order by create_time desc limit ? offset ? ".toString()
    }

    it("sql filter by status") {
      val sql = jobRequestSql.generateSqlByJobDetailsRequest(JobDetailsRequest(0, 0).withFilter(ByStatuses(NonEmptyList.of(Initialized, Queued))))
      sql.toString() shouldEqual sql"select * from job_details where status IN (?, ?) order by create_time desc limit ? offset ? ".toString()
    }

    it("sql complex filter") {
      val sql = jobRequestSql.generateSqlByJobDetailsRequest(JobDetailsRequest(0, 0).
        withFilter(ByStatuses(NonEmptyList.of(Initialized, Queued))).
        withFilter(ByWorkerId("ID")).
        withFilter(ByFunctionId("ID")))
      sql.toString() shouldEqual sql"select * from job_details where function = ? and worker_id = ? and status IN (?, ?) order by create_time desc limit ? offset ? ".toString()
    }
  }
  
  private def fixtureJobDetails(
    jobId: String,
    status: JobDetails.Status = JobDetails.Status.Initialized): JobDetails = {
    JobDetails(
      params = JobParams("path", "className", JsMap.empty, Action.Execute),
      jobId = jobId,
      source = Source.Http,
      function = "function",
      context = "context",
      externalId = None,
      status = status
    )
  }
  
} 
Example 143
Source File: EffectStep.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.steps.regular

import cats.data.{ EitherT, NonEmptyList }
import cats.syntax.either._
import com.github.agourlay.cornichon.core._
import com.github.agourlay.cornichon.core.ScenarioRunner._
import monix.eval.Task

import scala.concurrent.duration.Duration
import scala.concurrent.{ ExecutionContext, Future }

case class EffectStep(title: String, effect: ScenarioContext => Future[Either[CornichonError, Session]], show: Boolean = true) extends SessionValueStep {

  def setTitle(newTitle: String): Step = copy(title = newTitle)

  override def runSessionValueStep(runState: RunState): Task[Either[NonEmptyList[CornichonError], Session]] =
    Task.deferFuture(effect(runState.scenarioContext)).map(_.leftMap(NonEmptyList.one))

  override def onError(errors: NonEmptyList[CornichonError], runState: RunState, executionTime: Duration): (LogInstruction, FailedStep) =
    errorsToFailureStep(this, runState.depth, errors, Some(executionTime))

  override def logOnSuccess(result: Session, runState: RunState, executionTime: Duration): LogInstruction =
    successLog(title, runState.depth, show, executionTime)
}

object EffectStep {

  def fromEitherT(title: String, effect: ScenarioContext => EitherT[Future, CornichonError, Session], show: Boolean = true): EffectStep = {
    val effectT: ScenarioContext => Future[Either[CornichonError, Session]] = s => effect(s).value
    EffectStep(title, effectT, show)
  }

  def fromSync(title: String, effect: ScenarioContext => Session, show: Boolean = true): EffectStep = {
    val effectF: ScenarioContext => Future[Either[CornichonError, Session]] = s => Future.successful(effect(s).asRight)
    EffectStep(title, effectF, show)
  }

  def fromSyncE(title: String, effect: ScenarioContext => Either[CornichonError, Session], show: Boolean = true): EffectStep = {
    val effectF: ScenarioContext => Future[Either[CornichonError, Session]] = s => Future.successful(effect(s))
    EffectStep(title, effectF, show)
  }

  def fromAsync(title: String, effect: ScenarioContext => Future[Session], show: Boolean = true)(implicit ec: ExecutionContext): EffectStep = {
    val effectF: ScenarioContext => Future[Either[CornichonError, Session]] = s => effect(s).map(Right.apply)
    EffectStep(title, effectF, show)
  }
} 
Example 144
Source File: RetryMaxStep.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.steps.wrapped

import cats.data.{ NonEmptyList, StateT }
import com.github.agourlay.cornichon.core._
import com.github.agourlay.cornichon.core.Done._
import monix.eval.Task

case class RetryMaxStep(nested: List[Step], limit: Int) extends WrapperStep {

  require(limit > 0, "retry max limit must be a positive number")

  val title = s"RetryMax block with limit '$limit'"

  override val stateUpdate: StepState = StateT { runState =>

    def retryMaxSteps(runState: RunState, limit: Int, retriesNumber: Long): Task[(Long, RunState, Either[FailedStep, Done])] =
      ScenarioRunner.runStepsShortCircuiting(nested, runState.resetLogStack).flatMap {
        case (retriedState, Left(_)) if limit > 0 =>
          // In case of success all logs are returned but they are not printed by default.
          retryMaxSteps(runState.recordLogStack(retriedState.logStack), limit - 1, retriesNumber + 1)

        case (retriedState, l @ Left(_)) =>
          // In case of failure only the logs of the last run are shown to avoid giant traces.
          Task.now((retriesNumber, retriedState, l))

        case (retriedState, _) =>
          val successState = runState.withSession(retriedState.session).recordLogStack(retriedState.logStack)
          Task.now((retriesNumber, successState, rightDone))

      }

    retryMaxSteps(runState.nestedContext, limit, 0)
      .timed
      .map {
        case (executionTime, run) =>
          val (retries, retriedState, report) = run
          val depth = runState.depth
          val (logStack, res) = report.fold(
            failedStep => {
              val wrappedLogStack = FailureLogInstruction(s"RetryMax block with limit '$limit' failed", depth, Some(executionTime)) +: retriedState.logStack :+ failedTitleLog(depth)
              val artificialFailedStep = FailedStep.fromSingle(failedStep.step, RetryMaxBlockReachedLimit(limit, failedStep.errors))
              (wrappedLogStack, Left(artificialFailedStep))
            },
            _ => {
              val wrappedLogStack = SuccessLogInstruction(s"RetryMax block with limit '$limit' succeeded after '$retries' retries", depth, Some(executionTime)) +: retriedState.logStack :+ successTitleLog(depth)
              (wrappedLogStack, rightDone)
            }
          )
          (runState.mergeNested(retriedState, logStack), res)
      }
  }
}

case class RetryMaxBlockReachedLimit(limit: Int, errors: NonEmptyList[CornichonError]) extends CornichonError {
  lazy val baseErrorMessage = s"Retry max block failed '$limit' times"
  override val causedBy = errors.toList
} 
Example 145
Source File: RepeatWithStep.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.steps.wrapped

import cats.data.{ NonEmptyList, StateT }
import com.github.agourlay.cornichon.core.Done.rightDone
import com.github.agourlay.cornichon.core._
import monix.eval.Task

case class RepeatWithStep(nested: List[Step], elements: List[String], elementName: String) extends WrapperStep {

  require(elements.nonEmpty, "repeatWith block must contain a non empty sequence of elements")

  val printElements = s"[${elements.mkString(", ")}]"
  val title = s"RepeatWith block with elements $printElements"

  override val stateUpdate: StepState = StateT { runState =>

    def repeatSuccessSteps(remainingElements: List[String], runState: RunState): Task[(RunState, Either[(String, FailedStep), Done])] =
      remainingElements match {
        case Nil =>
          Task.now((runState, rightDone))
        case element :: tail =>
          // reset logs at each loop to have the possibility to not aggregate in failure case
          val rs = runState.resetLogStack
          val runStateWithIndex = rs.addToSession(elementName, element)
          ScenarioRunner.runStepsShortCircuiting(nested, runStateWithIndex).flatMap {
            case (onceMoreRunState, stepResult) =>
              stepResult.fold(
                failed => {
                  // In case of failure only the logs of the last run are shown to avoid giant traces.
                  Task.now((onceMoreRunState, Left((element, failed))))
                },
                _ => {
                  val successState = runState.mergeNested(onceMoreRunState)
                  repeatSuccessSteps(tail, successState)
                }
              )
          }
      }

    repeatSuccessSteps(elements, runState.nestedContext).timed
      .map {
        case (executionTime, (repeatedState, report)) =>
          val depth = runState.depth
          val (logStack, res) = report match {
            case Right(_) =>
              val wrappedLogStack = SuccessLogInstruction(s"RepeatWith block with elements $printElements succeeded", depth, Some(executionTime)) +: repeatedState.logStack :+ successTitleLog(depth)
              (wrappedLogStack, rightDone)
            case Left((failedElement, failedStep)) =>
              val wrappedLogStack = FailureLogInstruction(s"RepeatWith block with elements $printElements failed at element '$failedElement'", depth, Some(executionTime)) +: repeatedState.logStack :+ failedTitleLog(depth)
              val artificialFailedStep = FailedStep.fromSingle(failedStep.step, RepeatWithBlockContainFailedSteps(failedElement, failedStep.errors))
              (wrappedLogStack, Left(artificialFailedStep))
          }
          (runState.mergeNested(repeatedState, logStack), res)
      }
  }
}

case class RepeatWithBlockContainFailedSteps(element: String, errors: NonEmptyList[CornichonError]) extends CornichonError {
  lazy val baseErrorMessage = s"RepeatWith block failed for element '$element'"
  override val causedBy = errors.toList
} 
Example 146
Source File: WithDataInputStep.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.steps.wrapped

import cats.data.{ NonEmptyList, StateT }
import com.github.agourlay.cornichon.core._
import com.github.agourlay.cornichon.json.CornichonJson
import com.github.agourlay.cornichon.core.ScenarioRunner._
import com.github.agourlay.cornichon.core.Done._
import com.github.agourlay.cornichon.util.Printing._
import monix.eval.Task

case class WithDataInputStep(nested: List[Step], where: String) extends WrapperStep {

  val title = s"With data input block $where"

  override val stateUpdate: StepState = StateT { runState =>

    def runInputs(inputs: List[List[(String, String)]], runState: RunState): Task[(RunState, Either[(List[(String, String)], FailedStep), Done])] =
      if (inputs.isEmpty) Task.now((runState, rightDone))
      else {
        val currentInputs = inputs.head
        val runInfo = InfoLogInstruction(s"Run with inputs ${printArrowPairs(currentInputs)}", runState.depth)
        val bootstrapFilledInput = runState.addToSession(currentInputs).withLog(runInfo).goDeeper
        ScenarioRunner.runStepsShortCircuiting(nested, bootstrapFilledInput).flatMap {
          case (filledState, stepsResult) =>
            stepsResult.fold(
              failedStep => {
                // Prepend previous logs
                Task.now((runState.mergeNested(filledState), Left((currentInputs, failedStep))))
              },
              _ => {
                // Logs are propagated but not the session
                runInputs(inputs.tail, runState.recordLogStack(filledState.logStack))
              }
            )
        }
      }

    runState.scenarioContext.fillPlaceholders(where)
      .flatMap(CornichonJson.parseDataTable)
      .fold(
        t => Task.now(handleErrors(this, runState, NonEmptyList.one(t))),
        parsedTable => {
          val inputs = parsedTable.map { line =>
            line.toList.map { case (key, json) => (key, CornichonJson.jsonStringValue(json)) }
          }

          runInputs(inputs, runState.nestedContext)
            .timed
            .map {
              case (executionTime, (inputsState, inputsRes)) =>
                val initialDepth = runState.depth
                val (logStack, res) = inputsRes match {
                  case Right(_) =>
                    val wrappedLogStack = SuccessLogInstruction("With data input succeeded for all inputs", initialDepth, Some(executionTime)) +: inputsState.logStack :+ successTitleLog(initialDepth)
                    (wrappedLogStack, rightDone)
                  case Left((failedInputs, failedStep)) =>
                    val wrappedLogStack = FailureLogInstruction("With data input failed for one input", initialDepth, Some(executionTime)) +: inputsState.logStack :+ failedTitleLog(initialDepth)
                    val artificialFailedStep = FailedStep.fromSingle(failedStep.step, WithDataInputBlockFailedStep(failedInputs, failedStep.errors))
                    (wrappedLogStack, Left(artificialFailedStep))
                }
                (runState.mergeNested(inputsState, logStack), res)
            }
        }
      )
  }
}

case class WithDataInputBlockFailedStep(failedInputs: List[(String, String)], errors: NonEmptyList[CornichonError]) extends CornichonError {
  lazy val baseErrorMessage = s"WithDataInput block failed for inputs ${printArrowPairs(failedInputs)}"
  override val causedBy = errors.toList
} 
Example 147
Source File: RepeatStep.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.steps.wrapped

import cats.data.{ NonEmptyList, StateT }
import com.github.agourlay.cornichon.core._
import com.github.agourlay.cornichon.core.Done._
import monix.eval.Task

case class RepeatStep(nested: List[Step], occurrence: Int, indexName: Option[String]) extends WrapperStep {

  require(occurrence > 0, "repeat block must contain a positive number of occurrence")

  val title = s"Repeat block with occurrence '$occurrence'"

  override val stateUpdate: StepState = StateT { runState =>

    def repeatSuccessSteps(retriesNumber: Int, runState: RunState): Task[(Int, RunState, Either[FailedStep, Done])] = {
      // reset logs at each loop to have the possibility to not aggregate in failure case
      val rs = runState.resetLogStack
      val runStateWithIndex = indexName.fold(rs)(in => rs.addToSession(in, (retriesNumber + 1).toString))
      ScenarioRunner.runStepsShortCircuiting(nested, runStateWithIndex).flatMap {
        case (onceMoreRunState, stepResult) =>
          stepResult.fold(
            failed => {
              // In case of failure only the logs of the last run are shown to avoid giant traces.
              Task.now((retriesNumber, onceMoreRunState, Left(failed)))
            },
            _ => {
              val successState = runState.withSession(onceMoreRunState.session).recordLogStack(onceMoreRunState.logStack)
              // only show last successful run to avoid giant traces.
              if (retriesNumber == occurrence - 1) Task.now((retriesNumber, successState, rightDone))
              else repeatSuccessSteps(retriesNumber + 1, runState.withSession(onceMoreRunState.session))
            }
          )
      }
    }

    repeatSuccessSteps(0, runState.nestedContext)
      .timed
      .map {
        case (executionTime, run) =>
          val (retries, repeatedState, report) = run
          val depth = runState.depth
          val (logStack, res) = report.fold(
            failedStep => {
              val wrappedLogStack = FailureLogInstruction(s"Repeat block with occurrence '$occurrence' failed after '$retries' occurrence", depth, Some(executionTime)) +: repeatedState.logStack :+ failedTitleLog(depth)
              val artificialFailedStep = FailedStep.fromSingle(failedStep.step, RepeatBlockContainFailedSteps(retries, failedStep.errors))
              (wrappedLogStack, Left(artificialFailedStep))
            },
            _ => {
              val wrappedLockStack = SuccessLogInstruction(s"Repeat block with occurrence '$occurrence' succeeded", depth, Some(executionTime)) +: repeatedState.logStack :+ successTitleLog(depth)
              (wrappedLockStack, rightDone)
            }
          )
          (runState.mergeNested(repeatedState, logStack), res)
      }
  }
}

case class RepeatBlockContainFailedSteps(failedOccurrence: Int, errors: NonEmptyList[CornichonError]) extends CornichonError {
  lazy val baseErrorMessage = s"Repeat block failed at occurrence $failedOccurrence"
  override val causedBy = errors.toList
} 
Example 148
Source File: RepeatDuringStep.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.steps.wrapped

import java.util.concurrent.TimeUnit

import cats.data.{ NonEmptyList, StateT }
import com.github.agourlay.cornichon.core._
import com.github.agourlay.cornichon.core.Done._
import monix.eval.Task

import scala.concurrent.duration.FiniteDuration

case class RepeatDuringStep(nested: List[Step], duration: FiniteDuration) extends WrapperStep {

  val title = s"Repeat block during '$duration'"

  override val stateUpdate: StepState = StateT { runState =>
    val initialDepth = runState.depth

    def repeatStepsDuring(runState: RunState, duration: FiniteDuration, retriesNumber: Long): Task[(Long, RunState, Either[FailedStep, Done])] =
      ScenarioRunner.runStepsShortCircuiting(nested, runState.resetLogStack) // reset logs at each loop to have the possibility to not aggregate in failure case
        .timed
        .flatMap {
          case (executionTime, run) =>
            val (repeatedOnceMore, res) = run
            val remainingTime = duration - executionTime
            res.fold(
              failedStep => {
                // In case of failure only the logs of the last run are shown to avoid giant traces.
                Task.now((retriesNumber, repeatedOnceMore, Left(failedStep)))
              },
              _ => {
                val successState = runState.mergeNested(repeatedOnceMore)
                if (remainingTime.gt(FiniteDuration(0, TimeUnit.MILLISECONDS)))
                  repeatStepsDuring(successState, remainingTime, retriesNumber + 1)
                else
                  // In case of success all logs are returned but they are not printed by default.
                  Task.now((retriesNumber, successState, rightDone))
              }
            )
        }

    repeatStepsDuring(runState.nestedContext, duration, 0)
      .timed
      .map {
        case (executionTime, run) =>
          val (retries, repeatedRunState, report) = run
          val (logStack, res) = report.fold(
            failedStep => {
              val wrappedLogStack = FailureLogInstruction(s"Repeat block during '$duration' failed after being retried '$retries' times", initialDepth, Some(executionTime)) +: repeatedRunState.logStack :+ failedTitleLog(initialDepth)
              val artificialFailedStep = FailedStep.fromSingle(failedStep.step, RepeatDuringBlockContainFailedSteps(duration, failedStep.errors))
              (wrappedLogStack, Left(artificialFailedStep))
            },
            _ => {
              val wrappedLogStack = SuccessLogInstruction(s"Repeat block during '$duration' succeeded after '$retries' retries", initialDepth, Some(executionTime)) +: repeatedRunState.logStack :+ successTitleLog(initialDepth)
              (wrappedLogStack, rightDone)
            }
          )
          (runState.mergeNested(repeatedRunState, logStack), res)
      }
  }
}

case class RepeatDuringBlockContainFailedSteps(duration: FiniteDuration, errors: NonEmptyList[CornichonError]) extends CornichonError {
  lazy val baseErrorMessage = s"RepeatDuring block failed before '$duration'"
  override val causedBy = errors.toList
} 
Example 149
Source File: EffectStep.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.steps.cats

import cats.data.{ EitherT, NonEmptyList }
import cats.effect.Effect
import cats.syntax.either._
import com.github.agourlay.cornichon.core.ScenarioRunner.{ errorsToFailureStep, successLog }
import com.github.agourlay.cornichon.core._
import monix.eval.Task
import monix.execution.Scheduler

import scala.concurrent.duration.Duration

case class EffectStep[F[_]: Effect](title: String, effect: ScenarioContext => F[Either[CornichonError, Session]], show: Boolean = true) extends SessionValueStep {

  def setTitle(newTitle: String): Step = copy(title = newTitle)

  override def runSessionValueStep(runState: RunState): Task[Either[NonEmptyList[CornichonError], Session]] =
    Task.fromEffect(effect(runState.scenarioContext)).map(_.leftMap(NonEmptyList.one))

  override def onError(errors: NonEmptyList[CornichonError], runState: RunState, executionTime: Duration): (LogInstruction, FailedStep) =
    errorsToFailureStep(this, runState.depth, errors, Some(executionTime))

  override def logOnSuccess(result: Session, runState: RunState, executionTime: Duration): LogInstruction =
    successLog(title, runState.depth, show, executionTime)

}

object EffectStep {

  def fromEitherT[F[_]: Effect](title: String, effect: ScenarioContext => EitherT[F, CornichonError, Session], show: Boolean = true): Step = {
    val effectT: ScenarioContext => F[Either[CornichonError, Session]] = s => effect(s).value
    EffectStep(title, effectT, show)
  }

  def fromSync(title: String, effect: ScenarioContext => Session, show: Boolean = true): Step = {
    import Scheduler.Implicits.global
    val effectF: ScenarioContext => Task[Either[CornichonError, Session]] = s => Task.now(effect(s).asRight)
    EffectStep(title, effectF, show)
  }

  def fromSyncE(title: String, effect: ScenarioContext => Either[CornichonError, Session], show: Boolean = true): Step = {
    import Scheduler.Implicits.global
    val effectF: ScenarioContext => Task[Either[CornichonError, Session]] = s => Task.now(effect(s))
    EffectStep(title, effectF, show)
  }

  def fromAsync[F[_]: Effect](title: String, effect: ScenarioContext => F[Session], show: Boolean = true): Step = {
    import Scheduler.Implicits.global
    val effectF: ScenarioContext => Task[Either[CornichonError, Session]] = s => Task.fromEffect(effect(s)).map(Right.apply)
    EffectStep(title, effectF, show)
  }

} 
Example 150
Source File: ScenarioReport.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.core

import cats.data.Validated.Valid
import cats.data.{ NonEmptyList, ValidatedNel }
import cats.kernel.Monoid
import monix.eval.Task

import scala.concurrent.Future
import scala.concurrent.duration.{ Duration, FiniteDuration }

sealed trait ScenarioReport {
  def isSuccess: Boolean
  def scenarioName: String
  def session: Session
  def logs: List[LogInstruction]
  def duration: FiniteDuration
}

object ScenarioReport {
  def build(scenarioName: String, runState: RunState, result: ValidatedNel[FailedStep, Done], duration: FiniteDuration): ScenarioReport =
    result.fold(
      failedSteps => FailureScenarioReport(scenarioName, failedSteps, runState.session, runState.logStack, duration, runState.randomContext.initialSeed),
      _ => SuccessScenarioReport(scenarioName, runState.session, runState.logStack, duration, runState.randomContext.initialSeed)
    )
}

case class SuccessScenarioReport(scenarioName: String, session: Session, logStack: List[LogInstruction], duration: FiniteDuration, seed: Long) extends ScenarioReport {
  val isSuccess = true

  // keeping it lazy to avoid the reverse in case of no rendering
  lazy val logs = logStack.reverse
  // In case of success, logs are only shown if the scenario contains DebugLogInstruction
  lazy val shouldShowLogs: Boolean = logStack.exists(_.isInstanceOf[DebugLogInstruction])
}

case class IgnoreScenarioReport(scenarioName: String, reason: String, session: Session) extends ScenarioReport {
  val logs = Nil
  val isSuccess = false
  val duration = Duration.Zero
}

case class PendingScenarioReport(scenarioName: String, session: Session) extends ScenarioReport {
  val logs = Nil
  val isSuccess = false
  val duration = Duration.Zero
}

case class FailureScenarioReport(scenarioName: String, failedSteps: NonEmptyList[FailedStep], session: Session, logStack: List[LogInstruction], duration: FiniteDuration, seed: Long) extends ScenarioReport {
  val isSuccess = false

  val msg =
    s"""|Scenario '$scenarioName' failed:
        |${failedSteps.toList.iterator.map(_.messageForFailedStep).mkString("\nand\n")}
        |seed for the run was '$seed'
        |""".stripMargin

  lazy val logs = logStack.reverse
  lazy val renderedColoredLogs = LogInstruction.renderLogs(logs)
  lazy val renderedLogs = LogInstruction.renderLogs(logs, colorized = false)
}

sealed abstract class Done
case object Done extends Done {
  val rightDone = Right(Done)
  val validDone = Valid(Done)
  val futureDone = Future.successful(Done)
  val taskDone = Task.now(Done)
  implicit val monoid = new Monoid[Done] {
    def empty: Done = Done
    def combine(x: Done, y: Done): Done = x
  }
}

case class FailedStep(step: Step, errors: NonEmptyList[CornichonError]) {
  lazy val messageForFailedStep =
    s"""
       |at step:
       |${step.title}
       |
       |with error(s):
       |${errors.toList.iterator.map(_.renderedMessage).mkString("\nand\n")}
       |""".stripMargin

}

object FailedStep {
  def fromSingle(step: Step, error: CornichonError) = FailedStep(step, NonEmptyList.one(error))
} 
Example 151
Source File: Reduced.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.optics

import cats._
import cats.data.NonEmptyList
import tofu.optics.data.Constant
import cats.syntax.semigroup._


trait PReduced[-S, +T, +A, -B] extends PFolded[S, T, A, B] { self =>
  def reduceMap[X: Semigroup](s: S)(f: A => X): X

  override def foldMap[X: Monoid](s: S)(f: A => X): X = reduceMap(s)(f)
  def getAll1(s: S): NonEmptyList[A]                  = reduceMap(s)(NonEmptyList.one[A])

  def +++[S1 <: S, A1 >: A](other: PReduced[S1, Any, A1, Nothing]): PReduced[S1, T, A1, B] =
    new PReduced[S1, T, A1, B] {
      override def reduceMap[X: Semigroup](s: S1)(f: A1 => X): X =
        self.reduceMap(s)(f) |+| other.reduceMap(s)(f)
    }
}

object Reduced extends MonoOpticCompanion(PReduced) {
  def apply[S] = new ReducedApply[S]

  class ReducedApply[S] {
    type Arb

    def apply[A](fm: Semigroup[Arb] => (S, A => Arb) => Arb): Reduced[S, A] = new Reduced[S, A] {
      def reduceMap[X: Semigroup](s: S)(f: A => X): X =
        fm(Semigroup[X].asInstanceOf[Semigroup[Arb]])(s, f.asInstanceOf[A => Arb]).asInstanceOf[X]
    }
  }
}

object PReduced extends OpticCompanion[PReduced] {
  def compose[S, T, A, B, U, V](f: PReduced[A, B, U, V], g: PReduced[S, T, A, B]): PReduced[S, T, U, V] =
    new PReduced[S, T, U, V] {
      def reduceMap[X: Semigroup](s: S)(fux: U => X): X = g.reduceMap(s)(f.reduceMap(_)(fux))
    }

  final implicit def byReducible[F[_], T, A, B](implicit F: Reducible[F]): PReduced[F[A], T, A, B] =
    new PReduced[F[A], T, A, B] {
      def reduceMap[X: Semigroup](fa: F[A])(f: A => X): X = F.reduceMap(fa)(f)
    }

  trait Context extends PRepeated.Context with PExtract.Context {
    def algebra: Semigroup[X]
    override def functor: Apply[Constant[X, *]] = {
      implicit val alg: Semigroup[X] = algebra
      Apply[Constant[X, *]]
    }
  }

  override def toGeneric[S, T, A, B](o: PReduced[S, T, A, B]): Optic[Context, S, T, A, B]   =
    new Optic[Context, S, T, A, B] {
      def apply(c: Context)(p: A => Constant[c.X, B]): S => Constant[c.X, T] =
        s => Constant.Impl(o.reduceMap(s)(a => p(a).value)(c.algebra))
    }
  override def fromGeneric[S, T, A, B](o: Optic[Context, S, T, A, B]): PReduced[S, T, A, B] =
    new PReduced[S, T, A, B] {
      def reduceMap[Y: Semigroup](s: S)(f: A => Y): Y =
        o.apply(new Context {
            type X = Y
            def algebra = Semigroup[Y]
          })(a => Constant.Impl(f(a)))(s)
          .value

    }
} 
Example 152
Source File: Applied.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.optics
import cats.data.NonEmptyList
import cats.kernel.Semigroup
import cats.{Applicative, Apply, Monoid}
import tofu.optics.classes.Category2
import tofu.optics.tags.{PTagApply, Tagger}

final case class Applied[O[_, _, _, _], S, T, A, B](s: S, o: O[S, T, A, B]) {
  def >>[O1[s, t, a, b] >: O[s, t, a, b]: Category2, U, V](o1: O1[A, B, U, V]): Applied[O1, S, T, U, V] =
    Applied(s, Category2.compose(o1, o))

  def >[O1[s, t, a, b] >: O[s, t, a, b]](tagger: Tagger[O1]): AppliedWithTag[O1, S, T, A, B, tagger.Tag] =
    AppliedWithTag(s, o)

  def put(b: B)(implicit ev: O[S, T, A, B] <:< PUpdate[S, T, A, B]): T = ev(o).put(s, b)

  def update(f: A => B)(implicit ev: O[S, T, A, B] <:< PUpdate[S, T, A, B]): T = ev(o).update(s, f)

  def get(implicit ev: O[S, T, A, B] <:< PExtract[S, T, A, B]): A = ev(o).extract(s)

  def downcast(implicit ev: O[S, T, A, B] <:< PDowncast[S, T, A, B]): Option[A] = ev(o).downcast(s)

  def traverse[G[+_]: Applicative](f: A => G[B])(implicit ev: O[S, T, A, B] <:< PItems[S, T, A, B]): G[T] =
    ev(o).traverse(s)(f)

  def foldMap[M: Monoid](f: A => M)(implicit ev: O[S, T, A, B] <:< PFolded[S, T, A, B]): M =
    ev(o).foldMap(s)(f)

  def reduceMap[M: Semigroup](f: A => M)(implicit ev: O[S, T, A, B] <:< PReduced[S, T, A, B]): M =
    ev(o).reduceMap(s)(f)

  def getAll1(implicit ev: O[S, T, A, B] <:< PReduced[S, T, A, B]): NonEmptyList[A] =
    ev(o).getAll1(s)

  def getAll(implicit ev: O[S, T, A, B] <:< PFolded[S, T, A, B]): List[A] =
    ev(o).getAll(s)

  def traverse1[G[+_]: Apply](f: A => G[B])(implicit ev: O[S, T, A, B] <:< PRepeated[S, T, A, B]): G[T] =
    ev(o).traverse1(s)(f)
}

final case class AppliedWithTag[O[_, _, _, _], S, T, A, B, Tag](s: S, o: O[S, T, A, B]) {
  def >@[X, U, V](x: X)(implicit tag: PTagApply[O, A, B, U, V, Tag, X], cat: Category2[O]): Applied[O, S, T, U, V] =
    Applied(s, cat.compose(tag.continue(x), o))

  def >[O1[s, t, a, b] >: O[s, t, a, b], U, V](
      tagger: Tagger[O1]
  )(implicit tag: PTagApply[O, A, B, U, V, Tag, Unit], cat: Category2[O]): AppliedWithTag[O1, S, T, U, V, tagger.Tag] =
    end > tagger

  def >>[O1[s, t, a, b] >: O[s, t, a, b]: Category2, U, V, X, Y](o1: O1[U, V, X, Y])(implicit
      tag: PTagApply[O, A, B, U, V, Tag, Unit],
      cat: Category2[O]
  ): Applied[O1, S, T, X, Y] =
    end >> o1

  def end[U, V](implicit tag: PTagApply[O, A, B, U, V, Tag, Unit], cat: Category2[O]): Applied[O, S, T, U, V] =
    >@ {}
}

object chain {
  def to[T]          = new ChainTo[T]
  def apply[S](s: S) = Applied(s, PSame.id[S, S])

  class ChainTo[T] {
    def apply[S](s: S) = Applied(s, PSame.id[S, T])
  }
} 
Example 153
Source File: ConfigError.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu
package config

import cats.data.NonEmptyList
import tofu.config.ConfigItem.ValueTag
import cats.Show
import cats.syntax.show._
import cats.syntax.foldable._
import cats.instances.string._
import cats.instances.vector._

sealed trait ConfigError extends Product with Serializable
object ConfigError {
  case object NotFound                                                 extends ConfigError
  case object NoVariantFound                                           extends ConfigError
  final case class BadType(expected: List[ValueTag], actual: ValueTag) extends ConfigError
  final case class BadNumber(value: BigDecimal, message: String)       extends ConfigError
  final case class BadString(value: String, message: String)           extends ConfigError
  final case class Invalid(message: String)                            extends ConfigError
  final case class MultipleVariants(variants: NonEmptyList[String])    extends ConfigError

  implicit val configErrorShow: Show[ConfigError] = {
    case NotFound                   => "not found"
    case NoVariantFound             => "no variant found"
    case BadType(expected, actual)  => s"bad type, expected: ${expected.mkString(",")}, actual : $actual"
    case BadNumber(value, message)  => s"bad number $value : $message"
    case BadString(value, message)  => s"bad string '$value' : $message"
    case MultipleVariants(variants) => s"multiple variants found : $variants"
    case Invalid(message)           => message
  }
}

final case class ConfigParseMessage(path: Path, error: ConfigError)

object ConfigParseMessage {
  implicit val messageShow: Show[ConfigParseMessage] = message => {
    val pathShown = message.path.iterator.map(_.show).mkString(".")
    show"$pathShown : ${message.error}"
  }
}

final case class ConfigParseErrors(ms: MessageList) extends RuntimeException(ms.mkString_("\n")) 
Example 154
Source File: ExternalCfpRepoSql.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.infra.services.storage.sql

import java.time.Instant

import cats.data.NonEmptyList
import cats.effect.IO
import doobie.implicits._
import gospeak.core.domain._
import gospeak.core.domain.utils.{Info, UserAwareCtx, UserCtx}
import gospeak.core.services.storage.ExternalCfpRepo
import gospeak.infra.services.storage.sql.ExternalCfpRepoSql._
import gospeak.infra.services.storage.sql.utils.DoobieUtils.Mappings._
import gospeak.infra.services.storage.sql.utils.DoobieUtils._
import gospeak.infra.services.storage.sql.utils.GenericRepo
import gospeak.libs.scala.Extensions._
import gospeak.libs.scala.domain.{Done, Page}

class ExternalCfpRepoSql(protected[sql] val xa: doobie.Transactor[IO]) extends GenericRepo with ExternalCfpRepo {
  override def create(event: ExternalEvent.Id, data: ExternalCfp.Data)(implicit ctx: UserCtx): IO[ExternalCfp] =
    insert(ExternalCfp(data, event, Info(ctx.user.id, ctx.now))).run(xa)

  override def edit(cfp: ExternalCfp.Id)(data: ExternalCfp.Data)(implicit ctx: UserCtx): IO[Done] =
    update(cfp)(data, ctx.user.id, ctx.now).run(xa)

  override def listAllIds(): IO[Seq[ExternalCfp.Id]] = selectAllIds().runList(xa)

  override def listAll(event: ExternalEvent.Id): IO[Seq[ExternalCfp]] = selectAll(event).runList(xa)

  override def listIncoming(params: Page.Params)(implicit ctx: UserAwareCtx): IO[Page[CommonCfp]] = selectCommonPageIncoming(params).run(xa)

  override def listDuplicatesFull(p: ExternalCfp.DuplicateParams): IO[Seq[ExternalCfp.Full]] = selectDuplicatesFull(p).runList(xa)

  override def findFull(cfp: ExternalCfp.Id): IO[Option[ExternalCfp.Full]] = selectOneFull(cfp).runOption(xa)

  override def findCommon(cfp: Cfp.Slug): IO[Option[CommonCfp]] = selectOneCommon(cfp).runOption(xa)

  override def findCommon(cfp: ExternalCfp.Id): IO[Option[CommonCfp]] = selectOneCommon(cfp).runOption(xa)
}

object ExternalCfpRepoSql {
  private val _ = externalCfpIdMeta // for intellij not remove DoobieUtils.Mappings import
  private val table = Tables.externalCfps
  private val tableFull = table
    .join(Tables.externalEvents.dropFields(_.name.startsWith("location_")), _.event_id -> _.id).get
  private val commonTable = Table(
    name = "((SELECT c.name, g.logo, c.begin, c.close, g.location, c.description, c.tags, null as ext_id, null  as ext_url, null    as ext_event_start, null     as ext_event_finish, null  as ext_event_url, null          as ext_tickets_url, null         as ext_videos_url, null as twitter_account, null as twitter_hashtag, c.slug as int_slug, g.id as group_id, g.slug as group_slug FROM cfps c INNER JOIN groups g ON c.group_id=g.id) " +
      "UNION (SELECT e.name, e.logo, c.begin, c.close, e.location, c.description, e.tags, c.id as ext_id, c.url as ext_url, e.start as ext_event_start, e.finish as ext_event_finish, e.url as ext_event_url, e.tickets_url as ext_tickets_url, e.videos_url as ext_videos_url,       e.twitter_account,       e.twitter_hashtag, null   as int_slug, null as group_id,   null as group_slug FROM external_cfps c INNER JOIN external_events e ON c.event_id=e.id))",
    prefix = "c",
    joins = Seq(),
    fields = Seq(
      "name", "logo", "begin", "close", "location", "description", "tags",
      "ext_id", "ext_url", "ext_event_start", "ext_event_finish", "ext_event_url", "ext_tickets_url", "ext_videos_url", "twitter_account", "twitter_hashtag",
      "int_slug", "group_id", "group_slug").map(Field(_, "c")),
    aggFields = Seq(),
    customFields = Seq(),
    sorts = Sorts("close", "close date", Field("close", "c"), Field("name", "c")),
    search = Seq("name", "description", "tags").map(Field(_, "c")),
    filters = Seq())

  private[sql] def insert(e: ExternalCfp): Insert[ExternalCfp] = {
    val values = fr0"${e.id}, ${e.event}, ${e.description}, ${e.begin}, ${e.close}, ${e.url}, ${e.info.createdAt}, ${e.info.createdBy}, ${e.info.updatedAt}, ${e.info.updatedBy}"
    table.insert[ExternalCfp](e, _ => values)
  }

  private[sql] def update(id: ExternalCfp.Id)(e: ExternalCfp.Data, by: User.Id, now: Instant): Update = {
    val fields = fr0"description=${e.description}, begin=${e.begin}, close=${e.close}, url=${e.url}, updated_at=$now, updated_by=$by"
    table.update(fields, fr0"WHERE id=$id")
  }

  private[sql] def selectAllIds(): Select[ExternalCfp.Id] =
    table.select[ExternalCfp.Id](Seq(Field("id", "ec")))

  private[sql] def selectAll(id: ExternalEvent.Id): Select[ExternalCfp] =
    table.select[ExternalCfp](fr0"WHERE ec.event_id=$id")

  private[sql] def selectOneFull(id: ExternalCfp.Id): Select[ExternalCfp.Full] =
    tableFull.selectOne[ExternalCfp.Full](fr0"WHERE ec.id=$id")

  private[sql] def selectOneCommon(slug: Cfp.Slug): Select[CommonCfp] =
    commonTable.selectOne[CommonCfp](fr0"WHERE c.slug=$slug")

  private[sql] def selectOneCommon(id: ExternalCfp.Id): Select[CommonCfp] =
    commonTable.selectOne[CommonCfp](fr0"WHERE c.id=$id")

  private[sql] def selectCommonPageIncoming(params: Page.Params)(implicit ctx: UserAwareCtx): SelectPage[CommonCfp, UserAwareCtx] =
    commonTable.selectPage[CommonCfp, UserAwareCtx](params, fr0"WHERE (c.close IS NULL OR c.close >= ${ctx.now})")

  private[sql] def selectDuplicatesFull(p: ExternalCfp.DuplicateParams): Select[ExternalCfp.Full] = {
    val filters = Seq(
      p.cfpUrl.map(v => fr0"ec.url LIKE ${"%" + v + "%"}"),
      p.cfpEndDate.map(v => fr0"ec.close=$v")
    ).flatten
    if (filters.isEmpty) {
      tableFull.select[ExternalCfp.Full](fr0"WHERE ec.id='no-match'")
    } else {
      tableFull.select[ExternalCfp.Full](fr0"WHERE " ++ filters.reduce(_ ++ fr0" OR " ++ _))
    }
  }
} 
Example 155
Source File: SponsorPackRepoSql.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.infra.services.storage.sql

import java.time.Instant

import cats.data.NonEmptyList
import cats.effect.IO
import doobie.Fragments
import doobie.implicits._
import doobie.util.fragment.Fragment
import gospeak.core.domain.utils.OrgaCtx
import gospeak.core.domain.{Group, SponsorPack, User}
import gospeak.core.services.storage.SponsorPackRepo
import gospeak.infra.services.storage.sql.SponsorPackRepoSql._
import gospeak.infra.services.storage.sql.utils.DoobieUtils.Mappings._
import gospeak.infra.services.storage.sql.utils.DoobieUtils.{Insert, Select, Update}
import gospeak.infra.services.storage.sql.utils.GenericRepo
import gospeak.libs.scala.domain.{CustomException, Done}

class SponsorPackRepoSql(protected[sql] val xa: doobie.Transactor[IO]) extends GenericRepo with SponsorPackRepo {
  override def create(data: SponsorPack.Data)(implicit ctx: OrgaCtx): IO[SponsorPack] =
    insert(SponsorPack(ctx.group.id, data, ctx.info)).run(xa)

  override def edit(pack: SponsorPack.Slug, data: SponsorPack.Data)(implicit ctx: OrgaCtx): IO[Done] = {
    if (data.slug != pack) {
      find(data.slug).flatMap {
        case None => update(ctx.group.id, pack)(data, ctx.user.id, ctx.now).run(xa)
        case _ => IO.raiseError(CustomException(s"You already have a sponsor pack with slug ${data.slug}"))
      }
    } else {
      update(ctx.group.id, pack)(data, ctx.user.id, ctx.now).run(xa)
    }
  }

  override def disable(pack: SponsorPack.Slug)(implicit ctx: OrgaCtx): IO[Done] =
    setActive(ctx.group.id, pack)(active = false, ctx.user.id, ctx.now).run(xa)

  override def enable(pack: SponsorPack.Slug)(implicit ctx: OrgaCtx): IO[Done] =
    setActive(ctx.group.id, pack)(active = true, ctx.user.id, ctx.now).run(xa)

  override def find(pack: SponsorPack.Slug)(implicit ctx: OrgaCtx): IO[Option[SponsorPack]] = selectOne(ctx.group.id, pack).runOption(xa)

  override def listAll(group: Group.Id): IO[Seq[SponsorPack]] = selectAll(group).runList(xa)

  override def listAll(implicit ctx: OrgaCtx): IO[Seq[SponsorPack]] = selectAll(ctx.group.id).runList(xa)

  override def listActives(group: Group.Id): IO[Seq[SponsorPack]] = selectActives(group).runList(xa)

  override def listActives(implicit ctx: OrgaCtx): IO[Seq[SponsorPack]] = selectActives(ctx.group.id).runList(xa)
}

object SponsorPackRepoSql {
  private val _ = sponsorPackIdMeta // for intellij not remove DoobieUtils.Mappings import
  private val table = Tables.sponsorPacks

  private[sql] def insert(e: SponsorPack): Insert[SponsorPack] = {
    val values = fr0"${e.id}, ${e.group}, ${e.slug}, ${e.name}, ${e.description}, ${e.price.amount}, ${e.price.currency}, ${e.duration}, ${e.active}, ${e.info.createdAt}, ${e.info.createdBy}, ${e.info.updatedAt}, ${e.info.updatedBy}"
    table.insert(e, _ => values)
  }

  private[sql] def update(group: Group.Id, pack: SponsorPack.Slug)(data: SponsorPack.Data, by: User.Id, now: Instant): Update = {
    val fields = fr0"slug=${data.slug}, name=${data.name}, description=${data.description}, price=${data.price.amount}, currency=${data.price.currency}, duration=${data.duration}, updated_at=$now, updated_by=$by"
    table.update(fields, where(group, pack))
  }

  private[sql] def setActive(group: Group.Id, pack: SponsorPack.Slug)(active: Boolean, by: User.Id, now: Instant): Update =
    table.update(fr0"active=$active, updated_at=$now, updated_by=$by", where(group, pack))

  private[sql] def selectOne(group: Group.Id, pack: SponsorPack.Slug): Select[SponsorPack] =
    table.select[SponsorPack](where(group, pack))

  private[sql] def selectAll(ids: NonEmptyList[SponsorPack.Id]): Select[SponsorPack] =
    table.select[SponsorPack](fr0"WHERE " ++ Fragments.in(fr"sp.id", ids))

  private[sql] def selectAll(group: Group.Id): Select[SponsorPack] =
    table.select[SponsorPack](where(group))

  private[sql] def selectActives(group: Group.Id): Select[SponsorPack] = {
    val active = true
    table.select[SponsorPack](where(group) ++ fr0" AND sp.active=$active")
  }

  private def where(group: Group.Id, slug: SponsorPack.Slug): Fragment =
    fr0"WHERE sp.group_id=$group AND sp.slug=$slug"

  private def where(group: Group.Id): Fragment =
    fr0"WHERE sp.group_id=$group"
} 
Example 156
Source File: VenueRepoSqlSpec.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.infra.services.storage.sql

import cats.data.NonEmptyList
import gospeak.infra.services.storage.sql.ContactRepoSqlSpec.{fields => contactFields, table => contactTable}
import gospeak.infra.services.storage.sql.EventRepoSqlSpec.{table => eventTable}
import gospeak.infra.services.storage.sql.GroupRepoSqlSpec.{table => groupTable}
import gospeak.infra.services.storage.sql.PartnerRepoSqlSpec.{fields => partnerFields, table => partnerTable}
import gospeak.infra.services.storage.sql.VenueRepoSqlSpec._
import gospeak.infra.services.storage.sql.testingutils.RepoSpec

class VenueRepoSqlSpec extends RepoSpec {
  describe("VenueRepoSql") {
    describe("Queries") {
      it("should build insert") {
        val q = VenueRepoSql.insert(venue)
        check(q, s"INSERT INTO ${table.stripSuffix(" v")} (${mapFields(fieldsInsert, _.stripPrefix("v."))}) VALUES (${mapFields(fieldsInsert, _ => "?")})")
      }
      it("should build update") {
        val q = VenueRepoSql.update(group.id, venue.id)(venue.data, user.id, now)
        check(q, s"UPDATE $table SET contact_id=?, address=?, address_id=?, address_lat=?, address_lng=?, address_locality=?, address_country=?, notes=?, room_size=?, meetupGroup=?, meetupVenue=?, updated_at=?, updated_by=? WHERE v.id=(SELECT v.id FROM $tableFull WHERE pa.group_id=? AND v.id=? $orderByFull)")
      }
      it("should build delete") {
        val q = VenueRepoSql.delete(group.id, venue.id)
        check(q, s"DELETE FROM $table WHERE v.id=(SELECT v.id FROM $tableFull WHERE pa.group_id=? AND v.id=? $orderByFull)")
      }
      it("should build selectOneFull") {
        val q = VenueRepoSql.selectOneFull(venue.id)
        check(q, s"SELECT $fieldsFull FROM $tableFull WHERE v.id=? $orderBy")
      }
      it("should build selectOneFull in a group") {
        val q = VenueRepoSql.selectOneFull(group.id, venue.id)
        check(q, s"SELECT $fieldsFull FROM $tableFull WHERE pa.group_id=? AND v.id=? $orderBy")
      }
      it("should build selectPageFull") {
        val q = VenueRepoSql.selectPageFull(params)
        check(q, s"SELECT $fieldsFull FROM $tableFull WHERE pa.group_id=? $orderBy LIMIT 20 OFFSET 0")
      }
      it("should build selectAllFull for group id") {
        val q = VenueRepoSql.selectAllFull(group.id)
        check(q, s"SELECT $fieldsFull FROM $tableFull WHERE pa.group_id=? $orderBy")
      }
      it("should build selectAllFull for partner id") {
        val q = VenueRepoSql.selectAllFull(partner.id)
        check(q, s"SELECT $fieldsFull FROM $tableFull WHERE v.partner_id=? $orderBy")
      }
      it("should build selectAllFull for group id and ids") {
        val q = VenueRepoSql.selectAllFull(group.id, NonEmptyList.of(venue.id))
        check(q, s"SELECT $fieldsFull FROM $tableFull WHERE pa.group_id=? AND v.id IN (?)  $orderBy")
      }
      it("should build selectAll for contact") {
        val q = VenueRepoSql.selectAll(group.id, contact.id)
        check(q, s"SELECT $fields FROM $table WHERE v.contact_id=? $orderBy")
      }
      it("should build selectPagePublic") {
        val q = VenueRepoSql.selectPagePublic(params)
        check(q, s"SELECT $fieldsPublic FROM $tablePublic GROUP BY pa.slug, pa.name, pa.logo, v.address $orderByPublic LIMIT 20 OFFSET 0")
      }
      it("should build selectOnePublic") {
        val q = VenueRepoSql.selectOnePublic(group.id, venue.id)
        check(q, s"SELECT $fieldsPublic FROM $tablePublic WHERE v.id=? GROUP BY pa.slug, pa.name, pa.logo, v.address $orderByPublic")
      }
      it("should build selectPageCommon") {
        val q = VenueRepoSql.selectPageCommon(params)
        q.fr.query.sql shouldBe s"SELECT $commonFields FROM $commonTable $commonOrderBy LIMIT 20 OFFSET 0"
        // ignored because of fake nullable columns
        // check(q, s"SELECT $commonFields FROM $commonTable $commonOrderBy LIMIT 20 OFFSET 0")
      }
    }
  }
}

object VenueRepoSqlSpec {

  import RepoSpec._

  val table = "venues v"
  val fieldsInsert: String = mapFields("id, partner_id, contact_id, address, address_id, address_lat, address_lng, address_locality, address_country, notes, room_size, meetupGroup, meetupVenue, created_at, created_by, updated_at, updated_by", "v." + _)
  val fields: String = mapFields("id, partner_id, contact_id, address, notes, room_size, meetupGroup, meetupVenue, created_at, created_by, updated_at, updated_by", "v." + _)
  val orderBy = "ORDER BY v.created_at IS NULL, v.created_at"

  private val tableWithPartner = s"$table INNER JOIN $partnerTable ON v.partner_id=pa.id"

  private val tableFull = s"$tableWithPartner LEFT OUTER JOIN $contactTable ON v.contact_id=ct.id"
  private val fieldsFull = s"$fields, $partnerFields, $contactFields"
  private val orderByFull = "ORDER BY v.created_at IS NULL, v.created_at"

  private val tablePublic = s"$tableWithPartner INNER JOIN $groupTable ON pa.group_id=g.id AND g.id != ? INNER JOIN $eventTable ON g.id=e.group_id AND e.venue=v.id AND e.published IS NOT NULL"
  private val fieldsPublic = s"pa.slug, pa.name, pa.logo, v.address, MAX(v.id) as id, COALESCE(COUNT(e.id), 0) as events"
  private val orderByPublic = "ORDER BY pa.name IS NULL, pa.name"

  private val commonTable = s"(" +
    s"(SELECT false as public, pa.slug, pa.name, pa.logo, v.address, v.id, 0 as events FROM $tableWithPartner WHERE pa.group_id=? ORDER BY v.created_at IS NULL, v.created_at) UNION " +
    s"(SELECT true as public, $fieldsPublic FROM $tablePublic GROUP BY public, pa.slug, pa.name, pa.logo, v.address ORDER BY pa.name IS NULL, pa.name)) v"
  private val commonFields = "v.id, v.slug, v.name, v.logo, v.address, v.events, v.public"
  private val commonOrderBy = "ORDER BY v.public IS NULL, v.public, v.name IS NULL, v.name, v.events IS NULL, v.events DESC"
} 
Example 157
Source File: GroupSettingsRepoSqlSpec.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.infra.services.storage.sql

import cats.data.NonEmptyList
import gospeak.infra.services.storage.sql.GroupSettingsRepoSqlSpec._
import gospeak.infra.services.storage.sql.testingutils.RepoSpec
import gospeak.infra.services.storage.sql.testingutils.RepoSpec.mapFields

class GroupSettingsRepoSqlSpec extends RepoSpec {
  describe("GroupSettingsRepoSql") {
    describe("Queries") {
      it("should build insert group settings") {
        val q = GroupSettingsRepoSql.insert(group.id, groupSettings, user.id, now)
        check(q, s"INSERT INTO ${table.stripSuffix(" gs")} (${mapFields(fields, _.stripPrefix("gs."))}) VALUES (${mapFields(fields, _ => "?")})")
      }
      it("should build update group settings") {
        val q = GroupSettingsRepoSql.update(group.id, groupSettings, user.id, now)
        check(q, s"UPDATE $table SET ${fields.split(", ").drop(1).map(_.stripPrefix("gs.") + "=?").mkString(", ")} WHERE gs.group_id=?")
      }
      it("should build selectAll group settings") {
        val q = GroupSettingsRepoSql.selectAll(NonEmptyList.of(group.id))(adminCtx)
        check(q, s"SELECT gs.group_id, $fieldsSelect FROM $table WHERE gs.group_id IN (?)  $orderBy")
      }
      it("should build selectOne group settings") {
        val q = GroupSettingsRepoSql.selectOne(group.id)
        check(q, s"SELECT $fieldsSelect FROM $table WHERE gs.group_id=? $orderBy")
      }
      it("should build selectOneAccounts group settings") {
        val q = GroupSettingsRepoSql.selectOneAccounts(group.id)
        check(q, s"SELECT $meetupFields, $slackFields FROM $table WHERE gs.group_id=? $orderBy")
      }
      it("should build selectOneMeetup group settings") {
        val q = GroupSettingsRepoSql.selectOneMeetup(group.id)
        check(q, s"SELECT $meetupFields FROM $table WHERE gs.group_id=? $orderBy")
      }
      it("should build selectOneSlack group settings") {
        val q = GroupSettingsRepoSql.selectOneSlack(group.id)
        check(q, s"SELECT $slackFields FROM $table WHERE gs.group_id=? $orderBy")
      }
      it("should build selectOneEventDescription group settings") {
        val q = GroupSettingsRepoSql.selectOneEventDescription(group.id)
        check(q, s"SELECT gs.event_description FROM $table WHERE gs.group_id=? $orderBy")
      }
      it("should build selectOneEventTemplates group settings") {
        val q = GroupSettingsRepoSql.selectOneEventTemplates(group.id)
        check(q, s"SELECT gs.event_templates FROM $table WHERE gs.group_id=? $orderBy")
      }
      it("should build selectOneProposalTweet group settings") {
        val q = GroupSettingsRepoSql.selectOneProposalTweet(group.id)
        check(q, s"SELECT gs.proposal_tweet FROM $table WHERE gs.group_id=? $orderBy")
      }
      it("should build selectOneActions group settings") {
        val q = GroupSettingsRepoSql.selectOneActions(group.id)
        check(q, s"SELECT gs.actions FROM $table WHERE gs.group_id=? $orderBy")
      }
    }
  }
}

object GroupSettingsRepoSqlSpec {
  val meetupFields: String = mapFields("meetup_access_token, meetup_refresh_token, meetup_group_slug, meetup_logged_user_id, meetup_logged_user_name", "gs." + _)
  val slackFields: String = mapFields("slack_token, slack_bot_name, slack_bot_avatar", "gs." + _)
  val eventFields: String = mapFields("event_description, event_templates", "gs." + _)
  val proposalFields: String = mapFields("proposal_tweet", "gs." + _)

  val table = "group_settings gs"
  val fields = s"gs.group_id, $meetupFields, $slackFields, $eventFields, $proposalFields, gs.actions, gs.updated_at, gs.updated_by"
  val fieldsSelect = s"$meetupFields, $slackFields, $eventFields, $proposalFields, gs.actions"
  val orderBy = "ORDER BY gs.group_id IS NULL, gs.group_id"
} 
Example 158
Source File: PartnerRepoSqlSpec.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.infra.services.storage.sql

import cats.data.NonEmptyList
import gospeak.infra.services.storage.sql.ContactRepoSqlSpec.{table => contactTable}
import gospeak.infra.services.storage.sql.PartnerRepoSqlSpec._
import gospeak.infra.services.storage.sql.SponsorRepoSqlSpec.{table => sponsorTable}
import gospeak.infra.services.storage.sql.TablesSpec.socialFields
import gospeak.infra.services.storage.sql.VenueRepoSqlSpec.{table => venueTable}
import gospeak.infra.services.storage.sql.testingutils.RepoSpec
import gospeak.infra.services.storage.sql.testingutils.RepoSpec.mapFields

class PartnerRepoSqlSpec extends RepoSpec {
  describe("PartnerRepoSql") {
    describe("Queries") {
      it("should build insert") {
        val q = PartnerRepoSql.insert(partner)
        check(q, s"INSERT INTO ${table.stripSuffix(" pa")} (${mapFields(fields, _.stripPrefix("pa."))}) VALUES (${mapFields(fields, _ => "?")})")
      }
      it("should build update") {
        val q = PartnerRepoSql.update(group.id, partner.slug)(partner.data, user.id, now)
        check(q, s"UPDATE $table SET slug=?, name=?, notes=?, description=?, logo=?, " +
          s"social_facebook=?, social_instagram=?, social_twitter=?, social_linkedIn=?, social_youtube=?, social_meetup=?, social_eventbrite=?, social_slack=?, social_discord=?, social_github=?, " +
          s"updated_at=?, updated_by=? WHERE pa.group_id=? AND pa.slug=?")
      }
      it("should build delete") {
        val q = PartnerRepoSql.delete(group.id, partner.slug)
        check(q, s"DELETE FROM $table WHERE pa.group_id=? AND pa.slug=?")
      }
      it("should build selectPage") {
        val q = PartnerRepoSql.selectPage(params)
        check(q, s"SELECT $fields FROM $table WHERE pa.group_id=? $orderBy LIMIT 20 OFFSET 0")
      }
      it("should build selectPageFull") {
        val q = PartnerRepoSql.selectPageFull(params)
        check(q, s"SELECT $fieldsFull FROM $tableFull WHERE pa.group_id=? $groupByFull $orderByFull LIMIT 20 OFFSET 0")
      }
      it("should build selectAll") {
        val q = PartnerRepoSql.selectAll(group.id)
        check(q, s"SELECT $fields FROM $table WHERE pa.group_id=? $orderBy")
      }
      it("should build selectAll with partner ids") {
        val q = PartnerRepoSql.selectAll(NonEmptyList.of(partner.id))
        check(q, s"SELECT $fields FROM $table WHERE pa.id IN (?)  $orderBy")
      }
      it("should build selectOne by id") {
        val q = PartnerRepoSql.selectOne(group.id, partner.id)
        check(q, s"SELECT $fields FROM $table WHERE pa.group_id=? AND pa.id=? $orderBy")
      }
      it("should build selectOne by slug") {
        val q = PartnerRepoSql.selectOne(group.id, partner.slug)
        check(q, s"SELECT $fields FROM $table WHERE pa.group_id=? AND pa.slug=? $orderBy")
      }
    }
  }
}

object PartnerRepoSqlSpec {
  val table = "partners pa"
  val fields: String = mapFields(s"id, group_id, slug, name, notes, description, logo, $socialFields, created_at, created_by, updated_at, updated_by", "pa." + _)
  val orderBy = "ORDER BY pa.name IS NULL, pa.name"

  private val tableFull = s"$table LEFT OUTER JOIN $venueTable ON pa.id=v.partner_id LEFT OUTER JOIN $sponsorTable ON pa.id=s.partner_id LEFT OUTER JOIN $contactTable ON pa.id=ct.partner_id LEFT OUTER JOIN events e ON v.id=e.venue"
  private val fieldsFull = s"$fields, COALESCE(COUNT(DISTINCT v.id), 0) as venueCount, COALESCE(COUNT(DISTINCT s.id), 0) as sponsorCount, MAX(s.finish) as lastSponsorDate, COALESCE(COUNT(DISTINCT ct.id), 0) as contactCount, COALESCE(COUNT(DISTINCT e.id), 0) as eventCount, MAX(e.start) as lastEventDate"
  private val groupByFull = s"GROUP BY $fields"
  private val orderByFull = "ORDER BY LOWER(pa.name) IS NULL, LOWER(pa.name)"
} 
Example 159
Source File: SponsorPackRepoSqlSpec.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.infra.services.storage.sql

import cats.data.NonEmptyList
import gospeak.infra.services.storage.sql.SponsorPackRepoSqlSpec._
import gospeak.infra.services.storage.sql.testingutils.RepoSpec
import gospeak.infra.services.storage.sql.testingutils.RepoSpec.mapFields

class SponsorPackRepoSqlSpec extends RepoSpec {
  describe("SponsorPackRepoSql") {
    describe("Queries") {
      it("should build insert") {
        val q = SponsorPackRepoSql.insert(sponsorPack)
        check(q, s"INSERT INTO ${table.stripSuffix(" sp")} (${mapFields(fields, _.stripPrefix("sp."))}) VALUES (${mapFields(fields, _ => "?")})")
      }
      it("should build update") {
        val q = SponsorPackRepoSql.update(group.id, sponsorPack.slug)(sponsorPack.data, user.id, now)
        check(q, s"UPDATE $table SET slug=?, name=?, description=?, price=?, currency=?, duration=?, updated_at=?, updated_by=? WHERE sp.group_id=? AND sp.slug=?")
      }
      it("should build setActive") {
        val q = SponsorPackRepoSql.setActive(group.id, sponsorPack.slug)(active = true, user.id, now)
        check(q, s"UPDATE $table SET active=?, updated_at=?, updated_by=? WHERE sp.group_id=? AND sp.slug=?")
      }
      it("should build selectOne") {
        val q = SponsorPackRepoSql.selectOne(group.id, sponsorPack.slug)
        check(q, s"SELECT $fields FROM $table WHERE sp.group_id=? AND sp.slug=? $orderBy")
      }
      it("should build selectAll ids") {
        val q = SponsorPackRepoSql.selectAll(NonEmptyList.of(sponsorPack.id, sponsorPack.id))
        check(q, s"SELECT $fields FROM $table WHERE sp.id IN (?, ?)  $orderBy")
      }
      it("should build selectAll") {
        val q = SponsorPackRepoSql.selectAll(group.id)
        check(q, s"SELECT $fields FROM $table WHERE sp.group_id=? $orderBy")
      }
      it("should build selectActives") {
        val q = SponsorPackRepoSql.selectActives(group.id)
        check(q, s"SELECT $fields FROM $table WHERE sp.group_id=? AND sp.active=? $orderBy")
      }
    }
  }
}

object SponsorPackRepoSqlSpec {
  val table = "sponsor_packs sp"
  val fields: String = mapFields("id, group_id, slug, name, description, price, currency, duration, active, created_at, created_by, updated_at, updated_by", "sp." + _)
  val orderBy = "ORDER BY sp.active IS NULL, sp.active DESC, sp.price IS NULL, sp.price DESC"
} 
Example 160
Source File: Schemas.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.libs.openapi.models

import cats.data.NonEmptyList
import gospeak.libs.scala.Extensions._
import gospeak.libs.openapi.error.OpenApiError

final case class Schemas(value: Map[String, Schema]) extends AnyVal {
  def get(name: String): Option[Schema] = value.get(name)

  def resolve(schema: Schema): Either[NonEmptyList[OpenApiError], Option[Schema]] = schema match {
    case s: Schema.StringVal => Right(Some(s))
    case s: Schema.IntegerVal => Right(Some(s))
    case s: Schema.NumberVal => Right(Some(s))
    case s: Schema.BooleanVal => Right(Some(s))
    case s: Schema.ArrayVal => resolve(s.items).map(_.map(r => s.copy(items = r))).left.map(_.map(_.atPath(s".items")))
    case s: Schema.ObjectVal =>
      s.properties.map { case (name, value) =>
        resolve(value).map(res => (name, res)).left.map(_.map(_.atPath(".properties", s".$name")))
      }.sequence.map(p => p.map { case (k, v) => v.map(k -> _) }.sequence).map(_.map(p => s.copy(properties = p.toMap)))
    case s: Schema.ReferenceVal => s.$ref.localRef match {
      case Some(("schemas", name)) => get(name).toRight(NonEmptyList.of(OpenApiError.missingReference(s.$ref.value).atPath(".$ref"))).flatMap(resolve)
      case Some((component, _)) => Left(NonEmptyList.of(OpenApiError.badReference(s.$ref.value, component, "schemas")))
      case None => Right(None)
    }
    case s: Schema.CombinationVal => s.oneOf.map(_.zipWithIndex.map { case (s, i) =>
      resolve(s).left.map(_.map(_.atPath(".oneOf", s"[$i]")))
    }.sequence).sequence.map(_.flatMap(_.sequence.map(a => Schema.CombinationVal(Some(a)))))
  }

  def contains(name: String): Boolean = value.contains(name)
}

object Schemas {
  def apply(values: (String, Schema)*): Schemas = new Schemas(values.toMap)
} 
Example 161
Source File: OpenApi.scala    From gospeak   with Apache License 2.0 5 votes vote down vote up
package gospeak.libs.openapi.models

import cats.data.NonEmptyList
import gospeak.libs.openapi.OpenApiUtils
import gospeak.libs.openapi.error.OpenApiError
import gospeak.libs.openapi.models.utils.{TODO, Version}
import gospeak.libs.scala.Extensions._


final case class OpenApi(openapi: Version,
                         info: Info,
                         externalDocs: Option[ExternalDoc],
                         servers: Option[List[Server]],
                         tags: Option[List[Tag]],
                         security: Option[TODO],
                         components: Option[Components],
                         paths: Map[Path, PathItem],
                         extensions: Option[TODO]) {
  def getSchemas: Schemas = components.flatMap(_.schemas).getOrElse(Schemas())

  def getErrors: List[OpenApiError] = {
    val s = getSchemas
    OpenApi.groupErrors(
      OpenApiUtils.validate("servers", servers.getOrElse(List()), s) ++
        components.map(_.getErrors(s)).getOrElse(List()).map(_.atPath(".components")) ++
        OpenApiUtils.validate("paths", paths.map { case (k, v) => (k.value, v) }, s) ++
        OpenApiUtils.noDuplicates[Tag]("tags", tags.getOrElse(List()), _.name) ++
        OpenApi.checkDuplicatedPaths(paths).map(_.atPath(".paths")) ++
        OpenApi.checkDuplicatedOperationIds(paths).map(_.atPath(".paths"))
    )
  }
}

object OpenApi {
  def checkDuplicatedPaths(paths: Map[Path, PathItem]): List[OpenApiError] =
    paths.keys
      .groupBy(_.mapVariables(_ => "?").value)
      .filter(_._2.size > 1)
      .values.flatMap(_.lastOption).toList
      .map(path => OpenApiError.duplicateValue(path.value).atPath(s".${path.value}"))

  def checkDuplicatedOperationIds(paths: Map[Path, PathItem]): List[OpenApiError] =
    paths.flatMap { case (path, item) =>
      item.operations.flatMap { case (key, op) =>
        op.operationId.map(id => (List(s".${path.value}", s".$key"), id))
      }
    }.toList.groupBy(_._2)
      .filter(_._2.size > 1)
      .values.flatMap(_.lastOption).toList
      .map { case (path, opId) => OpenApiError.duplicateValue(opId).atPath(path) }

  def groupErrors(errors: List[OpenApiError]): List[OpenApiError] =
    errors.groupBy(_.path).flatMap { case (path, errors) =>
      errors.toNel.map(errs => OpenApiError(path, errs.flatMap(_.errors))).toOption
    }.toList.sortBy(_.path.mkString)
} 
Example 162
Source File: DenormalizedMatchingRulesSpecification.scala    From matcher   with MIT License 4 votes vote down vote up
package com.wavesplatform.dex.model

import cats.data.NonEmptyList
import com.wavesplatform.dex.settings.DenormalizedMatchingRule
import com.wavesplatform.dex.{MatcherSpecBase, NoShrink}
import org.scalacheck.Gen
import org.scalatest.matchers.should.Matchers
import org.scalatest.propspec.AnyPropSpec
import org.scalatestplus.scalacheck.{ScalaCheckPropertyChecks => PropertyChecks}

class DenormalizedMatchingRulesSpecification extends AnyPropSpec with PropertyChecks with Matchers with MatcherSpecBase with NoShrink {
  property("skipOutdated: rules.head.startOffset <= currentOffset < rules(1).startOffset") {
    val g = for {
      currOffset <- currOffsetGen
      rules      <- rulesChainGen(5)
    } yield (currOffset, rules)

    forAll(g) {
      case (currOffset, rules) =>
        val updatedRules = DenormalizedMatchingRule.skipOutdated(currOffset, rules)
        updatedRules.toList match {
          case first :: Nil =>
            withClue(s"first.startOffset=${first.startOffset}, currOffset=$currOffset") {
              first.startOffset shouldBe <=(currOffset)
            }
          case first :: second :: _ =>
            withClue(s"first.startOffset=${first.startOffset}, currOffset=$currOffset") {
              first.startOffset shouldBe <=(currOffset)
            }
            withClue(s"currOffset=$currOffset, second.startOffset=${second.startOffset}") {
              currOffset shouldBe <(second.startOffset)
            }
          case xs => throw new IllegalStateException(s"$xs")
        }
    }
  }

  private val currOffsetGen = Gen.choose(0L, Long.MaxValue)

  private def nextRulesGen(prevRules: DenormalizedMatchingRule): Gen[Option[DenormalizedMatchingRule]] =
    if (prevRules.startOffset == Long.MaxValue) Gen.const(None)
    else
      for {
        startOffset <- Gen.choose(prevRules.startOffset + 1, Long.MaxValue)
        tickSize    <- Gen.choose(1, Double.MaxValue)
      } yield Some(DenormalizedMatchingRule(startOffset, tickSize))

  private val firstRuleGen: Gen[DenormalizedMatchingRule] = Gen.choose(1, Double.MaxValue).map(DenormalizedMatchingRule(0L, _))

  private def rulesChainGen(maxNumber: Int): Gen[NonEmptyList[DenormalizedMatchingRule]] = {
    def loop(rest: Int, acc: Gen[NonEmptyList[DenormalizedMatchingRule]]): Gen[NonEmptyList[DenormalizedMatchingRule]] =
      if (rest == 0) acc
      else
        for {
          xs <- acc
          x  <- nextRulesGen(xs.head)
          r  <- x.fold(Gen.const(xs))(x => loop(rest - 1, Gen.const(x :: xs)))
        } yield r

    Gen.lzy(loop(maxNumber, firstRuleGen.map(NonEmptyList.one)).map(_.reverse))
  }
}