libsql-client-ts
libsql-client-ts copied to clipboard
Queries return non-plain objects (objects with hidden properties)
Hello! 👋
Today I went into a rabbit hole that led me to find out that objects returned by queries in this library are not "plain" JSONs, they contain some hidden (non-enumerable and non-configurable) properties.
The summary is that I can't use objects returned from this library with React Server Components (because those hidden properties cannot be serialized to JSON).
If you want more context, you can check https://github.com/kysely-org/kysely/issues/1394 (I also created an issue in https://github.com/tursodatabase/kysely-libsql/issues/27 for visibility).
Reproduction steps
I took this code from a test and modified it a bit to log the whole object (including all the hidden properties):
import { inspect } from 'node:utils';
// This assumes a client has been instantiated before
await client.batch(
[
"DROP TABLE IF EXISTS t",
"CREATE TABLE t (a)",
"INSERT INTO t VALUES ('three')",
],
"write",
);
const selectRs = await client.execute({
sql: "SELECT a FROM t",
})
// These should be the same, but they're not
console.log("original", inspect(selectRs.rows[0], true))
console.log("serialized-deserialized", inspect(JSON.parse(JSON.stringify(selectRs.rows[0])), true))
The output of the console is the following:
original { [0]: 'three', [length]: 1, a: 'three' } // <-- the original object includes these extra hidden properties
serialized-deserialized { a: 'three' }
I dug around the code a bit and I didn't find any obvious reason for these to be used (other than a couple tests that broke and I was able to fix when I removed the code). Let me know if there's something else I might not be looking.
Expected result
I would ideally like the result of every query to be a simple "plain" object. I know this is technically a breaking change (because people might be using these hidden properties in their code) but I don't think these should be available to the users of this library.
Using the previous example, I would expect to see:
original { a: 'three' } // <-- no extra properties
serialized-deserialized { a: 'three' }
I would like to know if there's any technical reason behind this decision, because this is also affecting how data is retrieved in other libraries (for instance, the particular example I shared using Kysely).
I am also open to work on a PR for this, provided you're okay with me submitting this (mostly given it's a breaking change).