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
processSync
. - 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
.
- 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
Store | |
|
(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
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. |
(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
Added | |
|
A local item of type a
with an identifier of type a
that has been synchronised
Synced | |
|
(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
SyncRequest | |
|
(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
SyncResponse | |
|
(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
CentralStore | |
|
(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
CentralItem | |
|
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.