mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-05 22:55:58 +00:00
Provide custom error structure for parse failures
This commit is contained in:
parent
d737da768e
commit
e079ec1987
@ -9,17 +9,18 @@ import docspell.query.internal.ExprUtil
|
|||||||
object ItemQueryParser {
|
object ItemQueryParser {
|
||||||
|
|
||||||
@JSExport
|
@JSExport
|
||||||
def parse(input: String): Either[String, ItemQuery] =
|
def parse(input: String): Either[ParseFailure, ItemQuery] =
|
||||||
if (input.isEmpty) Right(ItemQuery.all)
|
if (input.isEmpty) Right(ItemQuery.all)
|
||||||
else {
|
else {
|
||||||
val in = if (input.charAt(0) == '(') input else s"(& $input )"
|
val in = if (input.charAt(0) == '(') input else s"(& $input )"
|
||||||
ExprParser
|
ExprParser
|
||||||
.parseQuery(in)
|
.parseQuery(in)
|
||||||
.left
|
.left
|
||||||
.map(pe => s"Error parsing: '$input': $pe") //TODO
|
.map(ParseFailure.fromError(in))
|
||||||
.map(q => q.copy(expr = ExprUtil.reduce(q.expr)))
|
.map(q => q.copy(expr = ExprUtil.reduce(q.expr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
def parseUnsafe(input: String): ItemQuery =
|
def parseUnsafe(input: String): ItemQuery =
|
||||||
parse(input).fold(sys.error, identity)
|
parse(input).fold(m => sys.error(m.render), identity)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
package docspell.query
|
||||||
|
|
||||||
|
import cats.data.{NonEmptyList => Nel}
|
||||||
|
import cats.parse.Parser
|
||||||
|
import cats.parse.Parser.Expectation.EndOfString
|
||||||
|
import cats.parse.Parser.Expectation.ExpectedFailureAt
|
||||||
|
import cats.parse.Parser.Expectation.Fail
|
||||||
|
import cats.parse.Parser.Expectation.FailWith
|
||||||
|
import cats.parse.Parser.Expectation.InRange
|
||||||
|
import cats.parse.Parser.Expectation.Length
|
||||||
|
import cats.parse.Parser.Expectation.OneOfStr
|
||||||
|
import cats.parse.Parser.Expectation.StartOfString
|
||||||
|
|
||||||
|
final case class ParseFailure(
|
||||||
|
input: String,
|
||||||
|
failedAt: Int,
|
||||||
|
messages: Nel[ParseFailure.Message]
|
||||||
|
) {
|
||||||
|
|
||||||
|
def render: String = {
|
||||||
|
val items = messages.map(_.msg).toList.mkString(", ")
|
||||||
|
s"Failed to read input near $failedAt: $input\nDetails: $items"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ParseFailure {
|
||||||
|
|
||||||
|
final case class Message(offset: Int, msg: String)
|
||||||
|
|
||||||
|
private[query] def fromError(input: String)(pe: Parser.Error): ParseFailure =
|
||||||
|
ParseFailure(
|
||||||
|
input,
|
||||||
|
pe.failedAtOffset,
|
||||||
|
Parser.Expectation.unify(pe.expected).map(expectationToMsg)
|
||||||
|
)
|
||||||
|
|
||||||
|
private[query] def expectationToMsg(e: Parser.Expectation): Message =
|
||||||
|
e match {
|
||||||
|
case StartOfString(offset) =>
|
||||||
|
Message(offset, "Expected start of string")
|
||||||
|
|
||||||
|
case FailWith(offset, message) =>
|
||||||
|
Message(offset, message)
|
||||||
|
|
||||||
|
case InRange(offset, lower, upper) =>
|
||||||
|
if (lower == upper) Message(offset, s"Expected character: $lower")
|
||||||
|
else Message(offset, s"Expected character from range: [$lower .. $upper]")
|
||||||
|
|
||||||
|
case Length(offset, expected, actual) =>
|
||||||
|
Message(offset, s"Expected input of length $expected, but got $actual")
|
||||||
|
|
||||||
|
case ExpectedFailureAt(offset, matched) =>
|
||||||
|
Message(offset, s"Expected failing, but matched '$matched'")
|
||||||
|
|
||||||
|
case EndOfString(offset, length) =>
|
||||||
|
Message(offset, s"Expected end of string at length: $length")
|
||||||
|
|
||||||
|
case Fail(offset) =>
|
||||||
|
Message(offset, s"Failed to parse near $offset")
|
||||||
|
|
||||||
|
case OneOfStr(offset, strs) =>
|
||||||
|
val options = strs.mkString(", ")
|
||||||
|
Message(offset, s"Expected one of the following strings: $options")
|
||||||
|
}
|
||||||
|
}
|
@ -61,7 +61,7 @@ object ItemRoutes {
|
|||||||
val of = offset.getOrElse(0)
|
val of = offset.getOrElse(0)
|
||||||
query match {
|
query match {
|
||||||
case Left(err) =>
|
case Left(err) =>
|
||||||
BadRequest(BasicResult(false, err))
|
BadRequest(BasicResult(false, err.render))
|
||||||
case Right(sq) =>
|
case Right(sq) =>
|
||||||
for {
|
for {
|
||||||
items <- backend.itemSearch.findItems(cfg.maxNoteLength)(
|
items <- backend.itemSearch.findItems(cfg.maxNoteLength)(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user