import { Deno } from "https://deno.land/x/deno@v2.0.4/cli/tsc/dts/lib.deno.unstable.d.ts";
const { Kv } = Deno;
UNSTABLE: New API, yet to be vetted.
A key-value database that can be used to store and retrieve data.
Data is stored as key-value pairs, where the key is a Deno.KvKey
and the value is an arbitrary structured-serializable JavaScript value.
Keys are ordered lexicographically as described in the documentation for
Deno.KvKey
. Keys are unique within a database, and the last
value set for a given key is the one that is returned when reading the
key. Keys can be deleted from the database, in which case they will no
longer be returned when reading keys.
Values can be any structured-serializable JavaScript value (objects,
arrays, strings, numbers, etc.). The special value Deno.KvU64
can be used to store 64-bit unsigned integers in the database. This special
value can not be nested within other objects or arrays. In addition to the
regular database mutation operations, the unsigned 64-bit integer value
also supports sum
, max
, and min
mutations.
Keys are versioned on write by assigning the key an ever-increasing "versionstamp". The versionstamp represents the version of a key-value pair in the database at some point in time, and can be used to perform transactional operations on the database without requiring any locking. This is enabled by atomic operations, which can have conditions that ensure that the operation only succeeds if the versionstamp of the key-value pair matches an expected versionstamp.
Keys have a maximum length of 2048 bytes after serialization. Values have a maximum length of 64 KiB after serialization. Serialization of both keys and values is somewhat opaque, but one can usually assume that the serialization of any value is about the same length as the resulting string of a JSON serialization of that same value. If theses limits are exceeded, an exception will be thrown.
Methods
Create a new Deno.AtomicOperation
object which can be used to
perform an atomic transaction on the database. This does not perform any
operations on the database - the atomic transaction must be committed
explicitly using the Deno.AtomicOperation.commit
method once
all checks and mutations have been added to the operation.
Close the database connection. This will prevent any further operations from being performed on the database, and interrupt any in-flight operations immediately.
Get a symbol that represents the versionstamp of the current atomic
operation. This symbol can be used as the last part of a key in
.set()
, both directly on the Kv
object and on an AtomicOperation
object created from this Kv
instance.
Delete the value for the given key from the database. If no value exists for the key, this operation is a no-op.
const db = await Deno.openKv();
await db.delete(["foo"]);
Add a value into the database queue to be delivered to the queue
listener via Deno.Kv.listenQueue
.
const db = await Deno.openKv();
await db.enqueue("bar");
The delay
option can be used to specify the delay (in milliseconds)
of the value delivery. The default delay is 0, which means immediate
delivery.
const db = await Deno.openKv();
await db.enqueue("bar", { delay: 60000 });
The keysIfUndelivered
option can be used to specify the keys to
be set if the value is not successfully delivered to the queue
listener after several attempts. The values are set to the value of
the queued message.
The backoffSchedule
option can be used to specify the retry policy for
failed message delivery. Each element in the array represents the number of
milliseconds to wait before retrying the delivery. For example,
[1000, 5000, 10000]
means that a failed delivery will be retried
at most 3 times, with 1 second, 5 seconds, and 10 seconds delay
between each retry.
const db = await Deno.openKv();
await db.enqueue("bar", {
keysIfUndelivered: [["foo", "bar"]],
backoffSchedule: [1000, 5000, 10000],
});
Retrieve the value and versionstamp for the given key from the database
in the form of a Deno.KvEntryMaybe
. If no value exists for
the key, the returned entry will have a null
value and versionstamp.
const db = await Deno.openKv();
const result = await db.get(["foo"]);
result.key; // ["foo"]
result.value; // "bar"
result.versionstamp; // "00000000000000010000"
The consistency
option can be used to specify the consistency level
for the read operation. The default consistency level is "strong". Some
use cases can benefit from using a weaker consistency level. For more
information on consistency levels, see the documentation for
Deno.KvConsistencyLevel
.
Retrieve multiple values and versionstamps from the database in the form
of an array of Deno.KvEntryMaybe
objects. The returned array
will have the same length as the keys
array, and the entries will be in
the same order as the keys. If no value exists for a given key, the
returned entry will have a null
value and versionstamp.
const db = await Deno.openKv();
const result = await db.getMany([["foo"], ["baz"]]);
result[0].key; // ["foo"]
result[0].value; // "bar"
result[0].versionstamp; // "00000000000000010000"
result[1].key; // ["baz"]
result[1].value; // null
result[1].versionstamp; // null
The consistency
option can be used to specify the consistency level
for the read operation. The default consistency level is "strong". Some
use cases can benefit from using a weaker consistency level. For more
information on consistency levels, see the documentation for
Deno.KvConsistencyLevel
.
Retrieve a list of keys in the database. The returned list is an
Deno.KvListIterator
which can be used to iterate over the
entries in the database.
Each list operation must specify a selector which is used to specify the range of keys to return. The selector can either be a prefix selector, or a range selector:
- A prefix selector selects all keys that start with the given prefix of
key parts. For example, the selector
["users"]
will select all keys that start with the prefix["users"]
, such as["users", "alice"]
and["users", "bob"]
. Note that you can not partially match a key part, so the selector["users", "a"]
will not match the key["users", "alice"]
. A prefix selector may specify astart
key that is used to skip over keys that are lexicographically less than the start key. - A range selector selects all keys that are lexicographically between
the given start and end keys (including the start, and excluding the
end). For example, the selector
["users", "a"], ["users", "n"]
will select all keys that start with the prefix["users"]
and have a second key part that is lexicographically betweena
andn
, such as["users", "alice"]
,["users", "bob"]
, and["users", "mike"]
, but not["users", "noa"]
or["users", "zoe"]
.
const db = await Deno.openKv();
const entries = db.list({ prefix: ["users"] });
for await (const entry of entries) {
entry.key; // ["users", "alice"]
entry.value; // { name: "Alice" }
entry.versionstamp; // "00000000000000010000"
}
The options
argument can be used to specify additional options for the
list operation. See the documentation for Deno.KvListOptions
for more information.
Listen for queue values to be delivered from the database queue, which
were enqueued with Deno.Kv.enqueue
. The provided handler
callback is invoked on every dequeued value. A failed callback
invocation is automatically retried multiple times until it succeeds
or until the maximum number of retries is reached.
const db = await Deno.openKv();
db.listenQueue(async (msg: unknown) => {
await db.set(["foo"], msg);
});
Set the value for the given key in the database. If a value already exists for the key, it will be overwritten.
const db = await Deno.openKv();
await db.set(["foo"], "bar");
Optionally an expireIn
option can be specified to set a time-to-live
(TTL) for the key. The TTL is specified in milliseconds, and the key will
be deleted from the database at earliest after the specified number of
milliseconds have elapsed. Once the specified duration has passed, the
key may still be visible for some additional time. If the expireIn
option is not specified, the key will not expire.
Watch for changes to the given keys in the database. The returned stream
is a ReadableStream
that emits a new value whenever any of
the watched keys change their versionstamp. The emitted value is an array
of Deno.KvEntryMaybe
objects, with the same length and order
as the keys
array. If no value exists for a given key, the returned
entry will have a null
value and versionstamp.
The returned stream does not return every single intermediate state of the watched keys, but rather only keeps you up to date with the latest state of the keys. This means that if a key is modified multiple times quickly, you may not receive a notification for every single change, but rather only the latest state of the key.
const db = await Deno.openKv();
const stream = db.watch([["foo"], ["bar"]]);
for await (const entries of stream) {
entries[0].key; // ["foo"]
entries[0].value; // "bar"
entries[0].versionstamp; // "00000000000000010000"
entries[1].key; // ["bar"]
entries[1].value; // null
entries[1].versionstamp; // null
}
The options
argument can be used to specify additional options for the
watch operation. The raw
option can be used to specify whether a new
value should be emitted whenever a mutation occurs on any of the watched
keys (even if the value of the key does not change, such as deleting a
deleted key), or only when entries have observably changed in some way.
When raw: true
is used, it is possible for the stream to occasionally
emit values even if no mutations have occurred on any of the watched
keys. The default value for this option is false
.