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

Read our documentation on viewing source code .

Loading