github.com/jacekolszak/noteo@v0.5.0/notes/filter.go (about)

     1  package notes
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"regexp"
     7  	"time"
     8  
     9  	"github.com/jacekolszak/noteo/date"
    10  	"github.com/jacekolszak/noteo/tag"
    11  )
    12  
    13  func Filter(ctx context.Context, notes <-chan Note, predicates ...Predicate) (note <-chan Note, errors <-chan error) {
    14  	out := make(chan Note)
    15  	errs := make(chan error)
    16  	go func() {
    17  		defer close(out)
    18  		defer close(errs)
    19  		filterLoop(ctx, notes, predicates, out, errs)
    20  	}()
    21  	return out, errs
    22  }
    23  
    24  func filterLoop(ctx context.Context, notes <-chan Note, predicates []Predicate, out chan<- Note, errs chan<- error) {
    25  	for {
    26  		select {
    27  		case note, ok := <-notes:
    28  			if !ok {
    29  				return
    30  			}
    31  			if noteMatches(note, predicates, errs) {
    32  				out <- note
    33  			}
    34  		case <-ctx.Done():
    35  			return
    36  		}
    37  	}
    38  }
    39  
    40  func noteMatches(note Note, predicates []Predicate, errs chan<- error) bool {
    41  	for _, predicate := range predicates {
    42  		matches, err := predicate(note)
    43  		if err != nil {
    44  			errs <- fmt.Errorf("executing predicate failed on note %s: %v", note.Path(), err)
    45  			return false
    46  		}
    47  		if !matches {
    48  			return false
    49  		}
    50  	}
    51  	return true
    52  }
    53  
    54  type Predicate func(note Note) (bool, error)
    55  
    56  func Tag(t string) Predicate {
    57  	return func(note Note) (bool, error) {
    58  		tags, err := note.Tags()
    59  		if err != nil {
    60  			return false, err
    61  		}
    62  		for _, anotherTag := range tags {
    63  			if anotherTag.String() == t {
    64  				return true, nil
    65  			}
    66  		}
    67  		return false, nil
    68  	}
    69  }
    70  
    71  func NoTag(t string) Predicate {
    72  	return func(note Note) (bool, error) {
    73  		tags, err := note.Tags()
    74  		if err != nil {
    75  			return false, err
    76  		}
    77  		for _, anotherTag := range tags {
    78  			if anotherTag.String() == t {
    79  				return false, nil
    80  			}
    81  		}
    82  		return true, nil
    83  	}
    84  }
    85  
    86  func TagGrep(regex *regexp.Regexp) Predicate {
    87  	return func(note Note) (bool, error) {
    88  		tags, err := note.Tags()
    89  		if err != nil {
    90  			return false, err
    91  		}
    92  		for _, t := range tags {
    93  			if regex.MatchString(t.String()) {
    94  				return true, nil
    95  			}
    96  		}
    97  		return false, nil
    98  	}
    99  }
   100  
   101  func TagGreater(tagNameValue string) (Predicate, error) {
   102  	return tagNumber(tagNameValue, func(anotherNumber, number int) bool {
   103  		return anotherNumber > number
   104  	})
   105  }
   106  
   107  func TagLower(tagNameValue string) (Predicate, error) {
   108  	return tagNumber(tagNameValue, func(anotherNumber, number int) bool {
   109  		return anotherNumber < number
   110  	})
   111  }
   112  
   113  func tagNumber(tagNameValue string, f func(anotherNumber, number int) bool) (Predicate, error) {
   114  	kv, err := tag.New(tagNameValue)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	number, err := kv.Number()
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	return func(note Note) (bool, error) {
   123  		tags, err := note.Tags()
   124  		if err != nil {
   125  			return false, err
   126  		}
   127  		for _, another := range tags {
   128  			if another.Name() == kv.Name() {
   129  				anotherNumber, err := another.Number()
   130  				if err != nil {
   131  					return false, fmt.Errorf("error getting number from tag \"%s\": %v", another, err)
   132  				}
   133  				return f(anotherNumber, number), nil
   134  			}
   135  		}
   136  		return false, nil
   137  	}, nil
   138  }
   139  
   140  func TagAfter(tagNameValue string) (Predicate, error) {
   141  	return tagDate(tagNameValue, func(anotherDate, date time.Time) bool {
   142  		return anotherDate.After(date)
   143  	})
   144  }
   145  
   146  func TagBefore(tagNameValue string) (Predicate, error) {
   147  	return tagDate(tagNameValue, func(anotherDate, date time.Time) bool {
   148  		return anotherDate.Before(date)
   149  	})
   150  }
   151  
   152  func tagDate(tagNameValue string, f func(anotherDate, date time.Time) bool) (Predicate, error) {
   153  	kv, err := tag.New(tagNameValue)
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  	relativeDate, err := kv.RelativeDate()
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	return func(note Note) (bool, error) {
   162  		tags, err := note.Tags()
   163  		if err != nil {
   164  			return false, err
   165  		}
   166  		for _, another := range tags {
   167  			if another.Name() == kv.Name() {
   168  				anotherDate, err := another.AbsoluteDate()
   169  				if err != nil {
   170  					return false, fmt.Errorf("error getting date from tag \"%s\": %v", another, err)
   171  				}
   172  				return f(anotherDate, relativeDate), nil
   173  			}
   174  		}
   175  		return false, nil
   176  	}, nil
   177  }
   178  
   179  func NoTags() Predicate {
   180  	return func(note Note) (bool, error) {
   181  		tags, err := note.Tags()
   182  		if err != nil {
   183  			return false, err
   184  		}
   185  		return len(tags) == 0, nil
   186  	}
   187  }
   188  
   189  func ModifiedAfter(modifiedAfter string) (Predicate, error) {
   190  	t, err := date.Parse(modifiedAfter)
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  	return func(note Note) (bool, error) {
   195  		modified, err := note.Modified()
   196  		if err != nil {
   197  			return false, err
   198  		}
   199  		return modified.After(t), nil
   200  	}, nil
   201  }
   202  
   203  func ModifiedBefore(modifiedBefore string) (Predicate, error) {
   204  	t, err := date.Parse(modifiedBefore)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	return func(note Note) (bool, error) {
   209  		modified, err := note.Modified()
   210  		if err != nil {
   211  			return false, err
   212  		}
   213  		return modified.Before(t), nil
   214  	}, nil
   215  }
   216  
   217  func CreatedAfter(createdAfter string) (Predicate, error) {
   218  	t, err := date.Parse(createdAfter)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	return func(note Note) (bool, error) {
   223  		created, err := note.Created()
   224  		if err != nil {
   225  			return false, err
   226  		}
   227  		return created.After(t), nil
   228  	}, nil
   229  }
   230  
   231  func CreatedBefore(createdBefore string) (Predicate, error) {
   232  	t, err := date.Parse(createdBefore)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  	return func(note Note) (bool, error) {
   237  		created, err := note.Created()
   238  		if err != nil {
   239  			return false, err
   240  		}
   241  		return created.Before(t), nil
   242  	}, nil
   243  }
   244  
   245  func Grep(expr string) (Predicate, error) {
   246  	regex, err := regexp.Compile(expr)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	return func(note Note) (bool, error) {
   251  		body, err := note.Body()
   252  		if err != nil {
   253  			return false, err
   254  		}
   255  		return regex.MatchString(body), nil
   256  	}, nil
   257  }