Skip to content

Commit

Permalink
Refactor to add date typeaheads to field keys
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathonherbert committed Jul 12, 2024
1 parent 33d1a20 commit 520a8e4
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 59 deletions.
15 changes: 10 additions & 5 deletions src/main/scala/Handler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ class Handler

val guardianContentClient = new GuardianContentClient("test")
val typeaheadHelpers = new TypeaheadHelpersCapi(guardianContentClient)
val typeahead = new Typeahead(typeaheadHelpers.fieldResolvers, typeaheadHelpers.outputModifierResolvers)

val typeahead = new Typeahead(
typeaheadHelpers.fieldResolvers,
typeaheadHelpers.outputModifierResolvers
)

private val cql = new Cql(typeahead)

def handleRequest(
Expand Down Expand Up @@ -76,9 +79,11 @@ class Handler
logger.info(s"Responding with status ${statusCode}: ${responseBody}")

new APIGatewayProxyResponseEvent()
.withHeaders(Map(
"Access-Control-Allow-Origin" -> "*"
).asJava)
.withHeaders(
Map(
"Access-Control-Allow-Origin" -> "*"
).asJava
)
.withStatusCode(statusCode)
.withBody(
responseBody
Expand Down
5 changes: 4 additions & 1 deletion src/main/scala/HttpServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import com.gu.contentapi.client.GuardianContentClient
object HttpServer extends QueryJson {
val guardianContentClient = new GuardianContentClient("test")
val typeaheadHelpers = new TypeaheadHelpersCapi(guardianContentClient)
val typeahead = new Typeahead(typeaheadHelpers.fieldResolvers, typeaheadHelpers.outputModifierResolvers)
val typeahead = new Typeahead(
typeaheadHelpers.fieldResolvers,
typeaheadHelpers.outputModifierResolvers
)

val cql = new Cql(typeahead)

Expand Down
8 changes: 5 additions & 3 deletions src/main/scala/lang/CapiQueryString.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ object CapiQueryString {
program: QueryList
): String =
val (searchStrs, otherQueries) = program.exprs.partitionMap {
case q: QueryBinary => Left(strFromBinary(q))
case QueryField(key, Some(value)) => Right(s"${key.literal.getOrElse("")}=${value.literal.getOrElse("")}")
case q: QueryBinary => Left(strFromBinary(q))
case QueryField(key, Some(value)) =>
Right(s"${key.literal.getOrElse("")}=${value.literal.getOrElse("")}")
case QueryField(key, None) =>
throw new CapiQueryStringError(
s"The field '+$key' needs a value after it (e.g. +$key:tone/news)"
)
case QueryOutputModifier(key, Some(value)) => Right(s"${key.literal.getOrElse("")}=${value.literal.getOrElse("")}")
case QueryOutputModifier(key, Some(value)) =>
Right(s"${key.literal.getOrElse("")}=${value.literal.getOrElse("")}")
case QueryOutputModifier(key, None) =>
throw new CapiQueryStringError(
s"The output modifier '@$key' needs a value after it (e.g. +$key:all)"
Expand Down
4 changes: 3 additions & 1 deletion src/main/scala/lang/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ class Parser(tokens: List[Token]):
else if (startOfQueryOutputModifier.contains(peek().tokenType))
queryOutputModifier
else if (startOfQueryValue.contains(peek().tokenType))
throw new ParseError("I found an unexpected ':'. Did you intend to search for a tag, section or similar, e.g. tag:news? If you would like to add a search phrase containing a ':' character, please surround it in double quotes.")
throw new ParseError(
"I found an unexpected ':'. Did you intend to search for a tag, section or similar, e.g. tag:news? If you would like to add a search phrase containing a ':' character, please surround it in double quotes."
)
else queryBinary

private def queryBinary =
Expand Down
82 changes: 45 additions & 37 deletions src/main/scala/lang/Typeahead.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ case class TypeaheadSuggestion(
suggestions: Suggestions
)


sealed trait Suggestions

case class TextSuggestion(suggestions: List[TextSuggestionOption])
Expand Down Expand Up @@ -80,44 +79,41 @@ class Typeahead(
}
.map(_.flatten)

private def getSuggestionsForKeyToken(keyToken: Token) =
Future.successful(suggestFieldKey(keyToken.literal.getOrElse("")).map {
suggestions =>
TypeaheadSuggestion(
keyToken.start,
keyToken.end,
":",
suggestions
)
}.toList)

private def suggestQueryField(
q: QueryField
): Future[List[TypeaheadSuggestion]] =
q match {
case QueryField(keyToken, None) =>
Future.successful(
List(
TypeaheadSuggestion(
keyToken.start,
keyToken.end,
":",
suggestFieldKey(keyToken.literal.getOrElse(""))
)
)
)
getSuggestionsForKeyToken(keyToken)
case QueryField(keyToken, Some(valueToken)) =>
val keySuggestions = Future.successful(
TypeaheadSuggestion(
keyToken.start,
keyToken.end,
":",
suggestFieldKey(keyToken.literal.getOrElse(""))
)
)
val keySuggestions = getSuggestionsForKeyToken(keyToken)
val valueSuggestions =
suggestFieldValue(
keyToken.literal.getOrElse(""),
valueToken.literal.getOrElse("")
)
.map { suggestions =>
TypeaheadSuggestion(
valueToken.start,
valueToken.end,
" ",
TextSuggestion(suggestions)
)
.map {
_.map { suggestions =>
TypeaheadSuggestion(
valueToken.start,
valueToken.end,
" ",
suggestions
)
}
}
Future.sequence(List(keySuggestions, valueSuggestions))
Future.sequence(List(keySuggestions, valueSuggestions)).map(_.flatten)
}

private def suggestQueryOutputModifier(
Expand All @@ -137,7 +133,6 @@ class Typeahead(
)
}
case QueryOutputModifier(keyToken, Some(valueToken)) =>

val keySuggestion = suggestOutputModifierKey(
keyToken.literal.getOrElse("")
).map { suggestion =>
Expand All @@ -163,23 +158,36 @@ class Typeahead(
Future.sequence(List(keySuggestion, valueSuggestion))
}

private def suggestFieldKey(str: String): TextSuggestion =
private def suggestFieldKey(str: String): Option[TextSuggestion] =
str match
case "" => typeaheadFieldEntries
case "" => Some(typeaheadFieldEntries)
case str =>
typeaheadFieldEntries.copy(
suggestions = typeaheadFieldEntries.suggestions
.filter(_.value.contains(str.toLowerCase()))
)
typeaheadFieldEntries.suggestions
.filter(_.value.contains(str.toLowerCase())) match {
case suggestions @ nonEmptyList :: Nil =>
Some(
typeaheadFieldEntries.copy(
suggestions = suggestions
)
)
case _ => None
}

private def suggestFieldValue(
key: String,
str: String
): Future[List[TextSuggestionOption]] =
): Future[Option[Suggestions]] =
fieldResolvers
.find(_.id == key)
.map(_.resolveSuggestions(str))
.getOrElse(Future.successful(List.empty))
.map {
case typeaheadField if typeaheadField.suggestionType == "DATE" =>
Future.successful(Some(DateSuggestion(None, None)))
case textField =>
textField
.resolveSuggestions(str)
.map(options => Some(TextSuggestion(options)))
}
.getOrElse(Future.successful(None))

private def suggestOutputModifierKey(str: String): Future[TextSuggestion] =
Future.successful(
Expand Down
24 changes: 20 additions & 4 deletions src/main/scala/lang/TypeaheadHelpersCapi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ class TypeaheadHelpersCapi(client: GuardianContentClient) {
"Section",
"Search by content sections, e.g. section/news",
getSections
),
TypeaheadField(
"from-date",
"From date",
"The date to search from",
List.empty,
"DATE"
),
TypeaheadField(
"to-date",
"To date",
"The date to search to",
List.empty,
"DATE"
)
)

Expand Down Expand Up @@ -79,9 +93,7 @@ class TypeaheadHelpersCapi(client: GuardianContentClient) {
),
TextSuggestionOption("starRating", "starRating", "Description")
)
),
TypeaheadField("from-date", "From date", "The date to search from", List.empty),
TypeaheadField("to-date","To date", "The date to search to", List.empty)
)
)

private def getTags(str: String): Future[List[TextSuggestionOption]] =
Expand All @@ -90,7 +102,11 @@ class TypeaheadHelpersCapi(client: GuardianContentClient) {
case str => ContentApiClient.tags.q(str)
client.getResponse(query).map { response =>
response.results.map { tag =>
TextSuggestionOption(tag.webTitle, tag.id, tag.description.getOrElse(""))
TextSuggestionOption(
tag.webTitle,
tag.id,
tag.description.getOrElse("")
)
}.toList
}

Expand Down
9 changes: 1 addition & 8 deletions src/test/scala/lang/TypeaheadTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,7 @@ class TypeaheadTest extends BaseTest {
QueryList(List(queryField("example", None)))
)
.map { result =>
result shouldBe List(
TypeaheadSuggestion(
0,
7,
":",
TextSuggestion(List.empty)
)
)
result shouldBe List.empty
}
}

Expand Down

0 comments on commit 520a8e4

Please sign in to comment.