3 {-# LANGUAGE ConstraintKinds #-}
4 {-# LANGUAGE ScopedTypeVariables #-}
5 {-# LANGUAGE TemplateHaskell #-}
6 {-# LANGUAGE TypeOperators #-}
7 {-# LANGUAGE TypeFamilies #-}
8 {-# OPTIONS -fno-warn-orphans #-}
10 module Gargantext.API.Ngrams.Types where
12 import Codec.Serialise (Serialise())
13 import Control.Category ((>>>))
14 import Control.Concurrent
15 import Control.Lens (makeLenses, makePrisms, Getter, Iso', iso, from, (.~), (?=), (#), to, folded, {-withIndex, ifolded,-} view, use, (^.), (^?), (%~), (.~), (%=), at, _Just, Each(..), itraverse_, both, forOf_, (?~))
16 import Control.Monad.Reader
17 import Control.Monad.State
18 import Data.Aeson hiding ((.=))
19 import Data.Aeson.TH (deriveJSON)
20 import Data.Either (Either(..))
22 import Data.Hashable (Hashable)
23 import qualified Data.HashMap.Strict.InsOrd as InsOrdHashMap
24 import qualified Data.List as List
25 import Data.Map.Strict (Map)
26 import qualified Data.Map.Strict as Map
27 import qualified Data.Map.Strict.Patch as PM
28 import Data.Maybe (fromMaybe)
30 import Data.Patch.Class (Replace, replace, Action(act), Group, Applicable(..), Composable(..), Transformable(..),
31 PairPatch(..), Patched, ConflictResolution, ConflictResolutionReplace,
32 MaybePatch(Mod), unMod, old, new)
34 import qualified Data.Set as Set
35 import Data.String (IsString, fromString)
36 import Data.Swagger hiding (version, patch)
37 import Data.Text (Text, pack, strip)
39 import Database.PostgreSQL.Simple.FromField (FromField, fromField, ResultError(ConversionFailed), returnError)
40 import GHC.Generics (Generic)
41 import Servant hiding (Patch)
42 import Servant.Job.Utils (jsonOptions)
43 import System.FileLock (FileLock)
44 import Test.QuickCheck (elements, frequency)
45 import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
47 import Protolude (maybeToEither)
48 import Gargantext.Prelude
50 import Gargantext.Prelude.Crypto.Hash (IsHashable(..))
51 import Gargantext.Core.Text (size)
52 import Gargantext.Core.Types (ListType(..), ListId, NodeId)
53 import Gargantext.Core.Types (TODO)
54 import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixUntagged, unPrefixSwagger, wellNamedSchema)
55 import Gargantext.Database.Prelude (fromField', CmdM', HasConnectionPool, HasConfig)
56 import qualified Gargantext.Database.Query.Table.Ngrams as TableNgrams
58 ------------------------------------------------------------------------
59 --data FacetFormat = Table | Chart
60 data TabType = Docs | Trash | MoreFav | MoreTrash
61 | Terms | Sources | Authors | Institutes
63 deriving (Bounded, Enum, Eq, Generic, Ord, Show)
66 instance Hashable TabType
68 instance FromHttpApiData TabType
70 parseUrlPiece "Docs" = pure Docs
71 parseUrlPiece "Trash" = pure Trash
72 parseUrlPiece "MoreFav" = pure MoreFav
73 parseUrlPiece "MoreTrash" = pure MoreTrash
75 parseUrlPiece "Terms" = pure Terms
76 parseUrlPiece "Sources" = pure Sources
77 parseUrlPiece "Institutes" = pure Institutes
78 parseUrlPiece "Authors" = pure Authors
80 parseUrlPiece "Contacts" = pure Contacts
82 parseUrlPiece _ = Left "Unexpected value of TabType"
83 instance ToParamSchema TabType
84 instance ToJSON TabType
85 instance FromJSON TabType
86 instance ToSchema TabType
87 instance Arbitrary TabType
89 arbitrary = elements [minBound .. maxBound]
90 instance FromJSONKey TabType where
91 fromJSONKey = genericFromJSONKey defaultJSONKeyOptions
92 instance ToJSONKey TabType where
93 toJSONKey = genericToJSONKey defaultJSONKeyOptions
95 newtype MSet a = MSet (Map a ())
96 deriving (Eq, Ord, Show, Generic, Arbitrary, Semigroup, Monoid)
98 instance ToJSON a => ToJSON (MSet a) where
99 toJSON (MSet m) = toJSON (Map.keys m)
100 toEncoding (MSet m) = toEncoding (Map.keys m)
102 mSetFromSet :: Set a -> MSet a
103 mSetFromSet = MSet . Map.fromSet (const ())
105 mSetFromList :: Ord a => [a] -> MSet a
106 mSetFromList = MSet . Map.fromList . map (\x -> (x, ()))
108 -- mSetToSet :: Ord a => MSet a -> Set a
109 -- mSetToSet (MSet a) = Set.fromList ( Map.keys a)
110 mSetToSet :: Ord a => MSet a -> Set a
111 mSetToSet = Set.fromList . mSetToList
113 mSetToList :: MSet a -> [a]
114 mSetToList (MSet a) = Map.keys a
116 instance Foldable MSet where
117 foldMap f (MSet m) = Map.foldMapWithKey (\k _ -> f k) m
119 instance (Ord a, FromJSON a) => FromJSON (MSet a) where
120 parseJSON = fmap mSetFromList . parseJSON
122 instance (ToJSONKey a, ToSchema a) => ToSchema (MSet a) where
124 declareNamedSchema _ = wellNamedSchema "" (Proxy :: Proxy TODO)
126 ------------------------------------------------------------------------
127 newtype NgramsTerm = NgramsTerm { unNgramsTerm :: Text }
128 deriving (Ord, Eq, Show, Generic, ToJSONKey, ToJSON, FromJSON, Semigroup, Arbitrary, Serialise, ToSchema, Hashable)
130 instance IsHashable NgramsTerm where
131 hash (NgramsTerm t) = hash t
133 instance Monoid NgramsTerm where
134 mempty = NgramsTerm ""
136 instance FromJSONKey NgramsTerm where
137 fromJSONKey = FromJSONKeyTextParser $ \t -> pure $ NgramsTerm $ strip t
139 instance IsString NgramsTerm where
140 fromString s = NgramsTerm $ pack s
142 instance FromField NgramsTerm
144 fromField field mb = do
145 v <- fromField field mb
147 Success a -> pure $ NgramsTerm $ strip a
148 Error _err -> returnError ConversionFailed field
149 $ List.intercalate " " [ "cannot parse hyperdata for JSON: "
153 data RootParent = RootParent
154 { _rp_root :: NgramsTerm
155 , _rp_parent :: NgramsTerm
157 deriving (Ord, Eq, Show, Generic)
159 deriveJSON (unPrefix "_rp_") ''RootParent
160 makeLenses ''RootParent
162 data NgramsRepoElement = NgramsRepoElement
164 , _nre_list :: !ListType
165 , _nre_root :: !(Maybe NgramsTerm)
166 , _nre_parent :: !(Maybe NgramsTerm)
167 , _nre_children :: !(MSet NgramsTerm)
169 deriving (Ord, Eq, Show, Generic)
171 deriveJSON (unPrefix "_nre_") ''NgramsRepoElement
173 -- if ngrams & not size => size
176 makeLenses ''NgramsRepoElement
178 instance ToSchema NgramsRepoElement where
179 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_nre_")
181 instance Serialise (MSet NgramsTerm)
182 instance Serialise NgramsRepoElement
185 NgramsElement { _ne_ngrams :: NgramsTerm
187 , _ne_list :: ListType
188 , _ne_occurrences :: Int
189 , _ne_root :: Maybe NgramsTerm
190 , _ne_parent :: Maybe NgramsTerm
191 , _ne_children :: MSet NgramsTerm
193 deriving (Ord, Eq, Show, Generic)
195 deriveJSON (unPrefix "_ne_") ''NgramsElement
196 makeLenses ''NgramsElement
198 mkNgramsElement :: NgramsTerm
203 mkNgramsElement ngrams list rp children =
204 NgramsElement ngrams (size (unNgramsTerm ngrams)) list 1 (_rp_root <$> rp) (_rp_parent <$> rp) children
206 newNgramsElement :: Maybe ListType -> NgramsTerm -> NgramsElement
207 newNgramsElement mayList ngrams =
208 mkNgramsElement ngrams (fromMaybe MapTerm mayList) Nothing mempty
210 instance ToSchema NgramsElement where
211 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_ne_")
212 instance Arbitrary NgramsElement where
213 arbitrary = elements [newNgramsElement Nothing "sport"]
216 ------------------------------------------------------------------------
217 newtype NgramsTable = NgramsTable [NgramsElement]
218 deriving (Ord, Eq, Generic, ToJSON, FromJSON, Show)
220 type NgramsList = NgramsTable
222 makePrisms ''NgramsTable
224 -- | Question: why these repetition of Type in this instance
225 -- may you document it please ?
226 instance Each NgramsTable NgramsTable NgramsElement NgramsElement where
227 each = _NgramsTable . each
230 -- | TODO Check N and Weight
232 toNgramsElement :: [NgramsTableData] -> [NgramsElement]
233 toNgramsElement ns = map toNgramsElement' ns
235 toNgramsElement' (NgramsTableData _ p t _ lt w) = NgramsElement t lt' (round w) p' c'
239 Just x -> lookup x mapParent
240 c' = maybe mempty identity $ lookup t mapChildren
241 lt' = maybe (panic "API.Ngrams: listypeId") identity lt
243 mapParent :: Map Int Text
244 mapParent = Map.fromListWith (<>) $ map (\(NgramsTableData i _ t _ _ _) -> (i,t)) ns
246 mapChildren :: Map Text (Set Text)
247 mapChildren = Map.mapKeys (\i -> (maybe (panic "API.Ngrams.mapChildren: ParentId with no Terms: Impossible") identity $ lookup i mapParent))
248 $ Map.fromListWith (<>)
249 $ map (first fromJust)
250 $ filter (isJust . fst)
251 $ map (\(NgramsTableData _ p t _ _ _) -> (p, Set.singleton t)) ns
254 mockTable :: NgramsTable
255 mockTable = NgramsTable
256 [ mkNgramsElement "animal" MapTerm Nothing (mSetFromList ["dog", "cat"])
257 , mkNgramsElement "cat" MapTerm (rp "animal") mempty
258 , mkNgramsElement "cats" StopTerm Nothing mempty
259 , mkNgramsElement "dog" MapTerm (rp "animal") (mSetFromList ["dogs"])
260 , mkNgramsElement "dogs" StopTerm (rp "dog") mempty
261 , mkNgramsElement "fox" MapTerm Nothing mempty
262 , mkNgramsElement "object" CandidateTerm Nothing mempty
263 , mkNgramsElement "nothing" StopTerm Nothing mempty
264 , mkNgramsElement "organic" MapTerm Nothing (mSetFromList ["flower"])
265 , mkNgramsElement "flower" MapTerm (rp "organic") mempty
266 , mkNgramsElement "moon" CandidateTerm Nothing mempty
267 , mkNgramsElement "sky" StopTerm Nothing mempty
270 rp n = Just $ RootParent n n
272 instance Arbitrary NgramsTable where
273 arbitrary = pure mockTable
275 instance ToSchema NgramsTable
277 ------------------------------------------------------------------------
278 type NgramsTableMap = Map NgramsTerm NgramsRepoElement
279 ------------------------------------------------------------------------
280 -- On the Client side:
281 --data Action = InGroup NgramsId NgramsId
282 -- | OutGroup NgramsId NgramsId
283 -- | SetListType NgramsId ListType
285 data PatchSet a = PatchSet
289 deriving (Eq, Ord, Show, Generic)
291 makeLenses ''PatchSet
292 makePrisms ''PatchSet
294 instance ToJSON a => ToJSON (PatchSet a) where
295 toJSON = genericToJSON $ unPrefix "_"
296 toEncoding = genericToEncoding $ unPrefix "_"
298 instance (Ord a, FromJSON a) => FromJSON (PatchSet a) where
299 parseJSON = genericParseJSON $ unPrefix "_"
302 instance (Ord a, Arbitrary a) => Arbitrary (PatchSet a) where
303 arbitrary = PatchSet <$> arbitrary <*> arbitrary
305 type instance Patched (PatchSet a) = Set a
307 type ConflictResolutionPatchSet a = SimpleConflictResolution' (Set a)
308 type instance ConflictResolution (PatchSet a) = ConflictResolutionPatchSet a
310 instance Ord a => Semigroup (PatchSet a) where
311 p <> q = PatchSet { _rem = (q ^. rem) `Set.difference` (p ^. add) <> p ^. rem
312 , _add = (q ^. add) `Set.difference` (p ^. rem) <> p ^. add
315 instance Ord a => Monoid (PatchSet a) where
316 mempty = PatchSet mempty mempty
318 instance Ord a => Group (PatchSet a) where
319 invert (PatchSet r a) = PatchSet a r
321 instance Ord a => Composable (PatchSet a) where
322 composable _ _ = undefined
324 instance Ord a => Action (PatchSet a) (Set a) where
325 act p source = (source `Set.difference` (p ^. rem)) <> p ^. add
327 instance Applicable (PatchSet a) (Set a) where
328 applicable _ _ = mempty
330 instance Ord a => Validity (PatchSet a) where
331 validate p = check (Set.disjoint (p ^. rem) (p ^. add)) "_rem and _add should be dijoint"
333 instance Ord a => Transformable (PatchSet a) where
334 transformable = undefined
336 conflicts _p _q = undefined
338 transformWith conflict p q = undefined conflict p q
340 instance ToSchema a => ToSchema (PatchSet a)
343 type AddRem = Replace (Maybe ())
345 instance Serialise AddRem
347 remPatch, addPatch :: AddRem
348 remPatch = replace (Just ()) Nothing
349 addPatch = replace Nothing (Just ())
351 isRem :: Replace (Maybe ()) -> Bool
352 isRem = (== remPatch)
354 type PatchMap = PM.PatchMap
356 newtype PatchMSet a = PatchMSet (PatchMap a AddRem)
357 deriving (Eq, Show, Generic, Validity, Semigroup, Monoid, Group,
358 Transformable, Composable)
360 unPatchMSet :: PatchMSet a -> PatchMap a AddRem
361 unPatchMSet (PatchMSet a) = a
363 type ConflictResolutionPatchMSet a = a -> ConflictResolutionReplace (Maybe ())
364 type instance ConflictResolution (PatchMSet a) = ConflictResolutionPatchMSet a
366 instance (Serialise a, Ord a) => Serialise (PatchMap a AddRem)
367 instance (Serialise a, Ord a) => Serialise (PatchMSet a)
369 -- TODO this breaks module abstraction
370 makePrisms ''PM.PatchMap
372 makePrisms ''PatchMSet
374 _PatchMSetIso :: Ord a => Iso' (PatchMSet a) (PatchSet a)
375 _PatchMSetIso = _PatchMSet . _PatchMap . iso f g . from _PatchSet
377 f :: Ord a => Map a (Replace (Maybe ())) -> (Set a, Set a)
378 f = Map.partition isRem >>> both %~ Map.keysSet
380 g :: Ord a => (Set a, Set a) -> Map a (Replace (Maybe ()))
381 g (rems, adds) = Map.fromSet (const remPatch) rems
382 <> Map.fromSet (const addPatch) adds
384 instance Ord a => Action (PatchMSet a) (MSet a) where
385 act (PatchMSet p) (MSet m) = MSet $ act p m
387 instance Ord a => Applicable (PatchMSet a) (MSet a) where
388 applicable (PatchMSet p) (MSet m) = applicable p m
390 instance (Ord a, ToJSON a) => ToJSON (PatchMSet a) where
391 toJSON = toJSON . view _PatchMSetIso
392 toEncoding = toEncoding . view _PatchMSetIso
394 instance (Ord a, FromJSON a) => FromJSON (PatchMSet a) where
395 parseJSON = fmap (_PatchMSetIso #) . parseJSON
397 instance (Ord a, Arbitrary a) => Arbitrary (PatchMSet a) where
398 arbitrary = (PatchMSet . PM.fromMap) <$> arbitrary
400 instance ToSchema a => ToSchema (PatchMSet a) where
402 declareNamedSchema _ = wellNamedSchema "" (Proxy :: Proxy TODO)
404 type instance Patched (PatchMSet a) = MSet a
406 instance (Eq a, Arbitrary a) => Arbitrary (Replace a) where
407 arbitrary = uncurry replace <$> arbitrary
408 -- If they happen to be equal then the patch is Keep.
410 instance ToSchema a => ToSchema (Replace a) where
411 declareNamedSchema (_ :: Proxy (Replace a)) = do
412 -- TODO Keep constructor is not supported here.
413 aSchema <- declareSchemaRef (Proxy :: Proxy a)
414 return $ NamedSchema (Just "Replace") $ mempty
415 & type_ ?~ SwaggerObject
417 InsOrdHashMap.fromList
421 & required .~ [ "old", "new" ]
424 = NgramsPatch { _patch_children :: !(PatchMSet NgramsTerm)
425 , _patch_list :: !(Replace ListType) -- TODO Map UserId ListType
427 | NgramsReplace { _patch_old :: !(Maybe NgramsRepoElement)
428 , _patch_new :: !(Maybe NgramsRepoElement)
430 deriving (Eq, Show, Generic)
432 -- The JSON encoding is untagged, this is OK since the field names are disjoints and thus the encoding is unambiguous.
433 -- TODO: the empty object should be accepted and treated as mempty.
434 deriveJSON (unPrefixUntagged "_") ''NgramsPatch
435 makeLenses ''NgramsPatch
437 -- TODO: This instance is simplified since we should either have the fields children and/or list
438 -- or the fields old and/or new.
439 instance ToSchema NgramsPatch where
440 declareNamedSchema _ = do
441 childrenSch <- declareSchemaRef (Proxy :: Proxy (PatchMSet NgramsTerm))
442 listSch <- declareSchemaRef (Proxy :: Proxy (Replace ListType))
443 nreSch <- declareSchemaRef (Proxy :: Proxy NgramsRepoElement)
444 return $ NamedSchema (Just "NgramsPatch") $ mempty
445 & type_ ?~ SwaggerObject
447 InsOrdHashMap.fromList
448 [ ("children", childrenSch)
454 instance Arbitrary NgramsPatch where
455 arbitrary = frequency [ (9, NgramsPatch <$> arbitrary <*> (replace <$> arbitrary <*> arbitrary))
456 , (1, NgramsReplace <$> arbitrary <*> arbitrary)
459 instance Serialise NgramsPatch
460 instance Serialise (Replace ListType)
462 instance Serialise ListType
464 type NgramsPatchIso =
465 MaybePatch NgramsRepoElement (PairPatch (PatchMSet NgramsTerm) (Replace ListType))
467 _NgramsPatch :: Iso' NgramsPatch NgramsPatchIso
468 _NgramsPatch = iso unwrap wrap
470 unwrap (NgramsPatch c l) = Mod $ PairPatch (c, l)
471 unwrap (NgramsReplace o n) = replace o n
474 Just (PairPatch (c, l)) -> NgramsPatch c l
475 Nothing -> NgramsReplace (x ^? old . _Just) (x ^? new . _Just)
477 instance Semigroup NgramsPatch where
478 p <> q = _NgramsPatch # (p ^. _NgramsPatch <> q ^. _NgramsPatch)
480 instance Monoid NgramsPatch where
481 mempty = _NgramsPatch # mempty
483 instance Validity NgramsPatch where
484 validate p = p ^. _NgramsPatch . to validate
486 instance Transformable NgramsPatch where
487 transformable p q = transformable (p ^. _NgramsPatch) (q ^. _NgramsPatch)
489 conflicts p q = conflicts (p ^. _NgramsPatch) (q ^. _NgramsPatch)
491 transformWith conflict p q = (_NgramsPatch # p', _NgramsPatch # q')
493 (p', q') = transformWith conflict (p ^. _NgramsPatch) (q ^. _NgramsPatch)
495 type ConflictResolutionNgramsPatch =
496 ( ConflictResolutionReplace (Maybe NgramsRepoElement)
497 , ( ConflictResolutionPatchMSet NgramsTerm
498 , ConflictResolutionReplace ListType
502 type instance ConflictResolution NgramsPatch =
503 ConflictResolutionNgramsPatch
505 type PatchedNgramsPatch = Maybe NgramsRepoElement
506 type instance Patched NgramsPatch = PatchedNgramsPatch
508 instance Applicable (PairPatch (PatchMSet NgramsTerm) (Replace ListType)) NgramsRepoElement where
509 applicable (PairPatch (c, l)) n = applicable c (n ^. nre_children) <> applicable l (n ^. nre_list)
511 instance Action (PairPatch (PatchMSet NgramsTerm) (Replace ListType)) NgramsRepoElement where
512 act (PairPatch (c, l)) = (nre_children %~ act c)
513 . (nre_list %~ act l)
515 instance Applicable NgramsPatch (Maybe NgramsRepoElement) where
516 applicable p = applicable (p ^. _NgramsPatch)
518 instance Action NgramsPatch (Maybe NgramsRepoElement) where
519 act p = act (p ^. _NgramsPatch)
521 newtype NgramsTablePatch = NgramsTablePatch (PatchMap NgramsTerm NgramsPatch)
522 deriving (Eq, Show, Generic, ToJSON, FromJSON, Semigroup, Monoid, Validity, Transformable)
524 instance Serialise NgramsTablePatch
525 instance Serialise (PatchMap NgramsTerm NgramsPatch)
527 instance FromField NgramsTablePatch
529 fromField = fromField'
531 instance FromField (PatchMap TableNgrams.NgramsType (PatchMap NodeId NgramsTablePatch))
533 fromField = fromField'
535 type instance ConflictResolution NgramsTablePatch =
536 NgramsTerm -> ConflictResolutionNgramsPatch
538 type PatchedNgramsTablePatch = Map NgramsTerm PatchedNgramsPatch
539 -- ~ Patched (PatchMap NgramsTerm NgramsPatch)
540 type instance Patched NgramsTablePatch = PatchedNgramsTablePatch
542 makePrisms ''NgramsTablePatch
543 instance ToSchema (PatchMap NgramsTerm NgramsPatch)
544 instance ToSchema NgramsTablePatch
546 instance Applicable NgramsTablePatch (Maybe NgramsTableMap) where
547 applicable p = applicable (p ^. _NgramsTablePatch)
550 ngramsElementToRepo :: NgramsElement -> NgramsRepoElement
552 (NgramsElement { _ne_size = s
566 ngramsElementFromRepo :: NgramsTerm -> NgramsRepoElement -> NgramsElement
567 ngramsElementFromRepo
576 NgramsElement { _ne_size = s
581 , _ne_ngrams = ngrams
582 , _ne_occurrences = panic $ "API.Ngrams._ne_occurrences"
584 -- Here we could use 0 if we want to avoid any `panic`.
585 -- It will not happen using getTableNgrams if
586 -- getOccByNgramsOnly provides a count of occurrences for
587 -- all the ngrams given.
591 reRootChildren :: NgramsTerm -> ReParent NgramsTerm
592 reRootChildren root ngram = do
593 nre <- use $ at ngram
594 forOf_ (_Just . nre_children . folded) nre $ \child -> do
595 at child . _Just . nre_root ?= root
596 reRootChildren root child
598 reParent :: Maybe RootParent -> ReParent NgramsTerm
599 reParent rp child = do
600 at child . _Just %= ( (nre_parent .~ (_rp_parent <$> rp))
601 . (nre_root .~ (_rp_root <$> rp))
603 reRootChildren (fromMaybe child (rp ^? _Just . rp_root)) child
605 reParentAddRem :: RootParent -> NgramsTerm -> ReParent AddRem
606 reParentAddRem rp child p =
607 reParent (if isRem p then Nothing else Just rp) child
609 reParentNgramsPatch :: NgramsTerm -> ReParent NgramsPatch
610 reParentNgramsPatch parent ngramsPatch = do
611 root_of_parent <- use (at parent . _Just . nre_root)
613 root = fromMaybe parent root_of_parent
614 rp = RootParent { _rp_root = root, _rp_parent = parent }
615 itraverse_ (reParentAddRem rp) (ngramsPatch ^. patch_children . _PatchMSet . _PatchMap)
616 -- TODO FoldableWithIndex/TraversableWithIndex for PatchMap
618 reParentNgramsTablePatch :: ReParent NgramsTablePatch
619 reParentNgramsTablePatch p = itraverse_ reParentNgramsPatch (p ^. _NgramsTablePatch. _PatchMap)
620 -- TODO FoldableWithIndex/TraversableWithIndex for PatchMap
622 ------------------------------------------------------------------------
624 instance Action NgramsTablePatch (Maybe NgramsTableMap) where
626 fmap (execState (reParentNgramsTablePatch p)) .
627 act (p ^. _NgramsTablePatch)
629 instance Arbitrary NgramsTablePatch where
630 arbitrary = NgramsTablePatch <$> PM.fromMap <$> arbitrary
632 -- Should it be less than an Lens' to preserve PatchMap's abstraction.
633 -- ntp_ngrams_patches :: Lens' NgramsTablePatch (Map NgramsTerm NgramsPatch)
634 -- ntp_ngrams_patches = _NgramsTablePatch . undefined
636 type ReParent a = forall m. MonadState NgramsTableMap m => a -> m ()
638 ------------------------------------------------------------------------
641 data Versioned a = Versioned
642 { _v_version :: Version
645 deriving (Generic, Show, Eq)
646 deriveJSON (unPrefix "_v_") ''Versioned
647 makeLenses ''Versioned
648 instance (Typeable a, ToSchema a) => ToSchema (Versioned a) where
649 declareNamedSchema = wellNamedSchema "_v_"
650 instance Arbitrary a => Arbitrary (Versioned a) where
651 arbitrary = Versioned 1 <$> arbitrary -- TODO 1 is constant so far
653 ------------------------------------------------------------------------
655 { _r_version :: !Version
658 -- first patch in the list is the most recent
660 deriving (Generic, Show)
662 instance (FromJSON s, FromJSON p) => FromJSON (Repo s p) where
663 parseJSON = genericParseJSON $ unPrefix "_r_"
665 instance (ToJSON s, ToJSON p) => ToJSON (Repo s p) where
666 toJSON = genericToJSON $ unPrefix "_r_"
667 toEncoding = genericToEncoding $ unPrefix "_r_"
669 instance (Serialise s, Serialise p) => Serialise (Repo s p)
673 initRepo :: Monoid s => Repo s p
674 initRepo = Repo 1 mempty []
676 type NgramsRepo = Repo NgramsState NgramsStatePatch
677 type NgramsState = Map TableNgrams.NgramsType (Map NodeId NgramsTableMap)
678 type NgramsStatePatch = PatchMap TableNgrams.NgramsType (PatchMap NodeId NgramsTablePatch)
680 instance Serialise (PM.PatchMap NodeId NgramsTablePatch)
681 instance Serialise NgramsStatePatch
683 initMockRepo :: NgramsRepo
684 initMockRepo = Repo 1 s []
686 s = Map.singleton TableNgrams.NgramsTerms
687 $ Map.singleton 47254
689 [ (n ^. ne_ngrams, ngramsElementToRepo n) | n <- mockTable ^. _NgramsTable ]
691 data RepoEnv = RepoEnv
692 { _renv_var :: !(MVar NgramsRepo)
693 , _renv_saver :: !(IO ())
694 , _renv_lock :: !FileLock
700 class HasRepoVar env where
701 repoVar :: Getter env (MVar NgramsRepo)
703 instance HasRepoVar (MVar NgramsRepo) where
706 class HasRepoSaver env where
707 repoSaver :: Getter env (IO ())
709 class (HasRepoVar env, HasRepoSaver env) => HasRepo env where
710 repoEnv :: Getter env RepoEnv
712 instance HasRepo RepoEnv where
715 instance HasRepoVar RepoEnv where
718 instance HasRepoSaver RepoEnv where
719 repoSaver = renv_saver
721 type RepoCmdM env err m =
724 , HasConnectionPool env
729 type QueryParamR = QueryParam' '[Required, Strict]
733 instance Arbitrary NgramsRepoElement where
734 arbitrary = elements $ map ngramsElementToRepo ns
736 NgramsTable ns = mockTable
739 instance FromHttpApiData (Map TableNgrams.NgramsType (Versioned NgramsTableMap))
741 parseUrlPiece x = maybeToEither x (decode $ cs x)
744 ngramsTypeFromTabType :: TabType -> TableNgrams.NgramsType
745 ngramsTypeFromTabType tabType =
746 let lieu = "Garg.API.Ngrams: " :: Text in
748 Sources -> TableNgrams.Sources
749 Authors -> TableNgrams.Authors
750 Institutes -> TableNgrams.Institutes
751 Terms -> TableNgrams.NgramsTerms
752 _ -> panic $ lieu <> "No Ngrams for this tab"
753 -- TODO: This `panic` would disapear with custom NgramsType.
758 data UpdateTableNgramsCharts = UpdateTableNgramsCharts
759 { _utn_tab_type :: !TabType
760 , _utn_list_id :: !ListId
761 } deriving (Eq, Show, Generic)
763 makeLenses ''UpdateTableNgramsCharts
764 instance FromJSON UpdateTableNgramsCharts where
765 parseJSON = genericParseJSON $ jsonOptions "_utn_"
766 instance ToSchema UpdateTableNgramsCharts where
767 declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_utn_")