apiserver/folders: use exact match on GetFolderByTitle in legacy (#106867)

* apiserver/folders: use exact match on GetFolderByTitle in legacy

Signed-off-by: Maicon Costa <maiconscosta@gmail.com>


---------

Signed-off-by: Maicon Costa <maiconscosta@gmail.com>
This commit is contained in:
maicon
2025-06-24 17:42:08 -03:00
committed by GitHub
parent 988d889ba7
commit 8a05378ef3
9 changed files with 150 additions and 25 deletions
+1 -1
View File
@@ -882,7 +882,7 @@ func (d *dashboardStore) FindDashboards(ctx context.Context, query *dashboards.F
}
if len(query.Title) > 0 {
filters = append(filters, searchstore.TitleFilter{Dialect: d.store.GetDialect(), Title: query.Title})
filters = append(filters, searchstore.TitleFilter{Dialect: d.store.GetDialect(), Title: query.Title, TitleExactMatch: query.TitleExactMatch})
}
if len(query.Type) > 0 {
@@ -888,25 +888,47 @@ func TestIntegrationFindDashboardsByTitle(t *testing.T) {
}
testCases := []struct {
desc string
title string
expectedResult res
typ string
desc string
title string
titleExactMatch bool
expectedResult *res
typ string
}{
{
desc: "find dashboard under general",
title: "dashboard under general",
expectedResult: res{title: "dashboard under general"},
expectedResult: &res{title: "dashboard under general"},
},
{
desc: "find dashboard under f0",
title: "dashboard under f0",
expectedResult: res{title: "dashboard under f0", folderUID: f0.UID, folderTitle: f0.Title},
expectedResult: &res{title: "dashboard under f0", folderUID: f0.UID, folderTitle: f0.Title},
},
{
desc: "find dashboard under subfolder",
title: "dashboard under subfolder",
expectedResult: res{title: "dashboard under subfolder", folderUID: subfolder.UID, folderTitle: subfolder.Title},
expectedResult: &res{title: "dashboard under subfolder", folderUID: subfolder.UID, folderTitle: subfolder.Title},
},
{
desc: "find folder 'sub' using partial match: 1 result found",
title: "sub",
titleExactMatch: false,
typ: "dash-folder",
expectedResult: &res{title: "subfolder", folderUID: f0.UID, folderTitle: f0.Title},
},
{
desc: "find folder 'sub' using exact match: no results",
title: "sub",
titleExactMatch: true,
typ: "dash-folder",
expectedResult: nil,
},
{
desc: "find folder 'subfolder' using exact match: 1 result",
title: "subfolder",
titleExactMatch: true,
typ: "dash-folder",
expectedResult: &res{title: "subfolder", folderUID: f0.UID, folderTitle: f0.Title},
},
}
@@ -915,11 +937,18 @@ func TestIntegrationFindDashboardsByTitle(t *testing.T) {
dashboardStore, err := ProvideDashboardStore(sqlStore, cfg, features, tagimpl.ProvideService(sqlStore))
require.NoError(t, err)
res, err := dashboardStore.FindDashboards(context.Background(), &dashboards.FindPersistedDashboardsQuery{
SignedInUser: user,
Type: tc.typ,
Title: tc.title,
SignedInUser: user,
Type: tc.typ,
Title: tc.title,
TitleExactMatch: tc.titleExactMatch,
})
require.NoError(t, err)
if tc.expectedResult == nil {
require.Equal(t, 0, len(res))
return
}
require.Equal(t, 1, len(res))
r := tc.expectedResult
+7 -6
View File
@@ -430,12 +430,13 @@ type DashboardACLInfoDTO struct {
}
type FindPersistedDashboardsQuery struct {
Title string
OrgId int64
SignedInUser identity.Requester
DashboardIds []int64
DashboardUIDs []string
Type string
Title string
TitleExactMatch bool
OrgId int64
SignedInUser identity.Requester
DashboardIds []int64
DashboardUIDs []string
Type string
// Deprecated: use FolderUIDs instead
FolderIds []int64
FolderUIDs []string
@@ -310,11 +310,16 @@ func (s *Service) getFolderByTitleFromApiServer(ctx context.Context, orgID int64
request := &resourcepb.ResourceSearchRequest{
Options: &resourcepb.ListOptions{
Key: folderkey,
Fields: []*resourcepb.Requirement{},
Key: folderkey,
Fields: []*resourcepb.Requirement{
{
Key: resource.SEARCH_FIELD_TITLE_PHRASE, // nolint:staticcheck
Operator: string(selection.Equals),
Values: []string{title},
},
},
Labels: []*resourcepb.Requirement{},
},
Query: title,
Limit: folderSearchLimit}
if parentUID != nil {
@@ -792,11 +792,16 @@ func TestGetFoldersFromApiServer(t *testing.T) {
service.unifiedStore = fakeFolderStore
fakeK8sClient.On("Search", mock.Anything, int64(1), &resourcepb.ResourceSearchRequest{
Options: &resourcepb.ListOptions{
Key: folderkey,
Fields: []*resourcepb.Requirement{},
Key: folderkey,
Fields: []*resourcepb.Requirement{
&resourcepb.Requirement{
Key: resource.SEARCH_FIELD_TITLE_PHRASE, // nolint:staticcheck
Operator: string(selection.Equals),
Values: []string{"foo title"},
},
},
Labels: []*resourcepb.Requirement{},
},
Query: "foo title",
Limit: folderSearchLimit}).
Return(&resourcepb.ResourceSearchResponse{
Results: &resourcepb.ResourceTable{
+7 -2
View File
@@ -43,11 +43,16 @@ func (f OrgFilter) Where() (string, []any) {
}
type TitleFilter struct {
Dialect migrator.Dialect
Title string
Dialect migrator.Dialect
Title string
TitleExactMatch bool
}
func (f TitleFilter) Where() (string, []any) {
if f.TitleExactMatch {
return "dashboard.title = ?", []any{f.Title}
}
sql, params := f.Dialect.LikeOperator("dashboard.title", true, f.Title, true)
return sql, []any{params}
}
@@ -91,3 +91,44 @@ func TestFolderUIDFilter(t *testing.T) {
})
}
}
func TestTitleFilter(t *testing.T) {
testCases := []struct {
description string
title string
exactMatch bool
expectedSql string
expectedParams []any
}{
{
description: "searching foo folder - partial match",
title: "foo",
expectedSql: "dashboard.title LIKE ?",
expectedParams: []any{"%foo%"},
},
{
description: "searching foo folder - exact match",
title: "foo",
exactMatch: true,
expectedSql: "dashboard.title = ?",
expectedParams: []any{"foo"},
},
}
store := setupTestEnvironment(t)
for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
f := searchstore.TitleFilter{
Dialect: store.GetDialect(),
Title: tc.title,
TitleExactMatch: tc.exactMatch,
}
sql, params := f.Where()
assert.Equal(t, tc.expectedSql, sql)
assert.Equal(t, tc.expectedParams, params)
})
}
}