Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import de.upb.cs.swt.delphi.webapi.FeatureJson._
import de.upb.cs.swt.delphi.webapi.IpLogActor._
import de.upb.cs.swt.delphi.webapi.StatisticsJson._
import de.upb.cs.swt.delphi.webapi.search.QueryRequestJson._
import de.upb.cs.swt.delphi.webapi.search.{QueryRequest, SearchError, SearchQuery}
import de.upb.cs.swt.delphi.webapi.search.{InvalidQueryError, QueryRequest, SearchError, SearchQuery}
import spray.json._

import scala.concurrent.duration._
Expand Down Expand Up @@ -113,6 +113,9 @@ class DelphiRoutes(requestLimiter: RequestLimitScheduler) extends JsonSupport wi
case se: SearchError => {
HttpResponse(StatusCodes.ServerError(StatusCodes.InternalServerError.intValue)(se.toJson.toString(), ""))
}
case iqe: InvalidQueryError => {
HttpResponse(StatusCodes.ClientError(StatusCodes.BadRequest.intValue)(iqe.toJson.toString(), ""))
}
case _ => {
HttpResponse(StatusCodes.ServerError(StatusCodes.InternalServerError.intValue)("Search query failed", ""))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import scala.io.{Codec, Source}
import scala.util.{Failure, Success, Try}
import spray.json._
import de.upb.cs.swt.delphi.webapi.FeatureJson._
import org.parboiled2.{ParseError, Position}


class SearchQuery(configuration: Configuration, featureExtractor: FeatureQuery) {
Expand All @@ -52,7 +53,7 @@ class SearchQuery(configuration: Configuration, featureExtractor: FeatureQuery)
val publicFieldNames = internalFeatures.map(i => i.name)
val invalidFields = fields.toSet.filter(f => !publicFieldNames.contains(f))

if (invalidFields.size > 0) return Failure(new IllegalArgumentException(s"Unknown field name(s) used. (${invalidFields.mkString(",")})"))
if (invalidFields.size > 0) return Failure(new InvalidQueryFieldsError(parsedQuery.toString, invalidFields))

val translatedFields = fields.toSet.map(externalToInternalFeature(_))
def getPrefix (in: String) : String = {
Expand Down Expand Up @@ -80,7 +81,7 @@ class SearchQuery(configuration: Configuration, featureExtractor: FeatureQuery)

response match {
case RequestSuccess(_, body, _, result) => Success(result.hits)
case r => Failure(new IllegalArgumentException(r.toString))
case r => Failure(new SearchError(f"Failed to query database: ${r.toString}"))
}
}

Expand Down Expand Up @@ -166,18 +167,26 @@ class SearchQuery(configuration: Configuration, featureExtractor: FeatureQuery)
val validSize = size.exists(query.limit.getOrElse(defaultFetchSize) <= _)
if (validSize) {
val parserResult = new Syntax(query.query).QueryRule.run()

parserResult match {
case Failure(e) => Failure(e)
case Failure(ParseError(Position(_, line, column), _, _)) =>
Failure(new InvalidQueryError(f"Syntax error in query (near line $line, column $column)", query.query))
case Failure(e) =>
Failure(e)
case Success(parsedQuery) => {
checkAndExecuteParsedQuery(parsedQuery, query.limit.getOrElse(defaultFetchSize)) match {
case Failure(e) if e.isInstanceOf[InvalidQueryFieldsError] =>
// Required to set a valid 'query' attribute to the error
Failure(new InvalidQueryFieldsError(query.query, e.asInstanceOf[InvalidQueryFieldsError].invalidFields))
case Failure(e) => Failure(e)
case Success(hits) => Success(ArtifactTransformer.transformResults(hits))
}
}
}
}
else {
val errorMsg = new SearchError(s"Query limit exceeded default limit: ${query.limit}>${size}")
val errorMsg = new InvalidQueryError(
s"Query limit exceeded default limit: ${query.limit.getOrElse(defaultFetchSize)} > ${size.getOrElse("None")}", query.query)
Failure(errorMsg)
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/main/scala/de/upb/cs/swt/delphi/webapi/search/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,29 @@ package object search {

class SearchError(msg: String) extends RuntimeException(msg) with JsonSupport

class InvalidQueryError(val msg:String, val query: String) extends RuntimeException(msg) with JsonSupport

class InvalidQueryFieldsError(override val query: String, val invalidFields: Set[String])
extends InvalidQueryError("Query contained invalid query field names!", query)

implicit val searchErrorWriter = new JsonWriter[SearchError] {
override def write(obj: SearchError): JsValue = {
JsObject("msg" -> JsString(obj.getMessage))
}
}

implicit val invalidQueryErrorWriter = new JsonWriter[InvalidQueryError] {
override def write(obj: InvalidQueryError): JsValue = {

obj match {
case error: InvalidQueryFieldsError =>
JsObject("msg" -> JsString(obj.getMessage), "query" -> JsString(obj.query),
"invalid_fields" -> JsArray(error.invalidFields.toVector.map(JsString(_))))
case _ =>
JsObject("msg" -> JsString(obj.getMessage), "query" -> JsString(obj.query))
}

}
}

}