Open cllns opened 3 months ago
"bool.cast(TRUE
).as(:visible)" is a SQL statement, merely CAST(TRUE AS boolean) AS 'visible'
. Setting the bool
type does nothing on the casting side, it's on you. Sequel returns a string so it'll be a string. Same for all default types in rom-sql, they are nominal, with no typecasting for performance reasons.
Thanks @flash-gordon, that makes sense. That was a silly example since 'boolean' doesn't exist in SQLITE, but it's so permissive that it happens to work anyway. (and TRUE is an alias for 1).
My workaround for now is to override the initializer for my Struct with
def initialize(attributes)
# Workaround for SQLite not having boolean type
attributes[:visible] = attributes[:visible] == 1
super
end
I guess the right way to do this is with a mapper?
I guess the right way to do this is with a mapper?
Yes, but you can also replace the read type, it worked for me:
def with_visible
select_append {
`TRUE`.cast(:boolean).as(:visible).meta(
read: Types::Bool.constructor { _1.eql?(1) }
)
}
end
Oh nice, thanks. That works for me too.
Do you think there could be room for a ROM plugin that does this SQLite boolean coercion? It'd be nice to abstract away this quirk so it doesn't have to be done every time.
To do this, you need to swap the default :bool
type with something. I don't know if this can be nicely done by a plugin. We have a dedicated namespace for Posgres' JSON(b) types: Types::PG::JSONB
. We could have Types::SQLite::Bool
but's not enough, we need a way to associate :bool
with this particular type. I'll take a look into rom-sql's internals to see if it's possible to modify the type container for a relation.
Describe the bug
I'm trying to select_append a boolean from a subquery (here just rendered as
TRUE
for simplicity) in my app, which is built on SQLite.For background, SQLite doesn't have a boolean type (nor true nor false), and the convention is to use 1 and 0 instead. I used
bool::cast
to wrap the subquery, but it's still returning1
or0
.To Reproduce
Expected behavior
I would expect that when I use bool.cast, I'd get a boolean back, regardless of which database is used. Even the result, with auto_struct set to true, I'd expect I'd get
visible=true
.I'm not sure if this should be fixed in the casting code (as part of function) or implemented as an extension for SQLite.
A workaround that I found, shown above, is to use
Types::Params::Bool
, which maps 1 to true and 0 to false.That works in this simple example, but in my app that's not working either. In fact, both
Types::Bool
andTypes::Params::Bool
"work" but instead of raising a Dry::Struct::Error, they just work with visible=1, in violation of the specified types that says they should be bools.My environment
Rom-sql 3.6, Rom 5.3
Affects my production application: No
Ruby version: 3.3
OS: macOS 14.4.1