Skip to content

Commit ced27db

Browse files
authored
Merge pull request #5 from JuliaData/jq/missing
Fix #4 by appropriately converting nothing to missing for data tables
2 parents 39df489 + ca276f7 commit ced27db

File tree

2 files changed

+39
-12
lines changed

2 files changed

+39
-12
lines changed

src/JSONTables.jl

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,18 @@ Tables.istable(::Type{<:Table}) = true
2323
Tables.columnaccess(::Type{Table{true, T}}) where {T} = true
2424
Tables.columns(x::Table{true}) = x
2525

26+
miss(x) = ifelse(x === nothing, missing, x)
27+
struct MissingVector{T} <: AbstractVector{T}
28+
x::T
29+
end
30+
Base.IndexStyle(::Type{<:MissingVector}) = Base.IndexLinear()
31+
# Base.length(x::MissingVector) = length(x.x)
32+
Base.size(x::MissingVector) = size(x.x)
33+
@inline Base.getindex(x::MissingVector, i::Int) = miss(x.x[i])
34+
Base.copy(x::MissingVector) = map(y->y isa JSON3.Object || y isa JSON3.Array ? copy(y) : miss(y), x)
35+
2636
Base.propertynames(x::Table{true}) = Tuple(keys(getfield(x, :source)))
27-
Base.getproperty(x::Table{true}, nm::Symbol) = getproperty(getfield(x, :source), nm)
37+
Base.getproperty(x::Table{true}, nm::Symbol) = MissingVector(getproperty(getfield(x, :source), nm))
2838

2939
# row source
3040
Tables.rowaccess(::Type{Table{false, T}}) where {T} = true
@@ -35,8 +45,25 @@ Base.length(x::Table{false}) = length(x.source)
3545
Base.IteratorEltype(::Type{Table{false, T}}) where {T} = Base.HasEltype()
3646
Base.eltype(x::Table{false, JSON3.Array{T}}) where {T} = T
3747

38-
Base.iterate(x::Table{false}) = iterate(x.source)
39-
Base.iterate(x::Table{false}, st) = iterate(x.source, st)
48+
struct MissingRow{T}
49+
x::T
50+
end
51+
Base.propertynames(x::MissingRow) = propertynames(getfield(x, :x))
52+
Base.getproperty(x::MissingRow, nm::Symbol) = miss(getproperty(getfield(x, :x), nm))
53+
54+
@inline function Base.iterate(x::Table{false})
55+
st = iterate(x.source)
56+
st === nothing && return nothing
57+
val, state = st
58+
return MissingRow(val), state
59+
end
60+
61+
@inline function Base.iterate(x::Table{false}, st)
62+
st = iterate(x.source, st)
63+
st === nothing && return nothing
64+
val, state = st
65+
return MissingRow(val), state
66+
end
4067

4168
# write
4269
struct ObjectTable{T}

test/runtests.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ using Test, JSONTables, Tables, JSON3
44

55
cjson = replace(replace("""{
66
"a": [1,2,3],
7-
"b": [4.1, 5.2, 6.3],
8-
"c": ["7", "8", "9"]
7+
"b": [4.1, null, 6.3],
8+
"c": ["7", "8", null]
99
}""", " "=>""), "\n"=>"")
1010

1111
rjson = replace(replace("""[
1212
{"a": 1, "b": 4.1, "c": "7"},
13-
{"a": 2, "b": 5.2, "c": "8"},
14-
{"a": 3, "b": 6.3, "c": "9"}
13+
{"a": 2, "b": null, "c": "8"},
14+
{"a": 3, "b": 6.3, "c": null}
1515
]""", " "=>""), "\n"=>"")
1616

17-
ctable = (a=[1,2,3], b=[4.1, 5.2, 6.3], c=["7", "8", "9"])
17+
ctable = (a=[1,2,3], b=[4.1, missing, 6.3], c=["7", "8", missing])
1818
rtable = Tables.rowtable(ctable)
1919

2020
cjtable = JSONTables.jsontable(cjson)
@@ -37,10 +37,10 @@ rjtable = JSONTables.jsontable(rjson)
3737
@test Base.IteratorEltype(typeof(rjtable)) == Base.HasEltype()
3838
@test eltype(rjtable) == Any
3939

40-
@test Tables.columntable(cjtable) == ctable
41-
@test Tables.columntable(rjtable) == ctable
42-
@test Tables.rowtable(cjtable) == rtable
43-
@test Tables.rowtable(rjtable) == rtable
40+
@test isequal(Tables.columntable(cjtable), ctable)
41+
@test isequal(Tables.columntable(rjtable), ctable)
42+
@test isequal(Tables.rowtable(cjtable), rtable)
43+
@test isequal(Tables.rowtable(rjtable), rtable)
4444

4545
@test JSONTables.objecttable(ctable) == cjson
4646
@test JSONTables.objecttable(rtable) == cjson

0 commit comments

Comments
 (0)