{-# LANGUAGE OverloadedStrings #-}

-- | A modified version of Web.Bugzilla.Search to support
--   the list fields in Red Hat's modified bugzilla API.

module Web.RedHatBugzilla.Search
(
  -- * Search operators
  (.==.)
, (./=.)
, (.<.)
, (.<=.)
, (.>.)
, (.>=.)
, (.=~.)
, (./=~.)
, equalsAny
, contains
, containsCase
, containsAny
, containsAll
, changedBefore
, changedAfter
, changedSince
, changedUntil
, changedRange
, changedFrom
, changedTo
, changedBy
, contentMatches
, isEmpty
, isNotEmpty
, (.&&.)
, (.||.)
, not'

  -- * Search expressions
, Field (..)
, SearchExpression
, evalSearchExpr
) where

import qualified Data.Text as T
import Data.Time.Clock (UTCTime(..))

import Web.RedHatBugzilla.Internal.Search
import Web.RedHatBugzilla.Internal.Types

(.==.) :: FieldType a => Field a -> a -> SearchExpression
.==. :: Field a -> a -> SearchExpression
(.==.) = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"equals"
infix 4 .==.

(./=.) :: FieldType a => Field a -> a -> SearchExpression
./=. :: Field a -> a -> SearchExpression
(./=.) = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"notequals"
infix 4 ./=.

(.<.) :: FieldType a => Field a -> a -> SearchExpression
.<. :: Field a -> a -> SearchExpression
(.<.) = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"lessthan"
infix 4 .<.

(.<=.) :: FieldType a => Field a -> a -> SearchExpression
.<=. :: Field a -> a -> SearchExpression
(.<=.) = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"lessthaneq"
infix 4 .<=.

(.>.) :: FieldType a => Field a -> a -> SearchExpression
.>. :: Field a -> a -> SearchExpression
(.>.) = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"greaterthan"
infix 4 .>.

(.>=.) :: FieldType a => Field a -> a -> SearchExpression
.>=. :: Field a -> a -> SearchExpression
(.>=.) = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"greaterthaneq"
infix 4 .>=.

(.=~.) :: FieldType a => Field a -> a -> SearchExpression
.=~. :: Field a -> a -> SearchExpression
(.=~.) = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"regexp"

(./=~.) :: FieldType a => Field a -> a -> SearchExpression
./=~. :: Field a -> a -> SearchExpression
(./=~.) = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"notregexp"

equalsAny :: FieldType a => Field a -> [a] -> SearchExpression
equalsAny :: Field a -> [a] -> SearchExpression
equalsAny = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> ([a] -> SearchTerm) -> [a] -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) (([a] -> SearchTerm) -> [a] -> SearchExpression)
-> (Field a -> [a] -> SearchTerm)
-> Field a
-> [a]
-> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> [a] -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"anyexact"

contains :: Field T.Text -> T.Text -> SearchExpression
contains :: Field Text -> Text -> SearchExpression
contains = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (Text -> SearchTerm) -> Text -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((Text -> SearchTerm) -> Text -> SearchExpression)
-> (Field Text -> Text -> SearchTerm)
-> Field Text
-> Text
-> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field Text -> Text -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"substring"

containsCase :: Field T.Text -> T.Text -> SearchExpression
containsCase :: Field Text -> Text -> SearchExpression
containsCase = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (Text -> SearchTerm) -> Text -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((Text -> SearchTerm) -> Text -> SearchExpression)
-> (Field Text -> Text -> SearchTerm)
-> Field Text
-> Text
-> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field Text -> Text -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"casesubstring"

containsAny :: Field T.Text -> [T.Text] -> SearchExpression
containsAny :: Field Text -> [Text] -> SearchExpression
containsAny = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> ([Text] -> SearchTerm) -> [Text] -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) (([Text] -> SearchTerm) -> [Text] -> SearchExpression)
-> (Field Text -> [Text] -> SearchTerm)
-> Field Text
-> [Text]
-> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field Text -> [Text] -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"anywordssubstr"

containsAll :: Field T.Text -> [T.Text] -> SearchExpression
containsAll :: Field Text -> [Text] -> SearchExpression
containsAll = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> ([Text] -> SearchTerm) -> [Text] -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) (([Text] -> SearchTerm) -> [Text] -> SearchExpression)
-> (Field Text -> [Text] -> SearchTerm)
-> Field Text
-> [Text]
-> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field Text -> [Text] -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"allwordssubstr"

changedBefore :: FieldType a => Field a -> UTCTime -> SearchExpression
changedBefore :: Field a -> UTCTime -> SearchExpression
changedBefore = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (UTCTime -> SearchTerm) -> UTCTime -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((UTCTime -> SearchTerm) -> UTCTime -> SearchExpression)
-> (Field a -> UTCTime -> SearchTerm)
-> Field a
-> UTCTime
-> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> UTCTime -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"changedbefore"

changedAfter :: FieldType a => Field a -> UTCTime -> SearchExpression
changedAfter :: Field a -> UTCTime -> SearchExpression
changedAfter = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (UTCTime -> SearchTerm) -> UTCTime -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((UTCTime -> SearchTerm) -> UTCTime -> SearchExpression)
-> (Field a -> UTCTime -> SearchTerm)
-> Field a
-> UTCTime
-> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> UTCTime -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"changedafter"

-- | Filter bug changed since UTCTime
changedSince :: UTCTime -> SearchExpression
changedSince :: UTCTime -> SearchExpression
changedSince UTCTime
ts = SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression) -> SearchTerm -> SearchExpression
forall a b. (a -> b) -> a -> b
$ Field Text -> UTCTime -> SearchTerm
forall a b.
(FieldType a, FieldType b) =>
Field a -> b -> SearchTerm
EqTerm (Text -> Field Text
CustomField Text
"chfieldfrom") UTCTime
ts

-- | Filter bug changed until UTCTime
changedUntil :: UTCTime -> SearchExpression
changedUntil :: UTCTime -> SearchExpression
changedUntil UTCTime
ts = SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression) -> SearchTerm -> SearchExpression
forall a b. (a -> b) -> a -> b
$ Field Text -> UTCTime -> SearchTerm
forall a b.
(FieldType a, FieldType b) =>
Field a -> b -> SearchTerm
EqTerm (Text -> Field Text
CustomField Text
"chfieldto") UTCTime
ts

-- | Filter bug changed in range
changedRange :: UTCTime -> UTCTime -> SearchExpression
changedRange :: UTCTime -> UTCTime -> SearchExpression
changedRange UTCTime
from UTCTime
to = UTCTime -> SearchExpression
changedSince UTCTime
from SearchExpression -> SearchExpression -> SearchExpression
.&&. UTCTime -> SearchExpression
changedUntil UTCTime
to

changedFrom :: FieldType a => Field a -> a -> SearchExpression
changedFrom :: Field a -> a -> SearchExpression
changedFrom = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"changedfrom"

changedTo :: FieldType a => Field a -> a -> SearchExpression
changedTo :: Field a -> a -> SearchExpression
changedTo = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (a -> SearchTerm) -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> SearchTerm) -> a -> SearchExpression)
-> (Field a -> a -> SearchTerm) -> Field a -> a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> a -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"changedto"

changedBy :: FieldType a => Field a -> UserEmail -> SearchExpression
changedBy :: Field a -> Text -> SearchExpression
changedBy = (SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (Text -> SearchTerm) -> Text -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((Text -> SearchTerm) -> Text -> SearchExpression)
-> (Field a -> Text -> SearchTerm)
-> Field a
-> Text
-> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> Text -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"changedby"

contentMatches :: T.Text -> SearchExpression
contentMatches :: Text -> SearchExpression
contentMatches = SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (Text -> SearchTerm) -> Text -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field Text -> Text -> SearchTerm
forall a a.
(FieldType a, FieldType a) =>
Text -> Field a -> a -> SearchTerm
BinaryOp Text
"matches" Field Text
ContentField

isEmpty :: FieldType a => Field a -> SearchExpression
isEmpty :: Field a -> SearchExpression
isEmpty = SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (Field a -> SearchTerm) -> Field a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> SearchTerm
forall a. FieldType a => Text -> Field a -> SearchTerm
UnaryOp Text
"isempty"

isNotEmpty :: FieldType a => Field a -> SearchExpression
isNotEmpty :: Field a -> SearchExpression
isNotEmpty = SearchTerm -> SearchExpression
Term (SearchTerm -> SearchExpression)
-> (Field a -> SearchTerm) -> Field a -> SearchExpression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Field a -> SearchTerm
forall a. FieldType a => Text -> Field a -> SearchTerm
UnaryOp Text
"isnotempty"

(.&&.) :: SearchExpression -> SearchExpression -> SearchExpression
.&&. :: SearchExpression -> SearchExpression -> SearchExpression
(.&&.) (And [SearchExpression]
as) (And [SearchExpression]
bs) = [SearchExpression] -> SearchExpression
And ([SearchExpression]
as [SearchExpression] -> [SearchExpression] -> [SearchExpression]
forall a. [a] -> [a] -> [a]
++ [SearchExpression]
bs)
(.&&.) (And [SearchExpression]
as) SearchExpression
a = [SearchExpression] -> SearchExpression
And ([SearchExpression]
as [SearchExpression] -> [SearchExpression] -> [SearchExpression]
forall a. [a] -> [a] -> [a]
++ [SearchExpression
a])
(.&&.) SearchExpression
a (And [SearchExpression]
as) = [SearchExpression] -> SearchExpression
And (SearchExpression
aSearchExpression -> [SearchExpression] -> [SearchExpression]
forall a. a -> [a] -> [a]
:[SearchExpression]
as)
(.&&.) SearchExpression
a SearchExpression
b        = [SearchExpression] -> SearchExpression
And [SearchExpression
a, SearchExpression
b]
infixr 3 .&&.

(.||.) :: SearchExpression -> SearchExpression -> SearchExpression
.||. :: SearchExpression -> SearchExpression -> SearchExpression
(.||.) (Or [SearchExpression]
as) (Or [SearchExpression]
bs) = [SearchExpression] -> SearchExpression
Or ([SearchExpression]
as [SearchExpression] -> [SearchExpression] -> [SearchExpression]
forall a. [a] -> [a] -> [a]
++ [SearchExpression]
bs)
(.||.) SearchExpression
a (Or [SearchExpression]
as) = [SearchExpression] -> SearchExpression
Or (SearchExpression
aSearchExpression -> [SearchExpression] -> [SearchExpression]
forall a. a -> [a] -> [a]
:[SearchExpression]
as)
(.||.) (Or [SearchExpression]
as) SearchExpression
a = [SearchExpression] -> SearchExpression
Or ([SearchExpression]
as [SearchExpression] -> [SearchExpression] -> [SearchExpression]
forall a. [a] -> [a] -> [a]
++ [SearchExpression
a])
(.||.) SearchExpression
a SearchExpression
b       = [SearchExpression] -> SearchExpression
Or [SearchExpression
a, SearchExpression
b]
infixr 2 .||.

not' :: SearchExpression -> SearchExpression
not' :: SearchExpression -> SearchExpression
not' (Not SearchExpression
a) = SearchExpression
a
not' SearchExpression
a       = SearchExpression -> SearchExpression
Not SearchExpression
a