chore: add templates search query to a filter (#13772)

* chore: add templates search query to a filter
This commit is contained in:
Steven Masley
2024-07-03 13:42:23 -05:00
committed by GitHub
parent 8778aa0f71
commit ccf34901bc
8 changed files with 246 additions and 23 deletions
+46
View File
@@ -184,6 +184,52 @@ func Workspaces(query string, page codersdk.Pagination, agentInactiveDisconnectT
return filter, parser.Errors
}
func Templates(ctx context.Context, db database.Store, query string) (database.GetTemplatesWithFilterParams, []codersdk.ValidationError) {
// Always lowercase for all searches.
query = strings.ToLower(query)
values, errors := searchTerms(query, func(term string, values url.Values) error {
// Default to the template name
values.Add("name", term)
return nil
})
if len(errors) > 0 {
return database.GetTemplatesWithFilterParams{}, errors
}
parser := httpapi.NewQueryParamParser()
filter := database.GetTemplatesWithFilterParams{
Deleted: parser.Boolean(values, false, "deleted"),
// TODO: Should name be a fuzzy search?
ExactName: parser.String(values, "", "name"),
IDs: parser.UUIDs(values, []uuid.UUID{}, "ids"),
Deprecated: parser.NullableBoolean(values, sql.NullBool{}, "deprecated"),
}
// Convert the "organization" parameter to an organization uuid. This can require
// a database lookup.
organizationArg := parser.String(values, "", "organization")
if organizationArg != "" {
organizationID, err := uuid.Parse(organizationArg)
if err == nil {
filter.OrganizationID = organizationID
} else {
// Organization could be a name
organization, err := db.GetOrganizationByName(ctx, organizationArg)
if err != nil {
parser.Errors = append(parser.Errors, codersdk.ValidationError{
Field: "organization",
Detail: fmt.Sprintf("Organization %q either does not exist, or you are unauthorized to view it", organizationArg),
})
} else {
filter.OrganizationID = organization.ID
}
}
}
parser.ErrorExcessParams(values)
return filter, parser.Errors
}
func searchTerms(query string, defaultKey func(term string, values url.Values) error) (url.Values, []codersdk.ValidationError) {
searchValues := make(url.Values)
+43
View File
@@ -8,6 +8,7 @@ import (
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -454,3 +455,45 @@ func TestSearchUsers(t *testing.T) {
})
}
}
func TestSearchTemplates(t *testing.T) {
t.Parallel()
testCases := []struct {
Name string
Query string
Expected database.GetTemplatesWithFilterParams
ExpectedErrorContains string
}{
{
Name: "Empty",
Query: "",
Expected: database.GetTemplatesWithFilterParams{},
},
}
for _, c := range testCases {
c := c
t.Run(c.Name, func(t *testing.T) {
t.Parallel()
// Do not use a real database, this is only used for an
// organization lookup.
db := dbmem.New()
values, errs := searchquery.Templates(context.Background(), db, c.Query)
if c.ExpectedErrorContains != "" {
require.True(t, len(errs) > 0, "expect some errors")
var s strings.Builder
for _, err := range errs {
_, _ = s.WriteString(fmt.Sprintf("%s: %s\n", err.Field, err.Detail))
}
require.Contains(t, s.String(), c.ExpectedErrorContains)
} else {
require.Len(t, errs, 0, "expected no error")
if c.Expected.IDs == nil {
// Nil and length 0 are the same
c.Expected.IDs = []uuid.UUID{}
}
require.Equal(t, c.Expected, values, "expected values")
}
})
}
}