2 Module : Gargantext.Database.Schema.NodeNgrams
3 Description : NodeNgram for Ngram indexation or Lists
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
10 NodeNgram: relation between a Node and a Ngrams
12 if Node is a Document then it is indexing
13 if Node is a List then it is listing (either Stop, Candidate or Map)
17 {-# OPTIONS_GHC -fno-warn-orphans #-}
19 {-# LANGUAGE Arrows #-}
20 {-# LANGUAGE FlexibleInstances #-}
21 {-# LANGUAGE FunctionalDependencies #-}
22 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
23 {-# LANGUAGE MultiParamTypeClasses #-}
24 {-# LANGUAGE NoImplicitPrelude #-}
25 {-# LANGUAGE OverloadedStrings #-}
26 {-# LANGUAGE QuasiQuotes #-}
27 {-# LANGUAGE RankNTypes #-}
28 {-# LANGUAGE TemplateHaskell #-}
32 module Gargantext.Database.Schema.NodeNgram where
34 import Data.ByteString (ByteString)
35 import Data.Text (Text)
36 import Debug.Trace (trace)
37 import Control.Lens.TH (makeLenses)
38 import Control.Monad (void)
39 import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
40 import Database.PostgreSQL.Simple.Types (Values(..), QualifiedIdentifier(..))
41 import Database.PostgreSQL.Simple.SqlQQ (sql)
42 import Gargantext.Database.Utils (mkCmd, Cmd, execPGSQuery)
43 import Gargantext.Core.Types.Main (ListTypeId)
44 import Gargantext.Database.Types.Node (NodeId, ListId, NodeType(..))
45 import Gargantext.Database.Config (nodeTypeId, userMaster)
46 import Gargantext.Database.Schema.Node (pgNodeId)
47 import Gargantext.Database.Schema.Ngrams (NgramsTypeId, pgNgramsTypeId)
48 import Gargantext.Database.Schema.NodeNgramsNgrams (NgramsChild, NgramsParent, Action(..))
49 import Gargantext.Prelude
50 import Gargantext.Database.Utils (formatPGSQuery)
52 import qualified Database.PostgreSQL.Simple as PGS (Only(..), Query)
55 data NodeNgramPoly node_id ngrams_id parent_id ngrams_type list_type weight
56 = NodeNgram { _nn_node_id :: node_id
57 , _nn_ngrams_id :: ngrams_id
58 , _nn_parent_id :: parent_id
60 , _nn_ngramsType :: ngrams_type
61 , _nn_listType :: list_type
62 , _nn_weight :: weight
69 (Maybe (Column PGInt4))
85 type NodeNgramReadNull =
87 (Column (Nullable PGInt4 ))
88 (Column (Nullable PGInt4 ))
89 (Column (Nullable PGInt4 ))
91 (Column (Nullable PGInt4 ))
92 (Column (Nullable PGInt4 ))
93 (Column (Nullable PGFloat8))
96 NodeNgramPoly NodeId Int (Maybe NgramsParentId) NgramsTypeId Int Double
98 newtype NgramsParentId = NgramsParentId Int
99 deriving (Show, Eq, Num)
101 pgNgramsParentId :: NgramsParentId -> Column PGInt4
102 pgNgramsParentId (NgramsParentId n) = pgInt4 n
104 $(makeAdaptorAndInstance "pNodeNgram" ''NodeNgramPoly)
105 makeLenses ''NodeNgramPoly
107 nodeNgramTable :: Table NodeNgramWrite NodeNgramRead
108 nodeNgramTable = Table "nodes_ngrams"
109 ( pNodeNgram NodeNgram
110 { _nn_node_id = required "node_id"
111 , _nn_ngrams_id = required "ngrams_id"
112 , _nn_parent_id = optional "parent_id"
113 , _nn_ngramsType = required "ngrams_type"
114 , _nn_listType = required "list_type"
115 , _nn_weight = required "weight"
119 queryNodeNgramTable :: Query NodeNgramRead
120 queryNodeNgramTable = queryTable nodeNgramTable
122 insertNodeNgrams :: [NodeNgram] -> Cmd err Int
123 insertNodeNgrams = insertNodeNgramW
124 . map (\(NodeNgram n g p ngt lt w) ->
125 NodeNgram (pgNodeId n)
127 (pgNgramsParentId <$> p)
133 insertNodeNgramW :: [NodeNgramWrite] -> Cmd err Int
134 insertNodeNgramW nns =
135 mkCmd $ \c -> fromIntegral <$> runInsert_ c insertNothing
137 insertNothing = (Insert { iTable = nodeNgramTable
139 , iReturning = rCount
140 , iOnConflict = (Just DoNothing)
143 type NgramsText = Text
145 updateNodeNgrams' :: [(ListId, NgramsTypeId, NgramsText, ListTypeId)] -> Cmd err ()
146 updateNodeNgrams' [] = pure ()
147 updateNodeNgrams' input = void $ execPGSQuery updateQuery (PGS.Only $ Values fields input)
149 fields = map (\t-> QualifiedIdentifier Nothing t) ["int4","int4","text","int4"]
151 updateNodeNgrams'' :: [(ListId, NgramsTypeId, NgramsText, ListTypeId)] -> Cmd err ByteString
152 updateNodeNgrams'' input = formatPGSQuery updateQuery (PGS.Only $ Values fields input)
154 fields = map (\t-> QualifiedIdentifier Nothing t) ["int4","int4","text","int4"]
156 updateQuery :: PGS.Query
158 WITH new(node_id,ngrams_type,terms,typeList) as (?)
160 INSERT into nodes_ngrams (node_id,ngrams_id,ngrams_type,list_type,weight)
162 SELECT node_id,ngrams.id,ngrams_type,typeList,1 FROM new
163 JOIN ngrams ON ngrams.terms = new.terms
164 ON CONFLICT (node_id, ngrams_id, ngrams_type) DO
167 UPDATE SET list_type = excluded.list_type
172 ngramsGroup' :: Action -> [(ListId, NgramsTypeId, NgramsParent, NgramsChild)] -> Cmd err ()
173 ngramsGroup' _ [] = pure ()
174 ngramsGroup' a input = void $ trace (show input) $ execPGSQuery (ngramsGroupQuery a) (PGS.Only $ Values fields input')
176 fields = map (\t-> QualifiedIdentifier Nothing t) ["int4","int4","text","int4","text","text"]
177 input' = map (\(lid,ntpid,p,c) -> (lid, nodeTypeId NodeList, userMaster, ntpid, p,c)) input
180 ngramsGroupQuery :: Action -> PGS.Query
181 ngramsGroupQuery a = case a of
183 WITH input(lid,listTypeId,masterUsername,ntype,parent_terms,child_terms)
185 -- (VALUES (15::"int4",5::"int4",'gargantua'::"text",4::"int4",'input'::"text",'designer'::"text"))),
188 SELECT n.id from nodes n
189 JOIN auth_user u ON n.user_id = u.id
190 JOIN input ON n.typename = input.listTypeId
191 WHERE u.username = input.masterUsername
196 -- FIRST import parent from master to user list
197 INSERT INTO nodes_ngrams (node_id,ngrams_id,parent_id,ngrams_type,list_type,weight)
198 SELECT input.lid,nn.ngrams_id,nn.parent_id,nn.ngrams_type,nn.list_type, nn.weight
200 JOIN ngrams ng ON ng.terms = input.parent_terms
201 JOIN nodes_ngrams nn ON nn.ngrams_id = ng.id
202 JOIN list_master ON nn.node_id = list_master.id
205 ON CONFLICT (node_id,ngrams_id,ngrams_type) DO NOTHING
208 INSERT INTO nodes_ngrams (node_id,ngrams_id,parent_id,ngrams_type,list_type,weight)
210 SELECT input.lid, nc.id, nnpu.id, input.ntype, nnmaster.list_type, nnmaster.weight
213 JOIN ngrams np ON np.terms = input.parent_terms
214 JOIN ngrams nc ON nc.terms = input.child_terms
216 JOIN nodes_ngrams nnpu ON nnpu.ngrams_id = np.id
217 JOIN nodes_ngrams nnmaster ON nnmaster.ngrams_id = nc.id
218 JOIN list_master ON nnmaster.node_id = list_master.id
221 nnpu.node_id = input.lid
222 AND nnpu.ngrams_type = input.ntype
224 AND nnmaster.ngrams_id = nc.id
225 AND nnmaster.ngrams_type = ntype
227 ON CONFLICT (node_id,ngrams_id,ngrams_type) DO
228 UPDATE SET parent_id = excluded.parent_id
233 WITH input(lid,listTypeId,masterUsername,ntype,parent_terms,child_terms)
235 -- (VALUES (15::"int4",5::"int4",'gargantua'::"text",4::"int4",'input'::"text",'designer'::"text"))),
238 SELECT n.id from nodes n
239 JOIN auth_user u ON n.user_id = u.id
240 JOIN input ON n.typename = input.listTypeId
241 WHERE u.username = input.masterUsername
246 -- FIRST import parent from master to user list
247 INSERT INTO nodes_ngrams (node_id,ngrams_id,parent_id,ngrams_type,list_type,weight)
248 SELECT input.lid,nn.ngrams_id,nn.parent_id,nn.ngrams_type,nn.list_type, nn.weight
250 JOIN ngrams ng ON ng.terms = input.parent_terms
251 JOIN nodes_ngrams nn ON nn.ngrams_id = ng.id
252 JOIN list_master ON nn.node_id = list_master.id
255 ON CONFLICT (node_id,ngrams_id,ngrams_type) DO NOTHING
258 INSERT INTO nodes_ngrams (node_id,ngrams_id,parent_id,ngrams_type,list_type,weight)
260 SELECT input.lid, nc.id, NULL, input.ntype, nnmaster.list_type, nnmaster.weight
263 JOIN ngrams np ON np.terms = input.parent_terms
264 JOIN ngrams nc ON nc.terms = input.child_terms
266 JOIN nodes_ngrams nnmaster ON nnmaster.ngrams_id = nc.id
267 JOIN list_master ON nnmaster.node_id = list_master.id
270 nnmaster.ngrams_id = nc.id
271 AND nnmaster.ngrams_type = ntype
273 ON CONFLICT (node_id,ngrams_id,ngrams_type) DO
274 UPDATE SET parent_id = NULL
279 data NodeNgramsUpdate = NodeNgramsUpdate
280 { _nnu_lists_update :: [(ListId, NgramsTypeId, NgramsText, ListTypeId)]
281 , _nnu_add_children :: [(ListId, NgramsTypeId, NgramsParent, NgramsChild)]
282 , _nnu_rem_children :: [(ListId, NgramsTypeId, NgramsParent, NgramsChild)]
285 -- TODO wrap these updates in a transaction.
286 updateNodeNgrams :: NodeNgramsUpdate -> Cmd err ()
287 updateNodeNgrams nnu = do
288 updateNodeNgrams' $ _nnu_lists_update nnu
289 ngramsGroup' Add $ (trace $ show $ _nnu_add_children nnu) _nnu_add_children nnu
290 ngramsGroup' Del $ _nnu_rem_children nnu