-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module Galley.Cassandra.ConversationList
  ( interpretConversationListToCassandra,
    interpretRemoteConversationListToCassandra,
    interpretLegacyConversationListToCassandra,
  )
where

import Cassandra
import Data.Id
import Data.Qualified
import Data.Range
import Galley.Cassandra.Instances ()
import Galley.Cassandra.Queries qualified as Cql
import Galley.Cassandra.Store
import Galley.Cassandra.Util
import Galley.Effects.ListItems
import Imports hiding (max)
import Polysemy
import Polysemy.Input
import Polysemy.TinyLog
import Wire.Sem.Paging.Cassandra

-- | Deprecated, use 'localConversationIdsPageFrom'
conversationIdsFrom ::
  UserId ->
  Maybe ConvId ->
  Range 1 1000 Int32 ->
  Client (ResultSet ConvId)
conversationIdsFrom :: UserId
-> Maybe ConvId -> Range 1 1000 Int32 -> Client (ResultSet ConvId)
conversationIdsFrom UserId
usr Maybe ConvId
start (Range 1 1000 Int32 -> Int32
forall (n :: Nat) (m :: Nat) a. Range n m a -> a
fromRange -> Int32
max) =
  Page ConvId -> ResultSet ConvId
forall a. Page a -> ResultSet a
mkResultSet (Page ConvId -> ResultSet ConvId)
-> (Page (Identity ConvId) -> Page ConvId)
-> Page (Identity ConvId)
-> ResultSet ConvId
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Page ConvId -> Page ConvId
strip (Page ConvId -> Page ConvId)
-> (Page (Identity ConvId) -> Page ConvId)
-> Page (Identity ConvId)
-> Page ConvId
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Identity ConvId -> ConvId)
-> Page (Identity ConvId) -> Page ConvId
forall a b. (a -> b) -> Page a -> Page b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Identity ConvId -> ConvId
forall a. Identity a -> a
runIdentity (Page (Identity ConvId) -> ResultSet ConvId)
-> Client (Page (Identity ConvId)) -> Client (ResultSet ConvId)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> case Maybe ConvId
start of
    Just ConvId
c -> PrepQuery R (UserId, ConvId) (Identity ConvId)
-> QueryParams (UserId, ConvId) -> Client (Page (Identity ConvId))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Page b)
paginate PrepQuery R (UserId, ConvId) (Identity ConvId)
Cql.selectUserConvsFrom (Consistency
-> (UserId, ConvId) -> Int32 -> QueryParams (UserId, ConvId)
forall a. Consistency -> a -> Int32 -> QueryParams a
paramsP Consistency
LocalQuorum (UserId
usr, ConvId
c) (Int32
max Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
+ Int32
1))
    Maybe ConvId
Nothing -> PrepQuery R (Identity UserId) (Identity ConvId)
-> QueryParams (Identity UserId) -> Client (Page (Identity ConvId))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Page b)
paginate PrepQuery R (Identity UserId) (Identity ConvId)
Cql.selectUserConvs (Consistency
-> Identity UserId -> Int32 -> QueryParams (Identity UserId)
forall a. Consistency -> a -> Int32 -> QueryParams a
paramsP Consistency
LocalQuorum (UserId -> Identity UserId
forall a. a -> Identity a
Identity UserId
usr) (Int32
max Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
+ Int32
1))
  where
    strip :: Page ConvId -> Page ConvId
strip Page ConvId
p = Page ConvId
p {result = take (fromIntegral max) (result p)}

localConversationIdsPageFrom ::
  UserId ->
  Maybe PagingState ->
  Range 1 1000 Int32 ->
  Client (PageWithState ConvId)
localConversationIdsPageFrom :: UserId
-> Maybe PagingState
-> Range 1 1000 Int32
-> Client (PageWithState ConvId)
localConversationIdsPageFrom UserId
usr Maybe PagingState
pagingState (Range 1 1000 Int32 -> Int32
forall (n :: Nat) (m :: Nat) a. Range n m a -> a
fromRange -> Int32
max) =
  (Identity ConvId -> ConvId)
-> PageWithState (Identity ConvId) -> PageWithState ConvId
forall a b. (a -> b) -> PageWithState a -> PageWithState b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Identity ConvId -> ConvId
forall a. Identity a -> a
runIdentity (PageWithState (Identity ConvId) -> PageWithState ConvId)
-> Client (PageWithState (Identity ConvId))
-> Client (PageWithState ConvId)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> PrepQuery R (Identity UserId) (Identity ConvId)
-> QueryParams (Identity UserId)
-> Client (PageWithState (Identity ConvId))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (PageWithState b)
paginateWithState PrepQuery R (Identity UserId) (Identity ConvId)
Cql.selectUserConvs (Consistency
-> Identity UserId
-> Int32
-> Maybe PagingState
-> QueryParams (Identity UserId)
forall a.
Consistency -> a -> Int32 -> Maybe PagingState -> QueryParams a
paramsPagingState Consistency
LocalQuorum (UserId -> Identity UserId
forall a. a -> Identity a
Identity UserId
usr) Int32
max Maybe PagingState
pagingState)

remoteConversationIdsPageFrom ::
  UserId ->
  Maybe PagingState ->
  Int32 ->
  Client (PageWithState (Remote ConvId))
remoteConversationIdsPageFrom :: UserId
-> Maybe PagingState
-> Int32
-> Client (PageWithState (Remote ConvId))
remoteConversationIdsPageFrom UserId
usr Maybe PagingState
pagingState Int32
max =
  (Domain -> ConvId -> Remote ConvId)
-> (Domain, ConvId) -> Remote ConvId
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Domain -> ConvId -> Remote ConvId
forall a. Domain -> a -> Remote a
toRemoteUnsafe ((Domain, ConvId) -> Remote ConvId)
-> Client (PageWithState (Domain, ConvId))
-> Client (PageWithState (Remote ConvId))
forall (f :: * -> *) (g :: * -> *) a b.
(Functor f, Functor g) =>
(a -> b) -> f (g a) -> f (g b)
<$$> PrepQuery R (Identity UserId) (Domain, ConvId)
-> QueryParams (Identity UserId)
-> Client (PageWithState (Domain, ConvId))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (PageWithState b)
paginateWithState PrepQuery R (Identity UserId) (Domain, ConvId)
Cql.selectUserRemoteConvs (Consistency
-> Identity UserId
-> Int32
-> Maybe PagingState
-> QueryParams (Identity UserId)
forall a.
Consistency -> a -> Int32 -> Maybe PagingState -> QueryParams a
paramsPagingState Consistency
LocalQuorum (UserId -> Identity UserId
forall a. a -> Identity a
Identity UserId
usr) Int32
max Maybe PagingState
pagingState)

interpretConversationListToCassandra ::
  ( Member (Embed IO) r,
    Member (Input ClientState) r,
    Member TinyLog r
  ) =>
  Sem (ListItems CassandraPaging ConvId ': r) a ->
  Sem r a
interpretConversationListToCassandra :: forall (r :: EffectRow) a.
(Member (Embed IO) r, Member (Input ClientState) r,
 Member TinyLog r) =>
Sem (ListItems CassandraPaging ConvId : r) a -> Sem r a
interpretConversationListToCassandra = (forall (rInitial :: EffectRow) x.
 ListItems CassandraPaging ConvId (Sem rInitial) x -> Sem r x)
-> Sem (ListItems CassandraPaging ConvId : r) a -> Sem r a
forall (e :: (* -> *) -> * -> *) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret ((forall (rInitial :: EffectRow) x.
  ListItems CassandraPaging ConvId (Sem rInitial) x -> Sem r x)
 -> Sem (ListItems CassandraPaging ConvId : r) a -> Sem r a)
-> (forall (rInitial :: EffectRow) x.
    ListItems CassandraPaging ConvId (Sem rInitial) x -> Sem r x)
-> Sem (ListItems CassandraPaging ConvId : r) a
-> Sem r a
forall a b. (a -> b) -> a -> b
$ \case
  ListItems UserId
uid Maybe (PagingState CassandraPaging ConvId)
ps PagingBounds CassandraPaging ConvId
max -> do
    ByteString -> Sem r ()
forall (r :: EffectRow). Member TinyLog r => ByteString -> Sem r ()
logEffect ByteString
"ConversationList.ListItems"
    Client (PageWithState ConvId) -> Sem r (PageWithState ConvId)
forall (r :: EffectRow) a.
(Member (Embed IO) r, Member (Input ClientState) r) =>
Client a -> Sem r a
embedClient (Client (PageWithState ConvId) -> Sem r (PageWithState ConvId))
-> Client (PageWithState ConvId) -> Sem r (PageWithState ConvId)
forall a b. (a -> b) -> a -> b
$ UserId
-> Maybe PagingState
-> Range 1 1000 Int32
-> Client (PageWithState ConvId)
localConversationIdsPageFrom UserId
uid Maybe PagingState
Maybe (PagingState CassandraPaging ConvId)
ps PagingBounds CassandraPaging ConvId
Range 1 1000 Int32
max

interpretRemoteConversationListToCassandra ::
  ( Member (Embed IO) r,
    Member (Input ClientState) r,
    Member TinyLog r
  ) =>
  Sem (ListItems CassandraPaging (Remote ConvId) ': r) a ->
  Sem r a
interpretRemoteConversationListToCassandra :: forall (r :: EffectRow) a.
(Member (Embed IO) r, Member (Input ClientState) r,
 Member TinyLog r) =>
Sem (ListItems CassandraPaging (Remote ConvId) : r) a -> Sem r a
interpretRemoteConversationListToCassandra = (forall (rInitial :: EffectRow) x.
 ListItems CassandraPaging (Remote ConvId) (Sem rInitial) x
 -> Sem r x)
-> Sem (ListItems CassandraPaging (Remote ConvId) : r) a -> Sem r a
forall (e :: (* -> *) -> * -> *) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret ((forall (rInitial :: EffectRow) x.
  ListItems CassandraPaging (Remote ConvId) (Sem rInitial) x
  -> Sem r x)
 -> Sem (ListItems CassandraPaging (Remote ConvId) : r) a
 -> Sem r a)
-> (forall (rInitial :: EffectRow) x.
    ListItems CassandraPaging (Remote ConvId) (Sem rInitial) x
    -> Sem r x)
-> Sem (ListItems CassandraPaging (Remote ConvId) : r) a
-> Sem r a
forall a b. (a -> b) -> a -> b
$ \case
  ListItems UserId
uid Maybe (PagingState CassandraPaging (Remote ConvId))
ps PagingBounds CassandraPaging (Remote ConvId)
max -> do
    ByteString -> Sem r ()
forall (r :: EffectRow). Member TinyLog r => ByteString -> Sem r ()
logEffect ByteString
"RemoteConversationList.ListItems"
    Client (PageWithState (Remote ConvId))
-> Sem r (PageWithState (Remote ConvId))
forall (r :: EffectRow) a.
(Member (Embed IO) r, Member (Input ClientState) r) =>
Client a -> Sem r a
embedClient (Client (PageWithState (Remote ConvId))
 -> Sem r (PageWithState (Remote ConvId)))
-> Client (PageWithState (Remote ConvId))
-> Sem r (PageWithState (Remote ConvId))
forall a b. (a -> b) -> a -> b
$ UserId
-> Maybe PagingState
-> Int32
-> Client (PageWithState (Remote ConvId))
remoteConversationIdsPageFrom UserId
uid Maybe PagingState
Maybe (PagingState CassandraPaging (Remote ConvId))
ps (Range 1 1000 Int32 -> Int32
forall (n :: Nat) (m :: Nat) a. Range n m a -> a
fromRange PagingBounds CassandraPaging (Remote ConvId)
Range 1 1000 Int32
max)

interpretLegacyConversationListToCassandra ::
  ( Member (Embed IO) r,
    Member (Input ClientState) r,
    Member TinyLog r
  ) =>
  Sem (ListItems LegacyPaging ConvId ': r) a ->
  Sem r a
interpretLegacyConversationListToCassandra :: forall (r :: EffectRow) a.
(Member (Embed IO) r, Member (Input ClientState) r,
 Member TinyLog r) =>
Sem (ListItems LegacyPaging ConvId : r) a -> Sem r a
interpretLegacyConversationListToCassandra = (forall (rInitial :: EffectRow) x.
 ListItems LegacyPaging ConvId (Sem rInitial) x -> Sem r x)
-> Sem (ListItems LegacyPaging ConvId : r) a -> Sem r a
forall (e :: (* -> *) -> * -> *) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret ((forall (rInitial :: EffectRow) x.
  ListItems LegacyPaging ConvId (Sem rInitial) x -> Sem r x)
 -> Sem (ListItems LegacyPaging ConvId : r) a -> Sem r a)
-> (forall (rInitial :: EffectRow) x.
    ListItems LegacyPaging ConvId (Sem rInitial) x -> Sem r x)
-> Sem (ListItems LegacyPaging ConvId : r) a
-> Sem r a
forall a b. (a -> b) -> a -> b
$ \case
  ListItems UserId
uid Maybe (PagingState LegacyPaging ConvId)
ps PagingBounds LegacyPaging ConvId
max -> do
    ByteString -> Sem r ()
forall (r :: EffectRow). Member TinyLog r => ByteString -> Sem r ()
logEffect ByteString
"LegacyConversationList.ListItems"
    Client (ResultSet ConvId) -> Sem r (ResultSet ConvId)
forall (r :: EffectRow) a.
(Member (Embed IO) r, Member (Input ClientState) r) =>
Client a -> Sem r a
embedClient (Client (ResultSet ConvId) -> Sem r (ResultSet ConvId))
-> Client (ResultSet ConvId) -> Sem r (ResultSet ConvId)
forall a b. (a -> b) -> a -> b
$ UserId
-> Maybe ConvId -> Range 1 1000 Int32 -> Client (ResultSet ConvId)
conversationIdsFrom UserId
uid Maybe (PagingState LegacyPaging ConvId)
Maybe ConvId
ps PagingBounds LegacyPaging ConvId
Range 1 1000 Int32
max