mergeful-0.1.0.0

Safe HaskellNone
LanguageHaskell2010

Data.Mergeful.Item

Contents

Description

A way to synchronise an item with safe merge conflicts.

The item is "zero or one" value. One could say that Item a = Maybe a but there are so such types here. This methaphor just serves as explanation

The 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 client should operate as follows:

The clients starts with an initialClientItem.

The central server should operate as follows:

The server starts with an initialServerItem.

WARNING: This whole approach can break down if a server resets its server times or if a client syncs with two different servers using the same server times.

Synopsis

Documentation

initialClientItem :: ClientItem a Source #

A client item to start with.

It contains no value.

initialItemSyncRequest :: ItemSyncRequest a Source #

An intial ItemSyncRequest to start with.

It just asks the server to send over whatever it knows.

makeItemSyncRequest :: ClientItem a -> ItemSyncRequest a Source #

Produce an ItemSyncRequest from a ClientItem.

Send this to the server for synchronisation.

mergeItemSyncResponseRaw :: ClientItem a -> ItemSyncResponse a -> ItemMergeResult a Source #

Merge an ItemSyncResponse into the current ClientItem.

This function will not make any decisions about what to do with conflicts or mismatches between the request and the response. It only produces a ItemMergeResult so you can decide what to do with it.

data ItemMergeResult a Source #

Constructors

MergeSuccess !(ClientItem a)

The merger went succesfully, no conflicts or desyncs

MergeConflict !a !(Timed a)

The item at the server side | There was a merge conflict. The client had deleted the item while the server had modified it.

MergeConflictClientDeleted !(Timed a)

The item at the server side | There was a merge conflict. The server had deleted the item while the client had modified it.

MergeConflictServerDeleted !a

The item at the client side | The server responded with a response that did not make sense given the client's request.

MergeMismatch 
Instances
Eq a => Eq (ItemMergeResult a) Source # 
Instance details

Defined in Data.Mergeful.Item

Show a => Show (ItemMergeResult a) Source # 
Instance details

Defined in Data.Mergeful.Item

Generic (ItemMergeResult a) Source # 
Instance details

Defined in Data.Mergeful.Item

Associated Types

type Rep (ItemMergeResult a) :: Type -> Type #

Validity a => Validity (ItemMergeResult a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ItemMergeResult a) Source # 
Instance details

Defined in Data.Mergeful.Item

mergeItemSyncResponseIgnoreProblems :: ClientItem a -> ItemSyncResponse a -> ClientItem a Source #

Merge an ItemSyncResponse into the current ClientItem.

This function ignores any problems that may occur. In the case of a conclict, it will just not update the client item. The next sync request will then produce a conflict again.

mergeItemSyncResponseIgnoreProblems cs = mergeIgnoringProblems cs . mergeItemSyncResponseRaw cs

mergeIgnoringProblems :: ClientItem a -> ItemMergeResult a -> ClientItem a Source #

Ignore any merge problems in a ItemMergeResult.

This function just returns the original ClientItem if anything other than MergeSuccess occurs.

This function ignores any problems that may occur. In the case of a conclict, it will just not update the client item. The next sync request will then produce a conflict again.

Pro: does not lose data

Con: Clients will diverge when a conflict occurs

mergeFromServer :: ClientItem a -> ItemMergeResult a -> ClientItem a Source #

Resolve an ItemMergeResult by taking whatever the server gave the client.

Pro: Clients will converge on the same value.

Con: Conflicting updates will be lost.

data ItemMergeStrategy a Source #

A strategy to merge conflicts for item synchronisation

Constructors

ItemMergeStrategy 

Fields

Instances
Generic (ItemMergeStrategy a) Source # 
Instance details

Defined in Data.Mergeful.Item

Associated Types

type Rep (ItemMergeStrategy a) :: Type -> Type #

type Rep (ItemMergeStrategy a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ItemMergeStrategy a) = D1 (MetaData "ItemMergeStrategy" "Data.Mergeful.Item" "mergeful-0.1.0.0-ABXYstvyIa5Kq6M8t1wQCW" False) (C1 (MetaCons "ItemMergeStrategy" PrefixI True) (S1 (MetaSel (Just "itemMergeStrategyMergeChangeConflict") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (a -> Timed a -> Timed a)) :*: (S1 (MetaSel (Just "itemMergeStrategyMergeClientDeletedConflict") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Timed a -> Maybe (Timed a))) :*: S1 (MetaSel (Just "itemMergeStrategyMergeServerDeletedConflict") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (a -> Maybe a)))))

mergeUsingStrategy :: ItemMergeStrategy a -> ClientItem a -> ItemMergeResult a -> ClientItem a Source #

Resolve an ItemMergeResult using a given merge strategy.

This function ignores MergeMismatch and will just return the original ClientItem in that case.

In order for clients to converge on the same item correctly, this function must be:

  • Associative
  • Idempotent
  • The same on all clients

Server side

initialServerItem :: ServerItem a Source #

A server item to start with.

It contains no value.

Types, for reference

data ClientItem a Source #

Constructors

ClientEmpty

There is no item on the client side

ClientAdded !a

There is is an item but the server is not aware of it yet.

ClientItemSynced !(Timed a)

There is is an item and it has been synced with the server.

ClientItemSyncedButChanged !(Timed a)

There is is an item and it has been synced with the server, but it has since been modified.

ClientDeleted !ServerTime

There was an item, and it has been deleted locally, but the server has not been made aware of this.

Instances
Eq a => Eq (ClientItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

Methods

(==) :: ClientItem a -> ClientItem a -> Bool #

(/=) :: ClientItem a -> ClientItem a -> Bool #

Show a => Show (ClientItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

Generic (ClientItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

Associated Types

type Rep (ClientItem a) :: Type -> Type #

Methods

from :: ClientItem a -> Rep (ClientItem a) x #

to :: Rep (ClientItem a) x -> ClientItem a #

ToJSON a => ToJSON (ClientItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

FromJSON a => FromJSON (ClientItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

Validity a => Validity (ClientItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ClientItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ClientItem a) = D1 (MetaData "ClientItem" "Data.Mergeful.Item" "mergeful-0.1.0.0-ABXYstvyIa5Kq6M8t1wQCW" False) ((C1 (MetaCons "ClientEmpty" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "ClientAdded" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 a))) :+: (C1 (MetaCons "ClientItemSynced" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Timed a))) :+: (C1 (MetaCons "ClientItemSyncedButChanged" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Timed a))) :+: C1 (MetaCons "ClientDeleted" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 ServerTime)))))

data ItemSyncRequest a Source #

Constructors

ItemSyncRequestPoll

There is no item locally

ItemSyncRequestNew !a

There is an item locally that has not been synced to the server yet.

ItemSyncRequestKnown !ServerTime

There is an item locally that was synced at the given ServerTime

ItemSyncRequestKnownButChanged !(Timed a)

There is an item locally that was synced at the given ServerTime but it has been changed since then.

ItemSyncRequestDeletedLocally !ServerTime

There was an item locally that has been deleted but the deletion wasn't synced to the server yet.

Instances
Eq a => Eq (ItemSyncRequest a) Source # 
Instance details

Defined in Data.Mergeful.Item

Show a => Show (ItemSyncRequest a) Source # 
Instance details

Defined in Data.Mergeful.Item

Generic (ItemSyncRequest a) Source # 
Instance details

Defined in Data.Mergeful.Item

Associated Types

type Rep (ItemSyncRequest a) :: Type -> Type #

ToJSON a => ToJSON (ItemSyncRequest a) Source # 
Instance details

Defined in Data.Mergeful.Item

FromJSON a => FromJSON (ItemSyncRequest a) Source # 
Instance details

Defined in Data.Mergeful.Item

Validity a => Validity (ItemSyncRequest a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ItemSyncRequest a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ItemSyncRequest a) = D1 (MetaData "ItemSyncRequest" "Data.Mergeful.Item" "mergeful-0.1.0.0-ABXYstvyIa5Kq6M8t1wQCW" False) ((C1 (MetaCons "ItemSyncRequestPoll" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "ItemSyncRequestNew" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 a))) :+: (C1 (MetaCons "ItemSyncRequestKnown" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 ServerTime)) :+: (C1 (MetaCons "ItemSyncRequestKnownButChanged" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Timed a))) :+: C1 (MetaCons "ItemSyncRequestDeletedLocally" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 ServerTime)))))

data ItemSyncResponse a Source #

Constructors

ItemSyncResponseInSyncEmpty

The client and server are fully in sync, and both empty

Nothing needs to be done at the client side.

ItemSyncResponseInSyncFull

The client and server are fully in sync.

Nothing needs to be done at the client side.

ItemSyncResponseClientAdded !ServerTime

The client added an item and server has succesfully been made aware of that.

The client needs to update its server time

ItemSyncResponseClientChanged !ServerTime

The client changed an item and server has succesfully been made aware of that.

The client needs to update its server time

ItemSyncResponseClientDeleted

The client deleted an item and server has succesfully been made aware of that.

The client can delete it from its deleted items

ItemSyncResponseServerAdded !(Timed a)

This item has been added on the server side

The client should add it too.

ItemSyncResponseServerChanged !(Timed a)

This item has been modified on the server side.

The client should modify it too.

ItemSyncResponseServerDeleted

The item was deleted on the server side

The client should delete it too.

ItemSyncResponseConflict !(Timed a)

The item at the server side | A conflict occurred.

The server has an item but the client does not. The server kept its part, the client can either take whatever the server gave them or deal with the conflict somehow, and then try to re-sync.

ItemSyncResponseConflictClientDeleted !(Timed a)

The item at the server side | A conflict occurred.

The client has a (modified) item but the server does not have any item. The server left its item deleted, the client can either delete its item too or deal with the conflict somehow, and then try to re-sync.

ItemSyncResponseConflictServerDeleted 
Instances
Eq a => Eq (ItemSyncResponse a) Source # 
Instance details

Defined in Data.Mergeful.Item

Show a => Show (ItemSyncResponse a) Source # 
Instance details

Defined in Data.Mergeful.Item

Generic (ItemSyncResponse a) Source # 
Instance details

Defined in Data.Mergeful.Item

Associated Types

type Rep (ItemSyncResponse a) :: Type -> Type #

ToJSON a => ToJSON (ItemSyncResponse a) Source # 
Instance details

Defined in Data.Mergeful.Item

FromJSON a => FromJSON (ItemSyncResponse a) Source # 
Instance details

Defined in Data.Mergeful.Item

Validity a => Validity (ItemSyncResponse a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ItemSyncResponse a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ItemSyncResponse a) = D1 (MetaData "ItemSyncResponse" "Data.Mergeful.Item" "mergeful-0.1.0.0-ABXYstvyIa5Kq6M8t1wQCW" False) (((C1 (MetaCons "ItemSyncResponseInSyncEmpty" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "ItemSyncResponseInSyncFull" PrefixI False) (U1 :: Type -> Type)) :+: (C1 (MetaCons "ItemSyncResponseClientAdded" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 ServerTime)) :+: (C1 (MetaCons "ItemSyncResponseClientChanged" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 ServerTime)) :+: C1 (MetaCons "ItemSyncResponseClientDeleted" PrefixI False) (U1 :: Type -> Type)))) :+: ((C1 (MetaCons "ItemSyncResponseServerAdded" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Timed a))) :+: (C1 (MetaCons "ItemSyncResponseServerChanged" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Timed a))) :+: C1 (MetaCons "ItemSyncResponseServerDeleted" PrefixI False) (U1 :: Type -> Type))) :+: (C1 (MetaCons "ItemSyncResponseConflict" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Timed a))) :+: (C1 (MetaCons "ItemSyncResponseConflictClientDeleted" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Timed a))) :+: C1 (MetaCons "ItemSyncResponseConflictServerDeleted" PrefixI False) (U1 :: Type -> Type)))))

data ServerItem a Source #

Constructors

ServerEmpty

There is no item on the server side

ServerFull !(Timed a)

There is an item on the server side, and it was last synced at the given ServerTime.

Instances
Eq a => Eq (ServerItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

Methods

(==) :: ServerItem a -> ServerItem a -> Bool #

(/=) :: ServerItem a -> ServerItem a -> Bool #

Show a => Show (ServerItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

Generic (ServerItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

Associated Types

type Rep (ServerItem a) :: Type -> Type #

Methods

from :: ServerItem a -> Rep (ServerItem a) x #

to :: Rep (ServerItem a) x -> ServerItem a #

ToJSON a => ToJSON (ServerItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

FromJSON a => FromJSON (ServerItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

Validity a => Validity (ServerItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ServerItem a) Source # 
Instance details

Defined in Data.Mergeful.Item

type Rep (ServerItem a) = D1 (MetaData "ServerItem" "Data.Mergeful.Item" "mergeful-0.1.0.0-ABXYstvyIa5Kq6M8t1wQCW" False) (C1 (MetaCons "ServerEmpty" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "ServerFull" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Timed a))))