From 0a61ba83183d0a06f5d330aa298e71ad1e91afa2 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 4 Sep 2023 15:21:36 +0000 Subject: [PATCH] refactor(coderd/database): generate dbresetpw with queries for reset-password command This change removes 1 MB from the slim binary, and combined with the following PRs: #9481, #9506, #9508, #9517, a total of 4 MB. Ref: #9380 --- Makefile | 3 + cli/resetpassword.go | 8 +- coderd/database/dbresetpw/db.go | 31 +++++ coderd/database/dbresetpw/models.go | 121 ++++++++++++++++++ coderd/database/dbresetpw/sqlc.yaml | 13 ++ .../database/dbresetpw/users_resetpw.sql.go | 75 +++++++++++ coderd/database/queries.sql.go | 119 ++++++++--------- coderd/database/queries/users.sql | 19 --- coderd/database/queries/users_resetpw.sql | 23 ++++ 9 files changed, 332 insertions(+), 80 deletions(-) create mode 100644 coderd/database/dbresetpw/db.go create mode 100644 coderd/database/dbresetpw/models.go create mode 100644 coderd/database/dbresetpw/sqlc.yaml create mode 100644 coderd/database/dbresetpw/users_resetpw.sql.go create mode 100644 coderd/database/queries/users_resetpw.sql diff --git a/Makefile b/Makefile index 56acd83ff70c8..194e2fb899a50 100644 --- a/Makefile +++ b/Makefile @@ -516,6 +516,9 @@ coderd/database/dump.sql: coderd/database/gen/dump/main.go $(wildcard coderd/dat coderd/database/querier.go: coderd/database/sqlc.yaml coderd/database/dump.sql $(wildcard coderd/database/queries/*.sql) ./coderd/database/generate.sh +coderd/database/dbresetpw/users_resetpw.sql.go: coderd/database/querier.go coderd/database/dbresetpw/sqlc.yaml + sqlc generate -f ./coderd/database/dbresetpw/sqlc.yaml + coderd/database/dbmock/dbmock.go: coderd/database/db.go coderd/database/querier.go go generate ./coderd/database/dbmock/ diff --git a/cli/resetpassword.go b/cli/resetpassword.go index 7df9481417b28..37478d5cd3564 100644 --- a/cli/resetpassword.go +++ b/cli/resetpassword.go @@ -8,7 +8,7 @@ import ( "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" - "github.com/coder/coder/v2/coderd/database" + "github.com/coder/coder/v2/coderd/database/dbresetpw" "github.com/coder/coder/v2/coderd/database/migrations" "github.com/coder/coder/v2/coderd/userpassword" ) @@ -37,9 +37,9 @@ func (*RootCmd) resetPassword() *clibase.Cmd { if err != nil { return xerrors.Errorf("database needs migration: %w", err) } - db := database.New(sqlDB) + db := dbresetpw.New(sqlDB) - user, err := db.GetUserByEmailOrUsername(inv.Context(), database.GetUserByEmailOrUsernameParams{ + user, err := db.GetUserByEmailOrUsername(inv.Context(), dbresetpw.GetUserByEmailOrUsernameParams{ Username: username, }) if err != nil { @@ -73,7 +73,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd { return xerrors.Errorf("hash password: %w", err) } - err = db.UpdateUserHashedPassword(inv.Context(), database.UpdateUserHashedPasswordParams{ + err = db.UpdateUserHashedPassword(inv.Context(), dbresetpw.UpdateUserHashedPasswordParams{ ID: user.ID, HashedPassword: []byte(hashedPassword), }) diff --git a/coderd/database/dbresetpw/db.go b/coderd/database/dbresetpw/db.go new file mode 100644 index 0000000000000..836005787dd40 --- /dev/null +++ b/coderd/database/dbresetpw/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.20.0 + +package dbresetpw + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/coderd/database/dbresetpw/models.go b/coderd/database/dbresetpw/models.go new file mode 100644 index 0000000000000..7d553b7c82996 --- /dev/null +++ b/coderd/database/dbresetpw/models.go @@ -0,0 +1,121 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.20.0 + +package dbresetpw + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "time" + + "github.com/google/uuid" +) + +// Specifies the method of authentication. "none" is a special case in which no authentication method is allowed. +type LoginType string + +const ( + LoginTypePassword LoginType = "password" + LoginTypeGithub LoginType = "github" + LoginTypeOidc LoginType = "oidc" + LoginTypeToken LoginType = "token" + LoginTypeNone LoginType = "none" +) + +func (e *LoginType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = LoginType(s) + case string: + *e = LoginType(s) + default: + return fmt.Errorf("unsupported scan type for LoginType: %T", src) + } + return nil +} + +type NullLoginType struct { + LoginType LoginType + Valid bool // Valid is true if LoginType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullLoginType) Scan(value interface{}) error { + if value == nil { + ns.LoginType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.LoginType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullLoginType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.LoginType), nil +} + +// Defines the user status: active, dormant, or suspended. +type UserStatus string + +const ( + UserStatusActive UserStatus = "active" + UserStatusSuspended UserStatus = "suspended" + UserStatusDormant UserStatus = "dormant" +) + +func (e *UserStatus) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = UserStatus(s) + case string: + *e = UserStatus(s) + default: + return fmt.Errorf("unsupported scan type for UserStatus: %T", src) + } + return nil +} + +type NullUserStatus struct { + UserStatus UserStatus + Valid bool // Valid is true if UserStatus is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullUserStatus) Scan(value interface{}) error { + if value == nil { + ns.UserStatus, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.UserStatus.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullUserStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.UserStatus), nil +} + +type User struct { + ID uuid.UUID + Email string + Username string + HashedPassword []byte + CreatedAt time.Time + UpdatedAt time.Time + Status UserStatus + RbacRoles []string + LoginType LoginType + AvatarUrl sql.NullString + Deleted bool + LastSeenAt time.Time + // Daily (!) cron schedule (with optional CRON_TZ) signifying the start of the user's quiet hours. If empty, the default quiet hours on the instance is used instead. + QuietHoursSchedule string +} diff --git a/coderd/database/dbresetpw/sqlc.yaml b/coderd/database/dbresetpw/sqlc.yaml new file mode 100644 index 0000000000000..9148c6e085446 --- /dev/null +++ b/coderd/database/dbresetpw/sqlc.yaml @@ -0,0 +1,13 @@ +# This sqlc.yaml file is used by sqlc to generate a subset of the coderd +# database interface that can be used for the reset-password command. +version: "2" + +sql: + - schema: "../dump.sql" + queries: "../queries/users_resetpw.sql" + engine: "postgresql" + gen: + go: + package: "dbresetpw" + out: "." + omit_unused_structs: true diff --git a/coderd/database/dbresetpw/users_resetpw.sql.go b/coderd/database/dbresetpw/users_resetpw.sql.go new file mode 100644 index 0000000000000..066a0a53ce00b --- /dev/null +++ b/coderd/database/dbresetpw/users_resetpw.sql.go @@ -0,0 +1,75 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.20.0 +// source: users_resetpw.sql + +package dbresetpw + +import ( + "context" + + "github.com/google/uuid" + "github.com/lib/pq" +) + +const getUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one +/* + This file contains a subset of users.sql queries used by the + dbresetpw package. +*/ + +SELECT + id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule +FROM + users +WHERE + (LOWER(username) = LOWER($1) OR LOWER(email) = LOWER($2)) AND + deleted = false +LIMIT + 1 +` + +type GetUserByEmailOrUsernameParams struct { + Username string + Email string +} + +func (q *Queries) GetUserByEmailOrUsername(ctx context.Context, arg GetUserByEmailOrUsernameParams) (User, error) { + row := q.db.QueryRowContext(ctx, getUserByEmailOrUsername, arg.Username, arg.Email) + var i User + err := row.Scan( + &i.ID, + &i.Email, + &i.Username, + &i.HashedPassword, + &i.CreatedAt, + &i.UpdatedAt, + &i.Status, + pq.Array(&i.RbacRoles), + &i.LoginType, + &i.AvatarUrl, + &i.Deleted, + &i.LastSeenAt, + &i.QuietHoursSchedule, + ) + return i, err +} + +const updateUserHashedPassword = `-- name: UpdateUserHashedPassword :exec +UPDATE + users +SET + hashed_password = $2 +WHERE + id = $1 +` + +type UpdateUserHashedPasswordParams struct { + ID uuid.UUID + HashedPassword []byte +} + +func (q *Queries) UpdateUserHashedPassword(ctx context.Context, arg UpdateUserHashedPasswordParams) error { + _, err := q.db.ExecContext(ctx, updateUserHashedPassword, arg.ID, arg.HashedPassword) + return err +} diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index dbbb5d4085e93..3218d9a8fd374 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -5690,44 +5690,6 @@ func (q *sqlQuerier) GetAuthorizationUserRoles(ctx context.Context, userID uuid. return i, err } -const getUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one -SELECT - id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule -FROM - users -WHERE - (LOWER(username) = LOWER($1) OR LOWER(email) = LOWER($2)) AND - deleted = false -LIMIT - 1 -` - -type GetUserByEmailOrUsernameParams struct { - Username string `db:"username" json:"username"` - Email string `db:"email" json:"email"` -} - -func (q *sqlQuerier) GetUserByEmailOrUsername(ctx context.Context, arg GetUserByEmailOrUsernameParams) (User, error) { - row := q.db.QueryRowContext(ctx, getUserByEmailOrUsername, arg.Username, arg.Email) - var i User - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.HashedPassword, - &i.CreatedAt, - &i.UpdatedAt, - &i.Status, - &i.RBACRoles, - &i.LoginType, - &i.AvatarURL, - &i.Deleted, - &i.LastSeenAt, - &i.QuietHoursSchedule, - ) - return i, err -} - const getUserByID = `-- name: GetUserByID :one SELECT id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule @@ -6092,25 +6054,6 @@ func (q *sqlQuerier) UpdateUserDeletedByID(ctx context.Context, arg UpdateUserDe return err } -const updateUserHashedPassword = `-- name: UpdateUserHashedPassword :exec -UPDATE - users -SET - hashed_password = $2 -WHERE - id = $1 -` - -type UpdateUserHashedPasswordParams struct { - ID uuid.UUID `db:"id" json:"id"` - HashedPassword []byte `db:"hashed_password" json:"hashed_password"` -} - -func (q *sqlQuerier) UpdateUserHashedPassword(ctx context.Context, arg UpdateUserHashedPasswordParams) error { - _, err := q.db.ExecContext(ctx, updateUserHashedPassword, arg.ID, arg.HashedPassword) - return err -} - const updateUserLastSeenAt = `-- name: UpdateUserLastSeenAt :one UPDATE users @@ -6347,6 +6290,68 @@ func (q *sqlQuerier) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusP return i, err } +const getUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one +/* + This file contains a subset of users.sql queries used by the + dbresetpw package. +*/ + +SELECT + id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule +FROM + users +WHERE + (LOWER(username) = LOWER($1) OR LOWER(email) = LOWER($2)) AND + deleted = false +LIMIT + 1 +` + +type GetUserByEmailOrUsernameParams struct { + Username string `db:"username" json:"username"` + Email string `db:"email" json:"email"` +} + +func (q *sqlQuerier) GetUserByEmailOrUsername(ctx context.Context, arg GetUserByEmailOrUsernameParams) (User, error) { + row := q.db.QueryRowContext(ctx, getUserByEmailOrUsername, arg.Username, arg.Email) + var i User + err := row.Scan( + &i.ID, + &i.Email, + &i.Username, + &i.HashedPassword, + &i.CreatedAt, + &i.UpdatedAt, + &i.Status, + &i.RBACRoles, + &i.LoginType, + &i.AvatarURL, + &i.Deleted, + &i.LastSeenAt, + &i.QuietHoursSchedule, + ) + return i, err +} + +const updateUserHashedPassword = `-- name: UpdateUserHashedPassword :exec +UPDATE + users +SET + hashed_password = $2 +WHERE + id = $1 +` + +type UpdateUserHashedPasswordParams struct { + ID uuid.UUID `db:"id" json:"id"` + HashedPassword []byte `db:"hashed_password" json:"hashed_password"` +} + +func (q *sqlQuerier) UpdateUserHashedPassword(ctx context.Context, arg UpdateUserHashedPasswordParams) error { + _, err := q.db.ExecContext(ctx, updateUserHashedPassword, arg.ID, arg.HashedPassword) + return err +} + const deleteOldWorkspaceAgentLogs = `-- name: DeleteOldWorkspaceAgentLogs :exec DELETE FROM workspace_agent_logs WHERE agent_id IN (SELECT id FROM workspace_agents WHERE last_connected_at IS NOT NULL diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index 8560bf0abf696..4af7f7e8b7d0f 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -29,17 +29,6 @@ LIMIT -- for another user, then be deleted... we still want them to appear! SELECT * FROM users WHERE id = ANY(@ids :: uuid [ ]); --- name: GetUserByEmailOrUsername :one -SELECT - * -FROM - users -WHERE - (LOWER(username) = LOWER(@username) OR LOWER(email) = LOWER(@email)) AND - deleted = false -LIMIT - 1; - -- name: GetUserCount :one SELECT COUNT(*) @@ -92,14 +81,6 @@ WHERE id = @id RETURNING *; --- name: UpdateUserHashedPassword :exec -UPDATE - users -SET - hashed_password = $2 -WHERE - id = $1; - -- name: UpdateUserDeletedByID :exec UPDATE users diff --git a/coderd/database/queries/users_resetpw.sql b/coderd/database/queries/users_resetpw.sql new file mode 100644 index 0000000000000..49a2f2751dabe --- /dev/null +++ b/coderd/database/queries/users_resetpw.sql @@ -0,0 +1,23 @@ +/* + This file contains a subset of users.sql queries used by the + dbresetpw package. +*/ + +-- name: GetUserByEmailOrUsername :one +SELECT + * +FROM + users +WHERE + (LOWER(username) = LOWER(@username) OR LOWER(email) = LOWER(@email)) AND + deleted = false +LIMIT + 1; + +-- name: UpdateUserHashedPassword :exec +UPDATE + users +SET + hashed_password = $2 +WHERE + id = $1;