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 {-# OPTIONS_GHC -fno-warn-orphans #-}
12 {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
14 {-# LANGUAGE Arrows #-}
15 {-# LANGUAGE FunctionalDependencies #-}
16 {-# LANGUAGE QuasiQuotes #-}
17 {-# LANGUAGE NoMonomorphismRestriction #-}
18 {-# LANGUAGE TemplateHaskell #-}
19 {-# LANGUAGE TypeFamilies #-}
20 ------------------------------------------------------------------------
21 module Gargantext.Database.Query.Facet
33 , FacetPairedReadNullAgg
38 import Control.Arrow (returnA)
39 import Control.Lens ((^.))
40 import Data.Aeson (FromJSON, ToJSON)
41 import Data.Aeson.TH (deriveJSON)
42 import Data.Either(Either(Left))
43 import Data.Maybe (Maybe)
44 import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
46 import Data.Text (Text)
47 import Data.Time (UTCTime)
48 import Data.Time.Segment (jour)
49 import Data.Typeable (Typeable)
50 import GHC.Generics (Generic)
52 import Prelude hiding (null, id, map, sum, not, read)
54 import Test.QuickCheck (elements)
55 import Test.QuickCheck.Arbitrary
56 import qualified Opaleye.Internal.Unpackspec()
58 import Gargantext.Core.Types
59 import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger, wellNamedSchema)
60 import Gargantext.Database.Admin.Config (nodeTypeId)
61 import Gargantext.Database.Admin.Types.Hyperdata
62 import Gargantext.Database.Query.Filter
63 import Gargantext.Database.Query.Join (leftJoin5)
64 import Gargantext.Database.Query.Table.Ngrams
65 import Gargantext.Database.Query.Table.NodeNode
66 import Gargantext.Database.Query.Table.NodeNodeNgrams
67 import Gargantext.Database.Prelude
68 import Gargantext.Database.Schema.Node
70 ------------------------------------------------------------------------
73 -- data Facet = FacetDoc | FacetSources | FacetAuthors | FacetTerms
74 -- deriving (Show, Generic)
75 --instance FromJSON Facet
76 --instance ToJSON Facet
82 type FacetDoc = Facet NodeId UTCTime Title HyperdataDocument (Maybe Favorite) (Maybe Double)
83 -- type FacetSources = FacetDoc
84 -- type FacetAuthors = FacetDoc
85 -- type FacetTerms = FacetDoc
88 data Facet id created title hyperdata favorite ngramCount =
89 FacetDoc { facetDoc_id :: id
90 , facetDoc_created :: created
91 , facetDoc_title :: title
92 , facetDoc_hyperdata :: hyperdata
93 , facetDoc_favorite :: favorite
94 , facetDoc_ngramCount :: ngramCount
95 } deriving (Show, Generic)
97 data Facet id date hyperdata score =
98 FacetDoc { facetDoc_id :: id
99 , facetDoc_date :: date
100 , facetDoc_hyperdata :: hyperdata
101 , facetDoc_score :: score
102 } deriving (Show, Generic)
105 data Pair i l = Pair {_p_id :: i
107 } deriving (Show, Generic)
108 $(deriveJSON (unPrefix "_p_") ''Pair)
109 $(makeAdaptorAndInstance "pPair" ''Pair)
111 instance (Typeable i, Typeable l, ToSchema i, ToSchema l) => ToSchema (Pair i l) where
112 declareNamedSchema = wellNamedSchema "_p_"
113 instance (Arbitrary i, Arbitrary l) => Arbitrary (Pair i l) where
114 arbitrary = Pair <$> arbitrary <*> arbitrary
116 data FacetPaired id date hyperdata score =
117 FacetPaired {_fp_id :: id
119 ,_fp_hyperdata :: hyperdata
121 } deriving (Show, Generic)
122 $(deriveJSON (unPrefix "_fp_") ''FacetPaired)
123 $(makeAdaptorAndInstance "pFacetPaired" ''FacetPaired)
127 instance ( ToSchema id
135 ) => ToSchema (FacetPaired id date hyperdata score) where
136 declareNamedSchema = wellNamedSchema "_fp_"
138 instance ( Arbitrary id
140 , Arbitrary hyperdata
142 ) => Arbitrary (FacetPaired id date hyperdata score) where
143 arbitrary = FacetPaired <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
145 type FacetPairedRead = FacetPaired (Column PGInt4 )
146 (Column PGTimestamptz)
150 type FacetPairedReadNull = FacetPaired (Column (Nullable PGInt4) )
151 (Column (Nullable PGTimestamptz))
152 (Column (Nullable PGJsonb) )
153 (Column (Nullable PGInt4) )
155 type FacetPairedReadNullAgg = FacetPaired (Aggregator (Column (Nullable PGInt4) )
156 (Column (Nullable PGInt4) )
158 (Aggregator (Column (Nullable PGTimestamptz))
159 (Column (Nullable PGTimestamptz))
162 (Aggregator (Column (Nullable PGJsonb) )
163 (Column (Nullable PGJsonb) )
165 (Aggregator (Column (Nullable PGInt4) )
166 (Column (Nullable PGInt4) )
173 $(deriveJSON (unPrefix "facetDoc_") ''Facet)
175 -- | Documentation instance
176 instance ToSchema FacetDoc where
177 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "facetDoc_")
179 -- | Mock and Quickcheck instances
180 instance Arbitrary FacetDoc where
181 arbitrary = elements [ FacetDoc id' (jour year 01 01) t hp (Just cat) (Just ngramCount)
183 , year <- [1990..2000]
184 , t <- ["title", "another title"]
185 , hp <- arbitraryHyperdataDocuments
187 , ngramCount <- [3..100]
190 -- Facets / Views for the Front End
191 -- | Database instances
192 $(makeAdaptorAndInstance "pFacetDoc" ''Facet)
193 -- $(makeLensesWith abbreviatedFields ''Facet)
195 type FacetDocRead = Facet (Column PGInt4 )
196 (Column PGTimestamptz)
199 (Column (Nullable PGInt4)) -- Category
200 (Column (Nullable PGFloat8)) -- Score
202 -----------------------------------------------------------------------
203 -----------------------------------------------------------------------
204 data OrderBy = DateAsc | DateDesc
205 | TitleAsc | TitleDesc
206 | ScoreDesc | ScoreAsc
207 | SourceAsc | SourceDesc
208 deriving (Generic, Enum, Bounded, Read, Show)
210 instance FromHttpApiData OrderBy
212 parseUrlPiece "DateAsc" = pure DateAsc
213 parseUrlPiece "DateDesc" = pure DateDesc
214 parseUrlPiece "TitleAsc" = pure TitleAsc
215 parseUrlPiece "TitleDesc" = pure TitleDesc
216 parseUrlPiece "ScoreAsc" = pure ScoreAsc
217 parseUrlPiece "ScoreDesc" = pure ScoreDesc
218 parseUrlPiece "SourceAsc" = pure SourceAsc
219 parseUrlPiece "SourceDesc" = pure SourceDesc
220 parseUrlPiece _ = Left "Unexpected value of OrderBy"
222 instance ToParamSchema OrderBy
223 instance FromJSON OrderBy
224 instance ToJSON OrderBy
225 instance ToSchema OrderBy
226 instance Arbitrary OrderBy
228 arbitrary = elements [minBound..maxBound]
231 -- TODO-SECURITY check
234 runViewAuthorsDoc :: ContactId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
235 runViewAuthorsDoc cId t o l order = runOpaQuery $ filterWith o l order $ viewAuthorsDoc cId t ntId
240 viewAuthorsDoc :: ContactId -> IsTrash -> NodeType -> Query FacetDocRead
241 viewAuthorsDoc cId _ nt = proc () -> do
242 (doc,(_,(_,(_,contact)))) <- queryAuthorsDoc -< ()
244 {-nn <- queryNodeNodeTable -< ()
245 restrict -< nn_node1_id nn .== _node_id doc
246 -- restrict -< nn_delete nn .== (pgBool t)
249 restrict -< _node_id contact .== (toNullable $ pgNodeId cId)
250 restrict -< _node_typename doc .== (pgInt4 $ nodeTypeId nt)
252 returnA -< FacetDoc (_node_id doc)
255 (_node_hyperdata doc)
256 (toNullable $ pgInt4 1)
257 (toNullable $ pgDouble 1)
259 queryAuthorsDoc :: Query (NodeRead, (NodeNodeNgramsReadNull, (NgramsReadNull, (NodeNodeNgramsReadNull, NodeReadNull))))
260 queryAuthorsDoc = leftJoin5 queryNodeTable queryNodeNodeNgramsTable queryNgramsTable queryNodeNodeNgramsTable queryNodeTable cond12 cond23 cond34 cond45
262 cond12 :: (NodeNodeNgramsRead, NodeRead) -> Column PGBool
263 cond12 (nodeNgram, doc) = _node_id doc
264 .== _nnng_node1_id nodeNgram
266 cond23 :: (NgramsRead, (NodeNodeNgramsRead, NodeReadNull)) -> Column PGBool
267 cond23 (ngrams, (nodeNgram, _)) = ngrams^.ngrams_id
268 .== _nnng_ngrams_id nodeNgram
270 cond34 :: (NodeNodeNgramsRead, (NgramsRead, (NodeNodeNgramsReadNull, NodeReadNull))) -> Column PGBool
271 cond34 (nodeNgram2, (ngrams, (_,_)))= ngrams^.ngrams_id .== _nnng_ngrams_id nodeNgram2
273 cond45 :: (NodeRead, (NodeNodeNgramsRead, (NgramsReadNull, (NodeNodeNgramsReadNull, NodeReadNull)))) -> Column PGBool
274 cond45 (contact, (nodeNgram2, (_, (_,_)))) = _node_id contact .== _nnng_node1_id nodeNgram2
277 ------------------------------------------------------------------------
279 -- TODO-SECURITY check
280 runViewDocuments :: CorpusId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
281 runViewDocuments cId t o l order =
282 runOpaQuery $ filterWith o l order $ viewDocuments cId t ntId
284 ntId = nodeTypeId NodeDocument
286 viewDocuments :: CorpusId -> IsTrash -> NodeTypeId -> Query FacetDocRead
287 viewDocuments cId t ntId = proc () -> do
288 n <- queryNodeTable -< ()
289 nn <- queryNodeNodeTable -< ()
290 restrict -< n^.node_id .== nn^.nn_node2_id
291 restrict -< nn^.nn_node1_id .== (pgNodeId cId)
292 restrict -< n^.node_typename .== (pgInt4 ntId)
293 restrict -< if t then nn^.nn_category .== (pgInt4 0)
294 else nn^.nn_category .>= (pgInt4 1)
295 returnA -< FacetDoc (_node_id n)
299 (toNullable $ nn^.nn_category)
300 (toNullable $ nn^.nn_score)
302 ------------------------------------------------------------------------
303 filterWith :: (PGOrd date, PGOrd title, PGOrd score, hyperdata ~ Column SqlJsonb) =>
304 Maybe Gargantext.Core.Types.Offset
305 -> Maybe Gargantext.Core.Types.Limit
307 -> Select (Facet id (Column date) (Column title) hyperdata (Column score) ngramCount)
308 -> Select (Facet id (Column date) (Column title) hyperdata (Column score) ngramCount)
309 filterWith o l order q = limit' l $ offset' o $ orderBy (orderWith order) q
312 orderWith :: (PGOrd b1, PGOrd b2, PGOrd b3)
314 -> Order (Facet id (Column b1) (Column b2) (Column SqlJsonb) (Column b3) score)
315 orderWith (Just DateAsc) = asc facetDoc_created
316 orderWith (Just DateDesc) = desc facetDoc_created
318 orderWith (Just TitleAsc) = asc facetDoc_title
319 orderWith (Just TitleDesc) = desc facetDoc_title
321 orderWith (Just ScoreAsc) = asc facetDoc_favorite
322 orderWith (Just ScoreDesc) = desc facetDoc_favorite
324 orderWith (Just SourceAsc) = asc facetDoc_source
325 orderWith (Just SourceDesc) = desc facetDoc_source
327 orderWith _ = asc facetDoc_created
329 facetDoc_source :: PGIsJson a
330 => Facet id created title (Column a) favorite ngramCount
331 -> Column (Nullable PGText)
332 facetDoc_source x = toNullable (facetDoc_hyperdata x) .->> pgString "source"