diff --git a/internal/workspace/queries/credentials.sql b/internal/workspace/queries/credentials.sql new file mode 100644 index 0000000..9f5db9c --- /dev/null +++ b/internal/workspace/queries/credentials.sql @@ -0,0 +1,13 @@ +-- name: UpsertCredential :one +INSERT INTO git_credentials (id, workspace_id, kind, username, encrypted_secret, fingerprint) +VALUES ($1,$2,$3,$4,$5,$6) +ON CONFLICT (workspace_id) DO UPDATE + SET kind = EXCLUDED.kind, + username = EXCLUDED.username, + encrypted_secret = EXCLUDED.encrypted_secret, + fingerprint = EXCLUDED.fingerprint, + updated_at = now() +RETURNING *; + +-- name: GetCredentialByWorkspace :one +SELECT * FROM git_credentials WHERE workspace_id = $1; diff --git a/internal/workspace/queries/workspaces.sql b/internal/workspace/queries/workspaces.sql new file mode 100644 index 0000000..5eefc6d --- /dev/null +++ b/internal/workspace/queries/workspaces.sql @@ -0,0 +1,43 @@ +-- name: CreateWorkspace :one +INSERT INTO workspaces ( + id, project_id, slug, name, description, + git_remote_url, default_branch, main_path, sync_status +) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) +RETURNING *; + +-- name: GetWorkspaceByID :one +SELECT * FROM workspaces WHERE id = $1; + +-- name: GetWorkspaceBySlug :one +SELECT w.* FROM workspaces w +JOIN projects p ON p.id = w.project_id +WHERE p.slug = $1 AND w.slug = $2; + +-- name: ListWorkspacesByProject :many +SELECT * FROM workspaces WHERE project_id = $1 +ORDER BY created_at DESC; + +-- name: UpdateWorkspaceCore :one +UPDATE workspaces +SET name = $2, description = $3, default_branch = $4, updated_at = now() +WHERE id = $1 +RETURNING *; + +-- name: UpdateWorkspaceSyncStatus :one +UPDATE workspaces +SET sync_status = $2, + last_synced_at = $3, + last_sync_error = $4, + updated_at = now() +WHERE id = $1 +RETURNING *; + +-- name: DeleteWorkspace :exec +DELETE FROM workspaces WHERE id = $1; + +-- name: ResetStuckSyncStatuses :exec +UPDATE workspaces +SET sync_status = 'error', + last_sync_error = 'process_restarted_during_' || sync_status, + updated_at = now() +WHERE sync_status IN ('cloning', 'syncing'); diff --git a/internal/workspace/queries/worktrees.sql b/internal/workspace/queries/worktrees.sql new file mode 100644 index 0000000..929547a --- /dev/null +++ b/internal/workspace/queries/worktrees.sql @@ -0,0 +1,39 @@ +-- name: CreateWorktree :one +INSERT INTO workspace_worktrees ( + id, workspace_id, branch, path, status, active_holder, acquired_at +) VALUES ($1,$2,$3,$4,$5,$6,$7) +RETURNING *; + +-- name: GetWorktreeByID :one +SELECT * FROM workspace_worktrees WHERE id = $1; + +-- name: GetWorktreeByBranchForUpdate :one +SELECT * FROM workspace_worktrees +WHERE workspace_id = $1 AND branch = $2 +FOR UPDATE; + +-- name: ListWorktreesByWorkspace :many +SELECT * FROM workspace_worktrees +WHERE workspace_id = $1 +ORDER BY created_at DESC; + +-- name: SetWorktreeActive :one +UPDATE workspace_worktrees +SET status = 'active', active_holder = $2, acquired_at = now(), last_used_at = now() +WHERE id = $1 +RETURNING *; + +-- name: SetWorktreeIdle :one +UPDATE workspace_worktrees +SET status = 'idle', active_holder = NULL, acquired_at = NULL, last_used_at = now() +WHERE id = $1 +RETURNING *; + +-- name: SetWorktreePruning :one +UPDATE workspace_worktrees +SET status = 'pruning', last_used_at = now() +WHERE id = $1 +RETURNING *; + +-- name: DeleteWorktree :exec +DELETE FROM workspace_worktrees WHERE id = $1; diff --git a/internal/workspace/sqlc/credentials.sql.go b/internal/workspace/sqlc/credentials.sql.go new file mode 100644 index 0000000..51eb1aa --- /dev/null +++ b/internal/workspace/sqlc/credentials.sql.go @@ -0,0 +1,76 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: credentials.sql + +package workspacesqlc + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getCredentialByWorkspace = `-- name: GetCredentialByWorkspace :one +SELECT id, workspace_id, kind, username, encrypted_secret, fingerprint, created_at, updated_at FROM git_credentials WHERE workspace_id = $1 +` + +func (q *Queries) GetCredentialByWorkspace(ctx context.Context, workspaceID pgtype.UUID) (GitCredential, error) { + row := q.db.QueryRow(ctx, getCredentialByWorkspace, workspaceID) + var i GitCredential + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.Kind, + &i.Username, + &i.EncryptedSecret, + &i.Fingerprint, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const upsertCredential = `-- name: UpsertCredential :one +INSERT INTO git_credentials (id, workspace_id, kind, username, encrypted_secret, fingerprint) +VALUES ($1,$2,$3,$4,$5,$6) +ON CONFLICT (workspace_id) DO UPDATE + SET kind = EXCLUDED.kind, + username = EXCLUDED.username, + encrypted_secret = EXCLUDED.encrypted_secret, + fingerprint = EXCLUDED.fingerprint, + updated_at = now() +RETURNING id, workspace_id, kind, username, encrypted_secret, fingerprint, created_at, updated_at +` + +type UpsertCredentialParams struct { + ID pgtype.UUID `json:"id"` + WorkspaceID pgtype.UUID `json:"workspace_id"` + Kind string `json:"kind"` + Username *string `json:"username"` + EncryptedSecret []byte `json:"encrypted_secret"` + Fingerprint *string `json:"fingerprint"` +} + +func (q *Queries) UpsertCredential(ctx context.Context, arg UpsertCredentialParams) (GitCredential, error) { + row := q.db.QueryRow(ctx, upsertCredential, + arg.ID, + arg.WorkspaceID, + arg.Kind, + arg.Username, + arg.EncryptedSecret, + arg.Fingerprint, + ) + var i GitCredential + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.Kind, + &i.Username, + &i.EncryptedSecret, + &i.Fingerprint, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/internal/workspace/sqlc/db.go b/internal/workspace/sqlc/db.go new file mode 100644 index 0000000..008e95a --- /dev/null +++ b/internal/workspace/sqlc/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package workspacesqlc + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/workspace/sqlc/models.go b/internal/workspace/sqlc/models.go new file mode 100644 index 0000000..09bf0fb --- /dev/null +++ b/internal/workspace/sqlc/models.go @@ -0,0 +1,136 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package workspacesqlc + +import ( + "net/netip" + + "github.com/jackc/pgx/v5/pgtype" +) + +type AuditLog struct { + ID int64 `json:"id"` + UserID pgtype.UUID `json:"user_id"` + Action string `json:"action"` + TargetType *string `json:"target_type"` + TargetID *string `json:"target_id"` + Ip *netip.Addr `json:"ip"` + Metadata []byte `json:"metadata"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type GitCredential struct { + ID pgtype.UUID `json:"id"` + WorkspaceID pgtype.UUID `json:"workspace_id"` + Kind string `json:"kind"` + Username *string `json:"username"` + EncryptedSecret []byte `json:"encrypted_secret"` + Fingerprint *string `json:"fingerprint"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Issue struct { + ID pgtype.UUID `json:"id"` + ProjectID pgtype.UUID `json:"project_id"` + RequirementID pgtype.UUID `json:"requirement_id"` + Number int32 `json:"number"` + Title string `json:"title"` + Description string `json:"description"` + Status string `json:"status"` + AssigneeID pgtype.UUID `json:"assignee_id"` + CreatedBy pgtype.UUID `json:"created_by"` + ClosedAt pgtype.Timestamptz `json:"closed_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + WorkspaceID pgtype.UUID `json:"workspace_id"` +} + +type Notification struct { + ID pgtype.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + Topic string `json:"topic"` + Severity string `json:"severity"` + Title string `json:"title"` + Body string `json:"body"` + Link *string `json:"link"` + Metadata []byte `json:"metadata"` + ReadAt pgtype.Timestamptz `json:"read_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type Project struct { + ID pgtype.UUID `json:"id"` + Slug string `json:"slug"` + Name string `json:"name"` + Description string `json:"description"` + Visibility string `json:"visibility"` + OwnerID pgtype.UUID `json:"owner_id"` + ArchivedAt pgtype.Timestamptz `json:"archived_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Requirement struct { + ID pgtype.UUID `json:"id"` + ProjectID pgtype.UUID `json:"project_id"` + Number int32 `json:"number"` + Title string `json:"title"` + Description string `json:"description"` + Phase string `json:"phase"` + Status string `json:"status"` + OwnerID pgtype.UUID `json:"owner_id"` + ClosedAt pgtype.Timestamptz `json:"closed_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + WorkspaceID pgtype.UUID `json:"workspace_id"` +} + +type User struct { + ID pgtype.UUID `json:"id"` + Email string `json:"email"` + PasswordHash string `json:"password_hash"` + DisplayName string `json:"display_name"` + IsAdmin bool `json:"is_admin"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type UserSession struct { + ID pgtype.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + TokenHash []byte `json:"token_hash"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` + LastSeenAt pgtype.Timestamptz `json:"last_seen_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type Workspace struct { + ID pgtype.UUID `json:"id"` + ProjectID pgtype.UUID `json:"project_id"` + Slug string `json:"slug"` + Name string `json:"name"` + Description string `json:"description"` + GitRemoteUrl string `json:"git_remote_url"` + DefaultBranch string `json:"default_branch"` + MainPath string `json:"main_path"` + SyncStatus string `json:"sync_status"` + LastSyncedAt pgtype.Timestamptz `json:"last_synced_at"` + LastSyncError *string `json:"last_sync_error"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type WorkspaceWorktree struct { + ID pgtype.UUID `json:"id"` + WorkspaceID pgtype.UUID `json:"workspace_id"` + Branch string `json:"branch"` + Path string `json:"path"` + Status string `json:"status"` + ActiveHolder *string `json:"active_holder"` + AcquiredAt pgtype.Timestamptz `json:"acquired_at"` + LastUsedAt pgtype.Timestamptz `json:"last_used_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} diff --git a/internal/workspace/sqlc/workspaces.sql.go b/internal/workspace/sqlc/workspaces.sql.go new file mode 100644 index 0000000..80e8286 --- /dev/null +++ b/internal/workspace/sqlc/workspaces.sql.go @@ -0,0 +1,264 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: workspaces.sql + +package workspacesqlc + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const createWorkspace = `-- name: CreateWorkspace :one +INSERT INTO workspaces ( + id, project_id, slug, name, description, + git_remote_url, default_branch, main_path, sync_status +) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) +RETURNING id, project_id, slug, name, description, git_remote_url, default_branch, main_path, sync_status, last_synced_at, last_sync_error, created_at, updated_at +` + +type CreateWorkspaceParams struct { + ID pgtype.UUID `json:"id"` + ProjectID pgtype.UUID `json:"project_id"` + Slug string `json:"slug"` + Name string `json:"name"` + Description string `json:"description"` + GitRemoteUrl string `json:"git_remote_url"` + DefaultBranch string `json:"default_branch"` + MainPath string `json:"main_path"` + SyncStatus string `json:"sync_status"` +} + +func (q *Queries) CreateWorkspace(ctx context.Context, arg CreateWorkspaceParams) (Workspace, error) { + row := q.db.QueryRow(ctx, createWorkspace, + arg.ID, + arg.ProjectID, + arg.Slug, + arg.Name, + arg.Description, + arg.GitRemoteUrl, + arg.DefaultBranch, + arg.MainPath, + arg.SyncStatus, + ) + var i Workspace + err := row.Scan( + &i.ID, + &i.ProjectID, + &i.Slug, + &i.Name, + &i.Description, + &i.GitRemoteUrl, + &i.DefaultBranch, + &i.MainPath, + &i.SyncStatus, + &i.LastSyncedAt, + &i.LastSyncError, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteWorkspace = `-- name: DeleteWorkspace :exec +DELETE FROM workspaces WHERE id = $1 +` + +func (q *Queries) DeleteWorkspace(ctx context.Context, id pgtype.UUID) error { + _, err := q.db.Exec(ctx, deleteWorkspace, id) + return err +} + +const getWorkspaceByID = `-- name: GetWorkspaceByID :one +SELECT id, project_id, slug, name, description, git_remote_url, default_branch, main_path, sync_status, last_synced_at, last_sync_error, created_at, updated_at FROM workspaces WHERE id = $1 +` + +func (q *Queries) GetWorkspaceByID(ctx context.Context, id pgtype.UUID) (Workspace, error) { + row := q.db.QueryRow(ctx, getWorkspaceByID, id) + var i Workspace + err := row.Scan( + &i.ID, + &i.ProjectID, + &i.Slug, + &i.Name, + &i.Description, + &i.GitRemoteUrl, + &i.DefaultBranch, + &i.MainPath, + &i.SyncStatus, + &i.LastSyncedAt, + &i.LastSyncError, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getWorkspaceBySlug = `-- name: GetWorkspaceBySlug :one +SELECT w.id, w.project_id, w.slug, w.name, w.description, w.git_remote_url, w.default_branch, w.main_path, w.sync_status, w.last_synced_at, w.last_sync_error, w.created_at, w.updated_at FROM workspaces w +JOIN projects p ON p.id = w.project_id +WHERE p.slug = $1 AND w.slug = $2 +` + +type GetWorkspaceBySlugParams struct { + Slug string `json:"slug"` + Slug_2 string `json:"slug_2"` +} + +func (q *Queries) GetWorkspaceBySlug(ctx context.Context, arg GetWorkspaceBySlugParams) (Workspace, error) { + row := q.db.QueryRow(ctx, getWorkspaceBySlug, arg.Slug, arg.Slug_2) + var i Workspace + err := row.Scan( + &i.ID, + &i.ProjectID, + &i.Slug, + &i.Name, + &i.Description, + &i.GitRemoteUrl, + &i.DefaultBranch, + &i.MainPath, + &i.SyncStatus, + &i.LastSyncedAt, + &i.LastSyncError, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const listWorkspacesByProject = `-- name: ListWorkspacesByProject :many +SELECT id, project_id, slug, name, description, git_remote_url, default_branch, main_path, sync_status, last_synced_at, last_sync_error, created_at, updated_at FROM workspaces WHERE project_id = $1 +ORDER BY created_at DESC +` + +func (q *Queries) ListWorkspacesByProject(ctx context.Context, projectID pgtype.UUID) ([]Workspace, error) { + rows, err := q.db.Query(ctx, listWorkspacesByProject, projectID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Workspace + for rows.Next() { + var i Workspace + if err := rows.Scan( + &i.ID, + &i.ProjectID, + &i.Slug, + &i.Name, + &i.Description, + &i.GitRemoteUrl, + &i.DefaultBranch, + &i.MainPath, + &i.SyncStatus, + &i.LastSyncedAt, + &i.LastSyncError, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const resetStuckSyncStatuses = `-- name: ResetStuckSyncStatuses :exec +UPDATE workspaces +SET sync_status = 'error', + last_sync_error = 'process_restarted_during_' || sync_status, + updated_at = now() +WHERE sync_status IN ('cloning', 'syncing') +` + +func (q *Queries) ResetStuckSyncStatuses(ctx context.Context) error { + _, err := q.db.Exec(ctx, resetStuckSyncStatuses) + return err +} + +const updateWorkspaceCore = `-- name: UpdateWorkspaceCore :one +UPDATE workspaces +SET name = $2, description = $3, default_branch = $4, updated_at = now() +WHERE id = $1 +RETURNING id, project_id, slug, name, description, git_remote_url, default_branch, main_path, sync_status, last_synced_at, last_sync_error, created_at, updated_at +` + +type UpdateWorkspaceCoreParams struct { + ID pgtype.UUID `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + DefaultBranch string `json:"default_branch"` +} + +func (q *Queries) UpdateWorkspaceCore(ctx context.Context, arg UpdateWorkspaceCoreParams) (Workspace, error) { + row := q.db.QueryRow(ctx, updateWorkspaceCore, + arg.ID, + arg.Name, + arg.Description, + arg.DefaultBranch, + ) + var i Workspace + err := row.Scan( + &i.ID, + &i.ProjectID, + &i.Slug, + &i.Name, + &i.Description, + &i.GitRemoteUrl, + &i.DefaultBranch, + &i.MainPath, + &i.SyncStatus, + &i.LastSyncedAt, + &i.LastSyncError, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateWorkspaceSyncStatus = `-- name: UpdateWorkspaceSyncStatus :one +UPDATE workspaces +SET sync_status = $2, + last_synced_at = $3, + last_sync_error = $4, + updated_at = now() +WHERE id = $1 +RETURNING id, project_id, slug, name, description, git_remote_url, default_branch, main_path, sync_status, last_synced_at, last_sync_error, created_at, updated_at +` + +type UpdateWorkspaceSyncStatusParams struct { + ID pgtype.UUID `json:"id"` + SyncStatus string `json:"sync_status"` + LastSyncedAt pgtype.Timestamptz `json:"last_synced_at"` + LastSyncError *string `json:"last_sync_error"` +} + +func (q *Queries) UpdateWorkspaceSyncStatus(ctx context.Context, arg UpdateWorkspaceSyncStatusParams) (Workspace, error) { + row := q.db.QueryRow(ctx, updateWorkspaceSyncStatus, + arg.ID, + arg.SyncStatus, + arg.LastSyncedAt, + arg.LastSyncError, + ) + var i Workspace + err := row.Scan( + &i.ID, + &i.ProjectID, + &i.Slug, + &i.Name, + &i.Description, + &i.GitRemoteUrl, + &i.DefaultBranch, + &i.MainPath, + &i.SyncStatus, + &i.LastSyncedAt, + &i.LastSyncError, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/internal/workspace/sqlc/worktrees.sql.go b/internal/workspace/sqlc/worktrees.sql.go new file mode 100644 index 0000000..b20b2cb --- /dev/null +++ b/internal/workspace/sqlc/worktrees.sql.go @@ -0,0 +1,225 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: worktrees.sql + +package workspacesqlc + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const createWorktree = `-- name: CreateWorktree :one +INSERT INTO workspace_worktrees ( + id, workspace_id, branch, path, status, active_holder, acquired_at +) VALUES ($1,$2,$3,$4,$5,$6,$7) +RETURNING id, workspace_id, branch, path, status, active_holder, acquired_at, last_used_at, created_at +` + +type CreateWorktreeParams struct { + ID pgtype.UUID `json:"id"` + WorkspaceID pgtype.UUID `json:"workspace_id"` + Branch string `json:"branch"` + Path string `json:"path"` + Status string `json:"status"` + ActiveHolder *string `json:"active_holder"` + AcquiredAt pgtype.Timestamptz `json:"acquired_at"` +} + +func (q *Queries) CreateWorktree(ctx context.Context, arg CreateWorktreeParams) (WorkspaceWorktree, error) { + row := q.db.QueryRow(ctx, createWorktree, + arg.ID, + arg.WorkspaceID, + arg.Branch, + arg.Path, + arg.Status, + arg.ActiveHolder, + arg.AcquiredAt, + ) + var i WorkspaceWorktree + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.Branch, + &i.Path, + &i.Status, + &i.ActiveHolder, + &i.AcquiredAt, + &i.LastUsedAt, + &i.CreatedAt, + ) + return i, err +} + +const deleteWorktree = `-- name: DeleteWorktree :exec +DELETE FROM workspace_worktrees WHERE id = $1 +` + +func (q *Queries) DeleteWorktree(ctx context.Context, id pgtype.UUID) error { + _, err := q.db.Exec(ctx, deleteWorktree, id) + return err +} + +const getWorktreeByBranchForUpdate = `-- name: GetWorktreeByBranchForUpdate :one +SELECT id, workspace_id, branch, path, status, active_holder, acquired_at, last_used_at, created_at FROM workspace_worktrees +WHERE workspace_id = $1 AND branch = $2 +FOR UPDATE +` + +type GetWorktreeByBranchForUpdateParams struct { + WorkspaceID pgtype.UUID `json:"workspace_id"` + Branch string `json:"branch"` +} + +func (q *Queries) GetWorktreeByBranchForUpdate(ctx context.Context, arg GetWorktreeByBranchForUpdateParams) (WorkspaceWorktree, error) { + row := q.db.QueryRow(ctx, getWorktreeByBranchForUpdate, arg.WorkspaceID, arg.Branch) + var i WorkspaceWorktree + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.Branch, + &i.Path, + &i.Status, + &i.ActiveHolder, + &i.AcquiredAt, + &i.LastUsedAt, + &i.CreatedAt, + ) + return i, err +} + +const getWorktreeByID = `-- name: GetWorktreeByID :one +SELECT id, workspace_id, branch, path, status, active_holder, acquired_at, last_used_at, created_at FROM workspace_worktrees WHERE id = $1 +` + +func (q *Queries) GetWorktreeByID(ctx context.Context, id pgtype.UUID) (WorkspaceWorktree, error) { + row := q.db.QueryRow(ctx, getWorktreeByID, id) + var i WorkspaceWorktree + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.Branch, + &i.Path, + &i.Status, + &i.ActiveHolder, + &i.AcquiredAt, + &i.LastUsedAt, + &i.CreatedAt, + ) + return i, err +} + +const listWorktreesByWorkspace = `-- name: ListWorktreesByWorkspace :many +SELECT id, workspace_id, branch, path, status, active_holder, acquired_at, last_used_at, created_at FROM workspace_worktrees +WHERE workspace_id = $1 +ORDER BY created_at DESC +` + +func (q *Queries) ListWorktreesByWorkspace(ctx context.Context, workspaceID pgtype.UUID) ([]WorkspaceWorktree, error) { + rows, err := q.db.Query(ctx, listWorktreesByWorkspace, workspaceID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WorkspaceWorktree + for rows.Next() { + var i WorkspaceWorktree + if err := rows.Scan( + &i.ID, + &i.WorkspaceID, + &i.Branch, + &i.Path, + &i.Status, + &i.ActiveHolder, + &i.AcquiredAt, + &i.LastUsedAt, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const setWorktreeActive = `-- name: SetWorktreeActive :one +UPDATE workspace_worktrees +SET status = 'active', active_holder = $2, acquired_at = now(), last_used_at = now() +WHERE id = $1 +RETURNING id, workspace_id, branch, path, status, active_holder, acquired_at, last_used_at, created_at +` + +type SetWorktreeActiveParams struct { + ID pgtype.UUID `json:"id"` + ActiveHolder *string `json:"active_holder"` +} + +func (q *Queries) SetWorktreeActive(ctx context.Context, arg SetWorktreeActiveParams) (WorkspaceWorktree, error) { + row := q.db.QueryRow(ctx, setWorktreeActive, arg.ID, arg.ActiveHolder) + var i WorkspaceWorktree + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.Branch, + &i.Path, + &i.Status, + &i.ActiveHolder, + &i.AcquiredAt, + &i.LastUsedAt, + &i.CreatedAt, + ) + return i, err +} + +const setWorktreeIdle = `-- name: SetWorktreeIdle :one +UPDATE workspace_worktrees +SET status = 'idle', active_holder = NULL, acquired_at = NULL, last_used_at = now() +WHERE id = $1 +RETURNING id, workspace_id, branch, path, status, active_holder, acquired_at, last_used_at, created_at +` + +func (q *Queries) SetWorktreeIdle(ctx context.Context, id pgtype.UUID) (WorkspaceWorktree, error) { + row := q.db.QueryRow(ctx, setWorktreeIdle, id) + var i WorkspaceWorktree + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.Branch, + &i.Path, + &i.Status, + &i.ActiveHolder, + &i.AcquiredAt, + &i.LastUsedAt, + &i.CreatedAt, + ) + return i, err +} + +const setWorktreePruning = `-- name: SetWorktreePruning :one +UPDATE workspace_worktrees +SET status = 'pruning', last_used_at = now() +WHERE id = $1 +RETURNING id, workspace_id, branch, path, status, active_holder, acquired_at, last_used_at, created_at +` + +func (q *Queries) SetWorktreePruning(ctx context.Context, id pgtype.UUID) (WorkspaceWorktree, error) { + row := q.db.QueryRow(ctx, setWorktreePruning, id) + var i WorkspaceWorktree + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.Branch, + &i.Path, + &i.Status, + &i.ActiveHolder, + &i.AcquiredAt, + &i.LastUsedAt, + &i.CreatedAt, + ) + return i, err +} diff --git a/sqlc.yaml b/sqlc.yaml index 7b80d8b..f2577b8 100644 --- a/sqlc.yaml +++ b/sqlc.yaml @@ -40,3 +40,13 @@ sql: sql_package: pgx/v5 emit_pointers_for_null_types: true emit_json_tags: true + - engine: postgresql + queries: internal/workspace/queries + schema: migrations + gen: + go: + package: workspacesqlc + out: internal/workspace/sqlc + sql_package: pgx/v5 + emit_pointers_for_null_types: true + emit_json_tags: true