Commit 2b048538 authored by Alexandre Delanoë's avatar Alexandre Delanoë

[API/Count] Adding route and types.

parent 7d5a98c6
...@@ -2,26 +2,27 @@ ...@@ -2,26 +2,27 @@
-- --
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
-- --
-- hash: 20ddea403b5eab78aff204d088cc635422d7b9b34369ff1c4263e3ba67969442 -- hash: 3346e420cce910077cbb6172c7e942960a4edd72fbab96679d4b45dacd84dcd9
name: gargantext name: gargantext
version: 0.1.0.0 version: 0.1.0.0
synopsis: Deep (Collaborative) Text mining project synopsis: Deep (Collaborative) Text mining project
description: Please see README.md description: Please see README.md
homepage: https://gargantext.org category: Data
license: BSD3 homepage: https://gargantext.org
license-file: LICENSE author: Gargantext Team
author: Gargantext Team maintainer: team@gargantext.org
maintainer: team@gargantext.org copyright: Copyright: (c) 2017-2018: see git logs and README
copyright: Copyright: (c) 2017-2018: see git logs and README license: BSD3
category: Data license-file: LICENSE
build-type: Simple build-type: Simple
cabal-version: >= 1.10 cabal-version: >= 1.10
library library
hs-source-dirs: hs-source-dirs:
src src
default-extensions: NoImplicitPrelude default-extensions: NoImplicitPrelude
ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates -Werror
build-depends: build-depends:
aeson aeson
, aeson-lens , aeson-lens
...@@ -59,6 +60,7 @@ library ...@@ -59,6 +60,7 @@ library
, servant , servant
, servant-auth , servant-auth
, servant-client , servant-client
, servant-mock
, servant-multipart , servant-multipart
, servant-server , servant-server
, split , split
...@@ -114,12 +116,12 @@ library ...@@ -114,12 +116,12 @@ library
Gargantext.Utils.DateUtils Gargantext.Utils.DateUtils
Gargantext.Utils.Prefix Gargantext.Utils.Prefix
other-modules: other-modules:
Gargantext.API.Count
Gargantext.API.Node Gargantext.API.Node
Gargantext.Database.Queries Gargantext.Database.Queries
Gargantext.Utils Gargantext.Utils
Paths_gargantext Paths_gargantext
default-language: Haskell2010 default-language: Haskell2010
ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates -Werror
executable gargantext executable gargantext
main-is: Main.hs main-is: Main.hs
......
...@@ -90,6 +90,7 @@ library: ...@@ -90,6 +90,7 @@ library:
- safe - safe
- semigroups - semigroups
- servant - servant
- servant-mock
- servant-client - servant-client
- servant-multipart - servant-multipart
- servant-server - servant-server
......
{-| {-|
Module : Gargantext.Server Module : Gargantext.API
Description : Server API Description : Server API
Copyright : (c) CNRS, 2017-Present Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3 License : AGPL + CECILL v3
...@@ -16,6 +16,7 @@ TODO/IDEA, use MOCK feature of Servant to generate fake data (for tests) ...@@ -16,6 +16,7 @@ TODO/IDEA, use MOCK feature of Servant to generate fake data (for tests)
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DeriveGeneric #-}
module Gargantext.API module Gargantext.API
where where
...@@ -24,16 +25,19 @@ import Gargantext.Prelude ...@@ -24,16 +25,19 @@ import Gargantext.Prelude
import Network.Wai import Network.Wai
import Network.Wai.Handler.Warp import Network.Wai.Handler.Warp
import Servant import Servant
-- import Servant.API.Stream
import Database.PostgreSQL.Simple (Connection, connect) import Database.PostgreSQL.Simple (Connection, connect)
import System.IO (FilePath, print) import System.IO (FilePath, print)
-- import Gargantext.API.Auth -- import Gargantext.API.Auth
import Gargantext.API.Node ( Roots , roots import Gargantext.API.Node ( Roots , roots
, NodeAPI , nodeAPI , NodeAPI , nodeAPI
, NodesAPI , nodesAPI , NodesAPI , nodesAPI
) )
import Gargantext.API.Count ( CountAPI, count, Query)
import Gargantext.Database.Utils (databaseParameters) import Gargantext.Database.Utils (databaseParameters)
...@@ -50,9 +54,16 @@ startGargantext port file = do ...@@ -50,9 +54,16 @@ startGargantext port file = do
-- | Main routes of the API are typed -- | Main routes of the API are typed
type API = "roots" :> Roots type API = "roots" :> Roots
:<|> "node" :> Capture "id" Int :> NodeAPI :<|> "node" :> Capture "id" Int :> NodeAPI
:<|> "nodes" :> ReqBody '[JSON] [Int] :> NodesAPI :<|> "nodes" :> ReqBody '[JSON] [Int] :> NodesAPI
:<|> "count" :> ReqBody '[JSON] Query :> CountAPI
-- :<|> "counts" :> Stream GET NewLineFraming '[JSON] Count :> CountAPI
-- /mv/<id>/<id>
-- /merge/<id>/<id>
-- /rename/<id>
-- :<|> "static" -- :<|> "static"
-- :<|> "list" :> Capture "id" Int :> NodeAPI -- :<|> "list" :> Capture "id" Int :> NodeAPI
-- :<|> "ngrams" :> Capture "id" Int :> NodeAPI -- :<|> "ngrams" :> Capture "id" Int :> NodeAPI
...@@ -64,6 +75,10 @@ server :: Connection -> Server API ...@@ -64,6 +75,10 @@ server :: Connection -> Server API
server conn = roots conn server conn = roots conn
:<|> nodeAPI conn :<|> nodeAPI conn
:<|> nodesAPI conn :<|> nodesAPI conn
:<|> count
-- | TODO App type, the main monad in which the bot code is written with. -- | TODO App type, the main monad in which the bot code is written with.
-- Provide config, state, logs and IO -- Provide config, state, logs and IO
......
{-|
Module : Gargantext.API.Count
Description : Server API
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
Count API part of Gargantext.
-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DeriveGeneric #-}
module Gargantext.API.Count
where
import Gargantext.Prelude
import Data.Text (Text, pack)
import Servant
import GHC.Generics (Generic)
import Data.Aeson hiding (Error)
type CountAPI = Post '[JSON] Count
data Scraper = Pubmed | Hal
deriving (Generic)
instance FromJSON Scraper
instance ToJSON Scraper
data Query = Query { query_query :: Text
, query_name :: Maybe [Scraper]
}
deriving (Generic)
instance FromJSON Query
instance ToJSON Query
data Error = Error { error_message :: Text
, error_code :: Int
} deriving (Generic)
instance FromJSON Error
instance ToJSON Error
data Count = Count { count_name :: Scraper
, count_count :: Maybe Int
, count_errors :: Maybe [Error]
}
deriving (Generic)
instance FromJSON Count
instance ToJSON Count
count :: Query -> Handler Count
count _ = pure (Count Pubmed (Just 10) (Just [Error (pack "error message") 202]))
...@@ -18,13 +18,13 @@ Node API ...@@ -18,13 +18,13 @@ Node API
module Gargantext.API.Node module Gargantext.API.Node
where where
import Control.Monad
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Data.Aeson (Value()) import Data.Aeson (Value())
import Servant import Servant
import Servant.Multipart -- import Servant.Multipart
import System.IO (putStrLn, readFile) --import System.IO (putStrLn, readFile)
import Data.Text (Text(), pack) import Data.Text (Text())
--import Data.Text (Text(), pack)
import Database.PostgreSQL.Simple (Connection) import Database.PostgreSQL.Simple (Connection)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Types.Main (Node, NodeId, NodeType) import Gargantext.Types.Main (Node, NodeId, NodeType)
...@@ -57,7 +57,7 @@ type NodeAPI = Get '[JSON] (Node Value) ...@@ -57,7 +57,7 @@ type NodeAPI = Get '[JSON] (Node Value)
-- Depending on the Type of the Node, we could post -- Depending on the Type of the Node, we could post
-- New documents for a corpus -- New documents for a corpus
-- New map list terms -- New map list terms
:<|> "process" :> MultipartForm MultipartData :> Post '[JSON] Text -- :<|> "process" :> MultipartForm MultipartData :> Post '[JSON] Text
-- To launch a query and update the corpus -- To launch a query and update the corpus
:<|> "query" :> Capture "string" Text :> Get '[JSON] Text :<|> "query" :> Capture "string" Text :> Get '[JSON] Text
...@@ -73,7 +73,7 @@ nodeAPI conn id = liftIO (getNode conn id) ...@@ -73,7 +73,7 @@ nodeAPI conn id = liftIO (getNode conn id)
:<|> deleteNode' conn id :<|> deleteNode' conn id
:<|> getNodesWith' conn id :<|> getNodesWith' conn id
:<|> getDocFacet' conn id :<|> getDocFacet' conn id
:<|> upload -- :<|> upload
:<|> query :<|> query
nodesAPI :: Connection -> [NodeId] -> Server NodesAPI nodesAPI :: Connection -> [NodeId] -> Server NodesAPI
...@@ -99,18 +99,18 @@ query s = pure s ...@@ -99,18 +99,18 @@ query s = pure s
-- | Upload files -- | Upload files
-- TODO Is it possible to adapt the function according to iValue input ? -- TODO Is it possible to adapt the function according to iValue input ?
upload :: MultipartData -> Handler Text --upload :: MultipartData -> Handler Text
upload multipartData = do --upload multipartData = do
liftIO $ do -- liftIO $ do
putStrLn "Inputs:" -- putStrLn "Inputs:"
forM_ (inputs multipartData) $ \input -> -- forM_ (inputs multipartData) $ \input ->
putStrLn $ " " <> show (iName input) -- putStrLn $ " " <> show (iName input)
<> " -> " <> show (iValue input) -- <> " -> " <> show (iValue input)
--
forM_ (files multipartData) $ \file -> do -- forM_ (files multipartData) $ \file -> do
content <- readFile (fdFilePath file) -- content <- readFile (fdFilePath file)
putStrLn $ "Content of " <> show (fdFileName file) -- putStrLn $ "Content of " <> show (fdFileName file)
<> " at " <> fdFilePath file -- <> " at " <> fdFilePath file
putStrLn content -- putStrLn content
pure (pack "Data loaded") -- pure (pack "Data loaded")
{-|
Module : Gargantext.Database.Facet
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
-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE Arrows #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Gargantext.Database.Facet where
import Prelude hiding (null, id, map, sum, not)
import Gargantext.Types
import Gargantext.Types.Main (NodeType)
import Gargantext.Database.NodeNode
import Gargantext.Database.NodeNodeNgram
import Gargantext.Database.Node
import Gargantext.Database.Queries
import Gargantext.Utils.Prefix (unPrefix)
-- import Gargantext.Database.NodeNgram
-- import Data.Aeson (Value)
import Data.Aeson.TH (deriveJSON)
import Control.Arrow (returnA)
import Control.Lens.TH (makeLensesWith, abbreviatedFields)
import Data.Maybe (Maybe)
import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
import Data.Time (UTCTime)
import Database.PostgreSQL.Simple (Connection)
import Opaleye
import Opaleye.Internal.Join (NullMaker)
import qualified Opaleye.Internal.Unpackspec()
import Data.Profunctor.Product.Default (Default)
-- DocFacet
type FacetDoc = Facet NodeId UTCTime HyperdataDocument Bool -- Double
data Facet id created hyperdata favorite = FacetDoc { facetDoc_id :: id
, facetDoc_created :: created
, facetDoc_hyperdata :: hyperdata
, facetDoc_favorite :: favorite
-- To be added: Double
-- , facetDoc_ngramCount :: ngramCount
} deriving (Show)
$(deriveJSON (unPrefix "facetDoc_") ''Facet)
-- Facets / Views for the Front End
type FacetDocRead = Facet (Column PGInt4) (Column PGTimestamptz) (Column PGJsonb) (Column PGBool) -- (Column PGFloat8)
$(makeAdaptorAndInstance "pFacetDoc" ''Facet)
$(makeLensesWith abbreviatedFields ''Facet)
getDocFacet :: Connection -> Int -> Maybe NodeType -> Maybe Offset -> Maybe Limit -> IO [FacetDoc]
getDocFacet conn parentId nodeType maybeOffset maybeLimit =
runQuery conn $ selectDocFacet parentId nodeType maybeOffset maybeLimit
selectDocFacet :: ParentId -> Maybe NodeType -> Maybe Offset -> Maybe Limit -> Query FacetDocRead
selectDocFacet parentId maybeNodeType maybeOffset maybeLimit =
limit' maybeLimit $ offset' maybeOffset $ orderBy (asc facetDoc_created) $ selectDocFacet' parentId maybeNodeType
-- | Left join to the favorites
nodeNodeLeftJoin :: Query (NodeRead, NodeNodeReadNull)
nodeNodeLeftJoin = leftJoin queryNodeTable queryNodeNodeTable (eqNode)
where
eqNode (Node n1 _ _ _ _ _ _, NodeNode _ n2 _) = ((.==) n1 n2)
nodeNodeLeftJoin' :: (Column (Nullable PGInt4))
-> Query (NodeRead, NodeNodeReadNull)
nodeNodeLeftJoin' nId = leftJoin queryNodeTable queryNodeNodeTable (eqNode nId)
where
eqNode n (Node n1 _ _ _ _ _ _, NodeNode n1' n2 _)
= foldl (.&&) (pgBool True) [ ((.==) n1 n2)
, ((.==) n1' n)
]
nodeNodeLeftJoin'' :: Query (NodeRead, NodeRead, NodeNodeRead)
nodeNodeLeftJoin'' = join3 queryNodeTable queryNodeTable queryNodeNodeTable eqNode
where
eqNode (Node n1 _ _ _ _ _ _, Node n2 _ _ _ _ _ _, NodeNode n1' n2' _)
= foldl (.&&) (pgBool True) [ ((.==) n2 n2')
, ((.==) (toNullable n1) n1')
]
-- | Left join to the ngram count per document
nodeNodeNgramLeftJoin :: Query (NodeRead, NodeNodeNgramReadNull)
nodeNodeNgramLeftJoin = leftJoin queryNodeTable queryNodeNodeNgramTable (eqNode)
where
eqNode (Node n1 _ _ _ _ _ _, NodeNodeNgram n1' _ _ _) = ((.==) n1 n1')
nodeNodeNgramLeftJoin' :: Column (Nullable PGInt4)
-> Query (NodeRead, NodeNodeNgramReadNull)
nodeNodeNgramLeftJoin' nId = leftJoin queryNodeTable queryNodeNodeNgramTable (eqNode nId)
where
eqNode nId' (Node n1 _ _ _ _ _ _, NodeNodeNgram n1' n2 _ _)
= (.&&) ((.==) n1 n1')
((.==) nId' (toNullable n2))
leftJoin3 :: (Default NullMaker (columnsL1, nullableColumnsR) nullableColumnsR1,
Default NullMaker columnsR nullableColumnsR,
Default Unpackspec columnsR columnsR,
Default Unpackspec nullableColumnsR nullableColumnsR,
Default Unpackspec columnsL1 columnsL1,
Default Unpackspec columnsL columnsL) =>
Query columnsL1
-> Query columnsR
-> Query columnsL
-> ((columnsL1, columnsR) -> Column PGBool)
-> ((columnsL, (columnsL1, nullableColumnsR)) -> Column PGBool)
-> Query (columnsL, nullableColumnsR1)
leftJoin3 q1 q2 q3 cond12 cond23 = leftJoin q3 (leftJoin q1 q2 cond12) cond23
-- | Building the facet
selectDocFacet' :: ParentId -> Maybe NodeType -> Query FacetDocRead
selectDocFacet' parentId _ = proc () -> do
node <- (proc () -> do
-- Favorite Column
(Node _ favTypeId _ favParentId _ _ _) <- queryNodeTable -< ()
restrict -< favTypeId .== 15 .&& favParentId .== (toNullable $ pgInt4 parentId)
-- select nn.score from nodes n left join nodes_nodes nn on n.id = nn.node2_id where n.typename =4;
-- Selecting the documents and joining Favorite Node
(Node docId docTypeId _ docParentId _ created docHyperdata, NodeNode _ docTypeId' _) <- nodeNodeLeftJoin' (toNullable $ pgInt4 347537) -< ()
restrict -< docParentId .== (toNullable $ pgInt4 parentId)
let docTypeId'' = maybe 0 nodeTypeId (Just Document)
restrict -< if docTypeId'' > 0
then docTypeId .== (pgInt4 (docTypeId'' :: Int))
else (pgBool True)
-- Getting favorite data
let isFav = ifThenElse (isNull docTypeId') (pgBool False) (pgBool True)
-- Ngram count by document
-- Counting the ngram
-- (Node occId occTypeId _ _ _ _ _, NodeNode _ _ _ count) <- nodeNodeNgramLeftJoin -< ()
-- restrict -< occId .== 347540
--returnA -< (FacetDoc n_id hyperdata isFav ngramCount)) -< ()
returnA -< (FacetDoc docId created docHyperdata isFav)) -< ()
returnA -< node
{-|
Module : Gargantext.Database.Queries
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
-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE Arrows #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Gargantext.Database.Queries where
import Gargantext.Prelude
import Gargantext.Types (Limit, Offset, NodePoly)
import Data.Maybe (Maybe, maybe)
import Control.Arrow ((>>>))
import Control.Applicative ((<*>))
import Opaleye
-- (Query, limit, offset)
type NodeWrite = NodePoly (Maybe (Column PGInt4)) (Column PGInt4)
(Column PGInt4) (Column (Nullable PGInt4))
(Column (PGText)) (Maybe (Column PGTimestamptz))
(Column PGJsonb) -- (Maybe (Column PGTSVector))
type NodeRead = NodePoly (Column PGInt4) (Column PGInt4)
(Column PGInt4) (Column (Nullable PGInt4))
(Column (PGText)) (Column PGTimestamptz)
(Column PGJsonb) -- (Column PGTSVector)
join3 :: Query columnsA -> Query columnsB -> Query columnsC
-> ((columnsA, columnsB, columnsC) -> Column PGBool)
-> Query (columnsA, columnsB, columnsC)
join3 q1 q2 q3 cond = ((,,) <$> q1 <*> q2 <*> q3) >>> keepWhen cond
--leftJoin3 :: Query columnsL1 -> Query columnsR -> Query columnsL
-- -> ((columnsL1, columnsR) -> Column PGBool)
-- -> ((columnsL, (columnsL1, nullableColumnsR1)) -> Column PGBool)
-- -> Query (columnsL, nullableColumnsR)
--leftJoin3 q1 q2 q3 cond12 cond23 = leftJoin q3 (leftJoin q1 q2 cond12) cond23
limit' :: Maybe Limit -> Query a -> Query a
limit' maybeLimit query = maybe query (\l -> limit l query) maybeLimit
offset' :: Maybe Offset -> Query a -> Query a
offset' maybeOffset query = maybe query (\o -> offset o query) maybeOffset
...@@ -2,12 +2,21 @@ flags: {} ...@@ -2,12 +2,21 @@ flags: {}
extra-package-dbs: [] extra-package-dbs: []
packages: packages:
- . - .
#- /home/alexandre/local/logiciels/haskell/servant/servant-multipart
#- /home/alexandre/local/logiciels/haskell/utc
extra-deps: extra-deps:
- aeson-1.0.2.1 - aeson-1.0.2.1
- attoparsec-0.13.2.2
- duckling-0.1.3.0 - duckling-0.1.3.0
- http-media-0.7.1.2
- http-types-0.11
- mmorph-1.1.0
- protolude-0.2 - protolude-0.2
- servant-multipart-0.10.0.1 - servant-0.12.1
- servant-auth-0.3.0.1 - servant-auth-0.3.0.1
- servant-client-0.12.0.1
- servant-client-core-0.12
- servant-docs-0.11.1
- servant-mock-0.8.3
- servant-multipart-0.11.1
- servant-server-0.12
- text-1.2.3.0
resolver: lts-9.2 resolver: lts-9.2
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment