This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
1.0.0 1.1.0

CreateableRemoteData

Represents data that is downloaded from a server, edited on the client, then uploaded back to the server. It's really an extension of EditableRemoteData, using a Maybe data to represent data that might or might not exist locally or remotely.

Types

type alias CreateableRemoteData data downloadError uploadError = EditableRemoteData (Maybe data) downloadError uploadError

Represents data that can be created, edited, and deleted on the client, then uploaded to the server.

Functions

create : data -> CreateableRemoteData data de ue

Construct a new CreateableRemoteData that only exists locally

edit : (data -> data) -> CreateableRemoteData data de ue -> CreateableRemoteData data de ue

Modifies the local data if possible, otherwise does nothing

set : data -> CreateableRemoteData data de ue -> CreateableRemoteData data de ue

Similar to edit, but it sets the data without caring about the previous value

delete : CreateableRemoteData data de ue -> CreateableRemoteData data de ue

Modify a CreateableRemoteData to show that the data no longer exists locally

unwrapLocalRemote : a -> (LocalRemote (Maybe data) -> a) -> CreateableRemoteData data de ue -> a

Runs a function on the LocalRemote inside a CreateableRemoteData if possible, otherwise returns the default

unwrapLocal : a -> (Maybe data -> a) -> CreateableRemoteData data de ue -> a

Runs a function on the local data inside a CreateableRemoteData if possible, otherwise returns the default

maybeLocal : CreateableRemoteData data de ue -> Maybe data

Converts to a Just if the local data is availible, Nothing otherwise. This makes it impossible to distingish between, say, deleted data and loading data. So this should only be used in places where that won't matter.

fromResult : Result error data -> CreateableRemoteData data error ue

Creates a CreateableRemoteData from a Result. Designed to be used to turn an HTTP request result into CreateableRemoteData. The data in the Result is considered syncronized, so the local and remote data is the same at this point.

upload : CreateableRemoteData data de ue -> ( Maybe (LocalRemote (Maybe data)), CreateableRemoteData data de ue )

Try to put the CreateableRemoteData into the "Uploading" state. This only works if

  • The data has been successfully downloaded
  • The CreateableRemoteData isn't already uploading
  • The local and remote data is desyncronized

If this is successful, the data is returned as a Just LocalRemote. Otherwise Nothing is returned. It's up to your code to turn the Just LocalRemote into a Cmd that sends the request to the server.

forceUpload : CreateableRemoteData data de ue -> ( Maybe (LocalRemote (Maybe data)), CreateableRemoteData data de ue )

Very similar to upload, but will upload even if the remote has the same data as the server.

Note: This will likely be removed in the future in favor of a way to modify the remote's value. In other words, you'd mark the remote as deleted (Nothing) the use a regular save.

If this is successful, the data is returned as a Just LocalRemote. Otherwise Nothing is returned. It's up to your code to turn the Just LocalRemote into a Cmd that sends the request to the server.

uploaded : Result uploadError () -> CreateableRemoteData data de uploadError -> CreateableRemoteData data de uploadError

Use this after an upload has completed. This will update the CreateableRemoteData to refelect the result: either an error occured and the upload failed OR the data was successfully saved and the remote value of the LocalRemote can be updated.

Note that edits can still be made while uploading, after the upload completes the remote will be updated to refelect the data that was uploaded rather than the current local data.

isSaved : CreateableRemoteData date de uploadError -> Bool

Check if a CreateableRemoteData has its local and remote data syncronized

isLoading : CreateableRemoteData date de uploadError -> Bool

Check if a CreateableRemoteData is downloading. This will return false when the data is being uploaded.

isFailed : CreateableRemoteData date de uploadError -> Bool

Check if a CreateableRemoteData has failed to download

isSuccess : CreateableRemoteData date de uploadError -> Bool

Check if a CreateableRemoteData has been successfully downloaded

isUploading : CreateableRemoteData date de uploadError -> Bool

Check if a CreateableRemoteData is currently uploading to sync its data

isDeleted : CreateableRemoteData data de ue -> Bool

Check if a CreateableRemoteData is locally deleted

module CreateableRemoteData
    exposing
        ( CreateableRemoteData
        , create
        , edit
        , set
        , delete
        , unwrapLocalRemote
        , unwrapLocal
        , maybeLocal
        , fromResult
        , upload
        , forceUpload
        , uploaded
        , isSaved
        , isLoading
        , isFailed
        , isSuccess
        , isUploading
        , isDeleted
        )

{-| Represents data that is downloaded from a server, edited on the client, then
uploaded back to the server. It's really an extension of `EditableRemoteData`,
using a `Maybe data` to represent data that might or might not exist locally or
remotely.


# Types

@docs CreateableRemoteData


# Functions

@docs create, edit, set, delete, unwrapLocalRemote, unwrapLocal, maybeLocal, fromResult, upload, forceUpload, uploaded, isSaved, isLoading, isFailed, isSuccess, isUploading, isDeleted

-}

import RemoteData exposing (RemoteData(..))
import UploadStatus exposing (UploadStatus(..))
import EditableRemoteData exposing (EditableRemoteData, LocalRemote)


{-| Represents data that can be created, edited, and deleted on the client, then
uploaded to the server.
-}
type alias CreateableRemoteData data downloadError uploadError =
    EditableRemoteData (Maybe data) downloadError uploadError


{-| Construct a new CreateableRemoteData that only exists locally
-}
create : data -> CreateableRemoteData data de ue
create data =
    Success <| ( NotUploading, LocalRemote (Just data) Nothing )


{-| Modifies the local data if possible, otherwise does nothing
-}
edit : (data -> data) -> CreateableRemoteData data de ue -> CreateableRemoteData data de ue
edit fn =
    EditableRemoteData.edit (Maybe.map fn)


{-| Similar to `edit`, but it sets the data without caring about the previous value
-}
set : data -> CreateableRemoteData data de ue -> CreateableRemoteData data de ue
set data =
    EditableRemoteData.edit (always <| Just data)


{-| Modify a CreateableRemoteData to show that the data no longer exists locally
-}
delete : CreateableRemoteData data de ue -> CreateableRemoteData data de ue
delete =
    EditableRemoteData.edit (always Nothing)


{-| Runs a function on the LocalRemote inside a CreateableRemoteData if possible,
otherwise returns the default
-}
unwrapLocalRemote :
    a
    -> (LocalRemote (Maybe data) -> a)
    -> CreateableRemoteData data de ue
    -> a
unwrapLocalRemote =
    EditableRemoteData.unwrapLocalRemote


{-| Runs a function on the local data inside a CreateableRemoteData if possible,
otherwise returns the default
-}
unwrapLocal : a -> (Maybe data -> a) -> CreateableRemoteData data de ue -> a
unwrapLocal =
    EditableRemoteData.unwrapLocal


{-| Converts to a Just if the local data is availible, Nothing otherwise. This
makes it impossible to distingish between, say, deleted data and loading data.
So this should only be used in places where that won't matter.
-}
maybeLocal : CreateableRemoteData data de ue -> Maybe data
maybeLocal =
    EditableRemoteData.unwrapLocal Nothing identity


{-| Creates a CreateableRemoteData from a Result. Designed to be used to turn an
HTTP request result into CreateableRemoteData. The data in the Result is considered
syncronized, so the local and remote data is the same at this point.
-}
fromResult : Result error data -> CreateableRemoteData data error ue
fromResult =
    Result.map Just >> EditableRemoteData.fromResult


{-| Try to put the CreateableRemoteData into the "Uploading" state. This only works
if

  - The data has been successfully downloaded
  - The CreateableRemoteData isn't already uploading
  - The local and remote data is desyncronized

If this is successful, the data is returned as a `Just LocalRemote`. Otherwise
`Nothing` is returned. It's up to your code to turn the `Just LocalRemote` into
a Cmd that sends the request to the server.

-}
upload :
    CreateableRemoteData data de ue
    -> ( Maybe (LocalRemote (Maybe data)), CreateableRemoteData data de ue )
upload =
    EditableRemoteData.upload


{-| Very similar to `upload`, but will upload even if the remote has the same data
as the server.

*Note*: This will likely be removed in the future in favor of a way to modify
the remote's value. In other words, you'd mark the remote as deleted (`Nothing`)
the use a regular save.

If this is successful, the data is returned as a `Just LocalRemote`. Otherwise
`Nothing` is returned. It's up to your code to turn the `Just LocalRemote` into
a Cmd that sends the request to the server.

-}
forceUpload :
    CreateableRemoteData data de ue
    -> ( Maybe (LocalRemote (Maybe data)), CreateableRemoteData data de ue )
forceUpload =
    EditableRemoteData.forceUpload


{-| Use this after an upload has completed. This will update the CreateableRemoteData
to refelect the result: either an error occured and the upload failed OR the data
was successfully saved and the remote value of the LocalRemote can be updated.

Note that edits can still be made while uploading, after the upload completes the
remote will be updated to refelect the data that was uploaded rather than the
current local data.

-}
uploaded :
    Result uploadError ()
    -> CreateableRemoteData data de uploadError
    -> CreateableRemoteData data de uploadError
uploaded =
    EditableRemoteData.uploaded


{-| Check if a CreateableRemoteData has its local and remote data syncronized
-}
isSaved : CreateableRemoteData date de uploadError -> Bool
isSaved =
    EditableRemoteData.isSaved


{-| Check if a CreateableRemoteData is downloading. This will return `false` when
the data is being *uploaded*.
-}
isLoading : CreateableRemoteData date de uploadError -> Bool
isLoading =
    RemoteData.isLoading


{-| Check if a CreateableRemoteData has failed to download
-}
isFailed : CreateableRemoteData date de uploadError -> Bool
isFailed =
    RemoteData.isFailed


{-| Check if a CreateableRemoteData has been successfully downloaded
-}
isSuccess : CreateableRemoteData date de uploadError -> Bool
isSuccess =
    RemoteData.isSuccess


{-| Check if a CreateableRemoteData is currently uploading to sync its data
-}
isUploading : CreateableRemoteData date de uploadError -> Bool
isUploading =
    EditableRemoteData.isUploading


{-| Check if a CreateableRemoteData is locally deleted
-}
isDeleted : CreateableRemoteData data de ue -> Bool
isDeleted =
    RemoteData.unwrap False (always False) (Tuple.second >> .local >> (==) Nothing)