mirror of
https://github.com/coder/coder.git
synced 2025-07-18 14:17:22 +00:00
feat: Add support for renaming workspaces (#3409)
* feat: Implement workspace renaming * feat: Add hidden rename command (and data loss warning) * feat: Implement database.IsUniqueViolation
This commit is contained in:
committed by
GitHub
parent
623fc5baac
commit
c8f8c95f6a
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/lib/pq"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/coder/coder/coderd/database"
|
||||
@ -2086,6 +2087,32 @@ func (q *fakeQuerier) UpdateProvisionerJobWithCompleteByID(_ context.Context, ar
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) UpdateWorkspace(_ context.Context, arg database.UpdateWorkspaceParams) (database.Workspace, error) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
for i, workspace := range q.workspaces {
|
||||
if workspace.Deleted || workspace.ID != arg.ID {
|
||||
continue
|
||||
}
|
||||
for _, other := range q.workspaces {
|
||||
if other.Deleted || other.ID == workspace.ID || workspace.OwnerID != other.OwnerID {
|
||||
continue
|
||||
}
|
||||
if other.Name == arg.Name {
|
||||
return database.Workspace{}, &pq.Error{Code: "23505", Message: "duplicate key value violates unique constraint"}
|
||||
}
|
||||
}
|
||||
|
||||
workspace.Name = arg.Name
|
||||
q.workspaces[i] = workspace
|
||||
|
||||
return workspace, nil
|
||||
}
|
||||
|
||||
return database.Workspace{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) UpdateWorkspaceAutostart(_ context.Context, arg database.UpdateWorkspaceAutostartParams) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
38
coderd/database/errors.go
Normal file
38
coderd/database/errors.go
Normal file
@ -0,0 +1,38 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
// UniqueConstraint represents a named unique constraint on a table.
|
||||
type UniqueConstraint string
|
||||
|
||||
// UniqueConstraint enums.
|
||||
// TODO(mafredri): Generate these from the database schema.
|
||||
const (
|
||||
UniqueWorkspacesOwnerIDLowerIdx UniqueConstraint = "workspaces_owner_id_lower_idx"
|
||||
)
|
||||
|
||||
// IsUniqueViolation checks if the error is due to a unique violation.
|
||||
// If one or more specific unique constraints are given as arguments,
|
||||
// the error must be caused by one of them. If no constraints are given,
|
||||
// this function returns true for any unique violation.
|
||||
func IsUniqueViolation(err error, uniqueConstraints ...UniqueConstraint) bool {
|
||||
var pqErr *pq.Error
|
||||
if errors.As(err, &pqErr) {
|
||||
if pqErr.Code.Name() == "unique_violation" {
|
||||
if len(uniqueConstraints) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, uc := range uniqueConstraints {
|
||||
if pqErr.Constraint == string(uc) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@ -139,6 +139,7 @@ type querier interface {
|
||||
UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) (User, error)
|
||||
UpdateUserRoles(ctx context.Context, arg UpdateUserRolesParams) (User, error)
|
||||
UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) (User, error)
|
||||
UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (Workspace, error)
|
||||
UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error
|
||||
UpdateWorkspaceAgentKeysByID(ctx context.Context, arg UpdateWorkspaceAgentKeysByIDParams) error
|
||||
UpdateWorkspaceAutostart(ctx context.Context, arg UpdateWorkspaceAutostartParams) error
|
||||
|
@ -4732,6 +4732,40 @@ func (q *sqlQuerier) InsertWorkspace(ctx context.Context, arg InsertWorkspacePar
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateWorkspace = `-- name: UpdateWorkspace :one
|
||||
UPDATE
|
||||
workspaces
|
||||
SET
|
||||
name = $2
|
||||
WHERE
|
||||
id = $1
|
||||
AND deleted = false
|
||||
RETURNING id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl
|
||||
`
|
||||
|
||||
type UpdateWorkspaceParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (Workspace, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateWorkspace, arg.ID, arg.Name)
|
||||
var i Workspace
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.OwnerID,
|
||||
&i.OrganizationID,
|
||||
&i.TemplateID,
|
||||
&i.Deleted,
|
||||
&i.Name,
|
||||
&i.AutostartSchedule,
|
||||
&i.Ttl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateWorkspaceAutostart = `-- name: UpdateWorkspaceAutostart :exec
|
||||
UPDATE
|
||||
workspaces
|
||||
|
@ -112,6 +112,16 @@ SET
|
||||
WHERE
|
||||
id = $1;
|
||||
|
||||
-- name: UpdateWorkspace :one
|
||||
UPDATE
|
||||
workspaces
|
||||
SET
|
||||
name = $2
|
||||
WHERE
|
||||
id = $1
|
||||
AND deleted = false
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateWorkspaceAutostart :exec
|
||||
UPDATE
|
||||
workspaces
|
||||
|
Reference in New Issue
Block a user