bhftbootcamp / Serde.jl

Serde is a Julia library for (de)serializing data to/from various formats. The library offers a simple and concise API for defining custom (de)serialization behavior for user-defined types
Apache License 2.0
31 stars 7 forks source link

Empty values handling on specific field. #38

Closed NeroBlackstone closed 3 days ago

NeroBlackstone commented 2 months ago

Thanks to bhftbootcamp for developing such a great julia library! So elegant!

Currently, Empty values ​​handling cannot be applied to a single field:

struct Foo
           zero::Int
           cant_zero::Union{Nothing,Int}
end

function Serde.isempty(::Type{Foo}, x::Int)
           return x == 0
end

Serde.deser(Foo,Dict("zero"=>0,"cant_zero"=>0))

This will cause an error:

ERROR: ParamError: parameter 'zero::Int64' was not passed or has the value 'null'
Stacktrace:
 [1] eldeser(structtype::Type, elmtype::Type, key::Symbol, val::Nothing)
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:508
 [2] deser(::Serde.CustomType, ::Type{Foo}, data::Dict{String, Int64})
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:529
 [3] deser(::Type{Foo}, data::Dict{String, Int64})
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:164
 [4] top-level scope
   @ REPL[6]:1

caused by: MethodError: no method matching deser(::Serde.PrimitiveType, ::Type{Int64}, ::Nothing)

Closest candidates are:
  deser(::Serde.PrimitiveType, ::Type{T}, ::D) where {T<:Number, D<:Number}
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:191
  deser(::Serde.PrimitiveType, ::Type{T}, ::D) where {T<:Number, D<:AbstractString}
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:187
  deser(::Serde.PrimitiveType, ::Type{T}, ::T) where T
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:175
  ...

Stacktrace:
 [1] deser(::Type{Int64}, data::Nothing)
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:164
 [2] deser(::Type{Foo}, ::Type{Int64}, data::Nothing)
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:156
 [3] eldeser(structtype::Type, elmtype::Type, key::Symbol, val::Nothing)
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:504
 [4] deser(::Serde.CustomType, ::Type{Foo}, data::Dict{String, Int64})
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:529
 [5] deser(::Type{Foo}, data::Dict{String, Int64})
   @ Serde ~/.julia/packages/Serde/EcDvV/src/De/Deser.jl:164
 [6] top-level scope
   @ REPL[6]:1
NeroBlackstone commented 2 months ago

Maybe we can implement an api like:

function Serde.isempty(::Type{Foo}, x::Int,::Val{:cant_zero})
           return x == 0
end

to indicate field we want to apply empty values handling.

dmitrii-doronin commented 2 months ago

HI, @NeroBlackstone! You have a valid a point, IMO. There's a function in serialization submodule called ser_ignore_field (take a look at the docs). I see no reason to not have something like de_ignore_field.

Would you like to contribute?

NeroBlackstone commented 2 months ago

HI, @NeroBlackstone! You have a valid a point, IMO. There's a function in serialization submodule called ser_ignore_field (take a look at the docs). I see no reason to not have something like de_ignore_field.

Would you like to contribute?

I don't know if I can understand the source code! But I will try to read some tomorrow!

dmitrii-doronin commented 2 months ago

You can always ask here or in a PR. I'll help with the code and the review once you're ready.

gryumov commented 3 days ago

I still think that isempty is a property of the type, not the field

using Serde

struct Foo
    nonull_field1::Int
    nonull_field2::Int
    could_null::Union{Nothing,Int}

    function Foo(
        nonull_field1::Int, 
        nonull_field2::Int, 
        could_null::Union{Nothing,Int}
    )
        return new(nonull_field1, nonull_field2, could_null == 0 ? nothing : could_null)
    end
end

julia> Serde.deser(Foo, Dict("nonull_field1" => 0, "nonull_field2" => 0, "could_null" => 0))
Foo(0, 0, nothing)