libsql-client-ts icon indicating copy to clipboard operation
libsql-client-ts copied to clipboard

Queries return non-plain objects (objects with hidden properties)

Open serchtul opened this issue 7 months ago • 1 comments

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).

serchtul avatar Mar 18 '25 02:03 serchtul