Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
46ca00d
feat(coderd): add user_pinned_workspaces table
johnstcn Jan 16, 2024
015aabb
add unique index
johnstcn Jan 17, 2024
0b0dce6
rename migration
johnstcn Jan 17, 2024
9878da7
add queries to pin/unpin workspace
johnstcn Jan 17, 2024
4fba238
add pinned status to GetWorkspaces/GetAuthorizedWorkspaces queries
johnstcn Jan 17, 2024
83b03d9
add API endpoints and test (currently fails)
johnstcn Jan 18, 2024
0961298
rename to favorite workspace
johnstcn Jan 18, 2024
a814b65
move to top-level test
johnstcn Jan 22, 2024
89d618d
s/favored/favorite/g
johnstcn Jan 22, 2024
7238b95
move favorite status to workspaces table to avoid sqlc join sadness
johnstcn Jan 22, 2024
4eef59a
more wiring
johnstcn Jan 22, 2024
0f8904d
improve test to include sort order of favorites
johnstcn Jan 22, 2024
d921aa0
fix swagger summary
johnstcn Jan 22, 2024
b68c18e
make gen
johnstcn Jan 22, 2024
3d0545a
use dbfake for testing sort order
johnstcn Jan 22, 2024
46103a4
reduce scope of TestWorkspaceFavoriteUnfavorite to not include sortin…
johnstcn Jan 22, 2024
f6c0361
beef up sort order test
johnstcn Jan 22, 2024
89f0f50
rm unnecessary fixture
johnstcn Jan 22, 2024
c9ed43c
fix sort ordering, dbfake still TODO
johnstcn Jan 22, 2024
ff3cde2
remove unnecessary change to CreateFirstUser
johnstcn Jan 23, 2024
f735b69
best-effort fix but testing dbmem sort order is a waste of time
johnstcn Jan 23, 2024
f6e9531
requestor->requester
johnstcn Jan 23, 2024
34f2902
fixup! remove unnecessary change to CreateFirstUser
johnstcn Jan 23, 2024
99c7f96
remove unused resource
johnstcn Jan 23, 2024
d530546
fix sort ordering bug in dmem
johnstcn Jan 23, 2024
6392db9
add test case
johnstcn Jan 23, 2024
9979c53
remove need for conditional ordering
johnstcn Jan 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
move favorite status to workspaces table to avoid sqlc join sadness
  • Loading branch information
johnstcn committed Jan 23, 2024
commit 7238b95c0cbb6c18a6f2b7b18a7c28b3b4276158
5 changes: 0 additions & 5 deletions coderd/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,6 @@ func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {
return str
}

// "Pinning" (favoriting) a workspace is a separate thing.
if alog.ResourceType == database.ResourceTypeFavoriteWorkspace {
return fmt.Sprintf("{user} pinned workspace %s", alog.ResourceTarget)
}

str += fmt.Sprintf(" %s",
codersdk.ResourceType(alog.ResourceType).FriendlyString())

Expand Down
1 change: 0 additions & 1 deletion coderd/audit/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ type Auditable interface {
database.TemplateVersion |
database.User |
database.Workspace |
database.FavoriteWorkspace |
database.GitSSHKey |
database.WorkspaceBuild |
database.AuditableGroup |
Expand Down
6 changes: 0 additions & 6 deletions coderd/audit/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ func ResourceTarget[T Auditable](tgt T) string {
return string(typed.ToLoginType)
case database.HealthSettings:
return "" // no target?
case database.FavoriteWorkspace:
return typed.WorkspaceID.String()
default:
panic(fmt.Sprintf("unknown resource %T", tgt))
}
Expand Down Expand Up @@ -130,8 +128,6 @@ func ResourceID[T Auditable](tgt T) uuid.UUID {
case database.HealthSettings:
// Artificial ID for auditing purposes
return typed.ID
case database.FavoriteWorkspace:
return typed.WorkspaceID
default:
panic(fmt.Sprintf("unknown resource %T", tgt))
}
Expand Down Expand Up @@ -163,8 +159,6 @@ func ResourceType[T Auditable](tgt T) database.ResourceType {
return database.ResourceTypeConvertLogin
case database.HealthSettings:
return database.ResourceTypeHealthSettings
case database.FavoriteWorkspace:
return database.ResourceTypeFavoriteWorkspace
default:
panic(fmt.Sprintf("unknown resource %T", typed))
}
Expand Down
16 changes: 8 additions & 8 deletions coderd/database/dbauthz/dbauthz.go
Original file line number Diff line number Diff line change
Expand Up @@ -891,11 +891,11 @@ func (q *querier) DeleteTailnetTunnel(ctx context.Context, arg database.DeleteTa
return q.db.DeleteTailnetTunnel(ctx, arg)
}

func (q *querier) FavoriteWorkspace(ctx context.Context, arg database.FavoriteWorkspaceParams) error {
if _, err := q.GetWorkspaceByID(ctx, arg.WorkspaceID); err != nil {
return err
func (q *querier) FavoriteWorkspace(ctx context.Context, id uuid.UUID) error {
fetch := func(ctx context.Context, id uuid.UUID) (database.Workspace, error) {
return q.db.GetWorkspaceByID(ctx, id)
}
return q.db.FavoriteWorkspace(ctx, arg)
return update(q.log, q.auth, fetch, q.db.FavoriteWorkspace)(ctx, id)
}

func (q *querier) GetAPIKeyByID(ctx context.Context, id string) (database.APIKey, error) {
Expand Down Expand Up @@ -2516,11 +2516,11 @@ func (q *querier) UnarchiveTemplateVersion(ctx context.Context, arg database.Una
return q.db.UnarchiveTemplateVersion(ctx, arg)
}

func (q *querier) UnfavoriteWorkspace(ctx context.Context, arg database.UnfavoriteWorkspaceParams) error {
if _, err := q.GetWorkspaceByID(ctx, arg.WorkspaceID); err != nil {
return err
func (q *querier) UnfavoriteWorkspace(ctx context.Context, id uuid.UUID) error {
fetch := func(ctx context.Context, id uuid.UUID) (database.Workspace, error) {
return q.db.GetWorkspaceByID(ctx, id)
}
return q.db.UnfavoriteWorkspace(ctx, arg)
return update(q.log, q.auth, fetch, q.db.UnfavoriteWorkspace)(ctx, id)
}

func (q *querier) UpdateAPIKeyByID(ctx context.Context, arg database.UpdateAPIKeyByIDParams) error {
Expand Down
10 changes: 2 additions & 8 deletions coderd/database/dbauthz/dbauthz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1581,18 +1581,12 @@ func (s *MethodTestSuite) TestWorkspace() {
s.Run("FavoriteWorkspace", s.Subtest(func(db database.Store, check *expects) {
u := dbgen.User(s.T(), db, database.User{})
ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID})
check.Args(database.FavoriteWorkspaceParams{
UserID: u.ID,
WorkspaceID: ws.ID,
}).Asserts(ws, rbac.ActionRead).Returns()
check.Args(ws.ID).Asserts(ws, rbac.ActionUpdate).Returns()
}))
s.Run("UnfavoriteWorkspace", s.Subtest(func(db database.Store, check *expects) {
u := dbgen.User(s.T(), db, database.User{})
ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID})
check.Args(database.UnfavoriteWorkspaceParams{
UserID: u.ID,
WorkspaceID: ws.ID,
}).Asserts(ws, rbac.ActionRead).Returns()
check.Args(ws.ID).Asserts(ws, rbac.ActionUpdate).Returns()
}))
}

Expand Down
25 changes: 11 additions & 14 deletions coderd/database/dbmem/dbmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ func New() database.Store {
workspaceBuilds: make([]database.WorkspaceBuildTable, 0),
workspaceApps: make([]database.WorkspaceApp, 0),
workspaces: make([]database.Workspace, 0),
favoriteWorkspaces: make([]database.FavoriteWorkspace, 0),
licenses: make([]database.License, 0),
workspaceProxies: make([]database.WorkspaceProxy, 0),
locks: map[int64]struct{}{},
Expand Down Expand Up @@ -155,7 +154,6 @@ type data struct {
workspaceResourceMetadata []database.WorkspaceResourceMetadatum
workspaceResources []database.WorkspaceResource
workspaces []database.Workspace
favoriteWorkspaces []database.FavoriteWorkspace
workspaceProxies []database.WorkspaceProxy
// Locks is a map of lock names. Any keys within the map are currently
// locked.
Expand Down Expand Up @@ -1317,7 +1315,7 @@ func (*FakeQuerier) DeleteTailnetTunnel(_ context.Context, arg database.DeleteTa
return database.DeleteTailnetTunnelRow{}, ErrUnimplemented
}

func (q *FakeQuerier) FavoriteWorkspace(_ context.Context, arg database.FavoriteWorkspaceParams) error {
func (q *FakeQuerier) FavoriteWorkspace(_ context.Context, arg uuid.UUID) error {
err := validateDatabaseType(arg)
if err != nil {
return err
Expand All @@ -1326,10 +1324,13 @@ func (q *FakeQuerier) FavoriteWorkspace(_ context.Context, arg database.Favorite
q.mutex.Lock()
defer q.mutex.Unlock()

for _, upw := range q.favoriteWorkspaces {
if arg.UserID == upw.UserID && arg.WorkspaceID == upw.WorkspaceID {
return errDuplicateKey
for i := 0; i < len(q.workspaces); i++ {
if q.workspaces[i].ID != arg {
continue
}
q.workspaces[i].FavoriteOf.Valid = true
q.workspaces[i].FavoriteOf.UUID = q.workspaces[i].OwnerID
return nil
}
return nil
}
Expand Down Expand Up @@ -6003,7 +6004,7 @@ func (q *FakeQuerier) UnarchiveTemplateVersion(_ context.Context, arg database.U
return sql.ErrNoRows
}

func (q *FakeQuerier) UnfavoriteWorkspace(_ context.Context, arg database.UnfavoriteWorkspaceParams) error {
func (q *FakeQuerier) UnfavoriteWorkspace(_ context.Context, arg uuid.UUID) error {
err := validateDatabaseType(arg)
if err != nil {
return err
Expand All @@ -6012,15 +6013,11 @@ func (q *FakeQuerier) UnfavoriteWorkspace(_ context.Context, arg database.Unfavo
q.mutex.Lock()
defer q.mutex.Unlock()

for index, upw := range q.favoriteWorkspaces {
if upw.UserID != arg.UserID {
continue
}
if upw.WorkspaceID != arg.WorkspaceID {
for i := 0; i < len(q.workspaces); i++ {
if q.workspaces[i].ID != arg {
continue
}
q.favoriteWorkspaces[index] = q.favoriteWorkspaces[len(q.apiKeys)-1]
q.favoriteWorkspaces = q.favoriteWorkspaces[:len(q.favoriteWorkspaces)-1]
q.workspaces[i].FavoriteOf = uuid.NullUUID{}
return nil
}

Expand Down
4 changes: 2 additions & 2 deletions coderd/database/dbmetrics/dbmetrics.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions coderd/database/dbmock/dbmock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 5 additions & 11 deletions coderd/database/dump.sql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
DROP TABLE favorite_workspaces;
ALTER TABLE ONLY workspaces DROP COLUMN favorite_of;
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
CREATE TABLE favorite_workspaces (
user_id uuid NOT NULL,
workspace_id uuid NOT NULL,
UNIQUE(user_id, workspace_id)
);

ALTER TYPE resource_type ADD VALUE IF NOT EXISTS 'favorite_workspace';
ALTER TABLE ONLY workspaces
ADD COLUMN favorite_of uuid DEFAULT NULL;
COMMENT ON COLUMN workspaces.favorite_of IS 'FavoriteOf contains the UUID of the workspace owner if the workspace has been favorited.';
Comment on lines +1 to +3
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self-review: just storing a boolean value here doesn't provide enough context to the query to be able to know how to sort favorites.

Copy link
Member

@Emyrk Emyrk Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think there is any benefit to using a zero uuid here instead of null? It just makes you not need to use uuid.NullUUID{...}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't a workspace have the owner uuid already in the table? If so can't we just use a boolean + that? When I hear "favorite of" I kind of expect the data type to be an array and favorable by many.

If we don't have owner uuid in there, should we just add it vs. the current workaround?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was originally wary of making that conditional on owner_id, but now it's looking like it makes more sense in its current shape.

4 changes: 2 additions & 2 deletions coderd/database/modelqueries.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ func (q *sqlQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg GetWorkspa
// The name comment is for metric tracking
query := fmt.Sprintf("-- name: GetAuthorizedWorkspaces :many\n%s", filtered)
rows, err := q.db.QueryContext(ctx, query,
arg.OwnerID,
arg.Deleted,
arg.Status,
arg.OwnerID,
arg.OwnerUsername,
arg.TemplateName,
pq.Array(arg.TemplateIDs),
Expand Down Expand Up @@ -250,10 +250,10 @@ func (q *sqlQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg GetWorkspa
&i.DormantAt,
&i.DeletingAt,
&i.AutomaticUpdates,
&i.FavoriteOf,
&i.TemplateName,
&i.TemplateVersionID,
&i.TemplateVersionName,
&i.Favorite,
&i.Count,
); err != nil {
return nil, err
Expand Down
38 changes: 16 additions & 22 deletions coderd/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading