1
1
__precompile__ ()
2
2
module TableTraitsUtils
3
3
4
- using TableTraits, NamedTuples , DataValues
4
+ using IteratorInterfaceExtensions, TableTraits , DataValues, Missings
5
5
6
6
export create_tableiterator, create_columns_from_iterabletable
7
7
@@ -12,71 +12,45 @@ struct TableIterator{T, TS}
12
12
end
13
13
14
14
function create_tableiterator (columns, names:: Vector{Symbol} )
15
- col_expressions = Array {Expr,1} ()
16
- df_columns_tuple_type = Expr (:curly , :Tuple )
17
- for i in 1 : length (columns)
18
- etype = eltype (columns[i])
19
- if etype <: Nullable
20
- push! (col_expressions, Expr (:(:: ), names[i], DataValue{etype. parameters[1 ]}))
15
+ field_types = Type[]
16
+ for i in eltype .(columns)
17
+ if i >: Missing
18
+ push! (field_types, DataValue{Missings. T (i)})
21
19
else
22
- push! (col_expressions, Expr (:( :: ), names[i], etype) )
20
+ push! (field_types, i )
23
21
end
24
- push! (df_columns_tuple_type. args, typeof (columns[i]))
25
22
end
26
- t_expr = NamedTuples. make_tuple (col_expressions)
27
-
28
- t2 = :(TableIterator{Float64,Float64})
29
- t2. args[2 ] = t_expr
30
- t2. args[3 ] = df_columns_tuple_type
31
-
32
- t = eval (t2)
33
-
34
- e_df = t ((columns... ))
35
-
36
- return e_df
23
+ return TableIterator {NamedTuple{(names...,), Tuple{field_types...}}, Tuple{typeof.(columns)...}} ((columns... ,))
37
24
end
38
25
39
26
function Base. length (iter:: TableIterator{T,TS} ) where {T,TS}
40
27
return length (iter. columns[1 ])
41
28
end
42
29
43
- function Base. eltype (iter:: TableIterator{T,TS} ) where {T,TS}
44
- return T
45
- end
46
-
47
30
Base. eltype (:: Type{TableIterator{T,TS}} ) where {T,TS} = T
48
31
49
- function Base. start (iter:: TableIterator{T,TS} ) where {T,TS}
50
- return 1
51
- end
52
-
53
- @generated function Base. next (iter:: TableIterator{T,TS} , state) where {T,TS}
54
- constructor_call = Expr (:call , :($ T))
55
- for (i,t) in enumerate (T. parameters)
56
- if eltype (iter. parameters[2 ]. parameters[i]) <: Nullable
57
- push! (constructor_call. args, :(DataValue (columns[$ i][i])))
32
+ @generated function Base. iterate (iter:: TableIterator{T,TS} , state= 1 ) where {T,TS}
33
+ columns = map (1 : length (TS. parameters)) do i
34
+ if fieldtype (T,i) <: DataValue && eltype (TS. parameters[i]) >: Missing
35
+ return :($ (fieldtype (T,i))(iter. columns[$ i][state]))
58
36
else
59
- push! (constructor_call . args, :(columns[$ i][i]) )
37
+ return :(iter . columns[$ i][state] )
60
38
end
61
39
end
62
-
63
- quote
64
- i = state
65
- columns = iter . columns
66
- a = $ constructor_call
67
- return a, state + 1
40
+ return quote
41
+ if state > length (iter)
42
+ return nothing
43
+ else
44
+ return $ (T)(( $ (columns ... ),)), state + 1
45
+ end
68
46
end
69
47
end
70
48
71
- function Base. done (iter:: TableIterator{T,TS} , state) where {T,TS}
72
- return state> length (iter. columns[1 ])
73
- end
74
-
75
49
# Sink
76
50
77
51
@generated function _fill_cols_without_length (columns, enumerable)
78
52
push_exprs = Expr (:block )
79
- for i in find (collect (columns. types) .!= Void )
53
+ for i in findall (collect (columns. types) .!= Nothing )
80
54
ex = :( push! (columns[$ i], i[$ i]) )
81
55
push! (push_exprs. args, ex)
82
56
end
90
64
91
65
@generated function _fill_cols_with_length (columns, enumerable)
92
66
push_exprs = Expr (:block )
93
- for col_idx in find (collect (columns. types) .!= Void )
67
+ for col_idx in findall (collect (columns. types) .!= Nothing )
94
68
ex = :( columns[$ col_idx][i] = v[$ col_idx] )
95
69
push! (push_exprs. args, ex)
96
70
end
102
76
end
103
77
end
104
78
105
- function _default_array_factory (t,rows)
106
- if isa (t, TypeVar)
107
- return Array {Any} (rows)
108
- else
109
- return Array {t} (rows)
110
- end
111
- end
112
-
113
- function create_columns_from_iterabletable (source, sel_cols = :all ; array_factory:: Function = _default_array_factory)
79
+ function create_columns_from_iterabletable (source; sel_cols= :all , na_representation= :datavalue )
114
80
iter = getiterator (source)
115
81
116
82
T = eltype (iter)
117
83
if ! (T<: NamedTuple )
118
84
error (" Can only collect a NamedTuple iterator." )
119
85
end
120
86
121
- column_types = TableTraits. column_types (iter)
122
- column_names = TableTraits. column_names (iter)
87
+ array_factory = if na_representation== :datavalue
88
+ (t,rows) -> Array {t} (undef, rows)
89
+ elseif na_representation== :missing
90
+ (t,rows) -> begin
91
+ if t <: DataValue
92
+ return Array {Union{eltype(t),Missing}} (undef, rows)
93
+ else
94
+ return Array {t} (undef, rows)
95
+ end
96
+ end
97
+ end
98
+
99
+ column_types = collect (T. parameters[2 ]. parameters)
100
+ column_names = collect (T. parameters[1 ])
123
101
124
- rows = Base. iteratorsize (typeof (iter))== Base. HasLength () ? length (iter) : 0
102
+ rows = Base. IteratorSize (typeof (iter))== Base. HasLength () ? length (iter) : 0
125
103
126
104
columns = []
127
105
for (i, t) in enumerate (column_types)
@@ -132,10 +110,10 @@ function create_columns_from_iterabletable(source, sel_cols = :all; array_factor
132
110
end
133
111
end
134
112
135
- if Base. iteratorsize (typeof (iter))== Base. HasLength ()
136
- _fill_cols_with_length ((columns... ), iter)
113
+ if Base. IteratorSize (typeof (iter))== Base. HasLength ()
114
+ _fill_cols_with_length ((columns... , ), iter)
137
115
else
138
- _fill_cols_without_length ((columns... ), iter)
116
+ _fill_cols_without_length ((columns... , ), iter)
139
117
end
140
118
141
119
if sel_cols == :all
0 commit comments