Safe Haskell | None |
---|---|
Language | Haskell2010 |
A way to synchronise items without merge conflicts.
This concept has a few requirements:
- Items must be immutable.
- Items must allow for a centrally unique identifier.
- Identifiers for items must be generatable in such a way that they are certainly unique.
Should mutation be a requirement, then it can be build such that it entails deleting the old version and creating a new version that is the modification of the old version.
There are a few obvious candidates for identifiers:
- incremental identifiers
- universally unique identifiers (recommended).
The typical setup is as follows:
- A central server is set up to synchronise with
- Each client synchronises with the central server, but never with eachother
A central server should operate as follows:
- The server accepts a
SyncRequest
. - The server performs operations according to the functionality of
processServerSync
. - The server respons with a
SyncResponse
.
A client should operate as follows:
- The client produces a
SyncRequest
withmakeSyncRequest
. - The client sends that request to the central server and gets a
SyncResponse
. - The client then updates its local store with
mergeSyncResponse
.
Synopsis
- newtype ClientId = ClientId {
- unClientId :: Word64
- data ClientStore i a = ClientStore {
- clientStoreAdded :: !(Map ClientId a)
- clientStoreSynced :: !(Map i a)
- clientStoreDeleted :: !(Set i)
- emptyClientStore :: ClientStore i a
- storeSize :: ClientStore i a -> Int
- addItemToClientStore :: (Ord i, Ord a) => a -> ClientStore i a -> ClientStore i a
- deleteUnsyncedFromClientStore :: (Ord i, Ord a) => ClientId -> ClientStore i a -> ClientStore i a
- deleteSyncedFromClientStore :: (Ord i, Ord a) => i -> ClientStore i a -> ClientStore i a
- data SyncRequest i a = SyncRequest {
- syncRequestAdded :: !(Map ClientId a)
- syncRequestSynced :: !(Set i)
- syncRequestDeleted :: !(Set i)
- data SyncResponse i a = SyncResponse {
- syncResponseClientAdded :: !(Map ClientId i)
- syncResponseClientDeleted :: !(Set i)
- syncResponseServerAdded :: !(Map i a)
- syncResponseServerDeleted :: !(Set i)
- emptySyncResponse :: SyncResponse i ia
- makeSyncRequest :: (Ord i, Ord a) => ClientStore i a -> SyncRequest i a
- mergeSyncResponse :: forall i a. (Ord i, Ord a) => ClientStore i a -> SyncResponse i a -> ClientStore i a
- addRemotelyAddedItems :: (Ord i, Ord a) => Map i a -> ClientStore i a -> ClientStore i a
- addAddedItems :: forall i a. (Ord i, Ord a) => Map ClientId i -> ClientStore i a -> ClientStore i a
- deleteItemsToBeDeletedLocally :: (Ord i, Ord a) => Set i -> ClientStore i a -> ClientStore i a
- deleteLocalUndeletedItems :: (Ord i, Ord a) => Set i -> ClientStore i a -> ClientStore i a
- data ServerSyncProcessor i a m = ServerSyncProcessor {
- serverSyncProcessorDeleteMany :: Set i -> m (Set i)
- serverSyncProcessorQueryNoLongerSynced :: Set i -> m (Set i)
- serverSyncProcessorQueryNewRemote :: Set i -> m (Map i a)
- serverSyncProcessorInsertMany :: Map ClientId a -> m (Map ClientId i)
- processServerSyncCustom :: forall i a m. (Ord i, Ord a, Monad m) => ServerSyncProcessor i a m -> SyncRequest i a -> m (SyncResponse i a)
- newtype ServerStore i a = ServerStore {
- serverStoreItems :: Map i a
- emptyServerStore :: ServerStore i a
- processServerSync :: forall m i a. (Ord i, Ord a, Monad m) => m i -> ServerStore i a -> SyncRequest i a -> m (SyncResponse i a, ServerStore i a)
Documentation
A Client-side identifier for items.
These only need to be unique at the client.
Instances
Bounded ClientId Source # | |
Enum ClientId Source # | |
Defined in Data.Mergeless.Collection | |
Eq ClientId Source # | |
Ord ClientId Source # | |
Defined in Data.Mergeless.Collection | |
Show ClientId Source # | |
Generic ClientId Source # | |
ToJSON ClientId Source # | |
Defined in Data.Mergeless.Collection | |
ToJSONKey ClientId Source # | |
Defined in Data.Mergeless.Collection | |
FromJSON ClientId Source # | |
FromJSONKey ClientId Source # | |
NFData ClientId Source # | |
Defined in Data.Mergeless.Collection | |
Validity ClientId Source # | |
Defined in Data.Mergeless.Collection validate :: ClientId -> Validation # | |
type Rep ClientId Source # | |
Defined in Data.Mergeless.Collection |
data ClientStore i a Source #
A client-side store of items with Id's of type i
and values of type a
ClientStore | |
|
Instances
emptyClientStore :: ClientStore i a Source #
The store with no items.
storeSize :: ClientStore i a -> Int Source #
The number of items in a store
This does not count the deleted items, so that those really look deleted.
addItemToClientStore :: (Ord i, Ord a) => a -> ClientStore i a -> ClientStore i a Source #
Add an item to a client store as an added item.
This will take care of the uniqueness constraint of the ClientId
s in the map.
deleteUnsyncedFromClientStore :: (Ord i, Ord a) => ClientId -> ClientStore i a -> ClientStore i a Source #
deleteSyncedFromClientStore :: (Ord i, Ord a) => i -> ClientStore i a -> ClientStore i a Source #
data SyncRequest i a Source #
A synchronisation request for items with identifiers of type i
and values of type a
SyncRequest | |
|
Instances
data SyncResponse i a Source #
A synchronisation response for items with identifiers of type i
and values of type a
SyncResponse | |
|
Instances
emptySyncResponse :: SyncResponse i ia Source #
Client-side Synchronisation
makeSyncRequest :: (Ord i, Ord a) => ClientStore i a -> SyncRequest i a Source #
Produce a synchronisation request for a client-side store.
This request can then be sent to a central store for synchronisation.
mergeSyncResponse :: forall i a. (Ord i, Ord a) => ClientStore i a -> SyncResponse i a -> ClientStore i a Source #
Merge a synchronisation response back into a client-side store.
addRemotelyAddedItems :: (Ord i, Ord a) => Map i a -> ClientStore i a -> ClientStore i a Source #
addAddedItems :: forall i a. (Ord i, Ord a) => Map ClientId i -> ClientStore i a -> ClientStore i a Source #
deleteItemsToBeDeletedLocally :: (Ord i, Ord a) => Set i -> ClientStore i a -> ClientStore i a Source #
deleteLocalUndeletedItems :: (Ord i, Ord a) => Set i -> ClientStore i a -> ClientStore i a Source #
Server-side Synchronisation
General synchronisation
data ServerSyncProcessor i a m Source #
A record of the basic operations that are necessary to build a synchronisation processor.
ServerSyncProcessor | |
|
Instances
processServerSyncCustom :: forall i a m. (Ord i, Ord a, Monad m) => ServerSyncProcessor i a m -> SyncRequest i a -> m (SyncResponse i a) Source #
Process a server-side synchronisation request using a custom synchronisation processor
WARNING: The identifier generation function must produce newly unique identifiers such that each new item gets a unique identifier.
You can use this function with deterministically-random identifiers or incrementing identifiers.
Synchronisation with a simple central store
newtype ServerStore i a Source #
A central store of items with identifiers of type i
and values of type a
ServerStore | |
|
Instances
emptyServerStore :: ServerStore i a Source #
An empty central store to start with
processServerSync :: forall m i a. (Ord i, Ord a, Monad m) => m i -> ServerStore i a -> SyncRequest i a -> m (SyncResponse i a, ServerStore i a) Source #
Process a server-side synchronisation request using getCurrentTime
see processSyncCustom