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
37 import Control.Arrow (returnA)
38 import Control.Lens ((^.))
39 import Data.Aeson (FromJSON, ToJSON)
40 import Data.Aeson.TH (deriveJSON)
41 import Data.Either(Either(Left))
42 import Data.Maybe (Maybe)
43 import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
45 import Data.Text (Text)
46 import Data.Time (UTCTime)
47 import Data.Time.Segment (jour)
48 import Data.Typeable (Typeable)
49 import GHC.Generics (Generic)
51 import Prelude hiding (null, id, map, sum, not, read)
53 import Test.QuickCheck (elements)
54 import Test.QuickCheck.Arbitrary
55 import qualified Opaleye.Internal.Unpackspec()
57 import Gargantext.Core.Types
58 import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger, wellNamedSchema)
59 import Gargantext.Database.Admin.Config (nodeTypeId)
60 import Gargantext.Database.Admin.Types.Hyperdata
61 import Gargantext.Database.Query.Filter
62 import Gargantext.Database.Query.Join (leftJoin5)
63 import Gargantext.Database.Query.Table.Ngrams
64 import Gargantext.Database.Query.Table.NodeNode
65 import Gargantext.Database.Query.Table.NodeNodeNgrams
66 import Gargantext.Database.Prelude
67 import Gargantext.Database.Schema.Node
69 ------------------------------------------------------------------------
72 -- data Facet = FacetDoc | FacetSources | FacetAuthors | FacetTerms
73 -- deriving (Show, Generic)
74 --instance FromJSON Facet
75 --instance ToJSON Facet
81 type FacetDoc = Facet NodeId UTCTime Title HyperdataDocument (Maybe Favorite) (Maybe Double)
82 -- type FacetSources = FacetDoc
83 -- type FacetAuthors = FacetDoc
84 -- type FacetTerms = FacetDoc
87 data Facet id created title hyperdata favorite ngramCount =
88 FacetDoc { facetDoc_id :: id
89 , facetDoc_created :: created
90 , facetDoc_title :: title
91 , facetDoc_hyperdata :: hyperdata
92 , facetDoc_favorite :: favorite
93 , facetDoc_ngramCount :: ngramCount
94 } deriving (Show, Generic)
96 data Facet id date hyperdata score =
97 FacetDoc { facetDoc_id :: id
98 , facetDoc_date :: date
99 , facetDoc_hyperdata :: hyperdata
100 , facetDoc_score :: score
101 } deriving (Show, Generic)
104 data Pair i l = Pair {_p_id :: i
106 } deriving (Show, Generic)
107 $(deriveJSON (unPrefix "_p_") ''Pair)
108 $(makeAdaptorAndInstance "pPair" ''Pair)
110 instance (Typeable i, Typeable l, ToSchema i, ToSchema l) => ToSchema (Pair i l) where
111 declareNamedSchema = wellNamedSchema "_p_"
112 instance (Arbitrary i, Arbitrary l) => Arbitrary (Pair i l) where
113 arbitrary = Pair <$> arbitrary <*> arbitrary
115 data FacetPaired id date hyperdata score =
116 FacetPaired {_fp_id :: id
118 ,_fp_hyperdata :: hyperdata
120 } deriving (Show, Generic)
121 $(deriveJSON (unPrefix "_fp_") ''FacetPaired)
122 $(makeAdaptorAndInstance "pFacetPaired" ''FacetPaired)
124 instance ( ToSchema id
132 ) => ToSchema (FacetPaired id date hyperdata score) where
133 declareNamedSchema = wellNamedSchema "_fp_"
135 instance ( Arbitrary id
137 , Arbitrary hyperdata
139 ) => Arbitrary (FacetPaired id date hyperdata score) where
140 arbitrary = FacetPaired <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
142 type FacetPairedRead = FacetPaired (Column PGInt4 )
143 (Column PGTimestamptz)
147 type FacetPairedReadNull = FacetPaired (Column (Nullable PGInt4) )
148 (Column (Nullable PGTimestamptz))
149 (Column (Nullable PGJsonb) )
150 (Column (Nullable PGInt4) )
155 $(deriveJSON (unPrefix "facetDoc_") ''Facet)
157 -- | Documentation instance
158 instance ToSchema FacetDoc where
159 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "facetDoc_")
161 -- | Mock and Quickcheck instances
162 instance Arbitrary FacetDoc where
163 arbitrary = elements [ FacetDoc id' (jour year 01 01) t hp (Just cat) (Just ngramCount)
165 , year <- [1990..2000]
166 , t <- ["title", "another title"]
167 , hp <- arbitraryHyperdataDocuments
169 , ngramCount <- [3..100]
172 -- Facets / Views for the Front End
173 -- | Database instances
174 $(makeAdaptorAndInstance "pFacetDoc" ''Facet)
175 -- $(makeLensesWith abbreviatedFields ''Facet)
177 type FacetDocRead = Facet (Column PGInt4 )
178 (Column PGTimestamptz)
181 (Column (Nullable PGInt4)) -- Category
182 (Column (Nullable PGFloat8)) -- Score
184 -----------------------------------------------------------------------
185 -----------------------------------------------------------------------
186 data OrderBy = DateAsc | DateDesc
187 | TitleAsc | TitleDesc
188 | ScoreDesc | ScoreAsc
189 | SourceAsc | SourceDesc
190 deriving (Generic, Enum, Bounded, Read, Show)
192 instance FromHttpApiData OrderBy
194 parseUrlPiece "DateAsc" = pure DateAsc
195 parseUrlPiece "DateDesc" = pure DateDesc
196 parseUrlPiece "TitleAsc" = pure TitleAsc
197 parseUrlPiece "TitleDesc" = pure TitleDesc
198 parseUrlPiece "ScoreAsc" = pure ScoreAsc
199 parseUrlPiece "ScoreDesc" = pure ScoreDesc
200 parseUrlPiece "SourceAsc" = pure SourceAsc
201 parseUrlPiece "SourceDesc" = pure SourceDesc
202 parseUrlPiece _ = Left "Unexpected value of OrderBy"
204 instance ToParamSchema OrderBy
205 instance FromJSON OrderBy
206 instance ToJSON OrderBy
207 instance ToSchema OrderBy
208 instance Arbitrary OrderBy
210 arbitrary = elements [minBound..maxBound]
213 -- TODO-SECURITY check
216 runViewAuthorsDoc :: ContactId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
217 runViewAuthorsDoc cId t o l order = runOpaQuery $ filterWith o l order $ viewAuthorsDoc cId t ntId
222 viewAuthorsDoc :: ContactId -> IsTrash -> NodeType -> Query FacetDocRead
223 viewAuthorsDoc cId _ nt = proc () -> do
224 (doc,(_,(_,(_,contact)))) <- queryAuthorsDoc -< ()
226 {-nn <- queryNodeNodeTable -< ()
227 restrict -< nn_node1_id nn .== _node_id doc
228 -- restrict -< nn_delete nn .== (pgBool t)
231 restrict -< _node_id contact .== (toNullable $ pgNodeId cId)
232 restrict -< _node_typename doc .== (pgInt4 $ nodeTypeId nt)
234 returnA -< FacetDoc (_node_id doc)
237 (_node_hyperdata doc)
238 (toNullable $ pgInt4 1)
239 (toNullable $ pgDouble 1)
241 queryAuthorsDoc :: Query (NodeRead, (NodeNodeNgramsReadNull, (NgramsReadNull, (NodeNodeNgramsReadNull, NodeReadNull))))
242 queryAuthorsDoc = leftJoin5 queryNodeTable queryNodeNodeNgramsTable queryNgramsTable queryNodeNodeNgramsTable queryNodeTable cond12 cond23 cond34 cond45
244 cond12 :: (NodeNodeNgramsRead, NodeRead) -> Column PGBool
245 cond12 (nodeNgram, doc) = _node_id doc
246 .== _nnng_node1_id nodeNgram
248 cond23 :: (NgramsRead, (NodeNodeNgramsRead, NodeReadNull)) -> Column PGBool
249 cond23 (ngrams, (nodeNgram, _)) = ngrams^.ngrams_id
250 .== _nnng_ngrams_id nodeNgram
252 cond34 :: (NodeNodeNgramsRead, (NgramsRead, (NodeNodeNgramsReadNull, NodeReadNull))) -> Column PGBool
253 cond34 (nodeNgram2, (ngrams, (_,_)))= ngrams^.ngrams_id .== _nnng_ngrams_id nodeNgram2
255 cond45 :: (NodeRead, (NodeNodeNgramsRead, (NgramsReadNull, (NodeNodeNgramsReadNull, NodeReadNull)))) -> Column PGBool
256 cond45 (contact, (nodeNgram2, (_, (_,_)))) = _node_id contact .== _nnng_node1_id nodeNgram2
259 ------------------------------------------------------------------------
261 -- TODO-SECURITY check
262 runViewDocuments :: CorpusId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
263 runViewDocuments cId t o l order =
264 runOpaQuery $ filterWith o l order $ viewDocuments cId t ntId
266 ntId = nodeTypeId NodeDocument
268 viewDocuments :: CorpusId -> IsTrash -> NodeTypeId -> Query FacetDocRead
269 viewDocuments cId t ntId = proc () -> do
270 n <- queryNodeTable -< ()
271 nn <- queryNodeNodeTable -< ()
272 restrict -< n^.node_id .== nn^.nn_node2_id
273 restrict -< nn^.nn_node1_id .== (pgNodeId cId)
274 restrict -< n^.node_typename .== (pgInt4 ntId)
275 restrict -< if t then nn^.nn_category .== (pgInt4 0)
276 else nn^.nn_category .>= (pgInt4 1)
277 returnA -< FacetDoc (_node_id n)
281 (toNullable $ nn^.nn_category)
282 (toNullable $ nn^.nn_score)
284 ------------------------------------------------------------------------
285 filterWith :: (PGOrd date, PGOrd title, PGOrd score, hyperdata ~ Column SqlJsonb) =>
286 Maybe Gargantext.Core.Types.Offset
287 -> Maybe Gargantext.Core.Types.Limit
289 -> Select (Facet id (Column date) (Column title) hyperdata (Column score) ngramCount)
290 -> Select (Facet id (Column date) (Column title) hyperdata (Column score) ngramCount)
291 filterWith o l order q = limit' l $ offset' o $ orderBy (orderWith order) q
294 orderWith :: (PGOrd b1, PGOrd b2, PGOrd b3)
296 -> Order (Facet id (Column b1) (Column b2) (Column SqlJsonb) (Column b3) score)
297 orderWith (Just DateAsc) = asc facetDoc_created
298 orderWith (Just DateDesc) = desc facetDoc_created
300 orderWith (Just TitleAsc) = asc facetDoc_title
301 orderWith (Just TitleDesc) = desc facetDoc_title
303 orderWith (Just ScoreAsc) = asc facetDoc_favorite
304 orderWith (Just ScoreDesc) = desc facetDoc_favorite
306 orderWith (Just SourceAsc) = asc facetDoc_source
307 orderWith (Just SourceDesc) = desc facetDoc_source
309 orderWith _ = asc facetDoc_created
311 facetDoc_source :: PGIsJson a
312 => Facet id created title (Column a) favorite ngramCount
313 -> Column (Nullable PGText)
314 facetDoc_source x = toNullable (facetDoc_hyperdata x) .->> pgString "source"