2 Module : Gargantext.Database.Schema.Node
3 Description : Main requests of Node to the database
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
11 {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
12 {-# OPTIONS_GHC -fno-warn-orphans #-}
14 {-# LANGUAGE Arrows #-}
15 {-# LANGUAGE DeriveGeneric #-}
16 {-# LANGUAGE ConstraintKinds #-}
17 {-# LANGUAGE FlexibleContexts #-}
18 {-# LANGUAGE FlexibleInstances #-}
19 {-# LANGUAGE FunctionalDependencies #-}
20 {-# LANGUAGE OverloadedStrings #-}
21 {-# LANGUAGE MultiParamTypeClasses #-}
22 {-# LANGUAGE NoImplicitPrelude #-}
23 {-# LANGUAGE RankNTypes #-}
24 {-# LANGUAGE TemplateHaskell #-}
25 {-# LANGUAGE TypeFamilies #-}
27 module Gargantext.Database.Schema.Node where
29 import Control.Arrow (returnA)
30 import Control.Lens (Prism', set, view, (#), (^?))
31 import Control.Lens.TH (makeLensesWith, abbreviatedFields)
32 import Control.Monad.Error.Class (MonadError(..))
34 import Data.Maybe (Maybe(..), fromMaybe)
35 import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
36 import Data.Text (Text, pack)
37 import Database.PostgreSQL.Simple.FromField (FromField, fromField)
38 import GHC.Int (Int64)
39 import Gargantext.Core (Lang(..))
40 import Gargantext.Core.Types
41 import Gargantext.Core.Types.Individu (Username)
42 import Gargantext.Database.Config (nodeTypeId)
43 import Gargantext.Database.Queries.Filter (limit', offset')
44 import Gargantext.Database.Types.Node (NodeType(..), defaultCorpus, Hyperdata, HyperData(..))
45 import Gargantext.Database.Utils
46 import Gargantext.Prelude hiding (sum, head)
47 import Gargantext.Viz.Graph (HyperdataGraph(..))
49 import Opaleye hiding (FromField)
50 import Opaleye.Internal.QueryArr (Query)
51 import Prelude hiding (null, id, map, sum)
53 ------------------------------------------------------------------------
55 data NodeError = NoListFound
68 class HasNodeError e where
69 _NodeError :: Prism' e NodeError
71 nodeError :: (MonadError e m, HasNodeError e) => NodeError -> m a
72 nodeError ne = throwError $ _NodeError # ne
74 catchNodeError :: (MonadError e m, HasNodeError e) => m a -> (NodeError -> m a) -> m a
75 catchNodeError f g = catchError f (\e -> maybe (throwError e) g (e ^? _NodeError))
77 ------------------------------------------------------------------------
78 instance FromField HyperdataAny where
79 fromField = fromField'
81 instance FromField HyperdataCorpus
83 fromField = fromField'
85 instance FromField HyperdataDocument
87 fromField = fromField'
89 instance FromField HyperdataDocumentV3
91 fromField = fromField'
93 instance FromField HyperdataUser
95 fromField = fromField'
97 instance FromField HyperData
99 fromField = fromField'
101 instance FromField HyperdataListModel
103 fromField = fromField'
105 instance FromField HyperdataGraph
107 fromField = fromField'
109 instance FromField HyperdataPhylo
111 fromField = fromField'
113 instance FromField HyperdataAnnuaire
115 fromField = fromField'
117 instance FromField HyperdataList
119 fromField = fromField'
121 instance FromField (NodeId, Text)
123 fromField = fromField'
124 ------------------------------------------------------------------------
125 instance QueryRunnerColumnDefault PGJsonb HyperdataAny
127 queryRunnerColumnDefault = fieldQueryRunnerColumn
129 instance QueryRunnerColumnDefault PGJsonb HyperdataList
131 queryRunnerColumnDefault = fieldQueryRunnerColumn
133 instance QueryRunnerColumnDefault PGJsonb HyperData
135 queryRunnerColumnDefault = fieldQueryRunnerColumn
138 instance QueryRunnerColumnDefault PGJsonb HyperdataDocument
140 queryRunnerColumnDefault = fieldQueryRunnerColumn
142 instance QueryRunnerColumnDefault PGJsonb HyperdataDocumentV3
144 queryRunnerColumnDefault = fieldQueryRunnerColumn
146 instance QueryRunnerColumnDefault PGJsonb HyperdataCorpus
148 queryRunnerColumnDefault = fieldQueryRunnerColumn
150 instance QueryRunnerColumnDefault PGJsonb HyperdataUser
152 queryRunnerColumnDefault = fieldQueryRunnerColumn
154 instance QueryRunnerColumnDefault PGJsonb HyperdataListModel
156 queryRunnerColumnDefault = fieldQueryRunnerColumn
158 instance QueryRunnerColumnDefault PGJsonb HyperdataGraph
160 queryRunnerColumnDefault = fieldQueryRunnerColumn
162 instance QueryRunnerColumnDefault PGJsonb HyperdataPhylo
164 queryRunnerColumnDefault = fieldQueryRunnerColumn
166 instance QueryRunnerColumnDefault PGJsonb HyperdataAnnuaire
168 queryRunnerColumnDefault = fieldQueryRunnerColumn
170 instance QueryRunnerColumnDefault PGTSVector (Maybe TSVector)
172 queryRunnerColumnDefault = fieldQueryRunnerColumn
174 instance QueryRunnerColumnDefault PGInt4 (Maybe NodeId)
176 queryRunnerColumnDefault = fieldQueryRunnerColumn
178 instance QueryRunnerColumnDefault PGInt4 NodeId
180 queryRunnerColumnDefault = fieldQueryRunnerColumn
182 instance QueryRunnerColumnDefault (Nullable PGInt4) NodeId
184 queryRunnerColumnDefault = fieldQueryRunnerColumn
187 ------------------------------------------------------------------------
188 $(makeAdaptorAndInstance "pNode" ''NodePoly)
189 $(makeLensesWith abbreviatedFields ''NodePoly)
191 $(makeAdaptorAndInstance "pNodeSearch" ''NodePolySearch)
192 $(makeLensesWith abbreviatedFields ''NodePolySearch)
194 type NodeWrite = NodePoly (Maybe (Column PGInt4) )
197 (Maybe (Column PGInt4) )
199 (Maybe (Column PGTimestamptz))
202 type NodeRead = NodePoly (Column PGInt4 )
207 (Column PGTimestamptz )
210 type NodeReadNull = NodePoly (Column (Nullable PGInt4))
211 (Column (Nullable PGInt4))
212 (Column (Nullable PGInt4))
213 (Column (Nullable PGInt4))
214 (Column (Nullable PGText))
215 (Column (Nullable PGTimestamptz))
216 (Column (Nullable PGJsonb))
218 nodeTable :: Table NodeWrite NodeRead
219 nodeTable = Table "nodes" (pNode Node { _node_id = optional "id"
220 , _node_typename = required "typename"
221 , _node_userId = required "user_id"
223 , _node_parentId = optional "parent_id"
224 , _node_name = required "name"
225 , _node_date = optional "date"
227 , _node_hyperdata = required "hyperdata"
231 queryNodeTable :: Query NodeRead
232 queryNodeTable = queryTable nodeTable
234 ------------------------------------------------------------------------
235 -- | Node(Read|Write)Search is slower than Node(Write|Read) use it
236 -- for full text search only
237 type NodeSearchWrite =
239 (Maybe (Column PGInt4) )
242 (Column (Nullable PGInt4) )
244 (Maybe (Column PGTimestamptz))
246 (Maybe (Column PGTSVector) )
248 type NodeSearchRead =
253 (Column (Nullable PGInt4 ))
255 (Column PGTimestamptz )
259 type NodeSearchReadNull =
261 (Column (Nullable PGInt4) )
262 (Column (Nullable PGInt4) )
263 (Column (Nullable PGInt4) )
264 (Column (Nullable PGInt4) )
265 (Column (Nullable PGText) )
266 (Column (Nullable PGTimestamptz))
267 (Column (Nullable PGJsonb) )
268 (Column (Nullable PGTSVector) )
270 nodeTableSearch :: Table NodeSearchWrite NodeSearchRead
271 nodeTableSearch = Table "nodes" (pNodeSearch NodeSearch { _ns_id = optional "id"
272 , _ns_typename = required "typename"
273 , _ns_userId = required "user_id"
275 , _ns_parentId = required "parent_id"
276 , _ns_name = required "name"
277 , _ns_date = optional "date"
279 , _ns_hyperdata = required "hyperdata"
280 , _ns_search = optional "search"
284 queryNodeSearchTable :: Query NodeSearchRead
285 queryNodeSearchTable = queryTable nodeTableSearch
287 selectNode :: Column PGInt4 -> Query NodeRead
288 selectNode id = proc () -> do
289 row <- queryNodeTable -< ()
290 restrict -< _node_id row .== id
295 runGetNodes :: Query NodeRead -> Cmd err [Node HyperdataAny]
296 runGetNodes = runOpaQuery
298 ------------------------------------------------------------------------
299 ------------------------------------------------------------------------
300 -- | order by publication date
301 -- Favorites (Bool), node_ngrams
302 selectNodesWith :: ParentId -> Maybe NodeType
303 -> Maybe Offset -> Maybe Limit -> Query NodeRead
304 selectNodesWith parentId maybeNodeType maybeOffset maybeLimit =
305 --offset' maybeOffset $ limit' maybeLimit $ orderBy (asc (hyperdataDocument_Publication_date . node_hyperdata)) $ selectNodesWith' parentId typeId
306 limit' maybeLimit $ offset' maybeOffset
307 $ orderBy (asc _node_id)
308 $ selectNodesWith' parentId maybeNodeType
310 selectNodesWith' :: ParentId -> Maybe NodeType -> Query NodeRead
311 selectNodesWith' parentId maybeNodeType = proc () -> do
312 node <- (proc () -> do
313 row@(Node _ typeId _ parentId' _ _ _) <- queryNodeTable -< ()
314 restrict -< parentId' .== (pgNodeId parentId)
316 let typeId' = maybe 0 nodeTypeId maybeNodeType
318 restrict -< if typeId' > 0
319 then typeId .== (pgInt4 (typeId' :: Int))
321 returnA -< row ) -< ()
324 deleteNode :: NodeId -> Cmd err Int
325 deleteNode n = mkCmd $ \conn ->
326 fromIntegral <$> runDelete conn nodeTable
327 (\(Node n_id _ _ _ _ _ _) -> n_id .== pgNodeId n)
329 deleteNodes :: [NodeId] -> Cmd err Int
330 deleteNodes ns = mkCmd $ \conn ->
331 fromIntegral <$> runDelete conn nodeTable
332 (\(Node n_id _ _ _ _ _ _) -> in_ ((map pgNodeId ns)) n_id)
334 -- TODO: NodeType should match with `a'
335 getNodesWith :: JSONB a => NodeId -> proxy a -> Maybe NodeType
336 -> Maybe Offset -> Maybe Limit -> Cmd err [Node a]
337 getNodesWith parentId _ nodeType maybeOffset maybeLimit =
338 runOpaQuery $ selectNodesWith parentId nodeType maybeOffset maybeLimit
340 -- TODO: Why is the second parameter ignored?
341 -- TODO: Why not use getNodesWith?
342 getNodesWithParentId :: NodeId -> Maybe Text -> Cmd err [Node HyperdataAny]
343 getNodesWithParentId n _ = runOpaQuery $ selectNodesWithParentID n
345 ------------------------------------------------------------------------
346 getDocumentsV3WithParentId :: NodeId -> Cmd err [Node HyperdataDocumentV3]
347 getDocumentsV3WithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeDocument)
349 -- TODO: merge with getDocumentsWithParentId by having a class IsHyperdataDocument
350 getDocumentsWithParentId :: NodeId -> Cmd err [Node HyperdataDocument]
351 getDocumentsWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeDocument)
353 getListsModelWithParentId :: NodeId -> Cmd err [Node HyperdataListModel]
354 getListsModelWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeListModel)
356 getCorporaWithParentId :: NodeId -> Cmd err [Node HyperdataCorpus]
357 getCorporaWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeCorpus)
359 ------------------------------------------------------------------------
360 selectNodesWithParentID :: NodeId -> Query NodeRead
361 selectNodesWithParentID n = proc () -> do
362 row@(Node _ _ _ parent_id _ _ _) <- queryNodeTable -< ()
363 restrict -< parent_id .== (pgNodeId n)
366 selectNodesWithType :: Column PGInt4 -> Query NodeRead
367 selectNodesWithType type_id = proc () -> do
368 row@(Node _ tn _ _ _ _ _) <- queryNodeTable -< ()
369 restrict -< tn .== type_id
372 type JSONB = QueryRunnerColumnDefault PGJsonb
374 getNode :: JSONB a => NodeId -> proxy a -> Cmd err (Node a)
376 fromMaybe (error $ "Node does not exist: " <> show nId) . headMay
377 <$> runOpaQuery (limit 1 $ selectNode (pgNodeId nId))
379 getNodePhylo :: NodeId -> Cmd err (Node HyperdataPhylo)
380 getNodePhylo nId = do
381 fromMaybe (error $ "Node Phylo does not exist: " <> show nId) . headMay
382 <$> runOpaQuery (limit 1 $ selectNode (pgNodeId nId))
385 getNode' :: NodeId -> Cmd err (Node Value)
386 getNode' nId = fromMaybe (error $ "Node does not exist: " <> show nId) . headMay
387 <$> runOpaQuery (limit 1 $ selectNode (pgNodeId nId))
390 getNodesWithType :: Column PGInt4 -> Cmd err [Node HyperdataDocument]
391 getNodesWithType = runOpaQuery . selectNodesWithType
393 ------------------------------------------------------------------------
394 defaultUser :: HyperdataUser
395 defaultUser = HyperdataUser (Just $ (pack . show) EN)
397 nodeUserW :: Maybe Name -> Maybe HyperdataUser -> UserId -> NodeWrite
398 nodeUserW maybeName maybeHyperdata = node NodeUser name user Nothing
400 name = maybe "User" identity maybeName
401 user = maybe defaultUser identity maybeHyperdata
402 ------------------------------------------------------------------------
403 defaultFolder :: HyperdataFolder
404 defaultFolder = HyperdataFolder (Just "Markdown Description")
406 nodeFolderW :: Maybe Name -> Maybe HyperdataFolder -> ParentId -> UserId -> NodeWrite
407 nodeFolderW maybeName maybeFolder pid = node NodeFolder name folder (Just pid)
409 name = maybe "Folder" identity maybeName
410 folder = maybe defaultFolder identity maybeFolder
411 ------------------------------------------------------------------------
412 nodeCorpusW :: Maybe Name -> Maybe HyperdataCorpus -> ParentId -> UserId -> NodeWrite
413 nodeCorpusW maybeName maybeCorpus pId = node NodeCorpus name corpus (Just pId)
415 name = maybe "Corpus" identity maybeName
416 corpus = maybe defaultCorpus identity maybeCorpus
417 --------------------------
418 defaultDocument :: HyperdataDocument
419 defaultDocument = hyperdataDocument
421 nodeDocumentW :: Maybe Name -> Maybe HyperdataDocument -> CorpusId -> UserId -> NodeWrite
422 nodeDocumentW maybeName maybeDocument cId = node NodeDocument name doc (Just cId)
424 name = maybe "Document" identity maybeName
425 doc = maybe defaultDocument identity maybeDocument
426 ------------------------------------------------------------------------
427 defaultAnnuaire :: HyperdataAnnuaire
428 defaultAnnuaire = HyperdataAnnuaire (Just "Title") (Just "Description")
430 nodeAnnuaireW :: Maybe Name -> Maybe HyperdataAnnuaire -> ParentId -> UserId -> NodeWrite
431 nodeAnnuaireW maybeName maybeAnnuaire pId = node NodeAnnuaire name annuaire (Just pId)
433 name = maybe "Annuaire" identity maybeName
434 annuaire = maybe defaultAnnuaire identity maybeAnnuaire
436 ------------------------------------------------------------------------
439 class IsNodeDb a where
443 instance IsNodeDb NodeType where
446 instance HasHyperdata NodeType where
447 data Hyper NodeType = HyperList HyperdataList
448 | HyperCorpus HyperdataCorpus
450 hasHyperdata nt = case nt of
451 NodeList -> HyperList $ HyperdataList (Just "list")
453 unHyper h = case h of
459 class HasDefault a where
460 hasDefaultData :: a -> HyperData
461 hasDefaultName :: a -> Text
463 instance HasDefault NodeType where
464 hasDefaultData nt = case nt of
465 NodeTexts -> HyperdataTexts (Just "Preferences")
466 NodeList -> HyperdataList' (Just "Preferences")
468 --NodeAnnuaire -> HyperdataAnnuaire (Just "Title") (Just "Description")
470 hasDefaultName nt = case nt of
475 ------------------------------------------------------------------------
477 nodeDefault :: NodeType -> ParentId -> UserId -> NodeWrite
478 nodeDefault nt parent = node nt name hyper (Just parent)
480 name = (hasDefaultName nt)
481 hyper = (hasDefaultData nt)
483 ------------------------------------------------------------------------
485 arbitraryListModel :: HyperdataListModel
486 arbitraryListModel = HyperdataListModel (400,500) "data/models/test.model" (Just 0.83)
488 mkListModelNode :: HasNodeError err => ParentId -> UserId -> Cmd err [NodeId]
489 mkListModelNode p u = insertNodesR [nodeListModelW Nothing Nothing p u]
491 nodeListModelW :: Maybe Name -> Maybe HyperdataListModel -> ParentId -> UserId -> NodeWrite
492 nodeListModelW maybeName maybeListModel pId = node NodeListModel name list (Just pId)
494 name = maybe "List Model" identity maybeName
495 list = maybe arbitraryListModel identity maybeListModel
497 ------------------------------------------------------------------------
498 arbitraryGraph :: HyperdataGraph
499 arbitraryGraph = HyperdataGraph Nothing
501 nodeGraphW :: Maybe Name -> Maybe HyperdataGraph -> ParentId -> UserId -> NodeWrite
502 nodeGraphW maybeName maybeGraph pId = node NodeGraph name graph (Just pId)
504 name = maybe "Graph" identity maybeName
505 graph = maybe arbitraryGraph identity maybeGraph
507 mkGraph :: ParentId -> UserId -> Cmd err [GraphId]
508 mkGraph p u = insertNodesR [nodeGraphW Nothing Nothing p u]
510 insertGraph :: ParentId -> UserId -> HyperdataGraph -> Cmd err [GraphId]
511 insertGraph p u h = insertNodesR [nodeGraphW Nothing (Just h) p u]
513 ------------------------------------------------------------------------
514 arbitraryPhylo :: HyperdataPhylo
515 arbitraryPhylo = HyperdataPhylo Nothing Nothing
517 nodePhyloW :: Maybe Name -> Maybe HyperdataPhylo -> ParentId -> UserId -> NodeWrite
518 nodePhyloW maybeName maybePhylo pId = node NodePhylo name graph (Just pId)
520 name = maybe "Phylo" identity maybeName
521 graph = maybe arbitraryPhylo identity maybePhylo
524 ------------------------------------------------------------------------
525 arbitraryDashboard :: HyperdataDashboard
526 arbitraryDashboard = HyperdataDashboard (Just "Preferences")
527 ------------------------------------------------------------------------
529 node :: (ToJSON a, Hyperdata a) => NodeType -> Name -> a -> Maybe ParentId -> UserId -> NodeWrite
530 node nodeType name hyperData parentId userId = Node Nothing (pgInt4 typeId) (pgInt4 userId) (pgNodeId <$> parentId) (pgStrictText name) Nothing (pgJSONB $ cs $ encode hyperData)
532 typeId = nodeTypeId nodeType
534 -------------------------------
535 insertNodes :: [NodeWrite] -> Cmd err Int64
536 insertNodes ns = mkCmd $ \conn -> runInsertMany conn nodeTable ns
538 insertNodesR :: [NodeWrite] -> Cmd err [NodeId]
539 insertNodesR ns = mkCmd $ \conn ->
540 runInsert_ conn (Insert nodeTable ns (rReturning (\(Node i _ _ _ _ _ _) -> i)) Nothing)
542 insertNodesWithParent :: Maybe ParentId -> [NodeWrite] -> Cmd err Int64
543 insertNodesWithParent pid ns = insertNodes (set node_parentId (pgNodeId <$> pid) <$> ns)
545 insertNodesWithParentR :: Maybe ParentId -> [NodeWrite] -> Cmd err [NodeId]
546 insertNodesWithParentR pid ns = insertNodesR (set node_parentId (pgNodeId <$> pid) <$> ns)
547 ------------------------------------------------------------------------
548 -- TODO Hierachy of Nodes
549 -- post and get same types Node' and update if changes
551 {- TODO semantic to achieve
552 post c uid pid [ Node' NodeCorpus "name" "{}" []
553 , Node' NodeFolder "name" "{}" [Node' NodeCorpus "test 2" "" [ Node' NodeDocument "title" "metaData" []
554 , Node' NodeDocument "title" "jsonData" []
559 ------------------------------------------------------------------------
562 -- currently this function removes the child relation
563 -- needs a Temporary type between Node' and NodeWriteT
564 node2table :: UserId -> Maybe ParentId -> Node' -> NodeWrite
565 node2table uid pid (Node' nt txt v []) = Node Nothing (pgInt4 $ nodeTypeId nt) (pgInt4 uid) (fmap pgNodeId pid) (pgStrictText txt) Nothing (pgStrictJSONB $ cs $ encode v)
566 node2table _ _ (Node' _ _ _ _) = panic "node2table: should not happen, Tree insert not implemented yet"
569 data Node' = Node' { _n_type :: NodeType
572 , _n_children :: [Node']
575 mkNodes :: [NodeWrite] -> Cmd err Int64
576 mkNodes ns = mkCmd $ \conn -> runInsertMany conn nodeTable ns
578 mkNodeR :: [NodeWrite] -> Cmd err [NodeId]
579 mkNodeR ns = mkCmd $ \conn -> runInsertManyReturning conn nodeTable ns (_node_id)
581 ------------------------------------------------------------------------
583 data NewNode = NewNode { _newNodeId :: NodeId
584 , _newNodeChildren :: [NodeId] }
586 postNode :: HasNodeError err => UserId -> Maybe ParentId -> Node' -> Cmd err NewNode
588 postNode uid pid (Node' nt txt v []) = do
589 pids <- mkNodeR [node2table uid pid (Node' nt txt v [])]
591 [pid'] -> pure $ NewNode pid' []
592 _ -> nodeError ManyParents
594 postNode uid pid (Node' NodeCorpus txt v ns) = do
595 NewNode pid' _ <- postNode uid pid (Node' NodeCorpus txt v [])
596 pids <- mkNodeR (concat $ map (\n -> [childWith uid pid' n]) ns)
597 pure $ NewNode pid' pids
599 postNode uid pid (Node' NodeAnnuaire txt v ns) = do
600 NewNode pid' _ <- postNode uid pid (Node' NodeAnnuaire txt v [])
601 pids <- mkNodeR (concat $ map (\n -> [childWith uid pid' n]) ns)
602 pure $ NewNode pid' pids
604 postNode _ _ (Node' _ _ _ _) = nodeError NotImplYet
607 childWith :: UserId -> ParentId -> Node' -> NodeWrite
608 childWith uId pId (Node' NodeDocument txt v []) = node2table uId (Just pId) (Node' NodeDocument txt v [])
609 childWith uId pId (Node' NodeContact txt v []) = node2table uId (Just pId) (Node' NodeContact txt v [])
610 childWith _ _ (Node' _ _ _ _) = panic "This NodeType can not be a child"
613 -- | TODO mk all others nodes
614 mkNodeWithParent :: HasNodeError err => NodeType -> Maybe ParentId -> UserId -> Name -> Cmd err [NodeId]
615 mkNodeWithParent NodeUser (Just _) _ _ = nodeError UserNoParent
616 mkNodeWithParent NodeUser Nothing uId name =
617 insertNodesWithParentR Nothing [node NodeUser name hd Nothing uId]
619 hd = HyperdataUser . Just . pack $ show EN
620 mkNodeWithParent _ Nothing _ _ = nodeError HasParent
622 ------------------------------------------------------------------------
623 mkNodeWithParent NodeFolder (Just i) uId name =
624 insertNodesWithParentR (Just i) [node NodeFolder name hd Nothing uId]
626 hd = HyperdataFolder . Just . pack $ show EN
628 mkNodeWithParent NodeFolderPrivate (Just i) uId _ =
629 insertNodesWithParentR (Just i) [node NodeFolderPrivate "Private" hd Nothing uId]
631 hd = HyperdataFolder . Just . pack $ show EN
633 mkNodeWithParent NodeFolderShared (Just i) uId _ =
634 insertNodesWithParentR (Just i) [node NodeFolderShared "Shared" hd Nothing uId]
636 hd = HyperdataFolder . Just . pack $ show EN
638 mkNodeWithParent NodeFolderPublic (Just i) uId _ =
639 insertNodesWithParentR (Just i) [node NodeFolderPublic "Public" hd Nothing uId]
641 hd = HyperdataFolder . Just . pack $ show EN
643 mkNodeWithParent NodeTeam (Just i) uId _ =
644 insertNodesWithParentR (Just i) [node NodeTeam "Team" hd Nothing uId]
646 hd = HyperdataFolder . Just . pack $ show EN
649 ------------------------------------------------------------------------
653 mkNodeWithParent NodeCorpus (Just i) uId name =
654 insertNodesWithParentR (Just i) [node NodeCorpus name hd Nothing uId]
658 mkNodeWithParent _ _ _ _ = nodeError NotImplYet
662 mkRoot :: HasNodeError err => Username -> UserId -> Cmd err [RootId]
663 mkRoot uname uId = case uId > 0 of
664 False -> nodeError NegativeId
665 True -> mkNodeWithParent NodeUser Nothing uId uname
668 -- CorpusDocument is a corpus made from a set of documents
669 -- CorpusContact is a corpus made from a set of contacts (syn of Annuaire)
670 data CorpusType = CorpusDocument | CorpusContact
674 mk :: Maybe Name -> Maybe a -> ParentId -> UserId -> Cmd err [NodeId]
676 instance MkCorpus HyperdataCorpus
678 mk n h p u = insertNodesR [nodeCorpusW n h p u]
681 instance MkCorpus HyperdataAnnuaire
683 mk n h p u = insertNodesR [nodeAnnuaireW n h p u]
686 getOrMkList :: HasNodeError err => ParentId -> UserId -> Cmd err ListId
687 getOrMkList pId uId =
688 maybe (mkList' pId uId) (pure . view node_id) . headMay =<< getListsWithParentId pId
690 mkList' pId uId = maybe (nodeError MkNode) pure . headMay =<< mkNode NodeList pId uId
692 -- | TODO remove defaultList
693 defaultList :: HasNodeError err => CorpusId -> Cmd err ListId
695 maybe (nodeError NoListFound) (pure . view node_id) . headMay =<< getListsWithParentId cId
697 mkNode :: NodeType -> ParentId -> UserId -> Cmd err [NodeId]
698 mkNode nt p u = insertNodesR [nodeDefault nt p u]
700 mkDashboard :: ParentId -> UserId -> Cmd err [NodeId]
701 mkDashboard p u = insertNodesR [nodeDashboardW Nothing Nothing p u]
703 nodeDashboardW :: Maybe Name -> Maybe HyperdataDashboard -> ParentId -> UserId -> NodeWrite
704 nodeDashboardW maybeName maybeDashboard pId = node NodeDashboard name dashboard (Just pId)
706 name = maybe "Board" identity maybeName
707 dashboard = maybe arbitraryDashboard identity maybeDashboard
710 mkPhylo :: ParentId -> UserId -> Cmd err [NodeId]
711 mkPhylo p u = insertNodesR [nodePhyloW Nothing Nothing p u]
713 -- | Default CorpusId Master and ListId Master
715 pgNodeId :: NodeId -> Column PGInt4
716 pgNodeId = pgInt4 . id2int
718 getListsWithParentId :: NodeId -> Cmd err [Node HyperdataList]
719 getListsWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeList)