Plain objects in the store a database lives in: small objects with
conditional writes (get/3, put/4), such as leases (see
Slap.Cluster.Strategy.ObjectLease), and large ones streamed in and out
(upload/4, download/3), such as file bodies. Every call takes the
:timeout option (see Slap.SlateDB); for a stream it bounds each step.
{:ok, store} = Slap.SlateDB.ObjectStore.open("_cluster", store: {:url, "s3://bucket/prefix"})
{:ok, version} = Slap.SlateDB.ObjectStore.put(store, "leases/0", "a", mode: :create)
{:ok, {"a", ^version}} = Slap.SlateDB.ObjectStore.get(store, "leases/0")
{:error, :conflict} = Slap.SlateDB.ObjectStore.put(store, "leases/0", "b", mode: :create)
{:ok, _} = Slap.SlateDB.ObjectStore.put(store, "leases/0", "b", mode: {:update, version})Conditional updates ({:update, version}, an If-Match PUT) need a store
that supports them: S3 and S3-compatible stores such as RustFS, Azure,
GCS, and :memory. The local file system only supports :create, and
returns {:error, :unsupported} for an update.
An atom error means the store refused a condition or does not support it;
%Slap.SlateDB.Error{} means the operation failed.
Summary
Functions
Deletes an object. Deleting one that does not exist is not an error.
Opens the object at key for reading. Returns {:ok, {chunks, size, version}}, where chunks is a lazy stream of binaries (reading it
raises Slap.SlateDB.Error if the store fails) and size is the size of
the whole object, or {:ok, nil} if there is no object.
The object's body and version, or {:ok, nil} if there is none.
The keys under prefix, in no particular order.
Opens store (as for Slap.SlateDB.open/2). Keys are relative to path
within it (and to the prefix of a store URL). The :store option is required.
Writes an object. :mode is
Writes the object at key from chunks, an enumerable of binaries, and
returns {:ok, version}. Nothing is visible at key until the whole body
is written.
Types
Functions
@spec delete(t(), String.t(), keyword()) :: :ok | {:error, Slap.SlateDB.Error.t()}
Deletes an object. Deleting one that does not exist is not an error.
@spec download(t(), String.t(), keyword()) :: {:ok, {Enumerable.t(), non_neg_integer(), version()} | nil} | {:error, Slap.SlateDB.Error.t()}
Opens the object at key for reading. Returns {:ok, {chunks, size, version}}, where chunks is a lazy stream of binaries (reading it
raises Slap.SlateDB.Error if the store fails) and size is the size of
the whole object, or {:ok, nil} if there is no object.
range: {first, last} reads only the bytes from first to last,
inclusive, as an HTTP range does. A last past the end of the object
reads to its end. A range that starts past the end returns an error whose
form depends on the store, so check the range against the object's size
first.
@spec get(t(), String.t(), keyword()) :: {:ok, {binary(), version()} | nil} | {:error, Slap.SlateDB.Error.t()}
The object's body and version, or {:ok, nil} if there is none.
@spec list(t(), String.t(), keyword()) :: {:ok, [String.t()]} | {:error, Slap.SlateDB.Error.t()}
The keys under prefix, in no particular order.
@spec open(String.t(), keyword()) :: {:ok, t()} | {:error, Slap.SlateDB.Error.t()}
Opens store (as for Slap.SlateDB.open/2). Keys are relative to path
within it (and to the prefix of a store URL). The :store option is required.
A :memory store is new and empty each time it is opened.
@spec put(t(), String.t(), binary(), keyword()) :: {:ok, version()} | {:error, :conflict | :unsupported | Slap.SlateDB.Error.t()}
Writes an object. :mode is:
:overwrite(default) - unconditionally.:create- only if there is no object atkey.{:update, version}- only if the object is still atversion.
Returns {:ok, version}, {:error, :conflict} when the condition does not
hold, or {:error, :unsupported} when the store cannot check it.
@spec upload(t(), String.t(), Enumerable.t(), keyword()) :: {:ok, version()} | {:error, Slap.SlateDB.Error.t()}
Writes the object at key from chunks, an enumerable of binaries, and
returns {:ok, version}. Nothing is visible at key until the whole body
is written.
A body smaller than one part (5 MiB) is written with a single PUT; a
larger one as a multipart upload, a few parts at a time, which is aborted
if chunks raises or the upload fails. A process that dies during an
upload leaves its parts behind until the store expires them (S3 needs a
lifecycle rule for incomplete multipart uploads).