content: 
  module Hunt.Query.Language.Builder
    (   qWord
      , qWordNoCase
      , qFullWord
      , qFullWordNoCase
      , qPhrase
      , qPhraseNoCase
      , qPrefixPhrase
      , qPrefixPhraseNoCase
      , qRange
      , qAnd
      , qAnds
      , qOr
      , qOrs
      , qAndNot
      , qAndNots
      , qNext
      , qNexts
      , qFollow
      , qFollows
      , qNear
      , qNears
      , setNoCaseSearch
      , setFuzzySearch
      , setContext
      , setContexts
      , setBoost
      , withinContexts    -- deprecated
      , withinContext     -- deprecated
      , withBoost         -- deprecated
      , qContext
      )
  where
  
  import           Hunt.Query.Language.Grammar
  import           Data.Text                   (Text)
  import qualified Data.Text                   as T
  
  import           Hunt.Common.BasicTypes      (Context)
  import           Hunt.Scoring.Score          (Score)
  
  -- query construction
  
  -- | case sensitive prefix search of a single word
  
  qWord :: Text -> Query
  qWord = QWord QCase
  
  -- | case insensitive prefix search of a single word
  
  qWordNoCase :: Text -> Query
  qWordNoCase = QWord QNoCase
  
  -- | exact case sensitive search of a single word
  
  qFullWord :: Text -> Query
  qFullWord = QFullWord QCase
  
  -- | exact, but case insensitive search of a single word
  
  qFullWordNoCase :: Text -> Query
  qFullWordNoCase = QFullWord QNoCase
  
  -- --------------------
  --
  -- phrase search
  
  qPhrase' :: (Text -> Query) -> Text -> Query
  qPhrase' qf t
      = case T.words t of
          [w] -> qf w
          ws  -> qNexts $ map qf ws
  
  -- | exact search of a sequence of space separated words.
  -- For each word in the sequence, an exact word search is performed.
  
  qPhrase :: Text -> Query
  qPhrase = qPhrase' qFullWord
  
  -- | exact, but case insenitive search of a sequence of space separated words.
  -- For each word in the sequence, a word search is performed.
  
  qPhraseNoCase :: Text -> Query
  qPhraseNoCase = qPhrase' qFullWordNoCase
  
  -- | prefix search of a sequence of space separated words.
  -- For each word in the sequence, a prefix search is performed.
  
  qPrefixPhrase :: Text -> Query
  qPrefixPhrase = qPhrase' qWordNoCase
  
  -- | prefix search of a sequence of space separated words.
  -- For each word in the sequence, a prefix search is performed.
  
  qPrefixPhraseNoCase :: Text -> Query
  qPrefixPhraseNoCase = qPhrase' qWordNoCase
  
  -- --------------------
  
  -- | search a range of words or an intervall for numeric contexts
  qRange :: Text -> Text -> Query
  qRange = QRange
  
  -- | shortcut for case sensitive context search
  qContext :: Context -> Text -> Query
  qContext c w = QContext [c] $ QWord QCase w
  
  -- | and query
  qAnd :: Query -> Query -> Query
  qAnd q1 q2 = qAnds [q1, q2]
  
  --  | multiple @and@ queries. The list must not be emtpy
  qAnds :: [Query] -> Query
  qAnds = mkAssocSeq And
  
  -- | or query
  qOr :: Query -> Query -> Query
  qOr q1 q2 = qOrs [q1, q2]
  
  --  | multiple @or@ queries. The list must not be emtpy
  qOrs :: [Query] -> Query
  qOrs = mkAssocSeq Or
  
  -- | and not query
  qAndNot :: Query -> Query -> Query
  qAndNot q1 q2 = qAndNots [q1, q2]
  
  --  | multiple @and-not@ queries. The list must not be emtpy
  -- TODO handle left associativity
  
  qAndNots :: [Query] -> Query
  qAndNots = mkLeftAssocSeq AndNot
  
  -- | neighborhood queries. The list must not be empty
  --
  -- TODO: a better name for qNext and qNexts, qPhrase is already used
  
  qNext :: Query -> Query -> Query
  qNext q1 q2 = qNexts [q1, q2]
  
  qNexts :: [Query] -> Query
  qNexts = mkAssocSeq Phrase
  
  qFollow :: Int -> Query -> Query -> Query
  qFollow d q1 q2 = qFollows d [q1, q2]
  
  qFollows :: Int -> [Query] -> Query
  qFollows d = mkAssocSeq (Follow d)
  
  qNear :: Int -> Query -> Query -> Query
  qNear d q1 q2 = qNears d [q1, q2]
  
  qNears :: Int -> [Query] -> Query
  qNears d = mkAssocSeq (Near d)
  
  collectAssocs :: BinOp -> [Query] -> [Query]
  collectAssocs op qs
      = concatMap subqs qs
      where
        subqs (QSeq op' qs')
            | op == op'
                = qs'
        subqs q'
            = [q']
  
  mkAssocSeq :: BinOp -> [Query] -> Query
  mkAssocSeq op qs
      = remSingle $ QSeq op (collectAssocs op qs)
  
  mkLeftAssocSeq :: BinOp -> [Query] -> Query
  mkLeftAssocSeq op qs
      = remSingle $ QSeq op qs'
      where
        qs' = case qs of
                (QSeq op' qs1 : qs2)
                    | op == op'
                        -> qs1 ++ qs2
                _       -> qs
  
  remSingle :: Query -> Query
  remSingle (QSeq _ [q])
      = q
  remSingle q
      = q
  
  -- ------------------------------------------------------------
  -- configure simple search queries
  
  -- | case insensitve search, only sensible for word and phrase queries
  
  setNoCaseSearch :: Query -> Query
  setNoCaseSearch (QWord     _ w) = QWord     QNoCase w
  setNoCaseSearch (QFullWord _ w) = QFullWord QNoCase w
  setNoCaseSearch (QPhrase   _ w) = QPhrase   QNoCase w
  setNoCaseSearch q             = q
  
  -- | fuzzy search, only sensible for word and phrase queries
  
  setFuzzySearch :: Query -> Query
  setFuzzySearch (QWord     _ w) = QWord     QFuzzy w
  setFuzzySearch (QFullWord _ w) = QFullWord QFuzzy w
  setFuzzySearch (QPhrase   _ w) = QPhrase   QFuzzy w
  setFuzzySearch q             = q
  
  -- | restrict search to list of contexts
  
  setContexts :: [Context] -> Query -> Query
  setContexts = QContext
  
  withinContexts :: [Context] -> Query -> Query
  withinContexts = QContext
  {-# DEPRECATED withinContexts "Don't use this, use setContexts" #-}
  
  -- | restrict search to a single context
  
  setContext :: Context -> Query -> Query
  setContext cx = withinContexts [cx]
  
  withinContext :: Context -> Query -> Query
  withinContext cx = setContexts [cx]
  {-# DEPRECATED withinContext "Don't use this, use setContext" #-}
  
  
  -- | boost the search results by a factor
  
  setBoost :: Score -> Query -> Query
  setBoost = QBoost
  
  withBoost :: Score -> Query -> Query
  withBoost = QBoost
  {-# DEPRECATED withBoost "Don't use this, use setBoost" #-}    
  
  -- ------------------------------------------------------------
  