forked from lichess-org/lila
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DataForm.scala
124 lines (112 loc) · 4.35 KB
/
DataForm.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package lila.gameSearch
import chess.{ Mode }
import org.joda.time.DateTime
import play.api.data._
import play.api.data.Forms._
import lila.common.Form._
import lila.search.Range
private[gameSearch] final class DataForm {
val search = Form(mapping(
"players" -> mapping(
"a" -> optional(nonEmptyText),
"b" -> optional(nonEmptyText),
"winner" -> optional(nonEmptyText),
"white" -> optional(nonEmptyText),
"black" -> optional(nonEmptyText)
)(SearchPlayer.apply)(SearchPlayer.unapply),
"winnerColor" -> optional(numberIn(Query.winnerColors)),
"perf" -> optional(numberIn(Query.perfs)),
"source" -> optional(numberIn(Query.sources)),
"mode" -> optional(numberIn(Query.modes)),
"opening" -> optional(stringIn(Query.openings)),
"turnsMin" -> optional(numberIn(Query.turns)),
"turnsMax" -> optional(numberIn(Query.turns)),
"ratingMin" -> optional(numberIn(Query.averageRatings)),
"ratingMax" -> optional(numberIn(Query.averageRatings)),
"hasAi" -> optional(numberIn(Query.hasAis)),
"aiLevelMin" -> optional(numberIn(Query.aiLevels)),
"aiLevelMax" -> optional(numberIn(Query.aiLevels)),
"durationMin" -> optional(numberIn(Query.durations)),
"durationMax" -> optional(numberIn(Query.durations)),
"dateMin" -> optional(stringIn(Query.dates)),
"dateMax" -> optional(stringIn(Query.dates)),
"status" -> optional(numberIn(Query.statuses)),
"analysed" -> optional(number),
"sort" -> mapping(
"field" -> stringIn(Sorting.fields),
"order" -> stringIn(Sorting.orders)
)(SearchSort.apply)(SearchSort.unapply)
)(SearchData.apply)(SearchData.unapply)) fill SearchData()
}
private[gameSearch] case class SearchData(
players: SearchPlayer = SearchPlayer(),
winnerColor: Option[Int] = None,
perf: Option[Int] = None,
source: Option[Int] = None,
mode: Option[Int] = None,
opening: Option[String] = None,
turnsMin: Option[Int] = None,
turnsMax: Option[Int] = None,
ratingMin: Option[Int] = None,
ratingMax: Option[Int] = None,
hasAi: Option[Int] = None,
aiLevelMin: Option[Int] = None,
aiLevelMax: Option[Int] = None,
durationMin: Option[Int] = None,
durationMax: Option[Int] = None,
dateMin: Option[String] = None,
dateMax: Option[String] = None,
status: Option[Int] = None,
analysed: Option[Int] = None,
sort: SearchSort = SearchSort()) {
def query = Query(
user1 = players.cleanA,
user2 = players.cleanB,
winner = players.cleanWinner,
winnerColor = winnerColor,
perf = perf,
source = source,
rated = mode flatMap Mode.apply map (_.rated),
opening = opening map (_.trim.toLowerCase),
turns = Range(turnsMin, turnsMax),
averageRating = Range(ratingMin, ratingMax),
hasAi = hasAi map (_ == 1),
aiLevel = Range(aiLevelMin, aiLevelMax),
duration = Range(durationMin, durationMax),
date = Range(dateMin flatMap toDate, dateMax flatMap toDate),
status = status,
analysed = analysed map (_ == 1),
whiteUser = players.cleanWhite,
blackUser = players.cleanBlack,
sorting = Sorting(sort.field, sort.order))
def nonEmptyQuery = {
val q = query
q.nonEmpty option q
}
private val DateDelta = """^(\d+)(\w)$""".r
private def toDate(delta: String): Option[DateTime] = delta match {
case DateDelta(n, "h") => parseIntOption(n) map DateTime.now.minusHours
case DateDelta(n, "d") => parseIntOption(n) map DateTime.now.minusDays
case DateDelta(n, "w") => parseIntOption(n) map DateTime.now.minusWeeks
case DateDelta(n, "m") => parseIntOption(n) map DateTime.now.minusMonths
case DateDelta(n, "y") => parseIntOption(n) map DateTime.now.minusYears
case _ => None
}
}
private[gameSearch] case class SearchPlayer(
a: Option[String] = None,
b: Option[String] = None,
winner: Option[String] = None,
white: Option[String] = None,
black: Option[String] = None) {
lazy val cleanA = clean(a)
lazy val cleanB = clean(b)
def cleanWinner = oneOf(winner)
def cleanWhite = oneOf(white)
def cleanBlack = oneOf(black)
private def oneOf(s: Option[String]) = clean(s).filter(List(cleanA, cleanB).flatten.contains)
private def clean(s: Option[String]) = s map (_.trim.toLowerCase) filter (_.nonEmpty)
}
private[gameSearch] case class SearchSort(
field: String = Sorting.default.f,
order: String = Sorting.default.order)