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
Batch

Batched reads reduce database round-trips for arbitrary key value types.

Yes 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.

The top-level handler for running a transaction takes a Database and the transaction block to run:

Storage.transact :          Database
                            -> '{Transaction, Exception, Random, Batch} a
                            ->{Exception, Storage} 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 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

Batch

Batch is an ability which creates a batch of multiple reads across potentially different tables that can be performed in a single database round trip. It follows a fork/await pattern.

deploy : '{IO, Exception} (Text, Text, Boolean)
deploy = Cloud.main do
  (env, db) = createDb()
  (table1, table2) = (Table "table1", Table "table2")
  Cloud.submit env do
    Storage.write db table1 1 "🌹"
    Storage.write db table1 2 "🪻"
    Storage.write db table2 "3" false
    batchRead db do
      read1 : Read Text
      read1 = forkRead table1 1
      read2 : Read Text
      read2 = forkRead table1 2
      read3 : Read Boolean
      read3 = forkRead table2 "3"
      (awaitRead read1, awaitRead read2, awaitRead read3)

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