microlinkhq / keyvhq

Simple key-value storage with support for multiple backends.

Home Page:https://keyvhq.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incompatability with Redis + Sializer (Get returns String)

kinsi55 opened this issue · comments

I'm trying to use @keyvhq/redis with sializer as the De/Serializer. Heres the Keyv options I use:

{ store: new (require("@keyvhq/redis"))(REDISURL), serialize: sia, deserialize: desia }

The Problem now lies in the fact that when .get is called, a String will be passed to the deserialize method (

async get (key, { raw: asRaw = false } = {}) {
const raw = await this.store.get(this._getKeyPrefix(key))
if (raw === undefined) return undefined
const data = typeof raw === 'string' ? await this.deserialize(raw) : raw
) which in term causes the Desia Method to break.

My current workaround is changing the deserialize method to be this instead:

x => desia(Buffer.from(x))

Obviously this isnt super great, and I think a better solution would be having a new option which in term skips the redis > buffer > string conversion and just works with the buffer to begin with (I'm assuming here that thats what happens, I havent looked into it further)

Edit: Looks like my workaround doesnt consistently work.

What's sializer? Can you make a full code reproduction of the issue?

The contract is clear: .deserialize receives whatever you .serialized unless undefined

You should to follow the serializer contract 🙂

I can reproduce it consistently, heres the code for it:

const { sia, desia } = require("sializer");
const Keyv = require("@keyvhq/core");
const KeyvRedis = require("@keyvhq/redis");

const kv = new Keyv({
	store: new KeyvRedis("redis://vm"),
	serialize: x => {
		console.log("Serializing %s (%i):", typeof x, x?.length, x);

		const ser = sia(x);
		console.log("Serialized Type: %s", typeof ser);

		desia(ser);
		console.log("Successfully deserialized before Keyv");

		return ser;
	},
	deserialize: x => {
		console.log("Deserializing %s (%i):", typeof x, x?.length, x);

		const ser = desia(x);
		console.log("Deserialized Type: %s", typeof ser);

		return ser;
	}
});

(async() => {
	await kv.set("qux", {foo: [1,2,3], bar: { baz: true }});
	const out = await kv.get("qux");

	console.log(out);
})();

Result:

node repro.js
Serializing object (NaN): { value: { foo: [ 1, 2, 3 ], bar: { baz: true } }, expires: null }
Serialized Type: object
Successfully deserialized before Keyv

eserializing string (47): 4♣alue4♥oo/♥☻☺☻☻☻♥♥ar4♥az(55xpires5
node:internal/process/promises:288
triggerUncaughtException(err, true /* fromPromise */);
^

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Unsupported type: 4".] {
code: 'ERR_UNHANDLED_REJECTION'
}

Node.js v18.17.1