GenieFramework / SearchLight.jl

ORM layer for Genie.jl, the highly productive Julia web framework
https://genieframework.com
MIT License
139 stars 16 forks source link

For struct with `nothing` as default value, `find` converts non-NULL fields in the DB record to `nothing` #68

Open PGimenez opened 1 year ago

PGimenez commented 1 year ago

Full code for the MWE here: https://github.com/GenieFramework/CodeExamples/tree/main/src/3.database/null_values

I have a struct where one of its fields can be Intor Nothing

@kwdef mutable struct House <: AbstractModel
    id::DbId = DbId()
    street::String = "Random street"
    size::Float32 = 100.0
    rooms::Union{Int64,Nothing,Missing} = nothing
end

When running this to load two hoses, one with nothingin rooms and oner with 4

using SearchLight
using SearchLightSQLite
include("app/resources/houses/Houses.jl")
using .Houses
# Base.convert(t::Type{Nothing}, x::Int64) = x

SearchLight.Configuration.load() |> SearchLight.connect

h = House(street="Barcelona 2", size=400, rooms=nothing)
save(h)
h = House(street="Barcelona 3", size=400, rooms=4)
save(h)

@show find(House, SQLWhereExpression("street ==? AND size == ?", "Barcelona 2", 400))
@show find(House, SQLWhereExpression("street ==? AND size == ?", "Barcelona 3", 400))

the first one works, but the second one errors:

[ Info: SELECT "houses"."id" AS "houses_id", "houses"."street" AS "houses_street", "houses"."size" AS "houses_size", "houses"."rooms" AS "houses_
rooms" FROM "houses" WHERE street =='Barcelona 2' AND size == 400 ORDER BY houses.id ASC
find(House, SQLWhereExpression("street ==? AND size == ?", "Barcelona 2", 400)) = House[House
| KEY            | VALUE       |
|----------------|-------------|
| id::DbId       | 2           |
| rooms::Nothing | nothing     |
| size::Float32  | 400.0       |
| street::String | Barcelona 2 |
]
[ Info: SELECT "houses"."id" AS "houses_id", "houses"."street" AS "houses_street", "houses"."size" AS "houses_size", "houses"."rooms" AS "houses_
rooms" FROM "houses" WHERE street =='Barcelona 3' AND size == 400 ORDER BY houses.id ASC
┌ Error: MethodError(convert, (Nothing, 4), 0xffffffffffffffff)
└ @ SearchLight ~/.julia/packages/SearchLight/Ps2Js/src/SearchLight.jl:543
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type Nothing
**Error stacktrace**

It appears that findconverts the field in the record to the type of the default value in the struct. One would expect it to convert to the other type in the Union when the record value is non-NULL.

I've done a quickfix by extending convert to return the record value when it is not NULL.

Base.convert(t::Type{Nothing}, x::Int64) = x