libsql / hrana-client-ts

Hrana client for TypeScript and JavaScript
https://libsql.org/hrana-client-ts/
MIT License
23 stars 7 forks source link

Client config for boolean casting #15

Open voinik opened 6 months ago

voinik commented 6 months ago

This PR was instigated due to my Discord post and my involvement of this Kysely GitHub issue. In short: after switching from PlanetScale to Turso I was expecting boolean DB values that I fetch in my program to be actual booleans, but they weren't! I learned that SQLite saves booleans as integers, and hrana doesn't cast them to booleans.

As a workaround, I then forked the @libsql/kysely-libsql Kysely driver to get it to pass hrana/libsql's selected column data so that I could write a Kysely plugin that can do the cast in my own application code. The plugin can be found in the README of my fork, if anyone's interested.

But this led me to wonder why hrana isn't doing that cast. When data is inserted (updates/creates), JS booleans are in fact cast to integers/bigints prior to insertion. I would expect this to be done the in other direction as well. Considering hrana is already going through all the columns in the query results, it seemed like unnecessary overhead to then do that again in the developer's application code. And thus this PR was born.

I've basically added an optional config parameter that has an optional castBooleans property, for backwards compatibility. You can even use it to pass down other configuration in the future.

I got this working with the different @libsql/libsql-client-ts clients with a few minor adjustments (passing the config down where needed, about 25 lines of changes in that repo in total).

Please let me know what you think!

Edit: I just now changed all my tables to STRICT. The issue with that is that we are no longer allowed to use other data types than INT, INTEGER, BLOB, TEXT, REAL and ANY. So boolean isn't allowed. This makes my solution unusable for STRICT tables. I also noticed my solution (for now) only works if the column type was set to 'boolean', meaning it won't work for 'bool', for example; perhaps a .contains('bool') would suffice. Anyway, feel free to close this PR if you think there are too many conditions for this to work.