2 Module : Gargantext.Database.Query.Facet
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 {-# LANGUAGE Arrows #-}
12 {-# LANGUAGE FunctionalDependencies #-}
13 {-# LANGUAGE LambdaCase #-}
14 {-# LANGUAGE QuasiQuotes #-}
15 {-# LANGUAGE NoMonomorphismRestriction #-}
16 {-# LANGUAGE TemplateHaskell #-}
17 {-# LANGUAGE TypeFamilies #-}
18 ------------------------------------------------------------------------
19 module Gargantext.Database.Query.Facet
40 import Control.Arrow (returnA)
41 import Control.Lens ((^.))
42 import qualified Data.Text as T
44 import qualified Opaleye.Aggregate as OAgg
45 import Protolude hiding (null, map, sum, not)
46 import qualified Opaleye.Internal.Unpackspec()
48 import Gargantext.Core
49 import Gargantext.Core.Types
50 import Gargantext.Core.Types.Query (Limit, Offset, IsTrash)
51 import Gargantext.Database.Query.Filter
52 import Gargantext.Database.Query.Table.Context
53 import Gargantext.Database.Query.Table.ContextNodeNgrams
54 import Gargantext.Database.Query.Table.Ngrams
55 import Gargantext.Database.Query.Table.Node (defaultList)
56 import Gargantext.Database.Query.Table.Node.Error (HasNodeError)
57 import Gargantext.Database.Query.Table.NodeContext (queryNodeContextTable)
58 import Gargantext.Database.Query.Facet.Types
59 import Gargantext.Database.Prelude
60 import Gargantext.Database.Schema.Context
61 import Gargantext.Database.Schema.Node
62 import Gargantext.Database.Schema.NodeContext
64 ------------------------------------------------------------------------
67 -- TODO-SECURITY check
68 runViewAuthorsDoc :: HasDBid NodeType
75 runViewAuthorsDoc cId t o l order = runOpaQuery $ filterWith o l order $ viewAuthorsDoc cId t ntId
80 viewAuthorsDoc :: HasDBid NodeType
84 -> Select FacetDocRead
85 viewAuthorsDoc cId _ nt = proc () -> do
86 --(doc,(_,(_,(_,contact')))) <- queryAuthorsDoc -< ()
87 (doc, _, _, _, contact') <- queryAuthorsDoc -< ()
89 restrict -< fromMaybeFields (sqlInt4 $ -1) (_node_id <$> contact') .=== pgNodeId cId
90 restrict -< _node_typename doc .== sqlInt4 (toDBid nt)
92 returnA -< FacetDoc { facetDoc_id = _node_id doc
93 , facetDoc_created = _node_date doc
94 , facetDoc_title = _node_name doc
95 , facetDoc_hyperdata = _node_hyperdata doc
96 , facetDoc_category = toNullable $ sqlInt4 1
97 , facetDoc_ngramCount = toNullable $ sqlDouble 1.0
98 , facetDoc_score = toNullable $ sqlDouble 1 }
100 queryAuthorsDoc :: Select ( NodeRead
101 , MaybeFields ContextNodeNgramsRead
102 , MaybeFields NgramsRead
103 , MaybeFields ContextNodeNgramsRead
104 , MaybeFields NodeRead)
105 queryAuthorsDoc = proc () -> do
106 n <- queryNodeTable -< ()
107 cnn <- optionalRestrict queryContextNodeNgramsTable -<
108 \cnn' -> _node_id n .== _cnng_context_id cnn'
109 ng <- optionalRestrict queryNgramsTable -<
110 \ng' -> justFields (ng' ^. ngrams_id) .=== (_cnng_ngrams_id <$> cnn)
111 cnn2 <- optionalRestrict queryContextNodeNgramsTable -<
112 \cnn2' -> (_ngrams_id <$> ng) .=== justFields (_cnng_ngrams_id cnn2')
113 contact <- optionalRestrict queryNodeTable -<
114 \contact' -> justFields (_node_id contact') .=== (_cnng_context_id <$> cnn2)
116 returnA -< (n, cnn, ng, cnn2, contact)
119 ------------------------------------------------------------------------
120 -- TODO-SECURITY check
121 runViewDocuments :: (HasDBid NodeType, HasNodeError err)
129 -> Cmd err [FacetDoc]
130 runViewDocuments cId t o l order query year = do
131 listId <- defaultList cId
133 res <- runOpaQuery $ filterWith' o l order (sqlQuery listId) :: Cmd err [FacetDocAgg']
134 pure $ remapNgramsCount <$> res
136 sqlQuery lId = viewDocuments cId lId t (toDBid NodeDocument) query year
138 remapNgramsCount (FacetDoc { .. }) =
139 FacetDoc { facetDoc_ngramCount = Just $ fromIntegral facetDoc_ngramCount
140 , facetDoc_score = Just $ fromIntegral facetDoc_score
143 runCountDocuments :: (HasDBid NodeType, HasNodeError err)
144 => CorpusId -> IsTrash -> Maybe Text -> Maybe Text -> Cmd err Int
145 runCountDocuments cId t mQuery mYear = do
146 listId <- defaultList cId
147 runCountOpaQuery (sqlQuery listId)
149 sqlQuery lId = viewDocuments cId lId t (toDBid NodeDocument) mQuery mYear
151 viewDocuments :: CorpusId
157 -> Select FacetDocAgg
158 viewDocuments cId lId t ntId mQuery mYear =
159 aggregate (pFacetDoc FacetDoc { facetDoc_id = OAgg.groupBy
160 , facetDoc_created = OAgg.groupBy
161 , facetDoc_title = OAgg.groupBy
162 , facetDoc_hyperdata = OAgg.groupBy
163 , facetDoc_category = OAgg.groupBy
164 , facetDoc_ngramCount = OAgg.sumInt4
165 , facetDoc_score = OAgg.sumInt4 })
166 (viewDocumentsAgg cId lId t ntId mQuery mYear)
168 viewDocumentsAgg :: CorpusId
174 -> Select FacetDocAggPart
175 viewDocumentsAgg cId lId t ntId mQuery mYear = proc () -> do
176 (c, nc) <- viewDocumentsQuery cId t ntId mQuery mYear -< ()
177 cnng <- optionalRestrict queryContextNodeNgramsTable -<
178 \cnng' -> (cnng' ^. cnng_node_id) .== pgNodeId lId .&& -- (nc ^. nc_node_id) .&&
179 (cnng' ^. cnng_context_id) .== (c ^. cs_id)
180 let ngramCount = fromMaybeFields 0 $ _cnng_doc_count <$> cnng
181 returnA -< FacetDoc { facetDoc_id = _cs_id c
182 , facetDoc_created = _cs_date c
183 , facetDoc_title = _cs_name c
184 , facetDoc_hyperdata = _cs_hyperdata c
185 , facetDoc_category = nc ^. nc_category
186 , facetDoc_ngramCount = ngramCount
187 -- NOTE This is a slight abuse of "score" but
188 -- currently it is all 0's in the DB and the
189 -- search functionality on the frontend orders
191 , facetDoc_score = ngramCount
194 -- TODO Join with context_node_ngrams at context_id/node_id and sum by
196 viewDocumentsQuery :: CorpusId
201 -> Select (ContextSearchRead, NodeContextRead)
202 viewDocumentsQuery cId t ntId mQuery mYear = proc () -> do
203 c <- queryContextSearchTable -< ()
204 nc <- queryNodeContextTable -< ()
205 restrict -< (c^.cs_id) .== (nc^.nc_context_id)
206 restrict -< nc^.nc_node_id .== pgNodeId cId
207 restrict -< c^.cs_typename .== sqlInt4 ntId
208 restrict -< if t then nc^.nc_category .== sqlInt4 0
209 else nc^.nc_category .>= sqlInt4 1
212 query = (fromMaybe "" mQuery)
213 year = (fromMaybe "" mYear)
214 iLikeQuery = T.intercalate "" ["%", query, "%"]
215 abstractLHS h = fromNullable (sqlStrictText "")
216 $ toNullable h .->> sqlStrictText "abstract"
217 yearLHS h = fromNullable (sqlStrictText "")
218 $ toNullable h .->> sqlStrictText "publication_year"
221 if query == "" then sqlBool True
222 else ((c^.cs_name) `ilike` (sqlStrictText iLikeQuery))
223 .|| ((abstractLHS (c^.cs_hyperdata)) `ilike` (sqlStrictText iLikeQuery))
225 if year == "" then sqlBool True
226 else yearLHS (c ^. cs_hyperdata) .== sqlStrictText year
229 -- returnA -< (c, nc, cnng)
232 ------------------------------------------------------------------------
233 filterWith :: (SqlOrd date, SqlOrd title, SqlOrd category, SqlOrd score, hyperdata ~ SqlJsonb) =>
237 -> Select (Facet id (Field date) (Field title) (Field hyperdata) (FieldNullable category) ngramCount (FieldNullable score))
238 -> Select (Facet id (Field date) (Field title) (Field hyperdata)(FieldNullable category) ngramCount (FieldNullable score))
239 filterWith o l order q = limit' l $ offset' o $ orderBy (orderWith order) q
242 orderWith :: (SqlOrd b1, SqlOrd b2, SqlOrd b3, SqlOrd b4)
244 -> Order (Facet id (Field b1) (Field b2) (Field SqlJsonb) (FieldNullable b3) ngramCount (FieldNullable b4))
245 orderWith (Just DateAsc) = asc facetDoc_created
246 orderWith (Just DateDesc) = desc facetDoc_created
248 orderWith (Just TitleAsc) = asc facetDoc_title
249 orderWith (Just TitleDesc) = desc facetDoc_title
251 orderWith (Just ScoreAsc) = ascNullsLast facetDoc_score
252 orderWith (Just ScoreDesc) = descNullsLast facetDoc_score
254 orderWith (Just SourceAsc) = ascNullsLast facetDoc_source
255 orderWith (Just SourceDesc) = descNullsLast facetDoc_source
257 orderWith (Just TagAsc) = ascNullsLast facetDoc_category
258 orderWith (Just TagDesc) = descNullsLast facetDoc_category
260 orderWith _ = asc facetDoc_created
264 filterWith' :: (SqlOrd date, SqlOrd title, SqlOrd category, SqlOrd score, hyperdata ~ SqlJsonb, SqlOrd ngramCount) =>
268 -> Select (Facet id (Field date) (Field title) (Field hyperdata) (Field category) (Field ngramCount) (Field score))
269 -> Select (Facet id (Field date) (Field title) (Field hyperdata) (Field category) (Field ngramCount) (Field score))
270 filterWith' o l order q = limit' l $ offset' o $ orderBy (orderWith' order) q
273 orderWith' :: (SqlOrd date, SqlOrd title, SqlOrd category, SqlOrd ngramCount, SqlOrd score)
275 -> Order (Facet id (Field date) (Field title) (Field SqlJsonb) (Field category) (Field ngramCount) (Field score))
276 orderWith' (Just DateAsc) = asc facetDoc_created
277 orderWith' (Just DateDesc) = desc facetDoc_created
279 orderWith' (Just TitleAsc) = asc facetDoc_title
280 orderWith' (Just TitleDesc) = desc facetDoc_title
282 orderWith' (Just NgramCountAsc) = asc facetDoc_ngramCount
283 orderWith' (Just NgramCountDesc) = desc facetDoc_ngramCount
285 orderWith' (Just ScoreAsc) = asc facetDoc_score
286 orderWith' (Just ScoreDesc) = desc facetDoc_score
288 orderWith' (Just SourceAsc) = ascNullsLast facetDoc_source
289 orderWith' (Just SourceDesc) = descNullsLast facetDoc_source
291 orderWith' (Just TagAsc) = asc facetDoc_category
292 orderWith' (Just TagDesc) = desc facetDoc_category
294 orderWith' _ = asc facetDoc_created
296 facetDoc_source :: SqlIsJson a
297 => Facet id created title (Field a) favorite ngramCount score
298 -> FieldNullable SqlText
299 facetDoc_source x = (toNullable $ facetDoc_hyperdata x) .->> sqlString "source"