Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: using ducktape for object transformation #31

Merged
merged 1 commit into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ lazy val commons = project
Dependencies.borer ++
Dependencies.catsCore ++
Dependencies.catsEffect ++
Dependencies.ducktape ++
Dependencies.fs2Core ++
Dependencies.scodecBits ++
Dependencies.scribe,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package io.renku.search.model
import cats.kernel.Order
import io.bullet.borer.derivation.MapBasedCodecs.*
import io.bullet.borer.{Codec, Decoder, Encoder}
import io.github.arainko.ducktape.*
import io.renku.search.borer.codecs.all.given

import java.time.Instant
Expand All @@ -31,24 +32,28 @@ object projects:
object Id:
def apply(v: String): Id = v
extension (self: Id) def value: String = self
given Transformer[String, Id] = apply
given Codec[Id] = Codec.of[String]

opaque type Name = String
object Name:
def apply(v: String): Name = v
extension (self: Name) def value: String = self
given Transformer[String, Name] = apply
given Codec[Name] = Codec.of[String]

opaque type Slug = String
object Slug:
def apply(v: String): Slug = v
extension (self: Slug) def value: String = self
given Transformer[String, Slug] = apply
given Codec[Slug] = Codec.of[String]

opaque type Repository = String
object Repository:
def apply(v: String): Repository = v
extension (self: Repository) def value: String = self
given Transformer[String, Repository] = apply
given Codec[Repository] = Codec.of[String]

opaque type Description = String
Expand All @@ -62,12 +67,14 @@ object projects:
}
}
extension (self: Description) def value: String = self
given Transformer[String, Description] = apply
given Codec[Description] = Codec.of[String]

opaque type CreationDate = Instant
object CreationDate:
def apply(v: Instant): CreationDate = v
extension (self: CreationDate) def value: Instant = self
given Transformer[Instant, CreationDate] = apply
given Codec[CreationDate] = Codec.of[Instant]

enum Visibility derives Codec:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
package io.renku.search.model

import io.bullet.borer.Codec
import io.github.arainko.ducktape.Transformer

object users:

opaque type Id = String
object Id:
def apply(v: String): Id = v
extension (self: Id) def value: String = self
given Transformer[String, Id] = apply
given Codec[Id] = Codec.bimap[String, Id](_.value, Id.apply)
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ package io.renku.search.api

import cats.effect.Async
import cats.syntax.all.*
import io.github.arainko.ducktape.*
import io.renku.search.api.data.*
import io.renku.search.solr.client.SearchSolrClient
import io.renku.search.solr.documents.{Project as SolrProject, User as SolrUser}
import io.renku.search.solr.documents.Project as SolrProject
import io.renku.solr.client.QueryResponse
import org.http4s.dsl.Http4sDsl
import scribe.Scribe
import io.renku.search.api.data.*
import io.renku.solr.client.QueryResponse

private class SearchApiImpl[F[_]: Async](solrClient: SearchSolrClient[F])
extends Http4sDsl[F]
Expand All @@ -51,25 +52,11 @@ private class SearchApiImpl[F[_]: Async](solrClient: SearchSolrClient[F])
.as(message)
.map(_.asLeft[SearchResult])

private def toApiProject(p: SolrProject): SearchEntity =
def toUser(user: SolrUser): User = User(user.id)
Project(
p.id,
p.name,
p.slug,
p.repositories,
p.visibility,
p.description,
toUser(p.createdBy),
p.creationDate,
p.members.map(toUser)
)

private def toApiResult(currentPage: PageDef)(
solrResult: QueryResponse[SolrProject]
): SearchResult =
val hasMore = solrResult.responseBody.docs.size > currentPage.limit
val pageInfo = PageWithTotals(currentPage, solrResult.responseBody.numFound, hasMore)
val items = solrResult.responseBody.docs.map(toApiProject)
val items = solrResult.responseBody.docs.map(_.to[Project])
if (hasMore) SearchResult(items.init, pageInfo)
else SearchResult(items, pageInfo)
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import cats.effect.{Async, Resource, Temporal}
import cats.syntax.all.*
import fs2.Chunk
import fs2.io.net.Network
import io.github.arainko.ducktape.*
import io.renku.avro.codec.AvroReader
import io.renku.avro.codec.decoders.all.given
import io.renku.events.v1.ProjectCreated
import io.renku.events.v1
import io.renku.events.v1.{ProjectCreated, Visibility}
import io.renku.queue.client.*
import io.renku.redis.client.{ClientId, QueueName, RedisConfig}
import io.renku.search.model.*
Expand Down Expand Up @@ -126,23 +128,12 @@ private class SearchProvisionerImpl[F[_]: Async](
.onError(markProcessedOnFailure(lastMessage, queueClient))
}

private given Transformer[String, User] = (from: String) => User(users.Id(from))
private given Transformer[v1.Visibility, projects.Visibility] =
(from: v1.Visibility) => projects.Visibility.unsafeFromString(from.name())

private lazy val toSolrDocuments: Seq[ProjectCreated] => Seq[Project] =
_.map { pc =>

def toUser(id: String): User = User(users.Id(id))

Project(
projects.Id(pc.id),
projects.Name(pc.name),
projects.Slug(pc.slug),
pc.repositories.map(projects.Repository(_)),
projects.Visibility.unsafeFromString(pc.visibility.name()),
pc.description.map(projects.Description(_)),
toUser(pc.createdBy),
projects.CreationDate(pc.creationDate),
pc.members.map(toUser)
)
}
_.map(_.to[Project])

private def markProcessedOnFailure(
message: QueueMessage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,4 @@ class SearchProvisionerSpec extends CatsEffectSuite with QueueSpec with SearchSo
)

override def munitFixtures: Seq[Fixture[_]] =
List(withQueueClient, withSearchSolrClient)
List(withRedisClient, withQueueClient, withSearchSolrClient)
5 changes: 5 additions & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ object Dependencies {
val catsParse = "1.0.0"
val catsScalaCheck = "0.3.2"
val ciris = "3.5.0"
val ducktape = "0.1.11"
val fs2 = "3.9.4"
val http4s = "0.23.25"
val luceneQueryParser = "9.9.2"
Expand Down Expand Up @@ -81,6 +82,10 @@ object Dependencies {
"org.typelevel" %% "munit-cats-effect-3" % V.catsEffectMunit
)

val ducktape = Seq(
"io.github.arainko" %% "ducktape" % V.ducktape
)

val fs2Core = Seq(
"co.fs2" %% "fs2-core" % V.fs2
)
Expand Down
Loading