{-# OPTIONS_HADDOCK show-extensions #-}

{-|
Module      : Opaleye.TextSearch
Description : PostgreSQL Full Text Search support for opaleye
Copyright   : (c) Gargantext 2024-
License     : AGPL-3.0-or-later
Maintainer  : gargantext@iscpif.fr
Stability   : 0.1.0.0
Portability : POSIX
                                                               -}
module Opaleye.TextSearch (
  -- * How to use
  -- $use
    
  -- * Types
    SqlTSQuery
  , SqlTSVector

  -- * Functions and operators
  , (@@)
  , pgTSVector
  , pgTSQuery
  , sqlTSQuery
  
  -- * Various parsing queries
  -- $parsing_queries
  , sqlPlainToTSQuery
  , sqlToTSQuery

  -- * Internals (mostly)
  , to_pgTSQuery
  , plainto_pgTSQuery
  ) where

import           Opaleye.Internal.Column (Field)
import           Opaleye.Internal.PGTypesExternal (SqlText)
import           Opaleye.SqlTypes (sqlString)
import           Opaleye.TextSearch.Internal.Types
import           Opaleye.TextSearch.Operators ((@@))
import qualified Opaleye.Internal.Column as C
import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ
import GHC.RTS.Flags (TraceFlags(user))

{- $use

__Example__:
    
@
data MyEntity id text search =
  MyEntity { _id      :: id
           , _text    :: text
           , _search  :: search }
  deriving ('Show', 'GHC.Generics.Generic')

$('Data.Profunctor.Product.TH.makeAdaptorAndInstance' \"pMyEntity\" ''MyEntity)

type MyEntityRead =
  MyEntity
    ('Field' 'SqlInt4'     )
    ('Field' 'SqlText'     )
    ('Field' 'SqlTSVector' )

type MyEntityWrite =
  MyEntity
    ('Maybe' ('Field' 'SqlInt4' ))
    ('Field' 'SqlText'          )
    ('Field' 'SqlTSVector'      )

myEntityTable :: 'Opaleye.Internal.Table' MyEntityWrite MyEntityRead
myEntityTable = 'Opaleye.Internal.Table' \"my_entity\" ( pMyEntity
                                   MyEntity { _id           = 'Opaleye.Internal.Table.optionalTableField' \"id\"
                                            , _text         = 'Opaleye.Internal.Table.requiredTableField' \"text\"
                                            , _search       = 'Opaleye.Internal.Table.optionalTableField' \"search_vector\"
                                            }
                                   )

myQuery :: 'Text' -> 'Opaleye.Internal.Sql.Select' ('Opaleye.Internal.Column.Column' 'SqlInt4', 'Opaleye.Internal.Column' 'SqlText')
myQuery q = proc () -> do
    row <- myEntityTable -< ()
    'Opaleye.Operators.restrict' -< (_search row)    @@ ('sqlPlainToTSQuery' (unpack q))
    'Control.Arrow.returnA'  -< (_id row, _text row)
	
	
'Opaleye.runSelect' conn (myQuery \"hello world\")
@

-}
    
-- Full Text Search

-- | PostgreSQL @tsvector@ coercion from text.
pgTSVector :: Field SqlText -> Field SqlTSVector
pgTSVector :: Field SqlText -> Field SqlTSVector
pgTSVector (C.Column PrimExpr
e) = PrimExpr -> Field SqlTSVector
forall (n :: Nullability) sqlType. PrimExpr -> Field_ n sqlType
C.Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"tsvector" [PrimExpr
e])

-- | PostgreSQL @tsquery@ coercion from text.
pgTSQuery :: Field SqlText -> Field SqlTSQuery
pgTSQuery :: Field SqlText -> Field SqlTSQuery
pgTSQuery (C.Column PrimExpr
e) = PrimExpr -> Field SqlTSQuery
forall (n :: Nullability) sqlType. PrimExpr -> Field_ n sqlType
C.Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"tsquery" [PrimExpr
e])

-- | Coerce given 'String' to @tsquery@.
sqlTSQuery :: String -> Field SqlTSQuery
sqlTSQuery :: Name -> Field SqlTSQuery
sqlTSQuery = Field SqlText -> Field SqlTSQuery
pgTSQuery (Field SqlText -> Field SqlTSQuery)
-> (Name -> Field SqlText) -> Name -> Field SqlTSQuery
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Field SqlText
sqlString

{- $parsing_queries
For @to_tsquery@, @plainto_tsquery@, etc. functions, see "Parsing
queries" section in [PostgreSQL
docs](https://www.postgresql.org/docs/16/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES)
-}

-- | Call 'plainto_tsquery'.
sqlPlainToTSQuery :: String -> Field SqlTSQuery
sqlPlainToTSQuery :: Name -> Field SqlTSQuery
sqlPlainToTSQuery = Name -> Field SqlTSQuery
plainto_pgTSQuery
    
-- | Call @to_tsquery@ on the input string.
sqlToTSQuery :: String -> Field SqlTSQuery
sqlToTSQuery :: Name -> Field SqlTSQuery
sqlToTSQuery = Name -> Field SqlTSQuery
to_pgTSQuery

-- | Converts a 'String' into a Postgres' tsQuery by calling @to_tsquery@ on the input string.
to_pgTSQuery :: String -> Field SqlTSQuery
to_pgTSQuery :: Name -> Field SqlTSQuery
to_pgTSQuery Name
query = PrimExpr -> Field SqlTSQuery
forall (n :: Nullability) sqlType. PrimExpr -> Field_ n sqlType
C.Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"to_tsquery" [Literal -> PrimExpr
HPQ.ConstExpr (Name -> Literal
HPQ.StringLit Name
query)])

-- | Converts a 'String' into a Postgres' tsQuery by calling @plainto_tsquery@ on the input string.
plainto_pgTSQuery :: String -> Field SqlTSQuery
plainto_pgTSQuery :: Name -> Field SqlTSQuery
plainto_pgTSQuery Name
query = PrimExpr -> Field SqlTSQuery
forall (n :: Nullability) sqlType. PrimExpr -> Field_ n sqlType
C.Column (Name -> [PrimExpr] -> PrimExpr
HPQ.FunExpr Name
"plainto_tsquery" [Literal -> PrimExpr
HPQ.ConstExpr (Name -> Literal
HPQ.StringLit Name
query)])