| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Data.Mergeless
Description
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
processSync. - The server respons with a
SyncResponse.
A client should operate as follows:
- The client produces a
SyncRequestwithmakeSyncRequest. - The client sends that request to the central server and gets a
SyncResponse. - The client then updates its local store with
mergeSyncResponse.
- newtype Store i a = Store {
- storeItems :: Set (StoreItem i a)
- data StoreItem i a
- = UnsyncedItem !(Added a)
- | SyncedItem !(Synced i a)
- | UndeletedItem i
- data Added a = Added {
- addedValue :: !a
- addedCreated :: !UTCTime
- data Synced i a = Synced {
- syncedUuid :: i
- syncedValue :: !a
- syncedCreated :: !UTCTime
- syncedSynced :: !UTCTime
- data SyncRequest i a = SyncRequest {
- syncRequestAddedItems :: !(Set (Added a))
- syncRequestSyncedItems :: !(Set i)
- syncRequestUndeletedItems :: !(Set i)
- makeSyncRequest :: (Ord i, Ord a) => Store i a -> SyncRequest i a
- data SyncResponse i a = SyncResponse {
- syncResponseAddedItems :: !(Set (Synced i a))
- syncResponseNewRemoteItems :: !(Set (Synced i a))
- syncResponseItemsToBeDeletedLocally :: !(Set i)
- mergeSyncResponse :: (Ord i, Ord a) => Store i a -> SyncResponse i a -> Store i a
- newtype CentralStore i a = CentralStore {
- centralStoreItems :: Map i (CentralItem a)
- data CentralItem a = CentralItem {
- centralValue :: !a
- centralSynced :: !UTCTime
- centralCreated :: !UTCTime
- processSync :: (Ord i, Ord a, MonadIO m) => m i -> CentralStore i a -> SyncRequest i a -> m (SyncResponse i a, CentralStore i a)
- processSyncWith :: forall i a m. (Ord i, Ord a, Monad m) => m i -> UTCTime -> CentralStore i a -> SyncRequest i a -> m (SyncResponse i a, CentralStore i a)
Documentation
A client-side store of items with Id's of type i and values of type a
Constructors
| Store | |
Fields
| |
Instances
| (Eq a, Eq i) => Eq (Store i a) Source # | |
| (Ord a, Ord i) => Ord (Store i a) Source # | |
| (Show a, Show i) => Show (Store i a) Source # | |
| Generic (Store i a) Source # | |
| (ToJSON a, ToJSON i) => ToJSON (Store i a) Source # | |
| (FromJSON a, FromJSON i, Ord a, Ord i) => FromJSON (Store i a) Source # | |
| (Validity i, Validity a, Ord i, Ord a) => Validity (Store i a) Source # | |
| type Rep (Store i a) Source # | |
A store item with an Id of type i and a value of type a
Constructors
| UnsyncedItem !(Added a) | A local item that has not been synchronised to the central store yet |
| SyncedItem !(Synced i a) | A local item that has been synchronised to the central store already |
| UndeletedItem i | An item that has been synchronised to the central store, was subsequently deleted locally but this deletion has not been synchronised to the central store yet. |
Instances
| (Eq i, Eq a) => Eq (StoreItem i a) Source # | |
| (Ord i, Ord a) => Ord (StoreItem i a) Source # | |
| (Show i, Show a) => Show (StoreItem i a) Source # | |
| Generic (StoreItem i a) Source # | |
| (ToJSON i, ToJSON a) => ToJSON (StoreItem i a) Source # | |
| (FromJSON i, FromJSON a) => FromJSON (StoreItem i a) Source # | |
| (Validity i, Validity a) => Validity (StoreItem i a) Source # | |
| type Rep (StoreItem i a) Source # | |
A local item of type a that has been added but not synchronised yet
Constructors
| Added | |
Fields
| |
A local item of type a with an identifier of type a that has been synchronised
Constructors
| Synced | |
Fields
| |
Instances
| (Eq a, Eq i) => Eq (Synced i a) Source # | |
| (Ord a, Ord i) => Ord (Synced i a) Source # | |
| (Show a, Show i) => Show (Synced i a) Source # | |
| Generic (Synced i a) Source # | |
| (ToJSON i, ToJSON a) => ToJSON (Synced i a) Source # | |
| (FromJSON i, FromJSON a) => FromJSON (Synced i a) Source # | |
| (Validity i, Validity a) => Validity (Synced i a) Source # | |
| type Rep (Synced i a) Source # | |
data SyncRequest i a Source #
A synchronisation request for items with identifiers of type i and values of type a
Constructors
| SyncRequest | |
Fields
| |
Instances
| (Eq i, Eq a) => Eq (SyncRequest i a) Source # | |
| (Ord i, Ord a) => Ord (SyncRequest i a) Source # | |
| (Show i, Show a) => Show (SyncRequest i a) Source # | |
| Generic (SyncRequest i a) Source # | |
| (ToJSON i, ToJSON a) => ToJSON (SyncRequest i a) Source # | |
| (FromJSON i, FromJSON a, Ord i, Ord a) => FromJSON (SyncRequest i a) Source # | |
| (Validity i, Validity a, Ord i, Ord a) => Validity (SyncRequest i a) Source # | |
| type Rep (SyncRequest i a) Source # | |
makeSyncRequest :: (Ord i, Ord a) => Store 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.
data SyncResponse i a Source #
A synchronisation response for items with identifiers of type i and values of type a
Constructors
| SyncResponse | |
Fields
| |
Instances
| (Eq i, Eq a) => Eq (SyncResponse i a) Source # | |
| (Ord i, Ord a) => Ord (SyncResponse i a) Source # | |
| (Show i, Show a) => Show (SyncResponse i a) Source # | |
| Generic (SyncResponse i a) Source # | |
| (ToJSON i, ToJSON a) => ToJSON (SyncResponse i a) Source # | |
| (FromJSON i, FromJSON a, Ord i, Ord a) => FromJSON (SyncResponse i a) Source # | |
| (Validity i, Validity a, Ord i, Ord a) => Validity (SyncResponse i a) Source # | |
| type Rep (SyncResponse i a) Source # | |
mergeSyncResponse :: (Ord i, Ord a) => Store i a -> SyncResponse i a -> Store i a Source #
Merge a synchronisation response back into a client-side store.
newtype CentralStore i a Source #
A central store of items with identifiers of type i and values of type a
Constructors
| CentralStore | |
Fields
| |
Instances
| (Eq a, Eq i) => Eq (CentralStore i a) Source # | |
| (Ord a, Ord i) => Ord (CentralStore i a) Source # | |
| (Show a, Show i) => Show (CentralStore i a) Source # | |
| Generic (CentralStore i a) Source # | |
| (ToJSONKey i, ToJSON a) => ToJSON (CentralStore i a) Source # | |
| (FromJSON a, Ord i, FromJSONKey i) => FromJSON (CentralStore i a) Source # | |
| (Validity i, Validity a, Ord i, Ord a) => Validity (CentralStore i a) Source # | |
| type Rep (CentralStore i a) Source # | |
data CentralItem a Source #
An item in a central store with a value of type a
Constructors
| CentralItem | |
Fields
| |
Instances
| Eq a => Eq (CentralItem a) Source # | |
| Ord a => Ord (CentralItem a) Source # | |
| Show a => Show (CentralItem a) Source # | |
| Generic (CentralItem a) Source # | |
| ToJSON a => ToJSON (CentralItem a) Source # | |
| FromJSON a => FromJSON (CentralItem a) Source # | |
| Validity a => Validity (CentralItem a) Source # | |
| type Rep (CentralItem a) Source # | |
processSync :: (Ord i, Ord a, MonadIO m) => m i -> CentralStore i a -> SyncRequest i a -> m (SyncResponse i a, CentralStore i a) Source #
Process a server-side synchronisation request using getCurrentTime
processSyncWith :: forall i a m. (Ord i, Ord a, Monad m) => m i -> UTCTime -> CentralStore i a -> SyncRequest i a -> m (SyncResponse i a, CentralStore i a) Source #
Process a server-side synchronisation request using a time of syncing, and an identifier generation function.
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.