Cloud storage types cheat sheet

Storing and retrieving data on the Cloud is often a matter of choosing the right data type from the Cloud library and adding it to your deployment functions.

If you're not sure which storage type is right for your use case, this cheat sheet can help you decide; linked to each data type is a deployable code sample with a read and write operation:

Supports transactions Arbitrary types
OrderedTable

Stores key-value mappings in a sorted order.
Support for range queries and tuple key types.

Yes Yes
Cell

Stores a single durable value.

Yes Yes
Blobs

Blob object storage for binary data, retrievable by key and prefix.

No Yes
Config

Secure, encrypted storage for secrets and other configuration values.

No No
Scratch

Temporary in-memory caching for values at a particular compute location in the Cloud.

Bound to a `Location` so care should be taken when combined with the `Remote.fork` and `Remote.await` APIs.
No Yes
Table

Building block for other Cloud storage types.
Supports key-value lookups.

Requires tracking keys independently, lower-level API.
Yes Yes

Storage data types and code samples

Storage

Storage is the ability that many of the data types in the Cloud library use to interact with the storage layer. It provides a common interface for running transactions in a database via the Transaction ability.

There are two handlers for running transactions. Both take a Database and the transaction block to run, but operations that include transactional writes require a random seed.

Storage.transact :          Database
                            -> '{Transaction, Exception} a
                            ->{Exception, Storage} a
Storage.transact.random :   Database
                            -> '{Transaction, Exception, Random} a
                            ->{Exception, Storage, Random} a

The Storage ability itself is handled by top-level functions that submit work to the Cloud, like Cloud.submit or Cloud.deploy.

Databases

A Database is the top-level storage container in Unison Cloud. It groups together tables and other storage types in a particular Environment for basic access management and namespacing.

createDb : '{Cloud, Exception} (Environment, Database)
createDb = do
  db = Database.named "myDatabase"
  env = Environment.named "myAppEnv"
  Database.assign db env
  (env, db)

Database creation is lightweight and idempotent. You don't need to worry about a complex provisioning process, and you can rerun your deployments without accidentally recreating your databases.

OrderedTables

OrderedTables store arbitrary typed key-value data in a sorted order. They support database transactions and range queries. Many application-level concerns can be modeled with OrderedTables, including relational data, and data with compound key types.

deploy : '{IO, Exception} (Optional Nat, Text)
deploy = Cloud.main do
  (env, db) = createDb()
  userTable : OrderedTable Text (Optional Nat, Text)
  userTable = OrderedTable.named db "users" Universal.ordering
  Cloud.submit env do
    transact.random db do
      OrderedTable.write.tx userTable "alice" (Some 123, "alice@alice.com")
      OrderedTable.read.tx userTable "alice"

Read more about data modeling with OrderedTables in the Cloud.

Cell

A Cell is a table that stores a single value of any type.

deploy : '{IO, Exception} [Text]
deploy = Cloud.main do
  (env, db) = createDb()
  messagesCell : Cell [Text]
  messagesCell = Cell.named db "messages" []
  Cloud.submit env do
    modify_ messagesCell (msgs -> msgs ++ ["hello, world!"])
    read messagesCell

Blobs

Blob storage is commonly used for binary data like images or files. You can store and retrieve binary blob data or arbitrarily typed Unison values.

deploy : '{IO, Exception} Optional (Bytes, Metadata)
deploy = Cloud.main do
  (env, db) = createDb()
  bytes = Text.toUtf8 "hello, world!"
  Cloud.submit env do
    key = Key ("data/file.txt")
    ignore <| Blobs.bytes.write db key bytes
    Blobs.bytes.read db key

Config

Values saved in Config are stored encrypted on Unison Cloud. Config is used for storing sensitive data, like API keys, that should not be recorded in the codebase or in regular database storage.

deploy : '{IO, Exception} Optional Text
deploy = Cloud.main do
  env = Environment.named "my-env"
  Environment.setValue env "api-key" (getEnv "SECRET_API_KEY")
  Cloud.submit env do
    Environment.Config.lookup "api-key"

Scratch

Scratch is for caching values in memory during the runtime of a Cloud program. Scratch values are ephemeral and do not persist after the Cloud job or service is completed. Scratch is bound to a Location, so care should be taken combining it with the Remote.fork and Remote.await APIs, since the cached value may not be available to the forked task at a potentially different location.

deploy : '{IO, Exception} Optional Json
deploy = Cloud.main do
  env = Environment.named "my-env"
  json = readFileUtf8 <| FilePath "users.json" |> Json.fromText
  Cloud.submit env do
    hashedJson : Hashed Json
    hashedJson = Scratch.save json
    lookupHashed hashedJson

Table

Used primarily for building other Cloud storage data types, Tables store arbitrary typed data by a key. They are similar to OrderedTables but are considered a lower-level api, since they do not support the ability to retrieve the set of keys once written.

deploy : '{IO, Exception} Text
deploy = Cloud.main do
  (env, db) = createDb()
  table = Table.Table "my-table"
  Cloud.submit env do
      Storage.write db table 123 "hello"
      Storage.read db table 123