Repository: go-co-op/gocron
Pull request #443 (2023-04-11 07:19:34)

add func for getting all tags
### What does this do?

This PR adds a function for getting all tags.

#### Use Case

Imagine you have a database table of thousands of SQL queries you need to run according to their configured crontab schedules, and you have a service that fetches these configs and uses gocron to schedule each query to execute. This service also polls the database on a schedule to sync the configured query configs with corresponding jobs in the gocron scheduler. It would be nice to have some sort of `GetAllTags()` function so that if you needed to delete jobs that no longer need to run, you can compare the list of all tags to the list of all newly fetched query configs.

```golang
scheduler := gocron.NewScheduler(time.UTC)
scheduler.TagsUnique()

// map of active queries to schedule
queryConfigs := map[string]string{
  "query1": "select * from user",
  "query2": "select * from company",
}

// remove all jobs that no longer need to run
for _, tag := range scheduler.GetAllTags() {
  if _, ok := queryConfigs[tag]; !ok {
    scheduler.RemoveByTag(tag)
  }
}
```

### Which issue(s) does this PR fix/relate to?
<!--- Put `Resolves #XXX` here to auto-close the issue that your PR fixes (if such) --->

N/A

### List any changes that modify/break current functionality

None

### Have you included tests for your changes?

Yes

### Did you document any new/modified functionality?

- [x] Updated `example_test.go`
- [x] Updated `README.md` (marking this as done but didn't change anything)

### Notes




Patch:
diff --git a/scheduler.go b/scheduler.go
index 403a9be..06770a3 100644
--- a/scheduler.go
+++ b/scheduler.go
@@ -972,6 +972,15 @@ func (s *Scheduler) Tag(t ...string) *Scheduler {
 	return s
 }
 
+// GetAllTags returns all tags.
+func (s *Scheduler) GetAllTags() []string {
+	var tags []string
+	for _, job := range s.Jobs() {
+		tags = append(tags, job.Tags()...)
+	}
+	return tags
+}
+
 // StartAt schedules the next run of the Job. If this time is in the past, the configured interval will be used
 // to calculate the next future time
 func (s *Scheduler) StartAt(t time.Time) *Scheduler {


Test patch:
diff --git a/example_test.go b/example_test.go
index b3ba271..ead9155 100644
--- a/example_test.go
+++ b/example_test.go
@@ -351,6 +351,15 @@ func ExampleScheduler_Friday() {
 	// Friday
 }
 
+func ExampleScheduler_GetAllTags() {
+	s := gocron.NewScheduler(time.UTC)
+	_, _ = s.Every(1).Second().Tag("tag1").Do(task)
+	_, _ = s.Every(1).Second().Tag("tag2").Do(task)
+	fmt.Println(s.GetAllTags())
+	// Output:
+	// [tag1 tag2]
+}
+
 func ExampleScheduler_Hour() {
 	s := gocron.NewScheduler(time.UTC)
 
diff --git a/scheduler_test.go b/scheduler_test.go
index ff4ff06..bd8ef55 100644
--- a/scheduler_test.go
+++ b/scheduler_test.go
@@ -2,6 +2,7 @@ package gocron
 
 import (
 	"fmt"
+	"sort"
 	"sync"
 	"sync/atomic"
 	"testing"
@@ -2320,3 +2321,66 @@ func TestScheduler_DoWithJobDetails(t *testing.T) {
 		time.Sleep(500 * time.Millisecond)
 	})
 }
+
+func TestScheduler_GetAllTags(t *testing.T) {
+	t.Run("tags unique", func(t *testing.T) {
+		testCases := []struct {
+			description string
+			tags        []string
+			expected    []string
+		}{
+			{"no tags", []string{}, nil},
+			{"one tag", []string{"tag1"}, []string{"tag1"}},
+			{"two tags", []string{"tag1", "tag2"}, []string{"tag1", "tag2"}},
+			{"two tags with duplicates", []string{"tag1", "tag2", "tag1"}, []string{"tag1", "tag2"}},
+		}
+
+		for _, tc := range testCases {
+			t.Run(tc.description, func(t *testing.T) {
+				s := NewScheduler(time.UTC)
+				s.TagsUnique()
+
+				for _, tag := range tc.tags {
+					_, err := s.Tag(tag).Every("100ms").Do(func() {})
+					require.NoError(t, err)
+				}
+
+				tags := s.GetAllTags()
+				sort.Strings(tc.expected)
+				sort.Strings(tags)
+
+				assert.Equal(t, tc.expected, tags)
+			})
+		}
+	})
+
+	t.Run("tags not unique", func(t *testing.T) {
+		testCases := []struct {
+			description string
+			tags        []string
+			expected    []string
+		}{
+			{"no tags", []string{}, nil},
+			{"one tag", []string{"tag1"}, []string{"tag1"}},
+			{"two tags", []string{"tag1", "tag2"}, []string{"tag1", "tag2"}},
+			{"two tags with duplicates", []string{"tag1", "tag2", "tag1"}, []string{"tag1", "tag2", "tag1"}},
+		}
+
+		for _, tc := range testCases {
+			t.Run(tc.description, func(t *testing.T) {
+				s := NewScheduler(time.UTC)
+
+				for _, tag := range tc.tags {
+					_, err := s.Tag(tag).Every("100ms").Do(func() {})
+					require.NoError(t, err)
+				}
+
+				tags := s.GetAllTags()
+				sort.Strings(tc.expected)
+				sort.Strings(tags)
+
+				assert.Equal(t, tc.expected, tags)
+			})
+		}
+	})
+}