Skip to content

Commit dc1de58

Browse files
Emyrkf0ssel
andauthored
feat: workspace filter query supported in backend (coder#2232)
* feat: add support for template in workspace filter * feat: Implement workspace search filter to support names * Use new query param parser for pagination fields * Remove excessive calls, use filters on a single query Co-authored-by: Garrett <garrett@coder.com>
1 parent 5be52de commit dc1de58

20 files changed

+1063
-459
lines changed

coderd/database/databasefake/databasefake.go

Lines changed: 67 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -321,41 +321,47 @@ func (q *fakeQuerier) GetWorkspacesWithFilter(_ context.Context, arg database.Ge
321321

322322
workspaces := make([]database.Workspace, 0)
323323
for _, workspace := range q.workspaces {
324-
if arg.OrganizationID != uuid.Nil && workspace.OrganizationID != arg.OrganizationID {
325-
continue
326-
}
327324
if arg.OwnerID != uuid.Nil && workspace.OwnerID != arg.OwnerID {
328325
continue
329326
}
327+
if arg.OwnerUsername != "" {
328+
owner, err := q.GetUserByID(context.Background(), workspace.OwnerID)
329+
if err == nil && arg.OwnerUsername != owner.Username {
330+
continue
331+
}
332+
}
333+
if arg.TemplateName != "" {
334+
templates, err := q.GetTemplatesWithFilter(context.Background(), database.GetTemplatesWithFilterParams{
335+
ExactName: arg.TemplateName,
336+
})
337+
// Add to later param
338+
if err == nil {
339+
for _, t := range templates {
340+
arg.TemplateIds = append(arg.TemplateIds, t.ID)
341+
}
342+
}
343+
}
330344
if !arg.Deleted && workspace.Deleted {
331345
continue
332346
}
333347
if arg.Name != "" && !strings.Contains(workspace.Name, arg.Name) {
334348
continue
335349
}
336-
workspaces = append(workspaces, workspace)
337-
}
338-
339-
return workspaces, nil
340-
}
341-
342-
func (q *fakeQuerier) GetWorkspacesByTemplateID(_ context.Context, arg database.GetWorkspacesByTemplateIDParams) ([]database.Workspace, error) {
343-
q.mutex.RLock()
344-
defer q.mutex.RUnlock()
345-
346-
workspaces := make([]database.Workspace, 0)
347-
for _, workspace := range q.workspaces {
348-
if workspace.TemplateID.String() != arg.TemplateID.String() {
349-
continue
350-
}
351-
if workspace.Deleted != arg.Deleted {
352-
continue
350+
if len(arg.TemplateIds) > 0 {
351+
match := false
352+
for _, id := range arg.TemplateIds {
353+
if workspace.TemplateID == id {
354+
match = true
355+
break
356+
}
357+
}
358+
if !match {
359+
continue
360+
}
353361
}
354362
workspaces = append(workspaces, workspace)
355363
}
356-
if len(workspaces) == 0 {
357-
return nil, sql.ErrNoRows
358-
}
364+
359365
return workspaces, nil
360366
}
361367

@@ -641,25 +647,6 @@ func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(_ context.Con
641647
return database.WorkspaceBuild{}, sql.ErrNoRows
642648
}
643649

644-
func (q *fakeQuerier) GetWorkspacesByOrganizationIDs(_ context.Context, req database.GetWorkspacesByOrganizationIDsParams) ([]database.Workspace, error) {
645-
q.mutex.RLock()
646-
defer q.mutex.RUnlock()
647-
648-
workspaces := make([]database.Workspace, 0)
649-
for _, workspace := range q.workspaces {
650-
for _, id := range req.Ids {
651-
if workspace.OrganizationID != id {
652-
continue
653-
}
654-
if workspace.Deleted != req.Deleted {
655-
continue
656-
}
657-
workspaces = append(workspaces, workspace)
658-
}
659-
}
660-
return workspaces, nil
661-
}
662-
663650
func (q *fakeQuerier) GetOrganizations(_ context.Context) ([]database.Organization, error) {
664651
q.mutex.RLock()
665652
defer q.mutex.RUnlock()
@@ -786,6 +773,44 @@ func (q *fakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.Upd
786773
return sql.ErrNoRows
787774
}
788775

776+
func (q *fakeQuerier) GetTemplatesWithFilter(_ context.Context, arg database.GetTemplatesWithFilterParams) ([]database.Template, error) {
777+
q.mutex.RLock()
778+
defer q.mutex.RUnlock()
779+
780+
var templates []database.Template
781+
for _, template := range q.templates {
782+
if template.Deleted != arg.Deleted {
783+
continue
784+
}
785+
if arg.OrganizationID != uuid.Nil && template.OrganizationID != arg.OrganizationID {
786+
continue
787+
}
788+
789+
if arg.ExactName != "" && !strings.EqualFold(template.Name, arg.ExactName) {
790+
continue
791+
}
792+
793+
if len(arg.Ids) > 0 {
794+
match := false
795+
for _, id := range arg.Ids {
796+
if template.ID == id {
797+
match = true
798+
break
799+
}
800+
}
801+
if !match {
802+
continue
803+
}
804+
}
805+
templates = append(templates, template)
806+
}
807+
if len(templates) > 0 {
808+
return templates, nil
809+
}
810+
811+
return nil, sql.ErrNoRows
812+
}
813+
789814
func (q *fakeQuerier) GetTemplateVersionsByTemplateID(_ context.Context, arg database.GetTemplateVersionsByTemplateIDParams) (version []database.TemplateVersion, err error) {
790815
q.mutex.RLock()
791816
defer q.mutex.RUnlock()
@@ -923,45 +948,6 @@ func (q *fakeQuerier) GetParameterValueByScopeAndName(_ context.Context, arg dat
923948
return database.ParameterValue{}, sql.ErrNoRows
924949
}
925950

926-
func (q *fakeQuerier) GetTemplatesByOrganization(_ context.Context, arg database.GetTemplatesByOrganizationParams) ([]database.Template, error) {
927-
q.mutex.RLock()
928-
defer q.mutex.RUnlock()
929-
930-
templates := make([]database.Template, 0)
931-
for _, template := range q.templates {
932-
if template.Deleted != arg.Deleted {
933-
continue
934-
}
935-
if template.OrganizationID != arg.OrganizationID {
936-
continue
937-
}
938-
templates = append(templates, template)
939-
}
940-
if len(templates) == 0 {
941-
return nil, sql.ErrNoRows
942-
}
943-
return templates, nil
944-
}
945-
946-
func (q *fakeQuerier) GetTemplatesByIDs(_ context.Context, ids []uuid.UUID) ([]database.Template, error) {
947-
q.mutex.RLock()
948-
defer q.mutex.RUnlock()
949-
950-
templates := make([]database.Template, 0)
951-
for _, template := range q.templates {
952-
for _, id := range ids {
953-
if template.ID.String() != id.String() {
954-
continue
955-
}
956-
templates = append(templates, template)
957-
}
958-
}
959-
if len(templates) == 0 {
960-
return nil, sql.ErrNoRows
961-
}
962-
return templates, nil
963-
}
964-
965951
func (q *fakeQuerier) GetOrganizationMemberByUserID(_ context.Context, arg database.GetOrganizationMemberByUserIDParams) (database.OrganizationMember, error) {
966952
q.mutex.RLock()
967953
defer q.mutex.RUnlock()
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package databasefake_test
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
"testing"
7+
8+
"github.com/coder/coder/coderd/database"
9+
10+
"github.com/coder/coder/coderd/database/databasefake"
11+
)
12+
13+
// TestExactMethods will ensure the fake database does not hold onto excessive
14+
// functions. The fake database is a manual implementation, so it is possible
15+
// we forget to delete functions that we remove. This unit test just ensures
16+
// we remove the extra methods.
17+
func TestExactMethods(t *testing.T) {
18+
t.Parallel()
19+
20+
// extraFakeMethods contains the extra allowed methods that are not a part
21+
// of the database.Store interface.
22+
extraFakeMethods := map[string]string{
23+
// Example
24+
// "SortFakeLists": "Helper function used",
25+
}
26+
27+
fake := reflect.TypeOf(databasefake.New())
28+
fakeMethods := methods(fake)
29+
30+
store := reflect.TypeOf((*database.Store)(nil)).Elem()
31+
storeMethods := methods(store)
32+
33+
// Store should be a subset
34+
for k := range storeMethods {
35+
_, ok := fakeMethods[k]
36+
if !ok {
37+
panic(fmt.Sprintf("This should never happen. FakeDB missing method %s, so doesn't fit the interface", k))
38+
}
39+
delete(storeMethods, k)
40+
delete(fakeMethods, k)
41+
}
42+
43+
for k := range fakeMethods {
44+
_, ok := extraFakeMethods[k]
45+
if ok {
46+
continue
47+
}
48+
// If you are seeing this error, you have an extra function not required
49+
// for the database.Store. If you still want to keep it, add it to
50+
// 'extraFakeMethods' to allow it.
51+
t.Errorf("Fake method '%s()' is excessive and not needed to fit interface, delete it", k)
52+
}
53+
}
54+
55+
func methods(rt reflect.Type) map[string]bool {
56+
methods := make(map[string]bool)
57+
for i := 0; i < rt.NumMethod(); i++ {
58+
methods[rt.Method(i).Name] = true
59+
}
60+
return methods
61+
}

coderd/database/querier.go

Lines changed: 1 addition & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)