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.Core.Types.Node
72 import Gargantext.Database.Utils (connectGargandb)
73 import Gargantext.Database.Node
74 import Gargantext.Prelude
75 import Database.PostgreSQL.Simple (Connection)
76 import Data.Text (Text, pack)
77 import Opaleye hiding (FromField)
79 import Data.ByteString (ByteString)
80 import Data.List (last, concat)
85 -- type PWD a = PWD UserId [a]
87 --data PWD' a = a | PWD' [a]
89 -- | TODO get Children or Node
90 get :: Connection -> PWD -> IO [Node Value]
92 get conn pwd = runQuery conn $ selectNodesWithParentID (last pwd)
94 -- | Home, need to filter with UserId
95 home :: Connection -> IO PWD
96 home c = map node_id <$> getNodesWithParentId c 0 Nothing
98 -- | ls == get Children
99 ls :: Connection -> PWD -> IO [Node Value]
102 tree :: Connection -> PWD -> IO [Node Value]
105 cs <- mapM (\p' -> get c [p']) $ map node_id ns
106 pure $ ns <> (concat cs)
110 post :: Connection -> PWD -> [NodeWrite'] -> IO Int64
113 post c pth ns = mkNode c (last pth) ns
115 postR :: Connection -> PWD -> [NodeWrite'] -> IO [Int]
116 postR _ [] _ = pure [0]
117 postR _ _ [] = pure [0]
118 postR c pth ns = mkNodeR c (last pth) ns
121 rm :: Connection -> PWD -> [NodeId] -> IO Int
124 del :: Connection -> PWD -> [NodeId] -> IO Int
127 del c pth ns = deleteNodes c ns
129 put :: Connection -> PWD -> [a] -> IO Int64
133 -- cd (Home UserId) | (Node NodeId)
138 --------------------------------------------------------------
140 --------------------------------------------------------------
144 c <- connectGargandb "gargantext.ini"
147 ls' :: IO [Node Value]
149 c <- connectGargandb "gargantext.ini"
153 tree' :: IO [Node Value]
155 c <- connectGargandb "gargantext.ini"
161 c <- connectGargandb "gargantext.ini"
162 pid <- last <$> home c
164 postNode c uid pid ( Node' Corpus (pack "Premier corpus") (toJSON (pack "{}"::Text)) [ Node' Document (pack "Doc1") (toJSON (pack "{}" :: Text)) []
165 , Node' Document (pack "Doc2") (toJSON (pack "{}" :: Text)) []
166 , Node' Document (pack "Doc3") (toJSON (pack "{}" :: Text)) []
170 type CorpusName = Text
173 -- myCorpus <- Prelude.map doc2hyperdataDocument <$> toDocs <$> snd <$> readCsv "doc/corpus_imt/Gargantext_Corpus_small.csv"
174 -- There is an error in the CSV parsing...
175 -- let myCorpus' = Prelude.filter (\n -> T.length (maybe "" identity (hyperdataDocument_title n)) > 30) myCorpus
177 postCorpus :: ToJSON a => CorpusName -> (a -> Text) -> [a] -> IO [Int]
178 postCorpus corpusName title ns = do
179 c <- connectGargandb "gargantext.ini"
180 pid <- last <$> home c
182 postNode c uid pid ( Node' Corpus corpusName (toJSON (pack "{}"::Text))
183 (map (\n -> Node' Document (title n) (toJSON n) []) ns)
187 -- import IMTClient as C
188 -- postAnnuaire "Annuaire IMT" (\n -> (maybe "" identity (C.prenom n)) <> " " <> (maybe "" identity (C.nom n))) (take 30 annuaire)
189 postAnnuaire :: ToJSON a => CorpusName -> (a -> Text) -> [a] -> IO [Int]
190 postAnnuaire corpusName title ns = do
191 c <- connectGargandb "gargantext.ini"
192 pid <- last <$> home c
194 postNode c uid pid ( Node' Annuaire corpusName (toJSON (pack "{}"::Text))
195 (map (\n -> Node' UserPage (title n) (toJSON n) []) ns)
200 del' :: [NodeId] -> IO Int
202 c <- connectGargandb "gargantext.ini"