// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: issue_label.sql package db import ( "context" "github.com/jackc/pgx/v5/pgtype" ) const attachLabelToIssue = `-- name: AttachLabelToIssue :exec INSERT INTO issue_to_label (issue_id, label_id) SELECT $1::uuid, $2::uuid WHERE EXISTS ( SELECT 1 FROM issue i WHERE i.id = $1::uuid AND i.workspace_id = $3::uuid ) AND EXISTS ( SELECT 1 FROM issue_label l WHERE l.id = $2::uuid AND l.workspace_id = $3::uuid ) ON CONFLICT DO NOTHING ` type AttachLabelToIssueParams struct { IssueID pgtype.UUID `json:"issue_id"` LabelID pgtype.UUID `json:"label_id"` WorkspaceID pgtype.UUID `json:"workspace_id"` } // Workspace-guarded INSERT: the WHERE EXISTS clauses ensure both the issue // and the label belong to the given workspace. A future caller that forgets // handler-level prechecks still cannot attach labels across workspaces. func (q *Queries) AttachLabelToIssue(ctx context.Context, arg AttachLabelToIssueParams) error { _, err := q.db.Exec(ctx, attachLabelToIssue, arg.IssueID, arg.LabelID, arg.WorkspaceID) return err } const createLabel = `-- name: CreateLabel :one INSERT INTO issue_label (workspace_id, name, color) VALUES ($1, $2, $3) RETURNING id, workspace_id, name, color, created_at, updated_at ` type CreateLabelParams struct { WorkspaceID pgtype.UUID `json:"workspace_id"` Name string `json:"name"` Color string `json:"color"` } func (q *Queries) CreateLabel(ctx context.Context, arg CreateLabelParams) (IssueLabel, error) { row := q.db.QueryRow(ctx, createLabel, arg.WorkspaceID, arg.Name, arg.Color) var i IssueLabel err := row.Scan( &i.ID, &i.WorkspaceID, &i.Name, &i.Color, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const deleteLabel = `-- name: DeleteLabel :one DELETE FROM issue_label WHERE id = $1 AND workspace_id = $2 RETURNING id ` type DeleteLabelParams struct { ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` } // :one RETURNING id so the handler distinguishes pgx.ErrNoRows (→ 404) from // infrastructure errors (→ 500), and avoids a TOCTOU precheck. func (q *Queries) DeleteLabel(ctx context.Context, arg DeleteLabelParams) (pgtype.UUID, error) { row := q.db.QueryRow(ctx, deleteLabel, arg.ID, arg.WorkspaceID) var id pgtype.UUID err := row.Scan(&id) return id, err } const detachLabelFromIssue = `-- name: DetachLabelFromIssue :exec DELETE FROM issue_to_label WHERE issue_id = $1::uuid AND label_id = $2::uuid AND EXISTS ( SELECT 1 FROM issue i WHERE i.id = $1::uuid AND i.workspace_id = $3::uuid ) ` type DetachLabelFromIssueParams struct { IssueID pgtype.UUID `json:"issue_id"` LabelID pgtype.UUID `json:"label_id"` WorkspaceID pgtype.UUID `json:"workspace_id"` } // Workspace-guarded DELETE: only deletes if the issue is in the given // workspace. Mirror of the attach query. func (q *Queries) DetachLabelFromIssue(ctx context.Context, arg DetachLabelFromIssueParams) error { _, err := q.db.Exec(ctx, detachLabelFromIssue, arg.IssueID, arg.LabelID, arg.WorkspaceID) return err } const getLabel = `-- name: GetLabel :one SELECT id, workspace_id, name, color, created_at, updated_at FROM issue_label WHERE id = $1 AND workspace_id = $2 ` type GetLabelParams struct { ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` } func (q *Queries) GetLabel(ctx context.Context, arg GetLabelParams) (IssueLabel, error) { row := q.db.QueryRow(ctx, getLabel, arg.ID, arg.WorkspaceID) var i IssueLabel err := row.Scan( &i.ID, &i.WorkspaceID, &i.Name, &i.Color, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const listLabels = `-- name: ListLabels :many SELECT id, workspace_id, name, color, created_at, updated_at FROM issue_label WHERE workspace_id = $1 ORDER BY LOWER(name) ASC ` func (q *Queries) ListLabels(ctx context.Context, workspaceID pgtype.UUID) ([]IssueLabel, error) { rows, err := q.db.Query(ctx, listLabels, workspaceID) if err != nil { return nil, err } defer rows.Close() items := []IssueLabel{} for rows.Next() { var i IssueLabel if err := rows.Scan( &i.ID, &i.WorkspaceID, &i.Name, &i.Color, &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 listLabelsByIssue = `-- name: ListLabelsByIssue :many SELECT l.id, l.workspace_id, l.name, l.color, l.created_at, l.updated_at FROM issue_label l JOIN issue_to_label il ON il.label_id = l.id WHERE il.issue_id = $1::uuid AND l.workspace_id = $2::uuid ORDER BY LOWER(l.name) ASC ` type ListLabelsByIssueParams struct { IssueID pgtype.UUID `json:"issue_id"` WorkspaceID pgtype.UUID `json:"workspace_id"` } // Workspace filter at the SQL layer (mirrors GetProjectInWorkspace). Any caller // that passes the wrong workspace gets an empty list rather than leaking labels. func (q *Queries) ListLabelsByIssue(ctx context.Context, arg ListLabelsByIssueParams) ([]IssueLabel, error) { rows, err := q.db.Query(ctx, listLabelsByIssue, arg.IssueID, arg.WorkspaceID) if err != nil { return nil, err } defer rows.Close() items := []IssueLabel{} for rows.Next() { var i IssueLabel if err := rows.Scan( &i.ID, &i.WorkspaceID, &i.Name, &i.Color, &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 listLabelsForIssues = `-- name: ListLabelsForIssues :many SELECT il.issue_id, l.id, l.workspace_id, l.name, l.color, l.created_at, l.updated_at FROM issue_label l JOIN issue_to_label il ON il.label_id = l.id WHERE il.issue_id = ANY($1::uuid[]) AND l.workspace_id = $2::uuid ORDER BY il.issue_id, LOWER(l.name) ASC ` type ListLabelsForIssuesParams struct { IssueIds []pgtype.UUID `json:"issue_ids"` WorkspaceID pgtype.UUID `json:"workspace_id"` } type ListLabelsForIssuesRow struct { IssueID pgtype.UUID `json:"issue_id"` ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` Name string `json:"name"` Color string `json:"color"` CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` } // Bulk variant: fetch labels for many issues in one round-trip so the issue // list endpoints can fold labels into each row without N+1 queries from the // client. Workspace-guarded the same way as ListLabelsByIssue. func (q *Queries) ListLabelsForIssues(ctx context.Context, arg ListLabelsForIssuesParams) ([]ListLabelsForIssuesRow, error) { rows, err := q.db.Query(ctx, listLabelsForIssues, arg.IssueIds, arg.WorkspaceID) if err != nil { return nil, err } defer rows.Close() items := []ListLabelsForIssuesRow{} for rows.Next() { var i ListLabelsForIssuesRow if err := rows.Scan( &i.IssueID, &i.ID, &i.WorkspaceID, &i.Name, &i.Color, &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 updateLabel = `-- name: UpdateLabel :one UPDATE issue_label SET name = COALESCE($3, name), color = COALESCE($4, color), updated_at = now() WHERE id = $1 AND workspace_id = $2 RETURNING id, workspace_id, name, color, created_at, updated_at ` type UpdateLabelParams struct { ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` Name pgtype.Text `json:"name"` Color pgtype.Text `json:"color"` } func (q *Queries) UpdateLabel(ctx context.Context, arg UpdateLabelParams) (IssueLabel, error) { row := q.db.QueryRow(ctx, updateLabel, arg.ID, arg.WorkspaceID, arg.Name, arg.Color, ) var i IssueLabel err := row.Scan( &i.ID, &i.WorkspaceID, &i.Name, &i.Color, &i.CreatedAt, &i.UpdatedAt, ) return i, err }