fix: tag search never matches on slug name
The search term was formatted into LOWER(%s) and passed as the *value* of the
LIKE, so the function name ended up inside the pattern:
slug_name LIKE '%LOWER(coco)%'
That can never match. Only the display_name clause did any work, and LIKE is
case-sensitive on Postgres, so searching a tag by the name it is written in
returns nothing:
slug_name=Coco -> matches
slug_name=coco -> no match
Tags are lower case by convention, so lower case is what users type, and the
filter appears to report that no such tag exists.
Lower both sides instead. The term normalisation is extracted so it can be
covered by a test without a database.
This commit is contained in:
@@ -21,7 +21,6 @@ package tag_common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -171,10 +170,20 @@ func (tr *tagCommonRepo) GetTagPage(ctx context.Context, page, pageSize int, tag
|
||||
session := tr.data.DB.Context(ctx)
|
||||
|
||||
if len(tag.SlugName) > 0 {
|
||||
// Both sides lowered, so the search is case-insensitive.
|
||||
//
|
||||
// This previously read LOWER(%s) formatted against the *search term*,
|
||||
// which put the function name into the value: the query became
|
||||
// slug_name LIKE '%LOWER(coco)%' and could never match. Only the
|
||||
// display_name clause did anything, and that is case-sensitive on
|
||||
// Postgres, so typing a tag in lower case -- which is how tags are
|
||||
// written and therefore how anyone types them -- returned nothing at all
|
||||
// and read as "no such tag".
|
||||
search := searchTermForTag(tag.SlugName)
|
||||
mainTagCond := builder.And(
|
||||
builder.Or(
|
||||
builder.Like{"slug_name", fmt.Sprintf("LOWER(%s)", tag.SlugName)},
|
||||
builder.Like{"display_name", tag.SlugName},
|
||||
builder.Like{"LOWER(slug_name)", search},
|
||||
builder.Like{"LOWER(display_name)", search},
|
||||
),
|
||||
builder.Eq{"main_tag_id": 0},
|
||||
)
|
||||
@@ -293,3 +302,10 @@ func (tr *tagCommonRepo) UpdateTagsAttribute(ctx context.Context, tags []string,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// searchTermForTag normalises a tag search term. Lowering it here, and lowering
|
||||
// the columns in the query, is what makes the search case-insensitive: tags are
|
||||
// written in lower case, so that is how people type them.
|
||||
func searchTermForTag(term string) string {
|
||||
return strings.ToLower(strings.TrimSpace(term))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package tag_common
|
||||
|
||||
import "testing"
|
||||
|
||||
// The bug: the search term was formatted into LOWER(%s), which put the function
|
||||
// name into the value rather than applying it to the column, so the query became
|
||||
// slug_name LIKE '%LOWER(coco)%' and matched nothing. Only display_name did any
|
||||
// work, and that is case-sensitive on Postgres -- so typing a tag the way tags
|
||||
// are actually written returned "no such tag".
|
||||
func TestSearchTermIsLoweredNotWrapped(t *testing.T) {
|
||||
for _, in := range []string{"Coco", "COCO", "coco"} {
|
||||
got := searchTermForTag(in)
|
||||
if got != "coco" {
|
||||
t.Errorf("searchTermForTag(%q) = %q, want %q", in, got, "coco")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user