Skip to content

Commit 6a91583

Browse files
authored
Cleanup integration w/ queryverse; provide Tables.DataValueUnwrapper for sinks to unwrap potentially DataValue-based NamedTuples (#16)
1 parent d9100de commit 6a91583

File tree

4 files changed

+28
-28
lines changed

4 files changed

+28
-28
lines changed

src/Tables.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export rowtable, columntable
66

77
function __init__()
88
@require DataValues="e7dc6d0d-1eca-5fa6-8ad6-5aecde8b7ea5" include("datavalues.jl")
9-
@require Query="1a8c2f83-1ff3-5112-b086-8aa67b057ba1" include("enumerable.jl")
109
@require CategoricalArrays="324d7699-5711-5eae-9e2f-1d82baa6b597" begin
1110
using .CategoricalArrays
1211
allocatecolumn(::Type{CategoricalString{R}}, rows) where {R} = CategoricalArray{String, 1, R}(undef, rows)
@@ -178,4 +177,7 @@ include("namedtuples.jl")
178177
# generic fallback definitions
179178
include("fallbacks.jl")
180179

180+
# integration with queryverse
181+
include("query.jl")
182+
181183
end # module

src/datavalues.jl

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,10 @@
11
using .DataValues
22

3-
# DataValue-compatible row iteration for Data.Sources
3+
# DataValue overloads for query.jl definitions
44
nondatavaluetype(::Type{DataValue{T}}) where {T} = Union{T, Missing}
5-
nondatavaluetype(::Type{T}) where {T} = T
6-
Base.@pure function nondatavaluetype(::Type{NT}) where {NT <: NamedTuple{names}} where {names}
7-
TT = Tuple{Any[ nondatavaluetype(fieldtype(NT, i)) for i = 1:fieldcount(NT) ]...}
8-
return NamedTuple{names, TT}
9-
end
10-
11-
unwrap(x) = x
125
unwrap(x::DataValue) = isna(x) ? missing : DataValues.unsafe_get(x)
13-
146
datavaluetype(::Type{T}) where {T <: DataValue} = T
15-
datavaluetype(::Type{T}) where {T} = T
167
datavaluetype(::Type{Union{T, Missing}}) where {T} = DataValue{T}
17-
Base.@pure function datavaluetype(::Tables.Schema{names, types}) where {names, types}
18-
TT = Tuple{Any[ datavaluetype(fieldtype(types, i)) for i = 1:fieldcount(types) ]...}
19-
return NamedTuple{names, TT}
20-
end
218

229
struct DataValueRowIterator{NT, S}
2310
x::S
@@ -26,6 +13,7 @@ DataValueRowIterator(::Type{NT}, x::S) where {NT <: NamedTuple, S} = DataValueRo
2613

2714
"Returns a DataValue-based NamedTuple-iterator"
2815
DataValueRowIterator(::Type{Schema{names, types}}, x::S) where {names, types, S} = DataValueRowIterator{datavaluetype(NamedTuple{names, types}), S}(x)
16+
2917
function datavaluerows(x)
3018
r = Tables.rows(x)
3119
#TODO: add support for unknown schema
@@ -55,6 +43,9 @@ function Base.iterate(rows::DataValueRowIterator{NT, S}, st=()) where {NT <: Nam
5543
end
5644
end
5745

46+
# Alternative lazy row implementation; currently though, Query.jl relies on
47+
# being able to infer return types via all the type information of NamedTuples
48+
5849
# function Base.iterate(rows::DataValueRowIterator{NT}, st=()) where {NT}
5950
# state = iterate(rows.x, st...)
6051
# state === nothing && return nothing

src/enumerable.jl renamed to src/query.jl

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
1-
using .Query
1+
nondatavaluetype(::Type{T}) where {T} = T
2+
datavaluetype(::Type{T}) where {T} = T
23

3-
@static if isdefined(Query.QueryOperators, :Enumerable)
4+
Base.@pure function nondatavaluetype(::Type{NT}) where {NT <: NamedTuple{names}} where {names}
5+
TT = Tuple{Any[ nondatavaluetype(fieldtype(NT, i)) for i = 1:fieldcount(NT) ]...}
6+
return NamedTuple{names, TT}
7+
end
48

5-
import .Query.QueryOperators: Enumerable
9+
Base.@pure function datavaluetype(::Tables.Schema{names, types}) where {names, types}
10+
TT = Tuple{Any[ datavaluetype(fieldtype(types, i)) for i = 1:fieldcount(types) ]...}
11+
return NamedTuple{names, TT}
12+
end
613

7-
Tables.istable(::Type{<:Enumerable}) = true
8-
Tables.rowaccess(::Type{<:Enumerable}) = true
9-
Tables.rows(e::Enumerable) = DataValueUnwrapper(e)
14+
unwrap(x) = x
1015

1116
struct DataValueUnwrapper{S}
1217
x::S
1318
end
1419

20+
Tables.istable(::Type{<:DataValueUnwrapper}) = true
21+
Tables.rowaccess(::Type{<:DataValueUnwrapper}) = true
22+
Tables.rows(x::DataValueUnwrapper) = x
23+
1524
function Tables.schema(dv::DataValueUnwrapper)
1625
eT = eltype(dv.x)
1726
!(eT <: NamedTuple) && return nothing
@@ -34,6 +43,4 @@ end
3443

3544
Base.getproperty(d::DataValueUnwrapRow, ::Type{T}, col::Int, nm::Symbol) where {T} = unwrap(getproperty(getfield(d, 1), T, col, nm))
3645
Base.getproperty(d::DataValueUnwrapRow, nm::Symbol) = unwrap(getproperty(getfield(d, 1), nm))
37-
Base.propertynames(d::DataValueUnwrapRow) = propertynames(getfield(d, 1))
38-
39-
end # isdefined
46+
Base.propertynames(d::DataValueUnwrapRow) = propertynames(getfield(d, 1))

test/runtests.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ end
8787

8888
@test Tables.buildcolumns(nothing, rt) == nt
8989
@test Tables.columntable(nothing, nt) == nt
90-
90+
9191
# append
9292
nt2 = columntable(nt, rt)
9393
@test Tables.rowcount(nt2) == 6
@@ -195,19 +195,19 @@ end
195195
rt2 = collect(dv)
196196
@test rt2[1] == (a = 1, b = DataValue{Float64}(4.0), c = "7")
197197

198-
ei = QueryOperators.EnumerableIterable{eltype(dv), typeof(dv)}(dv)
198+
ei = Tables.DataValueUnwrapper(QueryOperators.EnumerableIterable{eltype(dv), typeof(dv)}(dv))
199199
nt = ei |> columntable
200200
@test isequal(rt, nt)
201201
rt3 = ei |> rowtable
202202
@test isequal(rt |> rowtable, rt3)
203203

204204
# rt = [(a=1, b=4.0, c="7"), (a=2, b=5.0, c="8"), (a=3, b=6.0, c="9")]
205-
mt = ei |> y->QueryOperators.map(y, x->(a=x.b, c=x.c), Expr(:block))
205+
mt = Tables.DataValueUnwrapper(ei.x |> y->QueryOperators.map(y, x->(a=x.b, c=x.c), Expr(:block)))
206206
@inferred (mt |> columntable)
207207
@inferred (mt |> rowtable)
208208

209209
# uninferrable case
210-
mt = ei |> y->QueryOperators.map(y, x->(a=x.a, c=x.c), Expr(:block))
210+
mt = Tables.DataValueUnwrapper(ei.x |> y->QueryOperators.map(y, x->(a=x.a, c=x.c), Expr(:block)))
211211
@test (mt |> columntable) == (a = Real[1, 2.0, 3], c = ["7", "8", "9"])
212212
@test length(mt |> rowtable) == 3
213213
end

0 commit comments

Comments
 (0)