2 Module : Gargantext.Database
3 Description : Main commands of BASHQL a Domain Specific Language to deal with Gargantext Database.
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
10 * BASHQL = functional (Bash * SQL)
12 * Which language to chose when working with a database ? To make it
13 simple, instead of all common Object Relational Mapping (ORM) [1]
14 strategy used nowadays inspired more by object logic than functional
15 logic, the semantics of BASHQL with focus on the function first.
17 * BASHQL focus on the function, i.e. use bash language function name,
18 and make it with SQL behind the scene. Then BASHQL is inspired more
19 by Bash language [2] than SQL and then follows its main commands as
20 specification and documentation.
23 1. Theoritical: database and FileSystems are each thought as a single
24 category, assumption based on theoretical work on databases by David Spivak [0].
25 2. Practical argument: basic bash commands are a daily practice among
29 1. Choose a command you like in Bash
30 2. Implement it in Haskell-SQL according to Gargantext Shema (Tree like
32 3. Translate it in BASHQL (follow previous implementations)
33 4. Make a pull request (enjoy the community)
35 * Implementation strategy: Functional adapations are made to the
36 gargantext languages options and SQL optimization are done continuously
37 during the project. For the Haskellish part, you may be inspired by
38 Turtle implementation written by Gabriel Gonzales [3] which shows how to
39 write Haskell bash translations.
42 - FileSystem is now a NodeSystem where each File is a Node in a Directed Graph (DG).
45 [0] MIT Press has published "Category theory for the sciences". The book
46 can also be purchased on Amazon. Here are reviews by the MAA, by the
49 [1] https://en.wikipedia.org/wiki/Object-relational_mapping
51 [2] https://en.wikipedia.org/wiki/Bash_(Unix_shell)
53 [3] https://github.com/Gabriel439/Haskell-Turtle-Library
57 {-# LANGUAGE NoImplicitPrelude #-}
59 module Gargantext.Database ( module Gargantext.Database.Utils
66 , postCorpus, postAnnuaire
70 import Gargantext.Core.Types
71 import Gargantext.Database.Utils (connectGargandb)
72 import Gargantext.Database.Node
73 import Gargantext.Prelude
74 import Database.PostgreSQL.Simple (Connection)
75 import Data.Text (Text, pack)
76 import Opaleye hiding (FromField)
78 import Data.List (last, concat)
84 -- type PWD a = PWD UserId [a]
86 --data PWD' a = a | PWD' [a]
88 -- | TODO get Children or Node
89 get :: Connection -> PWD -> IO [Node Value]
91 get conn pwd = runQuery conn $ selectNodesWithParentID (last pwd)
93 -- | Home, need to filter with UserId
94 home :: Connection -> IO PWD
95 home c = map node_id <$> getNodesWithParentId c 0 Nothing
97 -- | ls == get Children
98 ls :: Connection -> PWD -> IO [Node Value]
101 tree :: Connection -> PWD -> IO [Node Value]
104 children <- mapM (\p' -> get c [p']) $ map node_id ns
105 pure $ ns <> (concat children)
109 post :: Connection -> PWD -> [NodeWrite'] -> IO Int64
112 post c pth ns = mkNode c (last pth) ns
114 --postR :: Connection -> PWD -> [NodeWrite'] -> IO [Int]
115 --postR _ [] _ = pure [0]
116 --postR _ _ [] = pure [0]
117 --postR c pth ns = mkNodeR c (last pth) ns
120 --rm :: Connection -> PWD -> [NodeId] -> IO Int
123 del :: Connection -> [NodeId] -> IO Int
125 del c ns = deleteNodes c ns
128 --put :: Connection -> PWD -> [a] -> IO Int64
132 -- cd (Home UserId) | (Node NodeId)
137 --------------------------------------------------------------
139 --------------------------------------------------------------
143 c <- connectGargandb "gargantext.ini"
146 ls' :: IO [Node Value]
148 c <- connectGargandb "gargantext.ini"
152 tree' :: IO [Node Value]
154 c <- connectGargandb "gargantext.ini"
160 c <- connectGargandb "gargantext.ini"
161 pid <- last <$> home c
163 postNode c uid pid ( Node' NodeCorpus (pack "Premier corpus") (toJSON (pack "{}"::Text)) [ Node' Document (pack "Doc1") (toJSON (pack "{}" :: Text)) []
164 , Node' Document (pack "Doc2") (toJSON (pack "{}" :: Text)) []
165 , Node' Document (pack "Doc3") (toJSON (pack "{}" :: Text)) []
169 type CorpusName = Text
172 -- myCorpus <- Prelude.map doc2hyperdataDocument <$> toDocs <$> snd <$> readCsv "doc/corpus_imt/Gargantext_Corpus_small.csv"
173 -- There is an error in the CSV parsing...
174 -- let myCorpus' = Prelude.filter (\n -> T.length (maybe "" identity (hyperdataDocument_title n)) > 30) myCorpus
176 postCorpus :: ToJSON a => CorpusName -> (a -> Text) -> [a] -> IO [Int]
177 postCorpus corpusName title ns = do
178 c <- connectGargandb "gargantext.ini"
179 pid <- last <$> home c
181 postNode c uid pid ( Node' NodeCorpus corpusName (toJSON (pack "{}"::Text))
182 (map (\n -> Node' Document (title n) (toJSON n) []) ns)
186 -- import IMTClient as C
187 -- postAnnuaire "Annuaire IMT" (\n -> (maybe "" identity (C.prenom n)) <> " " <> (maybe "" identity (C.nom n))) (take 30 annuaire)
188 postAnnuaire :: ToJSON a => CorpusName -> (a -> Text) -> [a] -> IO [Int]
189 postAnnuaire corpusName title ns = do
190 c <- connectGargandb "gargantext.ini"
191 pid <- last <$> home c
193 postNode c uid pid ( Node' Annuaire corpusName (toJSON (pack "{}"::Text))
194 (map (\n -> Node' UserPage (title n) (toJSON n) []) ns)
198 del' :: [NodeId] -> IO Int
200 c <- connectGargandb "gargantext.ini"