1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

fix(dts): improve types for the Deno.KV API (#18510)

This commit is contained in:
Luca Casonato 2023-03-30 22:52:31 +02:00 committed by GitHub
parent e888c3f534
commit 02e01b171f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 91 additions and 33 deletions

View file

@ -6,6 +6,7 @@ import {
assertRejects, assertRejects,
assertThrows, assertThrows,
} from "./test_util.ts"; } from "./test_util.ts";
import { assertType, IsExact } from "../../../test_util/std/testing/types.ts";
let isCI: boolean; let isCI: boolean;
try { try {
@ -529,8 +530,10 @@ Deno.test("KvU64 unbox", () => {
assertEquals(a.value, 1n); assertEquals(a.value, 1n);
}); });
async function collect(iter: Deno.KvListIterator): Promise<Deno.KvEntry[]> { async function collect<T>(
const entries: Deno.KvEntry[] = []; iter: Deno.KvListIterator<T>,
): Promise<Deno.KvEntry<T>[]> {
const entries: Deno.KvEntry<T>[] = [];
for await (const entry of iter) { for await (const entry of iter) {
entries.push(entry); entries.push(entry);
} }
@ -1134,3 +1137,46 @@ dbTest("operation size limit", async (db) => {
"too many mutations (max 10)", "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);
}

View file

@ -1661,7 +1661,7 @@ declare namespace Deno {
* *
* @category KV * @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 * 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 * can be used to resume the iteration from the current position in the
@ -1669,8 +1669,8 @@ declare namespace Deno {
*/ */
get cursor(): string; get cursor(): string;
next(): Promise<IteratorResult<KvEntry, any>>; next(): Promise<IteratorResult<KvEntry<T>, undefined>>;
[Symbol.asyncIterator](): AsyncIterableIterator<KvEntry>; [Symbol.asyncIterator](): AsyncIterableIterator<KvEntry<T>>;
} }
/** **UNSTABLE**: New API, yet to be vetted. /** **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 * 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 * 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}. * 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 * @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; key: KvKey;
value: unknown; value: null;
versionstamp: string | null; versionstamp: null;
} };
/** **UNSTABLE**: New API, yet to be vetted. /** **UNSTABLE**: New API, yet to be vetted.
* *
@ -1881,8 +1891,8 @@ declare namespace Deno {
export class Kv { export class Kv {
/** /**
* Retrieve the value and versionstamp for the given key from the database * 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, * in the form of a {@linkcode Deno.KvEntryMaybe}. If no value exists for
* the returned entry will have a `null` value and versionstamp. * the key, the returned entry will have a `null` value and versionstamp.
* *
* ```ts * ```ts
* const db = await Deno.openKv(); * const db = await Deno.openKv();
@ -1898,17 +1908,17 @@ declare namespace Deno {
* information on consistency levels, see the documentation for * information on consistency levels, see the documentation for
* {@linkcode Deno.KvConsistencyLevel}. * {@linkcode Deno.KvConsistencyLevel}.
*/ */
get( get<T = unknown>(
key: KvKey, key: KvKey,
options?: { consistency?: KvConsistencyLevel }, options?: { consistency?: KvConsistencyLevel },
): Promise<KvEntry>; ): Promise<KvEntryMaybe<T>>;
/** /**
* Retrieve multiple values and versionstamps from the database in the form * Retrieve multiple values and versionstamps from the database in the form
* of an array of {@linkcode Deno.KvEntry} objects. The returned array will * of an array of {@linkcode Deno.KvEntryMaybe} objects. The returned array
* have the same length as the `keys` array, and the entries will be in the * will have the same length as the `keys` array, and the entries will be in
* same order as the keys. If no value exists for a given key, the returned * the same order as the keys. If no value exists for a given key, the
* entry will have a `null` value and versionstamp. * returned entry will have a `null` value and versionstamp.
* *
* ```ts * ```ts
* const db = await Deno.openKv(); * const db = await Deno.openKv();
@ -1927,11 +1937,10 @@ declare namespace Deno {
* information on consistency levels, see the documentation for * information on consistency levels, see the documentation for
* {@linkcode Deno.KvConsistencyLevel}. * {@linkcode Deno.KvConsistencyLevel}.
*/ */
getMany( getMany<T extends readonly unknown[]>(
keys: KvKey[], keys: readonly [...{ [K in keyof T]: KvKey }],
options?: { consistency?: KvConsistencyLevel }, 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 * Set the value for the given key in the database. If a value already
* exists for the key, it will be overwritten. * exists for the key, it will be overwritten.
@ -1993,7 +2002,10 @@ declare namespace Deno {
* list operation. See the documentation for {@linkcode Deno.KvListOptions} * list operation. See the documentation for {@linkcode Deno.KvListOptions}
* for more information. * 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 * Create a new {@linkcode Deno.AtomicOperation} object which can be used to

View file

@ -75,7 +75,7 @@ class Kv {
async getMany( async getMany(
keys: Deno.KvKey[], keys: Deno.KvKey[],
opts?: { consistency?: Deno.KvConsistencyLevel }, opts?: { consistency?: Deno.KvConsistencyLevel },
): Promise<Deno.KvEntry[]> { ): Promise<Deno.KvEntry<unknown>[]> {
keys = keys.map(convertKey); keys = keys.map(convertKey);
const ranges: RawKvEntry[][] = await core.opAsync( const ranges: RawKvEntry[][] = await core.opAsync(
"op_kv_snapshot_read", "op_kv_snapshot_read",
@ -174,7 +174,7 @@ class Kv {
cursor: string | undefined, cursor: string | undefined,
reverse: boolean, reverse: boolean,
consistency: Deno.KvConsistencyLevel, consistency: Deno.KvConsistencyLevel,
) => Promise<Deno.KvEntry[]> { ) => Promise<Deno.KvEntry<unknown>[]> {
return async (selector, cursor, reverse, consistency) => { return async (selector, cursor, reverse, consistency) => {
const [entries]: [RawKvEntry[]] = await core.opAsync( const [entries]: [RawKvEntry[]] = await core.opAsync(
"op_kv_snapshot_read", "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; const { kind, value } = entry.value;
switch (kind) { switch (kind) {
case "v8": case "v8":
@ -357,9 +357,9 @@ const AsyncIteratorPrototype = ObjectGetPrototypeOf(AsyncGeneratorPrototype);
const AsyncIterator = AsyncIteratorPrototype.constructor; const AsyncIterator = AsyncIteratorPrototype.constructor;
class KvListIterator extends AsyncIterator class KvListIterator extends AsyncIterator
implements AsyncIterator<Deno.KvEntry> { implements AsyncIterator<Deno.KvEntry<unknown>> {
#selector: Deno.KvListSelector; #selector: Deno.KvListSelector;
#entries: Deno.KvEntry[] | null = null; #entries: Deno.KvEntry<unknown>[] | null = null;
#cursorGen: (() => string) | null = null; #cursorGen: (() => string) | null = null;
#done = false; #done = false;
#lastBatch = false; #lastBatch = false;
@ -368,7 +368,7 @@ class KvListIterator extends AsyncIterator
cursor: string | undefined, cursor: string | undefined,
reverse: boolean, reverse: boolean,
consistency: Deno.KvConsistencyLevel, consistency: Deno.KvConsistencyLevel,
) => Promise<Deno.KvEntry[]>; ) => Promise<Deno.KvEntry<unknown>[]>;
#limit: number | undefined; #limit: number | undefined;
#count = 0; #count = 0;
#reverse: boolean; #reverse: boolean;
@ -388,7 +388,7 @@ class KvListIterator extends AsyncIterator
cursor: string | undefined, cursor: string | undefined,
reverse: boolean, reverse: boolean,
consistency: Deno.KvConsistencyLevel, consistency: Deno.KvConsistencyLevel,
) => Promise<Deno.KvEntry[]>; ) => Promise<Deno.KvEntry<unknown>[]>;
}, },
) { ) {
super(); super();
@ -443,7 +443,7 @@ class KvListIterator extends AsyncIterator
return this.#cursorGen(); return this.#cursorGen();
} }
async next(): Promise<IteratorResult<Deno.KvEntry>> { async next(): Promise<IteratorResult<Deno.KvEntry<unknown>>> {
// Fused or limit exceeded // Fused or limit exceeded
if ( if (
this.#done || this.#done ||
@ -493,7 +493,7 @@ class KvListIterator extends AsyncIterator
}; };
} }
[Symbol.asyncIterator](): AsyncIterator<Deno.KvEntry> { [Symbol.asyncIterator](): AsyncIterator<Deno.KvEntry<unknown>> {
return this; return this;
} }
} }