1
struct EnumerableGather{T,S,F,I,A} <: Enumerable
2 47
    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 47
    fields = fieldnames(eltype(source))
16 47
    if length(args) > 0
17 39
        indexFields_vector = Vector{Symbol}(undef, 0)        
18
        firstArg = true
19 47
        for arg in args
20 9
            if typeof(arg) == Symbol
21 39
                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 47
            firstArg = false
30
        end
31 47
        indexFields = tuple(indexFields_vector...)
32
    else
33 47
        indexFields = fields
34
    end
35

36 47
    savedFields = (n for n in fields if !(n in indexFields)) # fields that are not in `indexFields`
37 47
    savedFieldsType = (fieldtype(eltype(source), savedField) for savedField in savedFields)
38

39 47
    valueTypes = (fieldtype(eltype(source), indexField) for indexField in indexFields)
40 47
    valueType = reduce(promote_type, valueTypes)
41

42 47
    T = NamedTuple{(savedFields..., key, value), Tuple{savedFieldsType..., Symbol, valueType}}
43 47
    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 47
    source_iterate = iterate(iter.source)
49 47
    if source_iterate == nothing || length(iter.indexFields) == 0
50 0
        return nothing
51
    end
52 39
    key = iter.indexFields[1]
53 47
    current_source_row = source_iterate[1]
54 39
    value = current_source_row[key]
55 47
    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 47
    current_index_field_index = state.current_index_field_index + 1
61 47
    if current_index_field_index > length(iter.indexFields)
62 39
        source_iterate = iterate(iter.source, state.source_state)
63 47
        if source_iterate == nothing || length(iter.indexFields) == 0
64 47
            return nothing
65
        end
66
        current_index_field_index = 1
67 47
        source_state = source_iterate[2]
68 47
        current_source_row = source_iterate[1]
69
    else
70 39
        source_state = state.source_state
71 47
        current_source_row = state.current_source_row
72
    end
73 47
    key = iter.indexFields[current_index_field_index]
74 47
    value = current_source_row[key]
75 47
    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