Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client config for boolean casting #15

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

voinik
Copy link

@voinik voinik commented May 2, 2024

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.

@@ -71,6 +72,7 @@ export function valueResultFromProto(result: proto.StmtResult, intMode: IntMode)
const stmtResult = stmtResultFromProto(result);
let value: Value | undefined;
if (result.rows.length > 0 && stmtResult.columnNames.length > 0) {
// TODO: How do we solve this? AFAICS we don't have column data when fetching a single value, so we don't know when to cast ints to booleans
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the biggest drawback of the whole PR I think. Since we don't get any column type data when fetching pure values, we can't know when we should cast. We'd have to make it very clear that the casting config only applies to query/queryRow and not when fetching values. Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant