Skip to content

Commit

Permalink
Cross compiling core module with scala 3
Browse files Browse the repository at this point in the history
  • Loading branch information
lenguyenthanh committed May 8, 2024
1 parent fbbe911 commit 8e074b4
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 102 deletions.
16 changes: 13 additions & 3 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
version = "3.5.8"
version = "3.8.1"
runner.dialect = scala213

align.preset = more
maxColumn = 110
spaces.inImportCurlyBraces = true
rewrite.rules = [SortImports, RedundantParens, SortModifiers]
rewrite.rules = [SortModifiers]
rewrite.redundantBraces.stringInterpolation = true
runner.dialect = scala213
rewrite.rules = [AvoidInfix]
fileOverride {
"glob:**/build.sbt" {
runner.dialect = scala213
}
"glob:**/project/**" {
runner.dialect = scala213
}
}
12 changes: 9 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import org.typelevel.scalacoptions.ScalacOption
import org.typelevel.scalacoptions.ScalacOptions

lazy val scala213 = "2.13.14"
lazy val scala3 = "3.4.1"
lazy val supportedScalaVersions = List(scala213, scala3)

inThisBuild(
Seq(
scalaVersion := "2.13.14",
scalaVersion := scala213,
versionScheme := Some("early-semver"),
version := "3.0.0-SNAPSHOT",
run / fork := true,
Expand All @@ -21,9 +26,10 @@ lazy val core = project
.in(file("modules/core"))
.settings(
commonSettings,
name := "core",
crossScalaVersions := supportedScalaVersions,
tpolecatScalacOptions ++= Set(ScalacOptions.source3),
name := "lila-search-core",
libraryDependencies ++= Seq(
"com.github.ornicar" %% "scalalib" % "7.1.0",
"com.sksamuel.elastic4s" %% "elastic4s-client-esjava" % "8.11.5",
"joda-time" % "joda-time" % "2.12.7"
)
Expand Down
42 changes: 26 additions & 16 deletions modules/core/src/main/scala/ESClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,44 @@ final class ESClient(client: ElasticClient)(implicit ec: ExecutionContext) {
response.fold[Future[A]](Future.failed(new Exception(response.error.reason)))(Future.successful)

def search[A](index: Index, query: A, from: From, size: Size)(implicit q: Queryable[A]) =
client execute {
q.searchDef(query)(from, size)(index)
} flatMap toResult map SearchResponse.apply
client
.execute {
q.searchDef(query)(from, size)(index)
}
.flatMap(toResult)
.map(SearchResponse.apply)

def count[A](index: Index, query: A)(implicit q: Queryable[A]) =
client execute {
q.countDef(query)(index)
} flatMap toResult map CountResponse.apply
client
.execute {
q.countDef(query)(index)
}
.flatMap(toResult)
.map(CountResponse.apply)

def store(index: Index, id: Id, obj: JsonObject) =
client execute {
indexInto(index.name) source obj.json id id.value
client.execute {
indexInto(index.name).source(obj.json).id(id.value)
}

def storeBulk(index: Index, objs: List[(String, JsonObject)]) =
if (objs.isEmpty) funit
else
client execute {
client.execute {
ElasticDsl.bulk {
objs.map { case (id, obj) =>
indexInto(index.name) source obj.json id id
indexInto(index.name).source(obj.json).id(id)
}
}
}

def deleteOne(index: Index, id: Id) =
client execute {
client.execute {
deleteById(index.toES, id.value)
}

def deleteMany(index: Index, ids: List[Id]) =
client execute {
client.execute {
ElasticDsl.bulk {
ids.map { id =>
deleteById(index.toES, id.value)
Expand All @@ -58,15 +64,19 @@ final class ESClient(client: ElasticClient)(implicit ec: ExecutionContext) {

def putMapping(index: Index, fields: Seq[ElasticField]) =
dropIndex(index) >> client.execute {
createIndex(index.name).mapping(
properties(fields) source false // all false
) shards 5 replicas 0 refreshInterval Which.refreshInterval(index)
createIndex(index.name)
.mapping(
properties(fields).source(false) // all false
)
.shards(5)
.replicas(0)
.refreshInterval(Which.refreshInterval(index))
}

def refreshIndex(index: Index) =
client
.execute {
ElasticDsl refreshIndex index.name
ElasticDsl.refreshIndex(index.name)
}
.void
.recover { case _: Exception =>
Expand Down
16 changes: 9 additions & 7 deletions modules/core/src/main/scala/Queryable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ trait Queryable[A] {

case class ParsedQuery(terms: List[String], filters: Map[String, String]) {

def apply(fk: String): Option[String] = filters get fk
def apply(fk: String): Option[String] = filters.get(fk)
}

object QueryParser {
Expand All @@ -23,12 +23,14 @@ object QueryParser {
val terms = spaceRegex.split(q.trim.toLowerCase).toList

terms.foldLeft(ParsedQuery(Nil, Map.empty)) { case (parsed, term) =>
filterKeys.collectFirst {
case fk if term startsWith s"$fk:" =>
parsed.copy(
filters = parsed.filters + (fk -> term.drop(fk.size + 1))
)
} getOrElse parsed.copy(terms = parsed.terms :+ term)
filterKeys
.collectFirst {
case fk if term.startsWith(s"$fk:") =>
parsed.copy(
filters = parsed.filters + (fk -> term.drop(fk.size + 1))
)
}
.getOrElse(parsed.copy(terms = parsed.terms :+ term))
}
}
}
8 changes: 4 additions & 4 deletions modules/core/src/main/scala/Range.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import com.sksamuel.elastic4s.ElasticDsl._
final class Range[A] private (val a: Option[A], val b: Option[A]) {

def queries(name: String) =
a.fold(b.toList map { bb => rangeQuery(name) lte bb.toString }) { aa =>
b.fold(List(rangeQuery(name) gte aa.toString)) { bb =>
List(rangeQuery(name) gte aa.toString lte bb.toString)
a.fold(b.toList.map { bb => rangeQuery(name).lte(bb.toString) }) { aa =>
b.fold(List(rangeQuery(name).gte(aa.toString))) { bb =>
List(rangeQuery(name).gte(aa.toString).lte(bb.toString))
}
}

def map[B](f: A => B) = new Range(a map f, b map f)
def map[B](f: A => B) = new Range(a.map(f), b.map(f))

def nonEmpty = a.nonEmpty || b.nonEmpty
}
Expand Down
17 changes: 10 additions & 7 deletions modules/core/src/main/scala/forum.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,23 @@ object ForumQuery {

def searchDef(query: Forum)(from: From, size: Size) =
index =>
search(index.name) query makeQuery(query) sortBy (
fieldSort(Fields.date) order SortOrder.DESC
) start from.value size size.value
search(index.name)
.query(makeQuery(query))
.sortBy(
fieldSort(Fields.date).order(SortOrder.DESC)
)
.start(from.value) size size.value

def countDef(query: Forum) = index => search(index.name) query makeQuery(query) size 0
def countDef(query: Forum) = index => search(index.name).query(makeQuery(query)) size 0

private def parsed(text: String) = QueryParser(text, List("user"))

private def makeQuery(query: Forum) = boolQuery().must(
parsed(query.text).terms.map { term =>
multiMatchQuery(term) fields (searchableFields: _*)
multiMatchQuery(term).fields(searchableFields*)
} ::: List(
parsed(query.text)("user") map { termQuery(Fields.author, _) },
!query.troll option termQuery(Fields.troll, false)
parsed(query.text)("user").map { termQuery(Fields.author, _) },
(!query.troll).option(termQuery(Fields.troll, false))
).flatten
)
}
Expand Down
35 changes: 19 additions & 16 deletions modules/core/src/main/scala/game.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,41 +57,44 @@ object GameQuery {

def searchDef(query: Game)(from: From, size: Size) =
index =>
search(index.name).query(
makeQuery(query)
) sortBy query.sorting.definition start from.value size size.value timeout timeout
(search(index.name)
.query(
makeQuery(query)
)
.sortBy(query.sorting.definition)
.start(from.value) size size.value).timeout(timeout)

def countDef(query: Game) = index => search(index.name) query makeQuery(query) size 0 timeout timeout
def countDef(query: Game) = index => (search(index.name).query(makeQuery(query)) size 0).timeout(timeout)

private def makeQuery(query: Game) = {

import query._
def usernames = List(user1, user2).flatten

def hasAiQueries =
hasAi.toList map { a =>
hasAi.toList.map { a =>
a.fold(existsQuery(Fields.ai), not(existsQuery(Fields.ai)))
}

def toQueries(query: Option[_], name: String) =
query.toList map {
def toQueries(query: Option[?], name: String) =
query.toList.map {
case s: String => termQuery(name, s.toLowerCase)
case x => termQuery(name, x)
}

List(
usernames map { termQuery(Fields.uids, _) },
usernames.map { termQuery(Fields.uids, _) },
toQueries(winner, Fields.winner),
toQueries(loser, Fields.loser),
toQueries(winnerColor, Fields.winnerColor),
turns queries Fields.turns,
averageRating queries Fields.averageRating,
duration queries Fields.duration,
clock.init queries Fields.clockInit,
clock.inc queries Fields.clockInc,
date map Date.formatter.print queries Fields.date,
turns.queries(Fields.turns),
averageRating.queries(Fields.averageRating),
duration.queries(Fields.duration),
clock.init.queries(Fields.clockInit),
clock.inc.queries(Fields.clockInc),
date.map(Date.formatter.print).queries(Fields.date),
hasAiQueries,
(hasAi | true).fold(aiLevel queries Fields.ai, Nil),
(hasAi.getOrElse(true)).fold(aiLevel.queries(Fields.ai), Nil),
if (perf.nonEmpty) List(termsQuery(Fields.perf, perf)) else Nil,
toQueries(source, Fields.source),
toQueries(rated, Fields.rated),
Expand All @@ -113,7 +116,7 @@ case class Sorting(f: String, order: String) {
def definition =
fieldSort {
(Sorting.fieldKeys contains f).fold(f, Sorting.default.f)
} order (order.toLowerCase == "asc").fold(SortOrder.ASC, SortOrder.DESC)
}.order((order.toLowerCase == "asc").fold(SortOrder.ASC, SortOrder.DESC))
}

object Sorting {
Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/main/scala/model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ case class SearchResponse(hitIds: List[String])
object SearchResponse {

def apply(res: ESR): SearchResponse =
SearchResponse(res.hits.hits.toList map (_.id))
SearchResponse(res.hits.hits.toList.map(_.id))
}

case class CountResponse(count: Int)
Expand Down
19 changes: 6 additions & 13 deletions modules/core/src/main/scala/package.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package lila

import alleycats.Zero
import scala.concurrent.Future
import scala.concurrent.ExecutionContext

Expand All @@ -9,31 +8,31 @@ package object search {
object Date {
import org.joda.time.format.{ DateTimeFormat, DateTimeFormatter }
val format = "yyyy-MM-dd HH:mm:ss"
val formatter: DateTimeFormatter = DateTimeFormat forPattern format
val formatter: DateTimeFormatter = DateTimeFormat.forPattern(format)
}

// fix scala

type Fu[+A] = Future[A]
type Funit = Fu[Unit]

def fuccess[A](a: A) = Future successful a
def fufail[A <: Throwable, B](a: A): Fu[B] = Future failed a
def fuccess[A](a: A) = Future.successful(a)
def fufail[A <: Throwable, B](a: A): Fu[B] = Future.failed(a)
def fufail[A](a: String): Fu[A] = fufail(new Exception(a))
val funit = fuccess(())

implicit final class LilaPimpedFuture[A](fua: Fu[A]) {

def >>-(sideEffect: => Unit)(implicit ec: ExecutionContext): Fu[A] =
fua andThen { case _ =>
fua.andThen { case _ =>
sideEffect
}

def >>[B](fub: => Fu[B])(implicit ec: ExecutionContext): Fu[B] = fua flatMap (_ => fub)
def >>[B](fub: => Fu[B])(implicit ec: ExecutionContext): Fu[B] = fua.flatMap(_ => fub)

def void: Funit = fua.map(_ => ())(ExecutionContext.parasitic)

def inject[B](b: => B)(implicit ec: ExecutionContext): Fu[B] = fua map (_ => b)
def inject[B](b: => B)(implicit ec: ExecutionContext): Fu[B] = fua.map(_ => b)
}

implicit class LilaPimpedBoolean(self: Boolean) {
Expand All @@ -43,10 +42,4 @@ package object search {
def option[A](a: => A): Option[A] = if (self) Some(a) else None
}

implicit class LilaPimpedOption[A](self: Option[A]) {

def |(a: => A): A = self getOrElse a

def unary_~(implicit z: Zero[A]): A = self getOrElse z.zero
}
}
19 changes: 10 additions & 9 deletions modules/core/src/main/scala/study.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ object StudyQuery {
search(index.name)
.query(makeQuery(query))
.sortBy(
fieldSort("_score") order SortOrder.DESC,
fieldSort(Fields.likes) order SortOrder.DESC
) start from.value size size.value
fieldSort("_score").order(SortOrder.DESC),
fieldSort(Fields.likes).order(SortOrder.DESC)
)
.start(from.value) size size.value

def countDef(query: Study) = index => search(index.name) query makeQuery(query) size 0
def countDef(query: Study) = index => search(index.name).query(makeQuery(query)) size 0

private def parsed(text: String) = QueryParser(text, List("owner", "member"))

Expand All @@ -55,12 +56,12 @@ object StudyQuery {
if (parsed(query.text).terms.isEmpty) matchAllQuery()
else
multiMatchQuery(
parsed(query.text).terms mkString " "
) fields (searchableFields: _*) analyzer "english" matchType "most_fields"
parsed(query.text).terms.mkString(" ")
).fields(searchableFields*).analyzer("english").matchType("most_fields")
must {
matcher :: List(
parsed(query.text)("owner") map { termQuery(Fields.owner, _) },
parsed(query.text)("member") map { member =>
parsed(query.text)("owner").map { termQuery(Fields.owner, _) },
parsed(query.text)("member").map { member =>
boolQuery()
.must(termQuery(Fields.members, member))
.not(termQuery(Fields.owner, member))
Expand All @@ -70,7 +71,7 @@ object StudyQuery {
Some(selectPublic),
query.userId.map(selectUserId)
).flatten
} minimumShouldMatch 1
}.minimumShouldMatch(1)

private val selectPublic = termQuery(Fields.public, true)

Expand Down
Loading

0 comments on commit 8e074b4

Please sign in to comment.