1
|
|
struct EnumerableGather{T,S,F,I,A} <: Enumerable
|
2
|
23
|
source::S
|
3
|
|
fields::F
|
4
|
|
indexFields::I
|
5
|
|
savedFields::A
|
6
|
|
key::Symbol
|
7
|
|
value::Symbol
|
8
|
|
end
|
9
|
|
|
10
|
|
struct Not{T}
|
11
|
|
val::T
|
12
|
|
end
|
13
|
|
|
14
|
|
function gather(source::Enumerable, args...; key::Symbol = :key, value::Symbol = :value)
|
15
|
23
|
fields = fieldnames(eltype(source))
|
16
|
23
|
if length(args) > 0
|
17
|
18
|
indexFields_vector = Vector{Symbol}(undef, 0)
|
18
|
|
firstArg = true
|
19
|
23
|
for arg in args
|
20
|
5
|
if typeof(arg) == Symbol
|
21
|
18
|
push!(indexFields_vector, arg)
|
22
|
0
|
else typeof(arg) == Not{Symbol}
|
23
|
0
|
if firstArg
|
24
|
0
|
indexFields_vector = [a for a in fields if a != arg.val]
|
25
|
|
else
|
26
|
0
|
indexFields_vector = [a for a in indexFields_vector if a != arg.val]
|
27
|
|
end
|
28
|
|
end
|
29
|
23
|
firstArg = false
|
30
|
|
end
|
31
|
23
|
indexFields = tuple(indexFields_vector...)
|
32
|
|
else
|
33
|
23
|
indexFields = fields
|
34
|
|
end
|
35
|
|
|
36
|
23
|
savedFields = (n for n in fields if !(n in indexFields)) # fields that are not in `indexFields`
|
37
|
23
|
savedFieldsType = (fieldtype(eltype(source), savedField) for savedField in savedFields)
|
38
|
|
|
39
|
23
|
valueTypes = (fieldtype(eltype(source), indexField) for indexField in indexFields)
|
40
|
23
|
valueType = reduce(promote_type, valueTypes)
|
41
|
|
|
42
|
23
|
T = NamedTuple{(savedFields..., key, value), Tuple{savedFieldsType..., Symbol, valueType}}
|
43
|
23
|
return EnumerableGather{T, typeof(source), typeof(fields), typeof(indexFields), typeof(savedFields)}(source,
|
44
|
|
fields, indexFields, savedFields, key, value)
|
45
|
|
end
|
46
|
|
|
47
|
|
function Base.iterate(iter::EnumerableGather{T, S, F, I, A}) where {T, S, F, I, A}
|
48
|
23
|
source_iterate = iterate(iter.source)
|
49
|
23
|
if source_iterate == nothing || length(iter.indexFields) == 0
|
50
|
0
|
return nothing
|
51
|
|
end
|
52
|
18
|
key = iter.indexFields[1]
|
53
|
23
|
current_source_row = source_iterate[1]
|
54
|
18
|
value = current_source_row[key]
|
55
|
23
|
return (T((Base.map(n->current_source_row[n], iter.savedFields)..., key, value)),
|
56
|
|
(current_source_row=current_source_row, source_state=source_iterate[2], current_index_field_index=1))
|
57
|
|
end
|
58
|
|
|
59
|
|
function Base.iterate(iter::EnumerableGather{T, S, F, I, A}, state) where {T, S, F, I, A}
|
60
|
23
|
current_index_field_index = state.current_index_field_index + 1
|
61
|
23
|
if current_index_field_index > length(iter.indexFields)
|
62
|
18
|
source_iterate = iterate(iter.source, state.source_state)
|
63
|
23
|
if source_iterate == nothing || length(iter.indexFields) == 0
|
64
|
23
|
return nothing
|
65
|
|
end
|
66
|
|
current_index_field_index = 1
|
67
|
23
|
source_state = source_iterate[2]
|
68
|
23
|
current_source_row = source_iterate[1]
|
69
|
|
else
|
70
|
18
|
source_state = state.source_state
|
71
|
23
|
current_source_row = state.current_source_row
|
72
|
|
end
|
73
|
23
|
key = iter.indexFields[current_index_field_index]
|
74
|
23
|
value = current_source_row[key]
|
75
|
23
|
return (T((Base.map(n->current_source_row[n], iter.savedFields)..., key, value)),
|
76
|
|
(current_source_row=current_source_row, source_state=source_state, current_index_field_index=current_index_field_index))
|
77
|
|
end
|
78
|
|
|
79
|
|
function Base.eltype(iter::EnumerableGather{T, S, F, I, A}) where {T, S, F, I, A}
|
80
|
0
|
return T
|
81
|
|
end
|