summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/unit/kv_test.ts50
-rw-r--r--cli/tsc/dts/lib.deno.unstable.d.ts56
-rw-r--r--ext/kv/01_db.ts18
3 files changed, 91 insertions, 33 deletions
diff --git a/cli/tests/unit/kv_test.ts b/cli/tests/unit/kv_test.ts
index 401eba9b6..69eb8bed9 100644
--- a/cli/tests/unit/kv_test.ts
+++ b/cli/tests/unit/kv_test.ts
@@ -6,6 +6,7 @@ import {
assertRejects,
assertThrows,
} from "./test_util.ts";
+import { assertType, IsExact } from "../../../test_util/std/testing/types.ts";
let isCI: boolean;
try {
@@ -529,8 +530,10 @@ Deno.test("KvU64 unbox", () => {
assertEquals(a.value, 1n);
});
-async function collect(iter: Deno.KvListIterator): Promise<Deno.KvEntry[]> {
- const entries: Deno.KvEntry[] = [];
+async function collect<T>(
+ iter: Deno.KvListIterator<T>,
+): Promise<Deno.KvEntry<T>[]> {
+ const entries: Deno.KvEntry<T>[] = [];
for await (const entry of iter) {
entries.push(entry);
}
@@ -1134,3 +1137,46 @@ dbTest("operation size limit", async (db) => {
"too many mutations (max 10)",
);
});
+
+// This function is never called, it is just used to check that all the types
+// are behaving as expected.
+async function _typeCheckingTests() {
+ const kv = new Deno.Kv();
+
+ const a = await kv.get(["a"]);
+ assertType<IsExact<typeof a, Deno.KvEntryMaybe<unknown>>>(true);
+
+ const b = await kv.get<string>(["b"]);
+ assertType<IsExact<typeof b, Deno.KvEntryMaybe<string>>>(true);
+
+ const c = await kv.getMany([["a"], ["b"]]);
+ assertType<
+ IsExact<typeof c, [Deno.KvEntryMaybe<unknown>, Deno.KvEntryMaybe<unknown>]>
+ >(true);
+
+ const d = await kv.getMany([["a"], ["b"]] as const);
+ assertType<
+ IsExact<typeof d, [Deno.KvEntryMaybe<unknown>, Deno.KvEntryMaybe<unknown>]>
+ >(true);
+
+ const e = await kv.getMany<[string, number]>([["a"], ["b"]]);
+ assertType<
+ IsExact<typeof e, [Deno.KvEntryMaybe<string>, Deno.KvEntryMaybe<number>]>
+ >(true);
+
+ const keys: Deno.KvKey[] = [["a"], ["b"]];
+ const f = await kv.getMany(keys);
+ assertType<IsExact<typeof f, Deno.KvEntryMaybe<unknown>[]>>(true);
+
+ const g = kv.list({ prefix: ["a"] });
+ assertType<IsExact<typeof g, Deno.KvListIterator<unknown>>>(true);
+ const h = await g.next();
+ assert(!h.done);
+ assertType<IsExact<typeof h.value, Deno.KvEntry<unknown>>>(true);
+
+ const i = kv.list<string>({ prefix: ["a"] });
+ assertType<IsExact<typeof i, Deno.KvListIterator<string>>>(true);
+ const j = await i.next();
+ assert(!j.done);
+ assertType<IsExact<typeof j.value, Deno.KvEntry<string>>>(true);
+}
diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts
index f4dab5663..b82a80382 100644
--- a/cli/tsc/dts/lib.deno.unstable.d.ts
+++ b/cli/tsc/dts/lib.deno.unstable.d.ts
@@ -1661,7 +1661,7 @@ declare namespace Deno {
*
* @category KV
*/
- export class KvListIterator implements AsyncIterableIterator<KvEntry> {
+ export class KvListIterator<T> implements AsyncIterableIterator<KvEntry<T>> {
/**
* Returns the cursor of the current position in the iteration. This cursor
* can be used to resume the iteration from the current position in the
@@ -1669,8 +1669,8 @@ declare namespace Deno {
*/
get cursor(): string;
- next(): Promise<IteratorResult<KvEntry, any>>;
- [Symbol.asyncIterator](): AsyncIterableIterator<KvEntry>;
+ next(): Promise<IteratorResult<KvEntry<T>, undefined>>;
+ [Symbol.asyncIterator](): AsyncIterableIterator<KvEntry<T>>;
}
/** **UNSTABLE**: New API, yet to be vetted.
@@ -1680,16 +1680,26 @@ declare namespace Deno {
* The `versionstamp` is a string that represents the current version of the
* key-value pair. It can be used to perform atomic operations on the KV store
* by passing it to the `check` method of a {@linkcode Deno.AtomicOperation}.
- * A `null` versionstamp indicates that no value exists for the given key in
- * the KV store.
*
* @category KV
*/
- export interface KvEntry {
+ export type KvEntry<T> = { key: KvKey; value: T; versionstamp: string };
+
+ /**
+ * **UNSTABLE**: New API, yet to be vetted.
+ *
+ * An optional versioned pair of key and value in a {@linkcode Deno.Kv}.
+ *
+ * This is the same as a {@linkcode KvEntry}, but the `value` and `versionstamp`
+ * fields may be `null` if no value exists for the given key in the KV store.
+ *
+ * @category KV
+ */
+ export type KvEntryMaybe<T> = KvEntry<T> | {
key: KvKey;
- value: unknown;
- versionstamp: string | null;
- }
+ value: null;
+ versionstamp: null;
+ };
/** **UNSTABLE**: New API, yet to be vetted.
*
@@ -1881,8 +1891,8 @@ declare namespace Deno {
export class Kv {
/**
* Retrieve the value and versionstamp for the given key from the database
- * in the form of a {@linkcode Deno.KvEntry}. If no value exists for the key,
- * the returned entry will have a `null` value and versionstamp.
+ * in the form of a {@linkcode Deno.KvEntryMaybe}. If no value exists for
+ * the key, the returned entry will have a `null` value and versionstamp.
*
* ```ts
* const db = await Deno.openKv();
@@ -1898,17 +1908,17 @@ declare namespace Deno {
* information on consistency levels, see the documentation for
* {@linkcode Deno.KvConsistencyLevel}.
*/
- get(
+ get<T = unknown>(
key: KvKey,
options?: { consistency?: KvConsistencyLevel },
- ): Promise<KvEntry>;
+ ): Promise<KvEntryMaybe<T>>;
/**
* Retrieve multiple values and versionstamps from the database in the form
- * of an array of {@linkcode Deno.KvEntry} 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.
+ * of an array of {@linkcode 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.
*
* ```ts
* const db = await Deno.openKv();
@@ -1927,11 +1937,10 @@ declare namespace Deno {
* information on consistency levels, see the documentation for
* {@linkcode Deno.KvConsistencyLevel}.
*/
- getMany(
- keys: KvKey[],
+ getMany<T extends readonly unknown[]>(
+ keys: readonly [...{ [K in keyof T]: KvKey }],
options?: { consistency?: KvConsistencyLevel },
- ): Promise<KvEntry[]>;
-
+ ): Promise<{ [K in keyof T]: KvEntryMaybe<T[K]> }>;
/**
* Set the value for the given key in the database. If a value already
* exists for the key, it will be overwritten.
@@ -1993,7 +2002,10 @@ declare namespace Deno {
* list operation. See the documentation for {@linkcode Deno.KvListOptions}
* for more information.
*/
- list(selector: KvListSelector, options?: KvListOptions): KvListIterator;
+ list<T = unknown>(
+ selector: KvListSelector,
+ options?: KvListOptions,
+ ): KvListIterator<T>;
/**
* Create a new {@linkcode Deno.AtomicOperation} object which can be used to
diff --git a/ext/kv/01_db.ts b/ext/kv/01_db.ts
index e0c5335e6..05e9a66d8 100644
--- a/ext/kv/01_db.ts
+++ b/ext/kv/01_db.ts
@@ -75,7 +75,7 @@ class Kv {
async getMany(
keys: Deno.KvKey[],
opts?: { consistency?: Deno.KvConsistencyLevel },
- ): Promise<Deno.KvEntry[]> {
+ ): Promise<Deno.KvEntry<unknown>[]> {
keys = keys.map(convertKey);
const ranges: RawKvEntry[][] = await core.opAsync(
"op_kv_snapshot_read",
@@ -174,7 +174,7 @@ class Kv {
cursor: string | undefined,
reverse: boolean,
consistency: Deno.KvConsistencyLevel,
- ) => Promise<Deno.KvEntry[]> {
+ ) => Promise<Deno.KvEntry<unknown>[]> {
return async (selector, cursor, reverse, consistency) => {
const [entries]: [RawKvEntry[]] = await core.opAsync(
"op_kv_snapshot_read",
@@ -304,7 +304,7 @@ function convertKey(key: Deno.KvKey | Deno.KvKeyPart): Deno.KvKey {
}
}
-function deserializeValue(entry: RawKvEntry): Deno.KvEntry {
+function deserializeValue(entry: RawKvEntry): Deno.KvEntry<unknown> {
const { kind, value } = entry.value;
switch (kind) {
case "v8":
@@ -357,9 +357,9 @@ const AsyncIteratorPrototype = ObjectGetPrototypeOf(AsyncGeneratorPrototype);
const AsyncIterator = AsyncIteratorPrototype.constructor;
class KvListIterator extends AsyncIterator
- implements AsyncIterator<Deno.KvEntry> {
+ implements AsyncIterator<Deno.KvEntry<unknown>> {
#selector: Deno.KvListSelector;
- #entries: Deno.KvEntry[] | null = null;
+ #entries: Deno.KvEntry<unknown>[] | null = null;
#cursorGen: (() => string) | null = null;
#done = false;
#lastBatch = false;
@@ -368,7 +368,7 @@ class KvListIterator extends AsyncIterator
cursor: string | undefined,
reverse: boolean,
consistency: Deno.KvConsistencyLevel,
- ) => Promise<Deno.KvEntry[]>;
+ ) => Promise<Deno.KvEntry<unknown>[]>;
#limit: number | undefined;
#count = 0;
#reverse: boolean;
@@ -388,7 +388,7 @@ class KvListIterator extends AsyncIterator
cursor: string | undefined,
reverse: boolean,
consistency: Deno.KvConsistencyLevel,
- ) => Promise<Deno.KvEntry[]>;
+ ) => Promise<Deno.KvEntry<unknown>[]>;
},
) {
super();
@@ -443,7 +443,7 @@ class KvListIterator extends AsyncIterator
return this.#cursorGen();
}
- async next(): Promise<IteratorResult<Deno.KvEntry>> {
+ async next(): Promise<IteratorResult<Deno.KvEntry<unknown>>> {
// Fused or limit exceeded
if (
this.#done ||
@@ -493,7 +493,7 @@ class KvListIterator extends AsyncIterator
};
}
- [Symbol.asyncIterator](): AsyncIterator<Deno.KvEntry> {
+ [Symbol.asyncIterator](): AsyncIterator<Deno.KvEntry<unknown>> {
return this;
}
}