|
1 | 1 | package tags |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "errors" |
4 | 5 | "fmt" |
5 | 6 | "regexp" |
6 | 7 | "strings" |
7 | 8 |
|
8 | 9 | "github.com/uptrace/bun" |
9 | 10 | ) |
10 | 11 |
|
11 | | -var tagPattern = regexp.MustCompile(`^[a-zA-Z0-9_\-+*/\\.:~=<>]+$`) |
| 12 | +const tagDelimiterChar string = "|" |
| 13 | +const tagPatternExp string = `^[a-zA-Z0-9_\-+*/.:~=]+$` |
| 14 | +const tagEscapeChar string = "!" |
| 15 | +const tagEscapedChars string = `%_[]^-{}` |
| 16 | + |
| 17 | +var tagPattern = regexp.MustCompile(tagPatternExp) |
12 | 18 |
|
13 | 19 | // TODO vendor out to seperate package |
14 | 20 | func reducex[T any, S ~[]T, U any](s S, f func(T, U) (U, error)) (U, error) { |
@@ -102,9 +108,17 @@ func parseTag(expr string, qb bun.QueryBuilder, mode bool, negate bool) (bun.Que |
102 | 108 | return nil, fmt.Errorf("invalid tag: %s", expr) |
103 | 109 | } |
104 | 110 |
|
| 111 | + // escape special chars just to be sure |
| 112 | + for _, c := range tagEscapedChars { |
| 113 | + expr = strings.ReplaceAll(expr, string(c), tagEscapeChar+string(c)) |
| 114 | + } |
| 115 | + // enable wildcards |
| 116 | + expr = strings.ReplaceAll(expr, "**", "%") |
| 117 | + expr = strings.ReplaceAll(expr, "*", "_") |
| 118 | + |
105 | 119 | query := map[bool]string{ |
106 | | - true: "tag <> ?", |
107 | | - false: "tag = ?", |
| 120 | + true: "tag NOT LIKE ? ESCAPE '" + tagEscapeChar + "'", |
| 121 | + false: "tag LIKE ? ESCAPE '" + tagEscapeChar + "'", |
108 | 122 | }[negated != negate] |
109 | 123 |
|
110 | 124 | if mode { |
@@ -153,3 +167,22 @@ func GetTagQueryBuilder(tag string) (func(bun.QueryBuilder) bun.QueryBuilder, er |
153 | 167 | return qb |
154 | 168 | }, nil |
155 | 169 | } |
| 170 | + |
| 171 | +func SplitTags(tag string) ([]string, error) { |
| 172 | + tag, exists_prefix := strings.CutPrefix(tag, tagDelimiterChar) |
| 173 | + tag, exists_suffix := strings.CutSuffix(tag, tagDelimiterChar) |
| 174 | + if !exists_prefix || !exists_suffix { |
| 175 | + return nil, errors.New("Prefix or suffix is missing") |
| 176 | + } |
| 177 | + |
| 178 | + return strings.Split(tag, tagDelimiterChar), nil |
| 179 | +} |
| 180 | + |
| 181 | +func SplitTagsSafe(tag string) []string { |
| 182 | + tags, _ := SplitTags(tag) |
| 183 | + return tags |
| 184 | +} |
| 185 | + |
| 186 | +func JoinTags(tags []string) string { |
| 187 | + return tagDelimiterChar + strings.Join(tags, tagDelimiterChar) + tagDelimiterChar |
| 188 | +} |
0 commit comments