Node.hs 6.75 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
{-|
Module      : Gargantext.Database.Node
Description : Main requests of Node to the database
Copyright   : (c) CNRS, 2017-Present
License     : AGPL + CECILL v3
Maintainer  : team@gargantext.org
Stability   : experimental
Portability : POSIX
-}

11
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
12 13 14 15 16
{-# OPTIONS_GHC -fno-warn-orphans        #-}

{-# LANGUAGE Arrows                 #-}
{-# LANGUAGE DeriveGeneric          #-}
{-# LANGUAGE FlexibleInstances      #-}
17
{-# LANGUAGE FunctionalDependencies #-}
18 19 20
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE NoImplicitPrelude      #-}
{-# LANGUAGE TemplateHaskell        #-}
21 22 23 24 25 26 27 28 29

module Gargantext.Database.Node where

import Database.PostgreSQL.Simple.FromField ( Conversion
                                            , ResultError(ConversionFailed)
                                            , FromField
                                            , fromField
                                            , returnError
                                            )
30
import Prelude hiding (null, id, map, sum)
31

32 33
import Gargantext.Core.Types
import Gargantext.Core.Types.Node (NodeType)
34
import Gargantext.Database.Queries
35 36
import Gargantext.Prelude hiding (sum)

37

38 39 40 41 42 43 44 45 46 47
import Database.PostgreSQL.Simple.Internal  (Field)
import Control.Arrow (returnA)
import Control.Lens.TH (makeLensesWith, abbreviatedFields)
import Data.Aeson
import Data.Maybe (Maybe, fromMaybe)
import Data.Text (Text)
import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
import Data.Typeable (Typeable)
import qualified Data.ByteString.Internal as DBI
import Database.PostgreSQL.Simple (Connection)
48
import Opaleye hiding (FromField)
49 50 51 52

-- | Types for Node Database Management
data PGTSVector

53

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
instance FromField HyperdataCorpus where
    fromField = fromField'

instance FromField HyperdataDocument where
    fromField = fromField'

instance FromField HyperdataProject where
    fromField = fromField'

instance FromField HyperdataUser where
    fromField = fromField'


instance QueryRunnerColumnDefault PGJsonb HyperdataDocument where
  queryRunnerColumnDefault = fieldQueryRunnerColumn

instance QueryRunnerColumnDefault PGJsonb HyperdataCorpus   where
  queryRunnerColumnDefault = fieldQueryRunnerColumn

instance QueryRunnerColumnDefault PGJsonb HyperdataProject  where
  queryRunnerColumnDefault = fieldQueryRunnerColumn

instance QueryRunnerColumnDefault PGJsonb HyperdataUser     where
  queryRunnerColumnDefault = fieldQueryRunnerColumn



81 82 83 84 85 86 87 88
fromField' :: (Typeable b, FromJSON b) => Field -> Maybe DBI.ByteString -> Conversion b
fromField' field mb = do
    v <- fromField field mb
    valueToHyperdata v
      where
          valueToHyperdata v = case fromJSON v of
             Success a  -> pure a
             Error _err -> returnError ConversionFailed field "cannot parse hyperdata"
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107


$(makeAdaptorAndInstance "pNode" ''NodePoly)
$(makeLensesWith abbreviatedFields   ''NodePoly)


nodeTable :: Table NodeWrite NodeRead
nodeTable = Table "nodes" (pNode Node { node_id                = optional "id"
                                        , node_typename        = required "typename"
                                        , node_userId          = required "user_id"
                                        , node_parentId        = required "parent_id"
                                        , node_name            = required "name"
                                        , node_date            = optional "date"
                                        , node_hyperdata       = required "hyperdata"
                     --                   , node_titleAbstract   = optional "title_abstract"
                                        }
                            )


108 109 110 111
queryNodeTable :: Query NodeRead
queryNodeTable = queryTable nodeTable


112 113 114 115 116 117
selectNodes :: Column PGInt4 -> Query NodeRead
selectNodes id = proc () -> do
    row <- queryNodeTable -< ()
    restrict -< node_id row .== id
    returnA -< row

118
runGetNodes :: Connection -> Query NodeRead -> IO [Node Value]
119 120
runGetNodes = runQuery

121 122
-- | order by publication date
-- Favorites (Bool), node_ngrams
Alexandre Delanoë's avatar
Alexandre Delanoë committed
123 124
selectNodesWith :: ParentId     -> Maybe NodeType
                -> Maybe Offset -> Maybe Limit   -> Query NodeRead
125 126
selectNodesWith parentId maybeNodeType maybeOffset maybeLimit = 
        --offset' maybeOffset $ limit' maybeLimit $ orderBy (asc (hyperdataDocument_Publication_date . node_hyperdata)) $ selectNodesWith' parentId typeId
127
        limit' maybeLimit $ offset' maybeOffset $ orderBy (asc node_id) $ selectNodesWith' parentId maybeNodeType
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

selectNodesWith' :: ParentId -> Maybe NodeType -> Query NodeRead
selectNodesWith' parentId maybeNodeType = proc () -> do
    node <- (proc () -> do
            row@(Node _ typeId _ parentId' _ _ _) <- queryNodeTable -< ()
            restrict -< parentId' .== (toNullable $ pgInt4 parentId)
            
            let typeId' = maybe 0 nodeTypeId maybeNodeType
            
            restrict -< if typeId' > 0
                           then typeId   .== (pgInt4 (typeId' :: Int))
                           else (pgBool True)
            returnA  -< row ) -< ()
    returnA -< node


144
deleteNode :: Connection -> Int -> IO Int
145 146 147
deleteNode conn n = fromIntegral 
                 <$> runDelete conn nodeTable 
                 (\(Node n_id _ _ _ _ _ _) -> n_id .== pgInt4 n)
148 149

deleteNodes :: Connection -> [Int] -> IO Int
150 151 152
deleteNodes conn ns = fromIntegral 
                   <$> runDelete conn nodeTable 
                   (\(Node n_id _ _ _ _ _ _) -> in_ ((map pgInt4 ns)) n_id)
153 154


Alexandre Delanoë's avatar
Alexandre Delanoë committed
155
getNodesWith :: Connection   -> Int         -> Maybe NodeType 
156
             -> Maybe Offset -> Maybe Limit -> IO [Node HyperdataDocument]
157 158 159
getNodesWith conn parentId nodeType maybeOffset maybeLimit = 
    runQuery conn $ selectNodesWith 
                  parentId nodeType maybeOffset maybeLimit
160 161 162


-- NP check type
Alexandre Delanoë's avatar
Alexandre Delanoë committed
163
getNodesWithParentId :: Connection -> Int 
164
                     -> Maybe Text -> IO [Node HyperdataDocument]
165
getNodesWithParentId conn n _ = runQuery conn $ selectNodesWithParentID n
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

selectNodesWithParentID :: Int -> Query NodeRead
selectNodesWithParentID n = proc () -> do
    row@(Node _ _ _ parent_id _ _ _) <- queryNodeTable -< ()
    restrict -< if n > 0
                   then
                        parent_id .== (toNullable $ pgInt4 n)
                   else
                        isNull parent_id
    returnA -< row


selectNodesWithType :: Column PGInt4 -> Query NodeRead
selectNodesWithType type_id = proc () -> do
    row@(Node _ tn _ _ _ _ _) <- queryNodeTable -< ()
    restrict -< tn .== type_id
    returnA -< row

184
getNode :: Connection -> Int -> IO (Node HyperdataDocument)
185
getNode conn id = do
186
    fromMaybe (error "TODO: 404") . headMay <$> runQuery conn (limit 1 $ selectNodes (pgInt4 id))
187

188
getNodesWithType :: Connection -> Column PGInt4 -> IO [Node HyperdataDocument]
189 190 191 192
getNodesWithType conn type_id = do
    runQuery conn $ selectNodesWithType type_id