packages feed

sphinx 0.5.3.1 → 0.6.0

raw patch · 9 files changed

+208/−103 lines, 9 filesdep +textdep +text-icudep −utf8-string

Dependencies added: text, text-icu

Dependencies removed: utf8-string

Files

README.md view
@@ -6,30 +6,53 @@  # Usage -`query` executes a single query.-`runQueries` executes multiple queries at once that were created them with `addQuery`+## Constructing Queries -In extended mode you may want to escape special query characters with `escapeString`+The data type `Query` is used to represent queries to the server. It specifies+a search string and the indexes to run the query on, as well as a comment,+which may be the empty string. In order to run a query on all indexes, use+`"*"` in the index field. -`buildExcerpts` creates highlighted excerpts+The convenience function `query` executes a single query and constructs the+`Query` by itself, so you don't have to. -You will probably need to import the types also:+To execute more than one `Query`, use `runQueries`. Details are below in the+section [*Batch Queries*](#batch-queries). To construct simple queries, you can+also use `simpleQuery :: Text -> Query` which constructs a `Query` over all+indexes. Don't forget that you can use record updates on a `Query`. +In extended mode you may want to escape special query characters with `escapeString`.++All interaction with the server, including sending queries and receiving+results, is based on the `Data.Text` string type. You might therefore want to+enable the `OverloadedStrings` pragma.++## Excerpts and XML Indexes++`buildExcerpts` creates highlighted excerpts.++You will probably need to import the types as well:+     import qualified Text.Search.Sphinx as Sphinx     import qualified Text.Search.Sphinx.Types as SphinxT -There is also an `Indexable` module for generating an xml file of data to be indexed+There is also an `Indexable` module for generating an xml file of data to be indexed. -## runQueries helpers+## Batch Queries -`runQueries` pipelines multiple queries together. If you are trying to combine the results, there are some helpers such as `maybeQueries` and `resultsToMatches`+You can send more than one query per request to the server (which may enable+server-side query optimization in certain cases. Refer to the+[Sphinx manual](http://sphinxsearch.com/docs/2.0.4/api-func-addquery.html)+for details.) The function `runQueries` pipelines multiple queries together. If you+are trying to combine the results, there are some helpers such as+`maybeQueries` and `resultsToMatches`.  ~~~~~~ {.haskell}       mr <- Sphinx.maybeQueries sphinxLogger sphinxConfig [-                 addQuery "db1" query1-               , addQuery "db2" query1-               , addQuery "db1" query2-               , addQuery "db2" query2+                 SphinxT.Query query1 "db1" ""+               , SphinxT.Query query1 "db2" ""+               , SphinxT.Query query2 "db1" ""+               , SphinxT.Query query2 "db2" ""                ]       case mr of         Nothing -> return Nothing@@ -40,9 +63,24 @@              else return $ Just combined ~~~~~~ +**A note** for those transitioning from `0.5.*` to `0.6`: the function `addQueries`+has been removed. You can now directly send a list of `Query` to the server by using+`runQueries`, which will handle the serialization for you behind the scenes. +## Encoding +The sphinx server itself does not know about encodings except for the+difference between single-byte encodings and multi-byte encodings. It assumes+that all incoming queries are already properly encoded and matches the raw+bytes it receives; the same holds for the results returned by the server. Hence+the responsibilty for using the proper encoding (and decoding) routines lies+with the caller. +Version 0.6.0 of `haskell-sphinx-client` introduces the `encoding` field in+both the `Configuration` data type and the `ExcerptConfiguration` data type.+The library handles proper encoding and decoding in the background; just+make sure you set the right encoding setting in the configuration!+ Details ======= @@ -59,4 +97,4 @@ Usage of this haskell client ---------------------------- Tupil originally wrote this for use on a commercial project.-This sphinx package is now finding some use in the Yesod community. [Here is a well described example usage](http://www.yesodweb.com/book/sphinx), but do keep in mind there is no requirement to tie the *generation* of sphinx documents to your web application, just your database. Used in Yesod applications yesdoweb.com and eatnutrients.com.+This sphinx package is now finding some use in the Yesod community. [Here is a well described example usage](https://github.com/yesodweb/yesod/wiki/Sphinx-Search), but do keep in mind there is no requirement to tie the *generation* of sphinx documents to your web application, just your database. Used in Yesod applications yesdoweb.com and eatnutrients.com.
Text/Search/Sphinx.hs view
@@ -5,13 +5,22 @@ -- setFilterFloatRange, setGeoAnchor -- resetFilters, resetGroupBy -- updateAttributes,--- buildKeyWords, escapeString, status, open, close-module Text.Search.Sphinx ( module Text.Search.Sphinx+-- buildKeyWords, status, open, close+module Text.Search.Sphinx +  ( escapeText+  , query+  , buildExcerpts+  , runQueries+  , runQueries'+  , resultsToMatches+  , maybeQueries+  , T.Query(..), simpleQuery   , Configuration(..), defaultConfig   ) where  import qualified Text.Search.Sphinx.Types as T (   Match,+  Query(..),   VerCommand(VcSearch, VcExcerpt),   SearchdCommand(ScSearch, ScExcerpt),   Filter, Filter(..),@@ -21,9 +30,9 @@  import Text.Search.Sphinx.Configuration (Configuration(..), defaultConfig) import qualified Text.Search.Sphinx.ExcerptConfiguration as ExConf (ExcerptConfiguration(..))-import Text.Search.Sphinx.Get (times, getResult, readHeader, getStr)+import Text.Search.Sphinx.Get (times, getResult, readHeader, getStr, getTxt) import Text.Search.Sphinx.Put (num, num64, enum, list, numC, strC, foldPuts,-                              numC64, stringIntList, str, cmd, verCmd)+                              numC64, stringIntList, str, txt, cmd, verCmd)  import Data.Binary.Put (Put, runPut) import Data.Binary.Get (runGet, getWord32be)@@ -38,6 +47,10 @@ import Prelude hiding (filter, tail) import Data.List (nub) +import Data.Text (Text)+import qualified Data.Text as X+import qualified Data.Text.ICU.Convert as ICU+ {- the funnest way to debug this is to run the same query with an existing working client and look at the difference  - sudo tcpflow -i lo dst port 9306  import Debug.Trace; debug a = trace (show a) a@@ -46,23 +59,22 @@ escapedChars :: String escapedChars =  '"':'\\':"-!@~/()*[]=" --- | escape all possible meta characters.---   most of these characters only need to be escaped in certain contexts+-- | Escape all possible meta characters.+--   Most of these characters only need to be escaped in certain contexts --   however, in normal searching they will all be ignored-escapeString :: String -> String-escapeString [] = []-escapeString (x:xs) = if x `elem` escapedChars-                        then '\\':x:escapeString xs-                        else      x:escapeString xs+escapeText :: Text -> Text+escapeText = X.intercalate "\\" . breakBy (`elem` escapedChars)+    where breakBy p t | X.null t  = [X.empty]+                      | otherwise = (if p $ X.head t then ("":) else id) $ X.groupBy (\_ x -> not $ p x) t  -- | The 'query' function runs a single query against the Sphinx daemon.---   To pipeline multiple queries in a batch, use addQuery and runQueries+--   To pipeline multiple queries in a batch, use and 'runQueries'. query :: Configuration -- ^ The configuration-      -> String        -- ^ The indexes, "*" means every index-      -> String        -- ^ The query string+      -> Text        -- ^ The indexes, \"*\" means every index+      -> Text        -- ^ The query string       -> IO (T.Result T.QueryResult) -- ^ just one search result back query config indexes search = do-    let q = addQuery config search indexes ""+    let q = T.Query search indexes X.empty     results <- runQueries' config [q]     -- same as toSearchResult, but we know there is just one query     -- could just remove and use runQueries in the future@@ -75,9 +87,16 @@       T.Retry   retry           -> T.Retry retry       T.Warning warning (result:results) -> case result of                         T.QueryOk result        -> T.Warning warning result-                        T.QueryWarning w result -> T.Warning (BS.append warning w) result+                        T.QueryWarning w result -> T.Warning (X.append warning w) result                         T.QueryError code e     -> T.Error code e +-- | This is a convenience function which accepts a search string and+-- builds a query for that string over all indexes without attaching+-- comments to the queries.+simpleQuery :: Text  -- ^ The query string+            -> T.Query -- ^ A query value that can be sent to 'runQueries'+simpleQuery q = T.Query q "*" X.empty+ connect :: String -> Int -> IO Handle connect host port = do   connection <- connectTo host (PortNumber $ fromIntegral $ port)@@ -89,24 +108,25 @@  -- | TODO: add configuration options buildExcerpts :: ExConf.ExcerptConfiguration -- ^ Contains host and port for connection and optional configuration for buildExcerpts-              -> [String]               -- ^ list of document contents to be highlighted-              -> String                 -- ^ The indexes, "*" means every index-              -> String                 -- ^ The query string to use for excerpts-              -> IO (T.Result [BS.ByteString]) -- ^ the documents with excerpts highlighted+              -> [Text]               -- ^ list of document contents to be highlighted+              -> Text                 -- ^ The indexes, \"*\" means every index+              -> Text                  -- ^ The query string to use for excerpts+              -> IO (T.Result [Text]) -- ^ the documents with excerpts highlighted buildExcerpts config docs indexes words = do   conn <- connect (ExConf.host config) (ExConf.port config)-  let req = runPut $ makeBuildExcerpt addExcerpt+  conv <- ICU.open (ExConf.encoding config) Nothing+  let req = runPut $ makeBuildExcerpt (addExcerpt conv)   BS.hPut conn req   hFlush conn   (status, response) <- getResponse conn   case status of-    T.OK      -> return $ T.Ok (getResults response)-    T.WARNING -> return $ T.Warning (runGet getStr response) (getResults response)-    T.RETRY   -> return $ T.Retry (errorMessage response)-    T.ERROR n -> return $ T.Error n (errorMessage response)+    T.OK      -> return $ T.Ok (getResults response conv)+    T.WARNING -> return $ T.Warning (runGet (getTxt conv) response) (getResults response conv)+    T.RETRY   -> return $ T.Retry (errorMessage conv response)+    T.ERROR n -> return $ T.Error n (errorMessage conv response)   where-    getResults response = runGet ((length docs) `times` getStr) response-    errorMessage response = BS.tail (BS.tail (BS.tail (BS.tail response)))+    getResults response conv = runGet ((length docs) `times` getTxt conv) response+    errorMessage conv response = runGet (getTxt conv) (BS.drop 4 response)      makeBuildExcerpt putExcerpt = do       cmd    T.ScExcerpt@@ -114,19 +134,19 @@       num $ fromEnum $ BS.length (runPut putExcerpt)       putExcerpt -    addExcerpt :: Put-    addExcerpt = do+    addExcerpt :: ICU.Converter -> Put+    addExcerpt conv = do       num 0 -- mode       num $ excerptFlags config-      str indexes-      str words+      txt conv indexes+      txt conv words       strC config [ExConf.beforeMatch, ExConf.afterMatch, ExConf.chunkSeparator]       numC config [ExConf.limit, ExConf.around, ExConf.limitPassages, ExConf.limitWords, ExConf.startPassageId]       str $ ExConf.htmlStripMode config #ifndef ONE_ONE_BETA       str $ ExConf.passageBoundary config #endif-      list str docs+      list (txt conv) docs      modeFlag :: ExConf.ExcerptConfiguration -> (ExConf.ExcerptConfiguration -> Bool) -> Int -> Int     modeFlag cfg setting value = if setting cfg then value else 0@@ -144,10 +164,10 @@       ])  --- | Use with addQuery to pipeline multiple queries.+-- | Make multiple queries at once, using a list of 'T.Query'. -- For a single query, just use the query method -- Easier handling of query result than runQueries'-runQueries :: Configuration -> [Put] -> IO (T.Result [T.QueryResult])+runQueries :: Configuration -> [T.Query] -> IO (T.Result [T.QueryResult]) runQueries cfg qs = runQueries' cfg qs >>= return . toSearchResult   where     --   with batched queries, each query can have an error code,@@ -161,39 +181,39 @@     toSearchResult :: T.Result [T.SingleResult] -> T.Result [T.QueryResult]     toSearchResult results =         case results of-          T.Ok rs              -> fromOk rs [] BS.empty+          T.Ok rs              -> fromOk rs [] X.empty           T.Warning warning rs -> fromWarn warning rs []           T.Retry   retry      -> T.Retry retry           T.Error   code error -> T.Error code error       where-        fromOk :: [T.SingleResult] -> [T.QueryResult] -> BS.ByteString -> T.Result [T.QueryResult]-        fromOk [] acc warn | BS.null warn = T.Ok acc+        fromOk :: [T.SingleResult] -> [T.QueryResult] -> Text -> T.Result [T.QueryResult]+        fromOk [] acc warn | X.null warn = T.Ok acc                            | otherwise = T.Warning warn acc         fromOk (r:rs) acc warn = case r of           T.QueryOk result        -> fromOk rs (acc ++ [result]) warn-          T.QueryWarning w result -> fromOk rs (acc ++ [result]) (BS.append warn w)+          T.QueryWarning w result -> fromOk rs (acc ++ [result]) (X.append warn w)           T.QueryError code e     -> T.Error code e -        fromWarn :: BS.ByteString -> [T.SingleResult] -> [T.QueryResult] -> T.Result [T.QueryResult]+        fromWarn :: Text -> [T.SingleResult] -> [T.QueryResult] -> T.Result [T.QueryResult]         fromWarn warning [] acc = T.Warning warning acc         fromWarn warning (r:rs) acc = case r of           T.QueryOk result        -> fromWarn warning rs (result:acc)-          T.QueryWarning w result -> fromWarn (BS.append warning w) rs (result:acc)+          T.QueryWarning w result -> fromWarn (X.append warning w) rs (result:acc)           T.QueryError code e     -> T.Error code e --- | lower level- called by 'runQueries'--- | This may be useful for debugging problems- warning messages won't get compressed-runQueries' :: Configuration -> [Put] -> IO (T.Result [T.SingleResult])+-- | Lower level- called by 'runQueries'.+-- This may be useful for debugging problems- warning messages won't get compressed+runQueries' :: Configuration -> [T.Query] -> IO (T.Result [T.SingleResult]) runQueries' config qs = do     conn <- connect (host config) (port config)-    BS.hPut conn request+    conv <- ICU.open (encoding config) Nothing+    let queryReq = foldPuts $ map (serializeQuery config conv) qs+    BS.hPut conn (request queryReq)     hFlush conn-    getSearchResult conn+    getSearchResult conn conv   where      numQueries = length qs-    queryReq = foldPuts qs--    request = runPut $ do+    request qr = runPut $ do                 cmd T.ScSearch                 verCmd T.VcSearch                 num $ @@ -202,24 +222,24 @@ #else                       8 #endif-                        + (fromEnum $ BS.length (runPut queryReq))+                        + (fromEnum $ BS.length (runPut qr)) #ifndef ONE_ONE_BETA                 num 0 #endif                 num numQueries-                queryReq+                qr -    getSearchResult :: Handle -> IO (T.Result [T.SingleResult])-    getSearchResult conn = do+    getSearchResult :: Handle -> ICU.Converter -> IO (T.Result [T.SingleResult])+    getSearchResult conn conv = do       (status, response) <- getResponse conn       case status of-        T.OK      -> return $ T.Ok (getResults response)-        T.WARNING -> return $ T.Warning (runGet getStr response) (getResults response)-        T.RETRY   -> return $ T.Retry (errorMessage response)-        T.ERROR n -> return $ T.Error n (errorMessage response)+        T.OK      -> return $ T.Ok (getResults response conv)+        T.WARNING -> return $ T.Warning (runGet (getTxt conv) response) (getResults response conv)+        T.RETRY   -> return $ T.Retry (errorMessage conv response)+        T.ERROR n -> return $ T.Error n (errorMessage conv response)       where-        getResults response = runGet (numQueries `times` getResult) response-        errorMessage response = BS.tail (BS.tail (BS.tail (BS.tail response)))+        getResults response conv = runGet (numQueries `times` getResult conv) response+        errorMessage conv response = runGet (getTxt conv) (BS.drop 4 response)   -- | Combine results from 'runQueries' into matches.@@ -237,7 +257,7 @@  -- | executes 'runQueries'. Log warning and errors, automatically retry. -- Return a Nothing on error, otherwise a Just.-maybeQueries :: (BS.ByteString -> IO ()) -> Configuration -> [Put] -> IO (Maybe [T.QueryResult])+maybeQueries :: (Text -> IO ()) -> Configuration -> [T.Query] -> IO (Maybe [T.QueryResult]) maybeQueries logCallback conf queries = do   result <- runQueries conf queries   case result of@@ -245,9 +265,8 @@     T.Retry msg      -> logCallback msg  >> maybeQueries logCallback conf queries     T.Warning w r    -> logCallback w    >> return (Just r)     T.Error code msg ->-      logCallback (BS.concat ["Error code ",BS8.pack $ show code,". ",msg]) >> return Nothing+      logCallback (X.concat ["Error code ",X.pack $ show code,". ",msg]) >> return Nothing --- | TODO: hide this function getResponse :: Handle -> IO (T.Status, BS.ByteString) getResponse conn = do   header <- BS.hGet conn 8@@ -259,17 +278,17 @@   return (status, response)  -- | use with runQueries to pipeline a batch of queries-addQuery :: Configuration -> String -> String -> String -> Put-addQuery cfg query indexes comment = do+serializeQuery :: Configuration -> ICU.Converter -> T.Query -> Put+serializeQuery cfg conv (T.Query qry indexes comment) = do     numC cfg [ offset              , limit              , fromEnum . mode              , fromEnum . ranker              , fromEnum . sort]     str (sortBy cfg)-    str query+    txt conv qry     list num (weights cfg)-    str indexes+    txt conv indexes     num 1                     -- id64 range marker     numC64 cfg [minId, maxId] -- id64 range @@ -287,7 +306,7 @@     stringIntList (indexWeights cfg)     num (maxQueryTime cfg)     stringIntList (fieldWeights cfg)-    str comment+    txt conv comment     num 0 -- attribute overrides (none)     str (selectClause cfg) -- select-list     where
Text/Search/Sphinx/Configuration.hs view
@@ -3,11 +3,28 @@ import qualified Text.Search.Sphinx.Types as T  -- | The configuration for a query+--+-- A note about encodings: The encoding specified here is used to encode+-- every @Text@ value that is sent to the server, and it used to decode all+-- of the server's answers, including error messages.+--+-- If the specified encoding doesn't support characters sent to the server,+-- they will silently be substituted with the byte value of @\'\\SUB\' ::+-- 'Char'@ before transmission.+--+-- If the server sends a byte value back that the encoding doesn't understand,+-- the affected bytes will be converted into special values as+-- specified by that encoding. For example, when decoding invalid UTF-8,+-- all invalid bytes are going to be substituted with @\'\\65533\' ::+-- 'Char'@.+-- data Configuration = Configuration {     -- | The hostname of the Sphinx daemon     host :: String     -- | The portnumber of the Sphinx daemon   , port :: Int+    -- | Encoding used to encode queries to the server, and decode server responses+  , encoding :: String     -- | Per-field weights   , weights :: [Int]     -- | How many records to seek from result-set start (default is 0)@@ -50,7 +67,7 @@   , maxQueryTime :: Int     -- | Per-field-name weights   , fieldWeights :: [(String, Int)]-    -- | attributes to select, defaults to '*'+    -- | attributes to select, defaults to \"*\"   , selectClause :: String -- setSelect in regular API }  deriving (Show)@@ -59,6 +76,7 @@ defaultConfig = Configuration {                   port          = 3312                 , host          = "127.0.0.1"+                , encoding      = "UTF-8"                 , weights       = []                 , offset        = 0                 , limit         = 20
Text/Search/Sphinx/ExcerptConfiguration.hs view
@@ -7,6 +7,8 @@     host :: String     -- | The portnumber of the Sphinx daemon   , port :: Int+    -- | Encoding used to encode queries to the server, and decode server responses+  , encoding :: String   , beforeMatch :: String   , afterMatch :: String   , chunkSeparator :: String@@ -33,6 +35,7 @@ defaultConfig = ExcerptConfiguration {     port          = 3312   , host          = "127.0.0.1"+  , encoding      = "utf8"   , beforeMatch = "<b>"   , afterMatch = "</b>"   , chunkSeparator = "..."
Text/Search/Sphinx/Get.hs view
@@ -10,6 +10,8 @@ import qualified Text.Search.Sphinx.Types as T import Data.Maybe (isJust, fromJust) +import qualified Data.Text.ICU.Convert as ICU+ -- Utility functions getNum :: Get Int getNum = getWord32be >>= return . fromEnum@@ -24,17 +26,23 @@                 num `times` f times = replicateM +getTxt conv = liftM (ICU.toUnicode conv) getStrStr+ getStr = do len <- getNum             getLazyByteString (fromIntegral len) -getResult :: Get (T.SingleResult)-getResult = do+-- Get a strict 'ByteString'.+getStrStr = do len <- getNum+               getByteString (fromIntegral len)++getResult :: ICU.Converter -> Get (T.SingleResult)+getResult conv = do   statusNum <- getNum   case T.toQueryStatus statusNum of-    T.QueryERROR n -> do e <- getStr+    T.QueryERROR n -> do e <- getTxt conv                          return $ T.QueryError statusNum e     T.QueryOK      -> getResultOk >>= return . T.QueryOk-    T.QueryWARNING -> do w <- getStr+    T.QueryWARNING -> do w <- getTxt conv                          getResultOk >>= return . (T.QueryWarning w)   where     getResultOk = do@@ -42,17 +50,18 @@       attrs      <- readList readAttrPair       matchCount <- getNum       id64       <- getNum-      matches    <- matchCount `times` readMatch (id64 > 0) (map snd attrs)+      matches    <- matchCount `times` readMatch (id64 > 0) (map snd attrs) conv       [total, totalFound, time, numWords] <- 4 `times` getNum-      wrds       <- numWords `times` readWord+      wrds       <- numWords `times` readWord conv       return $ T.QueryResult matches total totalFound wrds (map fst attrs)  -readWord = do s <- getStr-              [doc, hits] <- 2 `times` getNum-              return (s, doc, hits)+readWord conv = do+    s <- getStrStr+    [doc, hits] <- 2 `times` getNum+    return (ICU.toUnicode conv s, doc, hits) -readMatch isId64 attrs = do+readMatch isId64 attrs conv = do     doc <- if isId64 then getNum64 else (getNum >>= return . fromIntegral)     weight <- getNum     matchAttrs <- mapM readAttr attrs@@ -60,7 +69,7 @@   where     readAttr (T.AttrTMulti attr)  = (readList (readAttr attr)) >>= return . T.AttrMulti     readAttr T.AttrTBigInt    = getNum64 >>= return . T.AttrBigInt-    readAttr T.AttrTString    = getStr  >>= return . T.AttrString+    readAttr T.AttrTString    = getStrStr  >>= return . T.AttrString . ICU.toUnicode conv     readAttr T.AttrTUInt      = getNum >>= return . T.AttrUInt     readAttr T.AttrTFloat     = getFloat >>= return . T.AttrFloat     readAttr _                = getNum  >>= return . T.AttrUInt
Text/Search/Sphinx/Indexable.hs view
@@ -4,7 +4,7 @@   )   where -import Data.ByteString.Lazy.UTF8 (toString)+import Data.Text (unpack) import qualified Text.Search.Sphinx.Types as T  --import Text.Search.Sphinx.Types@@ -37,7 +37,7 @@ docEl (name, content) = normalEl name `text` indexableEl content  indexableEl (T.AttrUInt i)   = simpleText $ show i-indexableEl (T.AttrString s) = simpleText $ toString s+indexableEl (T.AttrString s) = simpleText $ unpack s indexableEl (T.AttrFloat f)  = simpleText $ show f indexableEl _  = error "not implemented" 
Text/Search/Sphinx/Put.hs view
@@ -8,6 +8,10 @@ import qualified Data.ByteString.Lazy as BS import qualified Text.Search.Sphinx.Types as T +import Data.Text (Text)+import qualified Data.Text.ICU.Convert as ICU+import qualified Data.ByteString as Strict (length)+ num     = putWord32be . fromIntegral num64 i = putWord64be $ fromIntegral i @@ -39,3 +43,8 @@ foldPuts [] = return () foldPuts [p] = p foldPuts (p:ps) = p >> foldPuts ps++txt :: ICU.Converter -> Text -> Put+txt conv t = do let bs = ICU.fromUnicode conv t+                num (fromEnum $ Strict.length bs)+                putByteString bs
Text/Search/Sphinx/Types.hs view
@@ -6,7 +6,15 @@ import Data.ByteString.Lazy (ByteString) import Data.Int (Int64) import Data.Maybe (Maybe, isJust)+import Data.Text (Text,empty) +-- | Data structure representing one query. It can be sent with 'runQueries'+-- or 'runQueries'' to the server in batch mode.+data Query = Query { queryString :: Text -- ^ The actual query string+                   , queryIndexes :: Text -- ^ The indexes, \"*\" means every index+                   , queryComment :: Text  -- ^ A comment string.+                   } deriving (Show)+ -- | Search commands data SearchdCommand = ScSearch                     | ScExcerpt@@ -160,7 +168,7 @@       -- | Total amount of matching documents in index.     , totalFound :: Int       -- | processed words with the number of docs and the number of hits.-    , words :: [(ByteString, Int, Int)]+    , words :: [(Text, Int, Int)]       -- | List of attribute names returned in the result.       -- | The Match will contain just the attribute values in the same order.     , attributeNames :: [ByteString]@@ -169,15 +177,15 @@  -- | a single query result, runQueries returns a list of these data SingleResult = QueryOk QueryResult-                  | QueryWarning ByteString QueryResult-                  | QueryError Int ByteString+                  | QueryWarning Text QueryResult+                  | QueryError Int Text                   deriving (Show)  -- | a result returned from searchd data Result a = Ok a-              | Warning ByteString a-              | Error Int ByteString-              | Retry ByteString+              | Warning Text a+              | Error Int Text+              | Retry Text               deriving (Show)  data Match = Match {@@ -196,6 +204,6 @@ data Attr = AttrMulti [Attr]           | AttrUInt  Int           | AttrBigInt Int64-          | AttrString ByteString+          | AttrString Text           | AttrFloat Float           deriving (Show)
sphinx.cabal view
@@ -1,12 +1,12 @@ Name:            sphinx-Version:         0.5.3.1+Version:         0.6.0 Synopsis:        Haskell bindings to the Sphinx full-text searching daemon. Description:     Haskell bindings to the Sphinx full-text searching daemon. Compatible with Sphinx version 2.0 Category:        Text, Search, Database License:         BSD3 License-file:    LICENSE Author:          Chris Eidhof <ce+sphinx@tupil.com>, Greg Weber-Maintainer:      Greg Weber <greg@gregweber.info>+Maintainer:      Greg Weber <greg@gregweber.info>, Aleksandar Dimitrov <aleks.dimitrov@gmail.com> homepage:        https://github.com/gregwebs/haskell-sphinx-client  cabal-version:   >= 1.2@@ -31,7 +31,8 @@   Build-Depends:   base >= 4 && < 5,                    binary, data-binary-ieee754,                    bytestring, network,-                   xml, utf8-string >= 0.3+                   xml, +                   text < 0.12, text-icu < 0.7    if flag(version-1-1-beta)     cpp-options:   -DONE_ONE_BETA