// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: attachment.sql package db import ( "context" "github.com/jackc/pgx/v5/pgtype" ) const bindChatAttachmentsToMessage = `-- name: BindChatAttachmentsToMessage :many UPDATE attachment SET chat_message_id = $1 WHERE workspace_id = $2 AND task_id = $3 AND issue_id IS NULL AND comment_id IS NULL AND chat_message_id IS NULL RETURNING id ` type BindChatAttachmentsToMessageParams struct { ChatMessageID pgtype.UUID `json:"chat_message_id"` WorkspaceID pgtype.UUID `json:"workspace_id"` TaskID pgtype.UUID `json:"task_id"` } // Bind a chat agent's task-scoped attachments to the assistant reply it just // produced. Only rows still unclaimed by any owner (issue/comment/chat_message) // are eligible, so an attachment already linked elsewhere is never stolen. // Returns the bound ids for logging. func (q *Queries) BindChatAttachmentsToMessage(ctx context.Context, arg BindChatAttachmentsToMessageParams) ([]pgtype.UUID, error) { rows, err := q.db.Query(ctx, bindChatAttachmentsToMessage, arg.ChatMessageID, arg.WorkspaceID, arg.TaskID) if err != nil { return nil, err } defer rows.Close() items := []pgtype.UUID{} for rows.Next() { var id pgtype.UUID if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const countUnboundChatAttachmentsForTask = `-- name: CountUnboundChatAttachmentsForTask :one SELECT COUNT(*) FROM attachment WHERE workspace_id = $1 AND task_id = $2 AND issue_id IS NULL AND comment_id IS NULL AND chat_message_id IS NULL ` type CountUnboundChatAttachmentsForTaskParams struct { WorkspaceID pgtype.UUID `json:"workspace_id"` TaskID pgtype.UUID `json:"task_id"` } // How many attachments the agent produced for this chat task that are still // unbound to any owner. Lets CompleteTask create an assistant message (and // bind them) even when the agent's text output was empty but it uploaded files. func (q *Queries) CountUnboundChatAttachmentsForTask(ctx context.Context, arg CountUnboundChatAttachmentsForTaskParams) (int64, error) { row := q.db.QueryRow(ctx, countUnboundChatAttachmentsForTask, arg.WorkspaceID, arg.TaskID) var count int64 err := row.Scan(&count) return count, err } const createAttachment = `-- name: CreateAttachment :one INSERT INTO attachment ( id, workspace_id, issue_id, comment_id, chat_session_id, task_id, uploader_type, uploader_id, filename, url, content_type, size_bytes ) VALUES ( $1, $2, $9, $10, $11, $12, $3, $4, $5, $6, $7, $8 ) RETURNING id, workspace_id, issue_id, comment_id, uploader_type, uploader_id, filename, url, content_type, size_bytes, created_at, chat_session_id, chat_message_id, task_id ` type CreateAttachmentParams struct { ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` UploaderType string `json:"uploader_type"` UploaderID pgtype.UUID `json:"uploader_id"` Filename string `json:"filename"` Url string `json:"url"` ContentType string `json:"content_type"` SizeBytes int64 `json:"size_bytes"` IssueID pgtype.UUID `json:"issue_id"` CommentID pgtype.UUID `json:"comment_id"` ChatSessionID pgtype.UUID `json:"chat_session_id"` TaskID pgtype.UUID `json:"task_id"` } func (q *Queries) CreateAttachment(ctx context.Context, arg CreateAttachmentParams) (Attachment, error) { row := q.db.QueryRow(ctx, createAttachment, arg.ID, arg.WorkspaceID, arg.UploaderType, arg.UploaderID, arg.Filename, arg.Url, arg.ContentType, arg.SizeBytes, arg.IssueID, arg.CommentID, arg.ChatSessionID, arg.TaskID, ) var i Attachment err := row.Scan( &i.ID, &i.WorkspaceID, &i.IssueID, &i.CommentID, &i.UploaderType, &i.UploaderID, &i.Filename, &i.Url, &i.ContentType, &i.SizeBytes, &i.CreatedAt, &i.ChatSessionID, &i.ChatMessageID, &i.TaskID, ) return i, err } const deleteAttachment = `-- name: DeleteAttachment :exec DELETE FROM attachment WHERE id = $1 AND workspace_id = $2 ` type DeleteAttachmentParams struct { ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` } func (q *Queries) DeleteAttachment(ctx context.Context, arg DeleteAttachmentParams) error { _, err := q.db.Exec(ctx, deleteAttachment, arg.ID, arg.WorkspaceID) return err } const detachAttachmentsFromUserChatMessageByTask = `-- name: DetachAttachmentsFromUserChatMessageByTask :many UPDATE attachment SET chat_message_id = NULL WHERE chat_message_id IN ( SELECT id FROM chat_message WHERE chat_message.task_id = $1 AND role = 'user' ) RETURNING id, workspace_id, issue_id, comment_id, uploader_type, uploader_id, filename, url, content_type, size_bytes, created_at, chat_session_id, chat_message_id, task_id ` // When an empty chat task is cancelled, its user message is deleted. The // attachment FK is ON DELETE CASCADE, so without this the bound rows would be // destroyed and a restored draft could never re-bind them. Detach first // (chat_message_id -> NULL, keep chat_session_id) so the rows survive as // workspace/session-scoped unattached attachments and re-send can re-link them. func (q *Queries) DetachAttachmentsFromUserChatMessageByTask(ctx context.Context, taskID pgtype.UUID) ([]Attachment, error) { rows, err := q.db.Query(ctx, detachAttachmentsFromUserChatMessageByTask, taskID) if err != nil { return nil, err } defer rows.Close() items := []Attachment{} for rows.Next() { var i Attachment if err := rows.Scan( &i.ID, &i.WorkspaceID, &i.IssueID, &i.CommentID, &i.UploaderType, &i.UploaderID, &i.Filename, &i.Url, &i.ContentType, &i.SizeBytes, &i.CreatedAt, &i.ChatSessionID, &i.ChatMessageID, &i.TaskID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getAttachment = `-- name: GetAttachment :one SELECT id, workspace_id, issue_id, comment_id, uploader_type, uploader_id, filename, url, content_type, size_bytes, created_at, chat_session_id, chat_message_id, task_id FROM attachment WHERE id = $1 AND workspace_id = $2 ` type GetAttachmentParams struct { ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` } func (q *Queries) GetAttachment(ctx context.Context, arg GetAttachmentParams) (Attachment, error) { row := q.db.QueryRow(ctx, getAttachment, arg.ID, arg.WorkspaceID) var i Attachment err := row.Scan( &i.ID, &i.WorkspaceID, &i.IssueID, &i.CommentID, &i.UploaderType, &i.UploaderID, &i.Filename, &i.Url, &i.ContentType, &i.SizeBytes, &i.CreatedAt, &i.ChatSessionID, &i.ChatMessageID, &i.TaskID, ) return i, err } const getAttachmentByIDOnly = `-- name: GetAttachmentByIDOnly :one SELECT id, workspace_id, issue_id, comment_id, uploader_type, uploader_id, filename, url, content_type, size_bytes, created_at, chat_session_id, chat_message_id, task_id FROM attachment WHERE id = $1 ` // Used by the download endpoint, which derives workspace context from the // attachment row itself rather than from request headers/query params. The // caller still has to verify the requester is a member of the returned // workspace_id before serving the bytes — this query is access-neutral on // purpose so a self-contained URL like /api/attachments/{id}/download can // work as a native /