github.com/jacekolszak/noteo@v0.5.0/notes/top.go (about) 1 package notes 2 3 import ( 4 "context" 5 "fmt" 6 "sort" 7 "time" 8 ) 9 10 func Top(ctx context.Context, limit int, notes <-chan Note, less Less) (note <-chan Note, errors <-chan error) { 11 out := make(chan Note) 12 errs := make(chan error) 13 14 go func() { 15 defer close(out) 16 defer close(errs) 17 slice := collectNotes(ctx, notes) 18 sortNotes(slice, less, errs) 19 if len(slice) > limit { 20 slice = slice[:limit] 21 } 22 for _, note := range slice { 23 out <- note 24 } 25 }() 26 return out, errs 27 } 28 29 func collectNotes(ctx context.Context, notes <-chan Note) []Note { 30 var collectedNotes []Note 31 for { 32 select { 33 case note, ok := <-notes: 34 if !ok { 35 return collectedNotes 36 } 37 collectedNotes = append(collectedNotes, note) 38 case <-ctx.Done(): 39 return nil 40 } 41 } 42 } 43 44 func sortNotes(slice []Note, less Less, errs chan<- error) { 45 sort.Slice(slice, func(i, j int) bool { 46 l, err := less(slice[i], slice[j]) 47 if err != nil { 48 errs <- fmt.Errorf("comparing notes failed %s and %s: %v", slice[i].Path(), slice[j].Path(), err) 49 } 50 return l 51 }) 52 } 53 54 type Less func(i, j Note) (bool, error) 55 56 var ModifiedDesc Less = func(i, j Note) (bool, error) { 57 firstModified, e := i.Modified() 58 if e != nil { 59 return false, e 60 } 61 secondModified, e := j.Modified() 62 if e != nil { 63 return false, e 64 } 65 return firstModified.After(secondModified), nil 66 } 67 68 var ModifiedAsc Less = func(i, j Note) (bool, error) { 69 firstModified, e := i.Modified() 70 if e != nil { 71 return false, e 72 } 73 secondModified, e := j.Modified() 74 if e != nil { 75 return false, e 76 } 77 return firstModified.Before(secondModified), nil 78 } 79 80 var CreatedDesc Less = func(first, second Note) (bool, error) { 81 firstCreated, e := first.Created() 82 if e != nil { 83 return false, e 84 } 85 secondCreated, e := second.Created() 86 if e != nil { 87 return false, e 88 } 89 return firstCreated.After(secondCreated), nil 90 } 91 92 var CreatedAsc Less = func(first, second Note) (bool, error) { 93 firstCreated, e := first.Created() 94 if e != nil { 95 return false, e 96 } 97 secondCreated, e := second.Created() 98 if e != nil { 99 return false, e 100 } 101 return firstCreated.Before(secondCreated), nil 102 } 103 104 func TagDateDesc(name string) Less { 105 return tagDateLess(name, func(first, second time.Time) bool { 106 return first.After(second) 107 }) 108 } 109 110 func TagDateAsc(name string) Less { 111 return tagDateLess(name, func(first, second time.Time) bool { 112 return first.Before(second) 113 }) 114 } 115 116 func tagDateLess(name string, less func(first, second time.Time) bool) Less { 117 return func(first, second Note) (bool, error) { 118 firstTag, found, err := FindTagByName(first, name) 119 if err != nil || !found { 120 return false, err 121 } 122 secondTag, found, err := FindTagByName(second, name) 123 if err != nil || !found { 124 return true, err 125 } 126 firstDate, err := firstTag.AbsoluteDate() 127 if err != nil { 128 return false, err 129 } 130 secondDate, err := secondTag.AbsoluteDate() 131 if err != nil { 132 return false, err 133 } 134 return less(firstDate, secondDate), nil 135 } 136 } 137 138 func TagNumberDesc(name string) Less { 139 return tagNumberLess(name, func(first, second int) bool { 140 return first > second 141 }) 142 } 143 144 func TagNumberAsc(name string) Less { 145 return tagNumberLess(name, func(first, second int) bool { 146 return first < second 147 }) 148 } 149 150 func tagNumberLess(name string, less func(first, second int) bool) Less { 151 return func(first, second Note) (bool, error) { 152 firstTag, found, err := FindTagByName(first, name) 153 if err != nil || !found { 154 return false, err 155 } 156 secondTag, found, err := FindTagByName(second, name) 157 if err != nil || !found { 158 return true, err 159 } 160 firstNumber, err := firstTag.Number() 161 if err != nil { 162 return false, err 163 } 164 secondNumber, err := secondTag.Number() 165 if err != nil { 166 return false, err 167 } 168 return less(firstNumber, secondNumber), nil 169 } 170 }