Skip to content

Commit 591385f

Browse files
authored
chore: implement fuzzy name matching for templates (#14211)
* chore: add fuzzy name search for templates * chore: implement fuzzy name matching for templates Templates search query defaults to a fuzzy name match
1 parent 27b8f20 commit 591385f

File tree

9 files changed

+71
-10
lines changed

9 files changed

+71
-10
lines changed

coderd/database/dbmem/dbmem.go

+5
Original file line numberDiff line numberDiff line change
@@ -9647,6 +9647,11 @@ func (q *FakeQuerier) GetAuthorizedTemplates(ctx context.Context, arg database.G
96479647
if arg.Deprecated.Valid && arg.Deprecated.Bool == (template.Deprecated != "") {
96489648
continue
96499649
}
9650+
if arg.FuzzyName != "" {
9651+
if !strings.Contains(strings.ToLower(template.Name), strings.ToLower(arg.FuzzyName)) {
9652+
continue
9653+
}
9654+
}
96509655

96519656
if len(arg.IDs) > 0 {
96529657
match := false

coderd/database/modelqueries.go

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
7676
arg.Deleted,
7777
arg.OrganizationID,
7878
arg.ExactName,
79+
arg.FuzzyName,
7980
pq.Array(arg.IDs),
8081
arg.Deprecated,
8182
)

coderd/database/queries.sql.go

+12-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/templates.sql

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ WHERE
2828
LOWER("name") = LOWER(@exact_name)
2929
ELSE true
3030
END
31+
-- Filter by name, matching on substring
32+
AND CASE
33+
WHEN @fuzzy_name :: text != '' THEN
34+
lower(name) ILIKE '%' || lower(@fuzzy_name) || '%'
35+
ELSE true
36+
END
3137
-- Filter by ids
3238
AND CASE
3339
WHEN array_length(@ids :: uuid[], 1) > 0 THEN

coderd/searchquery/search.go

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ func Templates(ctx context.Context, db database.Store, query string) (database.G
198198

199199
parser := httpapi.NewQueryParamParser()
200200
filter := database.GetTemplatesWithFilterParams{
201+
FuzzyName: parser.String(values, "", "name"),
201202
Deleted: parser.Boolean(values, false, "deleted"),
202203
ExactName: parser.String(values, "", "exact_name"),
203204
IDs: parser.UUIDs(values, []uuid.UUID{}, "ids"),

coderd/searchquery/search_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,13 @@ func TestSearchTemplates(t *testing.T) {
469469
Query: "",
470470
Expected: database.GetTemplatesWithFilterParams{},
471471
},
472+
{
473+
Name: "OnlyName",
474+
Query: "foobar",
475+
Expected: database.GetTemplatesWithFilterParams{
476+
FuzzyName: "foobar",
477+
},
478+
},
472479
}
473480

474481
for _, c := range testCases {

coderd/templates_test.go

+27-2
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,12 @@ func TestTemplatesByOrganization(t *testing.T) {
438438
user := coderdtest.CreateFirstUser(t, client)
439439
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
440440
version2 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
441-
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
442-
coderdtest.CreateTemplate(t, client, user.OrganizationID, version2.ID)
441+
foo := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(request *codersdk.CreateTemplateRequest) {
442+
request.Name = "foobar"
443+
})
444+
bar := coderdtest.CreateTemplate(t, client, user.OrganizationID, version2.ID, func(request *codersdk.CreateTemplateRequest) {
445+
request.Name = "barbaz"
446+
})
443447

444448
ctx := testutil.Context(t, testutil.WaitLong)
445449

@@ -460,6 +464,27 @@ func TestTemplatesByOrganization(t *testing.T) {
460464
require.Equal(t, tmpl.OrganizationDisplayName, org.DisplayName, "organization display name")
461465
require.Equal(t, tmpl.OrganizationIcon, org.Icon, "organization display name")
462466
}
467+
468+
// Check fuzzy name matching
469+
templates, err = client.Templates(ctx, codersdk.TemplateFilter{
470+
FuzzyName: "bar",
471+
})
472+
require.NoError(t, err)
473+
require.Len(t, templates, 2)
474+
475+
templates, err = client.Templates(ctx, codersdk.TemplateFilter{
476+
FuzzyName: "foo",
477+
})
478+
require.NoError(t, err)
479+
require.Len(t, templates, 1)
480+
require.Equal(t, foo.ID, templates[0].ID)
481+
482+
templates, err = client.Templates(ctx, codersdk.TemplateFilter{
483+
FuzzyName: "baz",
484+
})
485+
require.NoError(t, err)
486+
require.Len(t, templates, 1)
487+
require.Equal(t, bar.ID, templates[0].ID)
463488
})
464489
}
465490

codersdk/organizations.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,10 @@ func (c *Client) TemplatesByOrganization(ctx context.Context, organizationID uui
405405
}
406406

407407
type TemplateFilter struct {
408-
OrganizationID uuid.UUID
409-
ExactName string
408+
OrganizationID uuid.UUID `typescript:"-"`
409+
ExactName string `typescript:"-"`
410+
FuzzyName string `typescript:"-"`
411+
SearchQuery string `json:"q,omitempty"`
410412
}
411413

412414
// asRequestOption returns a function that can be used in (*Client).Request.
@@ -424,6 +426,13 @@ func (f TemplateFilter) asRequestOption() RequestOption {
424426
params = append(params, fmt.Sprintf("exact_name:%q", f.ExactName))
425427
}
426428

429+
if f.FuzzyName != "" {
430+
params = append(params, fmt.Sprintf("name:%q", f.FuzzyName))
431+
}
432+
if f.SearchQuery != "" {
433+
params = append(params, f.SearchQuery)
434+
}
435+
427436
q := r.URL.Query()
428437
q.Set("q", strings.Join(params, " "))
429438
r.URL.RawQuery = q.Encode()

site/src/api/typesGenerated.ts

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)