Commit c248eaf1 authored by Alfredo Di Napoli's avatar Alfredo Di Napoli

Support trees of export nodes (to be tested)

parent dd2049aa
...@@ -34,13 +34,13 @@ import Gargantext.Core (lookupDBid) ...@@ -34,13 +34,13 @@ import Gargantext.Core (lookupDBid)
import Gargantext.Database.Admin.Types.Node import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude (IsDBCmd) import Gargantext.Database.Prelude (IsDBCmd)
import Gargantext.Database.Query.Table.Node.Error (HasNodeError, nodeError, NodeError (..)) import Gargantext.Database.Query.Table.Node.Error (HasNodeError, nodeError, NodeError (..))
import Gargantext.Database.Query.Table.Node (getNode, insertNodeWithHyperdata) import Gargantext.Database.Query.Table.Node (insertNodeWithHyperdata, getNodes)
import Gargantext.Database.Schema.Node (NodePoly(..)) import Gargantext.Database.Schema.Node (NodePoly(..))
import Gargantext.Orphans () import Gargantext.Orphans ()
import Prelude import Prelude
import Protolude.Safe (headMay)
import Servant.Client.Streaming (mkClientEnv, withClientM, ClientError) import Servant.Client.Streaming (mkClientEnv, withClientM, ClientError)
import Servant.Server.Generic (AsServerT) import Servant.Server.Generic (AsServerT)
import Gargantext.Core.Types.Main
remoteAPI :: (MonadIO m, IsGargServer env BackendInternalError m) remoteAPI :: (MonadIO m, IsGargServer env BackendInternalError m)
=> AuthenticatedUser => AuthenticatedUser
...@@ -52,7 +52,7 @@ remoteAPI authenticatedUser = Named.RemoteAPI $ ...@@ -52,7 +52,7 @@ remoteAPI authenticatedUser = Named.RemoteAPI $
, remoteImportEp = remoteImportHandler authenticatedUser , remoteImportEp = remoteImportHandler authenticatedUser
} }
type ExpectedPayload = [Node JSON.Value] type ExpectedPayload = Tree (Node JSON.Value)
remoteImportHandler :: forall err env m. remoteImportHandler :: forall err env m.
(HasNodeError err, HasBackendInternalError err, IsDBCmd env err m, MonadIO m) (HasNodeError err, HasBackendInternalError err, IsDBCmd env err m, MonadIO m)
...@@ -65,19 +65,24 @@ remoteImportHandler loggedInUser c = do ...@@ -65,19 +65,24 @@ remoteImportHandler loggedInUser c = do
-- attempt insertion one element of the list at the time. -- attempt insertion one element of the list at the time.
case deserialiseOrFail @ExpectedPayload (B.toLazyByteString $ mconcat chunks) of case deserialiseOrFail @ExpectedPayload (B.toLazyByteString $ mconcat chunks) of
Left err -> throwError $ _BackendInternalError # InternalUnexpectedError (toException $ userError $ "Deserialization error: " ++ show err) Left err -> throwError $ _BackendInternalError # InternalUnexpectedError (toException $ userError $ "Deserialization error: " ++ show err)
Right [] -> throwError $ _BackendInternalError # InternalUnexpectedError (toException $ userError $ "Deserialization error: empty list") Right (TreeN x xs) -> do
Right (x:xs) -> do
-- Attempts to insert nodes a we go along. -- Attempts to insert nodes a we go along.
rootNode <- inserter [] x rootNode <- insertNode Nothing x
foldlM inserter rootNode xs foldlM (insertTrees (Just rootNode)) [rootNode] xs
where where
inserter :: [NodeId] -> Node JSON.Value -> m [NodeId] insertNode :: Maybe NodeId -> Node JSON.Value -> m NodeId
inserter !acc x = case lookupDBid $ _node_typename x of insertNode mb_parent x = case lookupDBid $ _node_typename x of
Nothing -> throwError $ _BackendInternalError # InternalUnexpectedError (toException $ userError $ "remoteImportHandler: impossible, node with invalid type.") Nothing -> throwError $ _BackendInternalError # InternalUnexpectedError (toException $ userError $ "remoteImportHandler: impossible, node with invalid type.")
Just ty -> do Just ty -> do
new_node <- insertNodeWithHyperdata ty (_node_name x) (_node_hyperdata x) (headMay acc) (_auth_user_id loggedInUser) new_node <- insertNodeWithHyperdata ty (_node_name x) (_node_hyperdata x) mb_parent (_auth_user_id loggedInUser)
pure $ new_node : acc pure new_node
insertTrees :: Maybe NodeId -> [NodeId] -> Tree (Node JSON.Value) -> m [NodeId]
insertTrees currentParent !acc (TreeN x xs) = do
childrenRoot <- insertNode currentParent x
(`mappend` acc) <$> foldlM (insertTrees (Just childrenRoot)) [childrenRoot] xs
remoteExportHandler :: ( MonadIO m, Safe.MonadCatch m remoteExportHandler :: ( MonadIO m, Safe.MonadCatch m
...@@ -87,13 +92,16 @@ remoteExportHandler :: ( MonadIO m, Safe.MonadCatch m ...@@ -87,13 +92,16 @@ remoteExportHandler :: ( MonadIO m, Safe.MonadCatch m
-> m [NodeId] -> m [NodeId]
remoteExportHandler Named.RemoteExportRequest{..} = do remoteExportHandler Named.RemoteExportRequest{..} = do
mgr <- view gargHttpManager mgr <- view gargHttpManager
-- FIXME(adn) Here I should somehow need to get all the children of the nodes <- getNodes _rer_node_id
-- node so that I can recostruct proper semantic context. checkNodesTypeAllowed nodes
node <- getNode _rer_node_id liftIO (withClientM (remoteImportClient _rer_instance_auth (streamEncoder nodes)) (mkClientEnv mgr _rer_instance_url) streamDecode)
checkNodeTypeAllowed node
liftIO (withClientM (remoteImportClient _rer_instance_auth (streamEncoder [node])) (mkClientEnv mgr _rer_instance_url) streamDecode)
`Safe.catch` \(e :: BackendInternalError) -> throwError $ _BackendInternalError # e `Safe.catch` \(e :: BackendInternalError) -> throwError $ _BackendInternalError # e
checkNodesTypeAllowed :: (MonadError e m, HasNodeError e) => Tree (Node a) -> m ()
checkNodesTypeAllowed (TreeN r xs) = do
checkNodeTypeAllowed r
mapM_ checkNodesTypeAllowed xs
checkNodeTypeAllowed :: (MonadError e m, HasNodeError e) => Node a -> m () checkNodeTypeAllowed :: (MonadError e m, HasNodeError e) => Node a -> m ()
checkNodeTypeAllowed n checkNodeTypeAllowed n
| Just nty <- lookupDBid (_node_typename n) | Just nty <- lookupDBid (_node_typename n)
......
...@@ -13,11 +13,13 @@ Portability : POSIX ...@@ -13,11 +13,13 @@ Portability : POSIX
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE BangPatterns #-}
----------------------------------------------------------------------- -----------------------------------------------------------------------
module Gargantext.Core.Types.Main where module Gargantext.Core.Types.Main where
------------------------------------------------------------------------ ------------------------------------------------------------------------
import Codec.Serialise.Class
import Data.Bimap (Bimap) import Data.Bimap (Bimap)
import Data.Bimap qualified as Bimap import Data.Bimap qualified as Bimap
import Data.Swagger ( ToSchema(..), ToParamSchema, genericDeclareNamedSchema ) import Data.Swagger ( ToSchema(..), ToParamSchema, genericDeclareNamedSchema )
...@@ -29,8 +31,8 @@ import Gargantext.Core.Utils.Swagger (wellNamedSchema) ...@@ -29,8 +31,8 @@ import Gargantext.Core.Utils.Swagger (wellNamedSchema)
import Gargantext.Database.Admin.Types.Node -- (NodeType(..), Node, Hyperdata(..)) import Gargantext.Database.Admin.Types.Node -- (NodeType(..), Node, Hyperdata(..))
import Gargantext.Prelude import Gargantext.Prelude
import Servant.API (FromHttpApiData(..), ToHttpApiData(..)) import Servant.API (FromHttpApiData(..), ToHttpApiData(..))
import Test.QuickCheck (elements)
import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary) import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
import Test.QuickCheck (elements)
type CorpusName = Text type CorpusName = Text
------------------------------------------------------------------------ ------------------------------------------------------------------------
...@@ -118,8 +120,44 @@ fromListTypeId = flip Bimap.lookupR listTypeIds ...@@ -118,8 +120,44 @@ fromListTypeId = flip Bimap.lookupR listTypeIds
data Tree a = TreeN { _tn_node :: a, _tn_children :: [Tree a] } data Tree a = TreeN { _tn_node :: a, _tn_children :: [Tree a] }
deriving (Show, Read, Eq, Generic, Ord) deriving (Show, Read, Eq, Generic, Ord)
instance Serialise a => Serialise (Tree a) where
instance NFData a => NFData (Tree a) where instance NFData a => NFData (Tree a) where
instance Functor Tree where
fmap = fmapTree
x <$ TreeN _ ts = TreeN x (map (x <$) ts)
fmapTree :: (a -> b) -> Tree a -> Tree b
fmapTree f (TreeN x ts) = TreeN (f x) (map (fmapTree f) ts)
instance Traversable Tree where
traverse f = go
where go (TreeN x ts) = liftA2 TreeN (f x) (traverse go ts)
{-# INLINE traverse #-}
instance Foldable Tree where
fold = foldMap identity
{-# INLINABLE fold #-}
foldMap = foldMapDefault
{-# INLINE foldMap #-}
foldr f z = \t -> go t z -- Use a lambda to allow inlining with two arguments
where
go (TreeN x ts) = f x . foldr (\t k -> go t . k) identity ts
{-# INLINE foldr #-}
foldl' f = go
where go !z (TreeN x ts) = foldl' go (f z x) ts
{-# INLINE foldl' #-}
null _ = False
{-# INLINE null #-}
elem = any . (==)
{-# INLINABLE elem #-}
$(deriveJSON (unPrefix "_tn_") ''Tree) $(deriveJSON (unPrefix "_tn_") ''Tree)
instance (Typeable a, ToSchema a) => ToSchema (Tree a) where instance (Typeable a, ToSchema a) => ToSchema (Tree a) where
......
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