-
Notifications
You must be signed in to change notification settings - Fork 35
Description
What's wrong?
I built a desktop client app to manage Deno KV databases.
I designed the app to work with both Deno.KV client and the Node implementation of Deno KV client
provided by the @deno/kv package, since both expose the same API and interact with the same database.
However, while developing and using the app, I noticed some inconsistent behaviors between the native Deno.KV.list() method (in Deno runtime) and the one of the @deno/kv package (in Node).
Behavior Differences
Here are three confusing and unexpected behaviors I encountered:
[1] Selector keys with undefined value
In Deno, when you pass selector keys with undefined value to Deno.KV.list method like the following:
const kv = await Deno.openKv();
const iterator = kv.list({ prefix: ["users"], end: undefined, start: undefined });
for await (const entry of iterator) {/*...*/}This will work fine as you only specified prefix selector (ignoring end and start because they are undefined)
But when you do the same in Node with @deno/kv package and pass selector keys with undefined value to the kv.list method:
import { openKv } from "@deno/kv";
const kv = await openKv();
const iterator = kv.list({ prefix: ["users"], end: undefined, start: undefined });
for await (const entry of iterator) {/*...*/}You get the following error:
TypeError: Selector can not specify both 'start' and 'end' keys when specifying 'prefix'
I looked at @deno/kv package's code. Apparently, this happens because the package uses the in operator to check keys existence regardless of the types of their values
[2] Invalid range key with prefix selector
When you pass an invalid range key ("end" or "start") with the prefix selector to Deno.KV.list method like the following:
const kv = await Deno.openKv();
const iterator = kv.list({ prefix: ["users"], end: ["C"] });
for await (const entry of iterator) {/*...*/}The following error will be thrown (which is expected):
TypeError: End key is not in the keyspace defined by prefix
But passing the same invalid range key in Node to @deno/kv package's list method does not throw any error:
import { openKv } from "@deno/kv";
const kv = await openKv();
const iterator = kv.list({ prefix: ["users"], end: ["C"] });
for await (const entry of iterator) {/*...*/}No error, even though the end key is outside the keyspace defined by the prefix.
[3] Incomplete selector keys
When passing an incomplete selector (e.g, passing only {start: [...]} or {end: [...]}, or an empty one {}) to the Deno.KV.list method like this:
const kv = await Deno.openKv();
const iterator = kv.list({ start: [10] }); // or `{ end: [10] }` or `{}`
for await (const entry of iterator) {/*...*/}An error will be thrown (which is also expected):
TypeError: Selector must specify either 'prefix' or both 'start' and 'end' key
But in Node with @deno/kv package, passing an incomplete selector throws a completely different and confusing error:
import { openKv } from "@deno/kv";
const kv = await openKv();
const iterator = kv.list({ start: [10] }); // or `{ end: [10] }` or `{}`
for await (const entry of iterator) {/*...*/}This error will be thrown:
TypeError: Cannot read properties of undefined (reading 'flatMap')