You've already forked agentic-coding-workflow
feat(chat): sqlc queries for conversations/messages/attachments/templates/endpoints/models/usage
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
-- name: InsertAttachment :one
|
||||||
|
INSERT INTO message_attachments (id, user_id, message_id, filename, mime_type, size_bytes, sha256, storage_path)
|
||||||
|
VALUES ($1, $2, NULL, $3, $4, $5, $6, $7)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetAttachment :one
|
||||||
|
SELECT * FROM message_attachments WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: ListAttachmentsForMessage :many
|
||||||
|
SELECT * FROM message_attachments WHERE message_id = $1 ORDER BY created_at ASC;
|
||||||
|
|
||||||
|
-- name: ListOrphanAttachmentsForUser :many
|
||||||
|
SELECT * FROM message_attachments
|
||||||
|
WHERE user_id = $1 AND message_id IS NULL AND id = ANY($2::uuid[]);
|
||||||
|
|
||||||
|
-- name: AttachToMessage :exec
|
||||||
|
UPDATE message_attachments SET message_id = $2 WHERE id = ANY($1::uuid[]);
|
||||||
|
|
||||||
|
-- name: DeleteAttachment :exec
|
||||||
|
DELETE FROM message_attachments WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: ListExpiredOrphans :many
|
||||||
|
SELECT id, storage_path FROM message_attachments
|
||||||
|
WHERE message_id IS NULL AND created_at < NOW() - ($1::interval);
|
||||||
|
|
||||||
|
-- name: ListAttachmentsForSoftDeletedConversations :many
|
||||||
|
SELECT a.id, a.storage_path
|
||||||
|
FROM message_attachments a
|
||||||
|
JOIN messages m ON m.id = a.message_id
|
||||||
|
JOIN conversations c ON c.id = m.conversation_id
|
||||||
|
WHERE c.deleted_at IS NOT NULL
|
||||||
|
AND c.deleted_at < NOW() - ($1::interval);
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
-- name: InsertConversation :one
|
||||||
|
INSERT INTO conversations (id, user_id, project_id, workspace_id, issue_id, model_id, system_prompt, title)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetConversation :one
|
||||||
|
SELECT * FROM conversations WHERE id = $1 AND deleted_at IS NULL;
|
||||||
|
|
||||||
|
-- name: ListConversationsByUser :many
|
||||||
|
SELECT * FROM conversations
|
||||||
|
WHERE user_id = $1 AND deleted_at IS NULL
|
||||||
|
AND ($2::uuid IS NULL OR project_id = $2)
|
||||||
|
AND ($3::uuid IS NULL OR workspace_id = $3)
|
||||||
|
AND ($4::uuid IS NULL OR issue_id = $4)
|
||||||
|
AND ($5::text = '' OR title ILIKE '%' || $5 || '%')
|
||||||
|
ORDER BY updated_at DESC
|
||||||
|
LIMIT $6;
|
||||||
|
|
||||||
|
-- name: UpdateConversationTitle :exec
|
||||||
|
UPDATE conversations SET title = $2, title_generated_at = NOW(), updated_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: SetConversationTitleManual :exec
|
||||||
|
UPDATE conversations SET title = $2, updated_at = NOW() WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: SoftDeleteConversation :exec
|
||||||
|
UPDATE conversations SET deleted_at = NOW(), updated_at = NOW()
|
||||||
|
WHERE id = $1 AND deleted_at IS NULL;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
-- name: InsertLLMEndpoint :one
|
||||||
|
INSERT INTO llm_endpoints (id, provider, display_name, base_url, api_key_encrypted, created_by)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetLLMEndpoint :one
|
||||||
|
SELECT * FROM llm_endpoints WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: ListLLMEndpoints :many
|
||||||
|
SELECT * FROM llm_endpoints ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- name: UpdateLLMEndpoint :exec
|
||||||
|
UPDATE llm_endpoints
|
||||||
|
SET display_name = COALESCE($2, display_name),
|
||||||
|
base_url = COALESCE($3, base_url),
|
||||||
|
api_key_encrypted = COALESCE($4, api_key_encrypted),
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: DeleteLLMEndpoint :exec
|
||||||
|
DELETE FROM llm_endpoints WHERE id = $1;
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
-- name: InsertMessage :one
|
||||||
|
INSERT INTO messages (conversation_id, role, content, status)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetMessage :one
|
||||||
|
SELECT * FROM messages WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: ListMessagesByConversation :many
|
||||||
|
SELECT * FROM messages
|
||||||
|
WHERE conversation_id = $1
|
||||||
|
AND ($2::bigint = 0 OR id < $2)
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT $3;
|
||||||
|
|
||||||
|
-- name: ListMessagesAscending :many
|
||||||
|
SELECT * FROM messages WHERE conversation_id = $1 ORDER BY id ASC;
|
||||||
|
|
||||||
|
-- name: UpdateMessageOK :exec
|
||||||
|
UPDATE messages
|
||||||
|
SET content = $2, thinking = $3,
|
||||||
|
prompt_tokens = $4, completion_tokens = $5, thinking_tokens = $6,
|
||||||
|
status = 'ok', updated_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: UpdateMessageError :exec
|
||||||
|
UPDATE messages
|
||||||
|
SET status = 'error', error_message = $2, updated_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: UpdateMessageCancelled :exec
|
||||||
|
UPDATE messages
|
||||||
|
SET status = 'cancelled', updated_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: DeleteMessage :exec
|
||||||
|
DELETE FROM messages WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: GetFirstUserMessage :one
|
||||||
|
SELECT * FROM messages
|
||||||
|
WHERE conversation_id = $1 AND role = 'user'
|
||||||
|
ORDER BY id ASC LIMIT 1;
|
||||||
|
|
||||||
|
-- name: MarkPendingAsErrorOnStartup :exec
|
||||||
|
UPDATE messages
|
||||||
|
SET status = 'error', error_message = 'server restart', updated_at = NOW()
|
||||||
|
WHERE status = 'pending';
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
-- name: InsertLLMModel :one
|
||||||
|
INSERT INTO llm_models (
|
||||||
|
id, endpoint_id, model_id, display_name, capabilities,
|
||||||
|
context_window, max_output_tokens,
|
||||||
|
prompt_price_per_million_usd, completion_price_per_million_usd, thinking_price_per_million_usd,
|
||||||
|
is_title_generator, enabled, sort_order
|
||||||
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetLLMModel :one
|
||||||
|
SELECT * FROM llm_models WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: GetTitleGeneratorModel :one
|
||||||
|
SELECT * FROM llm_models WHERE is_title_generator = true AND enabled = true LIMIT 1;
|
||||||
|
|
||||||
|
-- name: ListLLMModels :many
|
||||||
|
SELECT * FROM llm_models
|
||||||
|
WHERE ($1::boolean = false) OR enabled = true
|
||||||
|
ORDER BY sort_order, display_name;
|
||||||
|
|
||||||
|
-- name: UpdateLLMModel :exec
|
||||||
|
UPDATE llm_models
|
||||||
|
SET display_name = COALESCE($2, display_name),
|
||||||
|
capabilities = COALESCE($3, capabilities),
|
||||||
|
context_window = COALESCE($4, context_window),
|
||||||
|
max_output_tokens = COALESCE($5, max_output_tokens),
|
||||||
|
prompt_price_per_million_usd = COALESCE($6, prompt_price_per_million_usd),
|
||||||
|
completion_price_per_million_usd = COALESCE($7, completion_price_per_million_usd),
|
||||||
|
thinking_price_per_million_usd = COALESCE($8, thinking_price_per_million_usd),
|
||||||
|
is_title_generator = COALESCE($9, is_title_generator),
|
||||||
|
enabled = COALESCE($10, enabled),
|
||||||
|
sort_order = COALESCE($11, sort_order),
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: DeleteLLMModel :exec
|
||||||
|
DELETE FROM llm_models WHERE id = $1;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- name: InsertPromptTemplate :one
|
||||||
|
INSERT INTO prompt_templates (id, name, content, scope, owner_id)
|
||||||
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetPromptTemplate :one
|
||||||
|
SELECT * FROM prompt_templates WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: ListPromptTemplatesForUser :many
|
||||||
|
SELECT * FROM prompt_templates
|
||||||
|
WHERE scope = 'system' OR (scope = 'user' AND owner_id = $1)
|
||||||
|
ORDER BY scope, name;
|
||||||
|
|
||||||
|
-- name: UpdatePromptTemplate :exec
|
||||||
|
UPDATE prompt_templates SET name = $2, content = $3, updated_at = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: DeletePromptTemplate :exec
|
||||||
|
DELETE FROM prompt_templates WHERE id = $1;
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
-- name: InsertUsage :exec
|
||||||
|
INSERT INTO llm_usage (
|
||||||
|
conversation_id, message_id, user_id, endpoint_id, model_id,
|
||||||
|
prompt_tokens, completion_tokens, thinking_tokens, cost_usd
|
||||||
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9);
|
||||||
|
|
||||||
|
-- name: SummarizeUsageByUser :many
|
||||||
|
SELECT user_id,
|
||||||
|
SUM(prompt_tokens)::int AS prompt_tokens,
|
||||||
|
SUM(completion_tokens)::int AS completion_tokens,
|
||||||
|
SUM(thinking_tokens)::int AS thinking_tokens,
|
||||||
|
SUM(cost_usd)::numeric AS cost_usd
|
||||||
|
FROM llm_usage
|
||||||
|
WHERE created_at >= $1 AND created_at < $2
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY cost_usd DESC;
|
||||||
|
|
||||||
|
-- name: SummarizeUsageByModel :many
|
||||||
|
SELECT model_id,
|
||||||
|
SUM(prompt_tokens)::int AS prompt_tokens,
|
||||||
|
SUM(completion_tokens)::int AS completion_tokens,
|
||||||
|
SUM(thinking_tokens)::int AS thinking_tokens,
|
||||||
|
SUM(cost_usd)::numeric AS cost_usd
|
||||||
|
FROM llm_usage
|
||||||
|
WHERE created_at >= $1 AND created_at < $2
|
||||||
|
GROUP BY model_id
|
||||||
|
ORDER BY cost_usd DESC;
|
||||||
|
|
||||||
|
-- name: SummarizeUsageByDay :many
|
||||||
|
SELECT date_trunc('day', created_at) AS day,
|
||||||
|
SUM(prompt_tokens)::int AS prompt_tokens,
|
||||||
|
SUM(completion_tokens)::int AS completion_tokens,
|
||||||
|
SUM(thinking_tokens)::int AS thinking_tokens,
|
||||||
|
SUM(cost_usd)::numeric AS cost_usd
|
||||||
|
FROM llm_usage
|
||||||
|
WHERE created_at >= $1 AND created_at < $2
|
||||||
|
GROUP BY day
|
||||||
|
ORDER BY day;
|
||||||
|
|
||||||
|
-- name: SummarizeUserDaily :many
|
||||||
|
SELECT date_trunc('day', created_at) AS day,
|
||||||
|
SUM(prompt_tokens)::int AS prompt_tokens,
|
||||||
|
SUM(completion_tokens)::int AS completion_tokens,
|
||||||
|
SUM(thinking_tokens)::int AS thinking_tokens,
|
||||||
|
SUM(cost_usd)::numeric AS cost_usd
|
||||||
|
FROM llm_usage
|
||||||
|
WHERE user_id = $1 AND created_at >= $2 AND created_at < $3
|
||||||
|
GROUP BY day
|
||||||
|
ORDER BY day;
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: attachments.sql
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const attachToMessage = `-- name: AttachToMessage :exec
|
||||||
|
UPDATE message_attachments SET message_id = $2 WHERE id = ANY($1::uuid[])
|
||||||
|
`
|
||||||
|
|
||||||
|
type AttachToMessageParams struct {
|
||||||
|
Column1 []pgtype.UUID `json:"column_1"`
|
||||||
|
MessageID *int64 `json:"message_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) AttachToMessage(ctx context.Context, arg AttachToMessageParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, attachToMessage, arg.Column1, arg.MessageID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAttachment = `-- name: DeleteAttachment :exec
|
||||||
|
DELETE FROM message_attachments WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteAttachment(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteAttachment, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAttachment = `-- name: GetAttachment :one
|
||||||
|
SELECT id, user_id, message_id, filename, mime_type, size_bytes, sha256, storage_path, created_at FROM message_attachments WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAttachment(ctx context.Context, id pgtype.UUID) (MessageAttachment, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getAttachment, id)
|
||||||
|
var i MessageAttachment
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.MessageID,
|
||||||
|
&i.Filename,
|
||||||
|
&i.MimeType,
|
||||||
|
&i.SizeBytes,
|
||||||
|
&i.Sha256,
|
||||||
|
&i.StoragePath,
|
||||||
|
&i.CreatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertAttachment = `-- name: InsertAttachment :one
|
||||||
|
INSERT INTO message_attachments (id, user_id, message_id, filename, mime_type, size_bytes, sha256, storage_path)
|
||||||
|
VALUES ($1, $2, NULL, $3, $4, $5, $6, $7)
|
||||||
|
RETURNING id, user_id, message_id, filename, mime_type, size_bytes, sha256, storage_path, created_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertAttachmentParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
MimeType string `json:"mime_type"`
|
||||||
|
SizeBytes int64 `json:"size_bytes"`
|
||||||
|
Sha256 string `json:"sha256"`
|
||||||
|
StoragePath string `json:"storage_path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertAttachment(ctx context.Context, arg InsertAttachmentParams) (MessageAttachment, error) {
|
||||||
|
row := q.db.QueryRow(ctx, insertAttachment,
|
||||||
|
arg.ID,
|
||||||
|
arg.UserID,
|
||||||
|
arg.Filename,
|
||||||
|
arg.MimeType,
|
||||||
|
arg.SizeBytes,
|
||||||
|
arg.Sha256,
|
||||||
|
arg.StoragePath,
|
||||||
|
)
|
||||||
|
var i MessageAttachment
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.MessageID,
|
||||||
|
&i.Filename,
|
||||||
|
&i.MimeType,
|
||||||
|
&i.SizeBytes,
|
||||||
|
&i.Sha256,
|
||||||
|
&i.StoragePath,
|
||||||
|
&i.CreatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listAttachmentsForMessage = `-- name: ListAttachmentsForMessage :many
|
||||||
|
SELECT id, user_id, message_id, filename, mime_type, size_bytes, sha256, storage_path, created_at FROM message_attachments WHERE message_id = $1 ORDER BY created_at ASC
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListAttachmentsForMessage(ctx context.Context, messageID *int64) ([]MessageAttachment, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listAttachmentsForMessage, messageID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []MessageAttachment
|
||||||
|
for rows.Next() {
|
||||||
|
var i MessageAttachment
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.MessageID,
|
||||||
|
&i.Filename,
|
||||||
|
&i.MimeType,
|
||||||
|
&i.SizeBytes,
|
||||||
|
&i.Sha256,
|
||||||
|
&i.StoragePath,
|
||||||
|
&i.CreatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listAttachmentsForSoftDeletedConversations = `-- name: ListAttachmentsForSoftDeletedConversations :many
|
||||||
|
SELECT a.id, a.storage_path
|
||||||
|
FROM message_attachments a
|
||||||
|
JOIN messages m ON m.id = a.message_id
|
||||||
|
JOIN conversations c ON c.id = m.conversation_id
|
||||||
|
WHERE c.deleted_at IS NOT NULL
|
||||||
|
AND c.deleted_at < NOW() - ($1::interval)
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListAttachmentsForSoftDeletedConversationsRow struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
StoragePath string `json:"storage_path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListAttachmentsForSoftDeletedConversations(ctx context.Context, dollar_1 pgtype.Interval) ([]ListAttachmentsForSoftDeletedConversationsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listAttachmentsForSoftDeletedConversations, dollar_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ListAttachmentsForSoftDeletedConversationsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i ListAttachmentsForSoftDeletedConversationsRow
|
||||||
|
if err := rows.Scan(&i.ID, &i.StoragePath); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listExpiredOrphans = `-- name: ListExpiredOrphans :many
|
||||||
|
SELECT id, storage_path FROM message_attachments
|
||||||
|
WHERE message_id IS NULL AND created_at < NOW() - ($1::interval)
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListExpiredOrphansRow struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
StoragePath string `json:"storage_path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListExpiredOrphans(ctx context.Context, dollar_1 pgtype.Interval) ([]ListExpiredOrphansRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listExpiredOrphans, dollar_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ListExpiredOrphansRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i ListExpiredOrphansRow
|
||||||
|
if err := rows.Scan(&i.ID, &i.StoragePath); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listOrphanAttachmentsForUser = `-- name: ListOrphanAttachmentsForUser :many
|
||||||
|
SELECT id, user_id, message_id, filename, mime_type, size_bytes, sha256, storage_path, created_at FROM message_attachments
|
||||||
|
WHERE user_id = $1 AND message_id IS NULL AND id = ANY($2::uuid[])
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListOrphanAttachmentsForUserParams struct {
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
Column2 []pgtype.UUID `json:"column_2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListOrphanAttachmentsForUser(ctx context.Context, arg ListOrphanAttachmentsForUserParams) ([]MessageAttachment, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listOrphanAttachmentsForUser, arg.UserID, arg.Column2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []MessageAttachment
|
||||||
|
for rows.Next() {
|
||||||
|
var i MessageAttachment
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.MessageID,
|
||||||
|
&i.Filename,
|
||||||
|
&i.MimeType,
|
||||||
|
&i.SizeBytes,
|
||||||
|
&i.Sha256,
|
||||||
|
&i.StoragePath,
|
||||||
|
&i.CreatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: conversations.sql
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const getConversation = `-- name: GetConversation :one
|
||||||
|
SELECT id, user_id, project_id, workspace_id, issue_id, model_id, system_prompt, title, title_generated_at, created_at, updated_at, deleted_at FROM conversations WHERE id = $1 AND deleted_at IS NULL
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetConversation(ctx context.Context, id pgtype.UUID) (Conversation, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getConversation, id)
|
||||||
|
var i Conversation
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.WorkspaceID,
|
||||||
|
&i.IssueID,
|
||||||
|
&i.ModelID,
|
||||||
|
&i.SystemPrompt,
|
||||||
|
&i.Title,
|
||||||
|
&i.TitleGeneratedAt,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.DeletedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertConversation = `-- name: InsertConversation :one
|
||||||
|
INSERT INTO conversations (id, user_id, project_id, workspace_id, issue_id, model_id, system_prompt, title)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
|
RETURNING id, user_id, project_id, workspace_id, issue_id, model_id, system_prompt, title, title_generated_at, created_at, updated_at, deleted_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertConversationParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
ProjectID pgtype.UUID `json:"project_id"`
|
||||||
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
||||||
|
IssueID pgtype.UUID `json:"issue_id"`
|
||||||
|
ModelID pgtype.UUID `json:"model_id"`
|
||||||
|
SystemPrompt string `json:"system_prompt"`
|
||||||
|
Title *string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertConversation(ctx context.Context, arg InsertConversationParams) (Conversation, error) {
|
||||||
|
row := q.db.QueryRow(ctx, insertConversation,
|
||||||
|
arg.ID,
|
||||||
|
arg.UserID,
|
||||||
|
arg.ProjectID,
|
||||||
|
arg.WorkspaceID,
|
||||||
|
arg.IssueID,
|
||||||
|
arg.ModelID,
|
||||||
|
arg.SystemPrompt,
|
||||||
|
arg.Title,
|
||||||
|
)
|
||||||
|
var i Conversation
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.WorkspaceID,
|
||||||
|
&i.IssueID,
|
||||||
|
&i.ModelID,
|
||||||
|
&i.SystemPrompt,
|
||||||
|
&i.Title,
|
||||||
|
&i.TitleGeneratedAt,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.DeletedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listConversationsByUser = `-- name: ListConversationsByUser :many
|
||||||
|
SELECT id, user_id, project_id, workspace_id, issue_id, model_id, system_prompt, title, title_generated_at, created_at, updated_at, deleted_at FROM conversations
|
||||||
|
WHERE user_id = $1 AND deleted_at IS NULL
|
||||||
|
AND ($2::uuid IS NULL OR project_id = $2)
|
||||||
|
AND ($3::uuid IS NULL OR workspace_id = $3)
|
||||||
|
AND ($4::uuid IS NULL OR issue_id = $4)
|
||||||
|
AND ($5::text = '' OR title ILIKE '%' || $5 || '%')
|
||||||
|
ORDER BY updated_at DESC
|
||||||
|
LIMIT $6
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListConversationsByUserParams struct {
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
Column2 pgtype.UUID `json:"column_2"`
|
||||||
|
Column3 pgtype.UUID `json:"column_3"`
|
||||||
|
Column4 pgtype.UUID `json:"column_4"`
|
||||||
|
Column5 string `json:"column_5"`
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListConversationsByUser(ctx context.Context, arg ListConversationsByUserParams) ([]Conversation, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listConversationsByUser,
|
||||||
|
arg.UserID,
|
||||||
|
arg.Column2,
|
||||||
|
arg.Column3,
|
||||||
|
arg.Column4,
|
||||||
|
arg.Column5,
|
||||||
|
arg.Limit,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Conversation
|
||||||
|
for rows.Next() {
|
||||||
|
var i Conversation
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.WorkspaceID,
|
||||||
|
&i.IssueID,
|
||||||
|
&i.ModelID,
|
||||||
|
&i.SystemPrompt,
|
||||||
|
&i.Title,
|
||||||
|
&i.TitleGeneratedAt,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.DeletedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const setConversationTitleManual = `-- name: SetConversationTitleManual :exec
|
||||||
|
UPDATE conversations SET title = $2, updated_at = NOW() WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type SetConversationTitleManualParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Title *string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SetConversationTitleManual(ctx context.Context, arg SetConversationTitleManualParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, setConversationTitleManual, arg.ID, arg.Title)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const softDeleteConversation = `-- name: SoftDeleteConversation :exec
|
||||||
|
UPDATE conversations SET deleted_at = NOW(), updated_at = NOW()
|
||||||
|
WHERE id = $1 AND deleted_at IS NULL
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) SoftDeleteConversation(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, softDeleteConversation, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateConversationTitle = `-- name: UpdateConversationTitle :exec
|
||||||
|
UPDATE conversations SET title = $2, title_generated_at = NOW(), updated_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateConversationTitleParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Title *string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateConversationTitle(ctx context.Context, arg UpdateConversationTitleParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateConversationTitle, arg.ID, arg.Title)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: endpoints.sql
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const deleteLLMEndpoint = `-- name: DeleteLLMEndpoint :exec
|
||||||
|
DELETE FROM llm_endpoints WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteLLMEndpoint(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteLLMEndpoint, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLLMEndpoint = `-- name: GetLLMEndpoint :one
|
||||||
|
SELECT id, provider, display_name, base_url, api_key_encrypted, created_by, created_at, updated_at FROM llm_endpoints WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetLLMEndpoint(ctx context.Context, id pgtype.UUID) (LlmEndpoint, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getLLMEndpoint, id)
|
||||||
|
var i LlmEndpoint
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Provider,
|
||||||
|
&i.DisplayName,
|
||||||
|
&i.BaseUrl,
|
||||||
|
&i.ApiKeyEncrypted,
|
||||||
|
&i.CreatedBy,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertLLMEndpoint = `-- name: InsertLLMEndpoint :one
|
||||||
|
INSERT INTO llm_endpoints (id, provider, display_name, base_url, api_key_encrypted, created_by)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
|
RETURNING id, provider, display_name, base_url, api_key_encrypted, created_by, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertLLMEndpointParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
BaseUrl string `json:"base_url"`
|
||||||
|
ApiKeyEncrypted []byte `json:"api_key_encrypted"`
|
||||||
|
CreatedBy pgtype.UUID `json:"created_by"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertLLMEndpoint(ctx context.Context, arg InsertLLMEndpointParams) (LlmEndpoint, error) {
|
||||||
|
row := q.db.QueryRow(ctx, insertLLMEndpoint,
|
||||||
|
arg.ID,
|
||||||
|
arg.Provider,
|
||||||
|
arg.DisplayName,
|
||||||
|
arg.BaseUrl,
|
||||||
|
arg.ApiKeyEncrypted,
|
||||||
|
arg.CreatedBy,
|
||||||
|
)
|
||||||
|
var i LlmEndpoint
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Provider,
|
||||||
|
&i.DisplayName,
|
||||||
|
&i.BaseUrl,
|
||||||
|
&i.ApiKeyEncrypted,
|
||||||
|
&i.CreatedBy,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listLLMEndpoints = `-- name: ListLLMEndpoints :many
|
||||||
|
SELECT id, provider, display_name, base_url, api_key_encrypted, created_by, created_at, updated_at FROM llm_endpoints ORDER BY created_at DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListLLMEndpoints(ctx context.Context) ([]LlmEndpoint, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listLLMEndpoints)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []LlmEndpoint
|
||||||
|
for rows.Next() {
|
||||||
|
var i LlmEndpoint
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Provider,
|
||||||
|
&i.DisplayName,
|
||||||
|
&i.BaseUrl,
|
||||||
|
&i.ApiKeyEncrypted,
|
||||||
|
&i.CreatedBy,
|
||||||
|
&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 updateLLMEndpoint = `-- name: UpdateLLMEndpoint :exec
|
||||||
|
UPDATE llm_endpoints
|
||||||
|
SET display_name = COALESCE($2, display_name),
|
||||||
|
base_url = COALESCE($3, base_url),
|
||||||
|
api_key_encrypted = COALESCE($4, api_key_encrypted),
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateLLMEndpointParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
BaseUrl string `json:"base_url"`
|
||||||
|
ApiKeyEncrypted []byte `json:"api_key_encrypted"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateLLMEndpoint(ctx context.Context, arg UpdateLLMEndpointParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateLLMEndpoint,
|
||||||
|
arg.ID,
|
||||||
|
arg.DisplayName,
|
||||||
|
arg.BaseUrl,
|
||||||
|
arg.ApiKeyEncrypted,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: messages.sql
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const deleteMessage = `-- name: DeleteMessage :exec
|
||||||
|
DELETE FROM messages WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteMessage(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteMessage, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFirstUserMessage = `-- name: GetFirstUserMessage :one
|
||||||
|
SELECT id, conversation_id, role, content, thinking, tool_calls, status, error_message, prompt_tokens, completion_tokens, thinking_tokens, created_at, updated_at FROM messages
|
||||||
|
WHERE conversation_id = $1 AND role = 'user'
|
||||||
|
ORDER BY id ASC LIMIT 1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetFirstUserMessage(ctx context.Context, conversationID pgtype.UUID) (Message, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getFirstUserMessage, conversationID)
|
||||||
|
var i Message
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ConversationID,
|
||||||
|
&i.Role,
|
||||||
|
&i.Content,
|
||||||
|
&i.Thinking,
|
||||||
|
&i.ToolCalls,
|
||||||
|
&i.Status,
|
||||||
|
&i.ErrorMessage,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMessage = `-- name: GetMessage :one
|
||||||
|
SELECT id, conversation_id, role, content, thinking, tool_calls, status, error_message, prompt_tokens, completion_tokens, thinking_tokens, created_at, updated_at FROM messages WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetMessage(ctx context.Context, id int64) (Message, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getMessage, id)
|
||||||
|
var i Message
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ConversationID,
|
||||||
|
&i.Role,
|
||||||
|
&i.Content,
|
||||||
|
&i.Thinking,
|
||||||
|
&i.ToolCalls,
|
||||||
|
&i.Status,
|
||||||
|
&i.ErrorMessage,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertMessage = `-- name: InsertMessage :one
|
||||||
|
INSERT INTO messages (conversation_id, role, content, status)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
RETURNING id, conversation_id, role, content, thinking, tool_calls, status, error_message, prompt_tokens, completion_tokens, thinking_tokens, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertMessageParams struct {
|
||||||
|
ConversationID pgtype.UUID `json:"conversation_id"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertMessage(ctx context.Context, arg InsertMessageParams) (Message, error) {
|
||||||
|
row := q.db.QueryRow(ctx, insertMessage,
|
||||||
|
arg.ConversationID,
|
||||||
|
arg.Role,
|
||||||
|
arg.Content,
|
||||||
|
arg.Status,
|
||||||
|
)
|
||||||
|
var i Message
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ConversationID,
|
||||||
|
&i.Role,
|
||||||
|
&i.Content,
|
||||||
|
&i.Thinking,
|
||||||
|
&i.ToolCalls,
|
||||||
|
&i.Status,
|
||||||
|
&i.ErrorMessage,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listMessagesAscending = `-- name: ListMessagesAscending :many
|
||||||
|
SELECT id, conversation_id, role, content, thinking, tool_calls, status, error_message, prompt_tokens, completion_tokens, thinking_tokens, created_at, updated_at FROM messages WHERE conversation_id = $1 ORDER BY id ASC
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListMessagesAscending(ctx context.Context, conversationID pgtype.UUID) ([]Message, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listMessagesAscending, conversationID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Message
|
||||||
|
for rows.Next() {
|
||||||
|
var i Message
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ConversationID,
|
||||||
|
&i.Role,
|
||||||
|
&i.Content,
|
||||||
|
&i.Thinking,
|
||||||
|
&i.ToolCalls,
|
||||||
|
&i.Status,
|
||||||
|
&i.ErrorMessage,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&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 listMessagesByConversation = `-- name: ListMessagesByConversation :many
|
||||||
|
SELECT id, conversation_id, role, content, thinking, tool_calls, status, error_message, prompt_tokens, completion_tokens, thinking_tokens, created_at, updated_at FROM messages
|
||||||
|
WHERE conversation_id = $1
|
||||||
|
AND ($2::bigint = 0 OR id < $2)
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListMessagesByConversationParams struct {
|
||||||
|
ConversationID pgtype.UUID `json:"conversation_id"`
|
||||||
|
Column2 int64 `json:"column_2"`
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListMessagesByConversation(ctx context.Context, arg ListMessagesByConversationParams) ([]Message, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listMessagesByConversation, arg.ConversationID, arg.Column2, arg.Limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Message
|
||||||
|
for rows.Next() {
|
||||||
|
var i Message
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ConversationID,
|
||||||
|
&i.Role,
|
||||||
|
&i.Content,
|
||||||
|
&i.Thinking,
|
||||||
|
&i.ToolCalls,
|
||||||
|
&i.Status,
|
||||||
|
&i.ErrorMessage,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&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 markPendingAsErrorOnStartup = `-- name: MarkPendingAsErrorOnStartup :exec
|
||||||
|
UPDATE messages
|
||||||
|
SET status = 'error', error_message = 'server restart', updated_at = NOW()
|
||||||
|
WHERE status = 'pending'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) MarkPendingAsErrorOnStartup(ctx context.Context) error {
|
||||||
|
_, err := q.db.Exec(ctx, markPendingAsErrorOnStartup)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateMessageCancelled = `-- name: UpdateMessageCancelled :exec
|
||||||
|
UPDATE messages
|
||||||
|
SET status = 'cancelled', updated_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) UpdateMessageCancelled(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateMessageCancelled, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateMessageError = `-- name: UpdateMessageError :exec
|
||||||
|
UPDATE messages
|
||||||
|
SET status = 'error', error_message = $2, updated_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateMessageErrorParams struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ErrorMessage *string `json:"error_message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateMessageError(ctx context.Context, arg UpdateMessageErrorParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateMessageError, arg.ID, arg.ErrorMessage)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateMessageOK = `-- name: UpdateMessageOK :exec
|
||||||
|
UPDATE messages
|
||||||
|
SET content = $2, thinking = $3,
|
||||||
|
prompt_tokens = $4, completion_tokens = $5, thinking_tokens = $6,
|
||||||
|
status = 'ok', updated_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateMessageOKParams struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Thinking *string `json:"thinking"`
|
||||||
|
PromptTokens *int32 `json:"prompt_tokens"`
|
||||||
|
CompletionTokens *int32 `json:"completion_tokens"`
|
||||||
|
ThinkingTokens *int32 `json:"thinking_tokens"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateMessageOK(ctx context.Context, arg UpdateMessageOKParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateMessageOK,
|
||||||
|
arg.ID,
|
||||||
|
arg.Content,
|
||||||
|
arg.Thinking,
|
||||||
|
arg.PromptTokens,
|
||||||
|
arg.CompletionTokens,
|
||||||
|
arg.ThinkingTokens,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
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 Conversation struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
ProjectID pgtype.UUID `json:"project_id"`
|
||||||
|
WorkspaceID pgtype.UUID `json:"workspace_id"`
|
||||||
|
IssueID pgtype.UUID `json:"issue_id"`
|
||||||
|
ModelID pgtype.UUID `json:"model_id"`
|
||||||
|
SystemPrompt string `json:"system_prompt"`
|
||||||
|
Title *string `json:"title"`
|
||||||
|
TitleGeneratedAt pgtype.Timestamptz `json:"title_generated_at"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
DeletedAt pgtype.Timestamptz `json:"deleted_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 LlmEndpoint struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
BaseUrl string `json:"base_url"`
|
||||||
|
ApiKeyEncrypted []byte `json:"api_key_encrypted"`
|
||||||
|
CreatedBy pgtype.UUID `json:"created_by"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LlmModel struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
EndpointID pgtype.UUID `json:"endpoint_id"`
|
||||||
|
ModelID string `json:"model_id"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
Capabilities []byte `json:"capabilities"`
|
||||||
|
ContextWindow int32 `json:"context_window"`
|
||||||
|
MaxOutputTokens int32 `json:"max_output_tokens"`
|
||||||
|
PromptPricePerMillionUsd pgtype.Numeric `json:"prompt_price_per_million_usd"`
|
||||||
|
CompletionPricePerMillionUsd pgtype.Numeric `json:"completion_price_per_million_usd"`
|
||||||
|
ThinkingPricePerMillionUsd pgtype.Numeric `json:"thinking_price_per_million_usd"`
|
||||||
|
IsTitleGenerator bool `json:"is_title_generator"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LlmUsage struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ConversationID pgtype.UUID `json:"conversation_id"`
|
||||||
|
MessageID int64 `json:"message_id"`
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
EndpointID pgtype.UUID `json:"endpoint_id"`
|
||||||
|
ModelID pgtype.UUID `json:"model_id"`
|
||||||
|
PromptTokens int32 `json:"prompt_tokens"`
|
||||||
|
CompletionTokens int32 `json:"completion_tokens"`
|
||||||
|
ThinkingTokens int32 `json:"thinking_tokens"`
|
||||||
|
CostUsd pgtype.Numeric `json:"cost_usd"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ConversationID pgtype.UUID `json:"conversation_id"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Thinking *string `json:"thinking"`
|
||||||
|
ToolCalls []byte `json:"tool_calls"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
ErrorMessage *string `json:"error_message"`
|
||||||
|
PromptTokens *int32 `json:"prompt_tokens"`
|
||||||
|
CompletionTokens *int32 `json:"completion_tokens"`
|
||||||
|
ThinkingTokens *int32 `json:"thinking_tokens"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageAttachment struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
MessageID *int64 `json:"message_id"`
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
MimeType string `json:"mime_type"`
|
||||||
|
SizeBytes int64 `json:"size_bytes"`
|
||||||
|
Sha256 string `json:"sha256"`
|
||||||
|
StoragePath string `json:"storage_path"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 PromptTemplate struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
OwnerID pgtype.UUID `json:"owner_id"`
|
||||||
|
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"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: models.sql
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const deleteLLMModel = `-- name: DeleteLLMModel :exec
|
||||||
|
DELETE FROM llm_models WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteLLMModel(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteLLMModel, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLLMModel = `-- name: GetLLMModel :one
|
||||||
|
SELECT id, endpoint_id, model_id, display_name, capabilities, context_window, max_output_tokens, prompt_price_per_million_usd, completion_price_per_million_usd, thinking_price_per_million_usd, is_title_generator, enabled, sort_order, created_at, updated_at FROM llm_models WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetLLMModel(ctx context.Context, id pgtype.UUID) (LlmModel, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getLLMModel, id)
|
||||||
|
var i LlmModel
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.EndpointID,
|
||||||
|
&i.ModelID,
|
||||||
|
&i.DisplayName,
|
||||||
|
&i.Capabilities,
|
||||||
|
&i.ContextWindow,
|
||||||
|
&i.MaxOutputTokens,
|
||||||
|
&i.PromptPricePerMillionUsd,
|
||||||
|
&i.CompletionPricePerMillionUsd,
|
||||||
|
&i.ThinkingPricePerMillionUsd,
|
||||||
|
&i.IsTitleGenerator,
|
||||||
|
&i.Enabled,
|
||||||
|
&i.SortOrder,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTitleGeneratorModel = `-- name: GetTitleGeneratorModel :one
|
||||||
|
SELECT id, endpoint_id, model_id, display_name, capabilities, context_window, max_output_tokens, prompt_price_per_million_usd, completion_price_per_million_usd, thinking_price_per_million_usd, is_title_generator, enabled, sort_order, created_at, updated_at FROM llm_models WHERE is_title_generator = true AND enabled = true LIMIT 1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetTitleGeneratorModel(ctx context.Context) (LlmModel, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getTitleGeneratorModel)
|
||||||
|
var i LlmModel
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.EndpointID,
|
||||||
|
&i.ModelID,
|
||||||
|
&i.DisplayName,
|
||||||
|
&i.Capabilities,
|
||||||
|
&i.ContextWindow,
|
||||||
|
&i.MaxOutputTokens,
|
||||||
|
&i.PromptPricePerMillionUsd,
|
||||||
|
&i.CompletionPricePerMillionUsd,
|
||||||
|
&i.ThinkingPricePerMillionUsd,
|
||||||
|
&i.IsTitleGenerator,
|
||||||
|
&i.Enabled,
|
||||||
|
&i.SortOrder,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertLLMModel = `-- name: InsertLLMModel :one
|
||||||
|
INSERT INTO llm_models (
|
||||||
|
id, endpoint_id, model_id, display_name, capabilities,
|
||||||
|
context_window, max_output_tokens,
|
||||||
|
prompt_price_per_million_usd, completion_price_per_million_usd, thinking_price_per_million_usd,
|
||||||
|
is_title_generator, enabled, sort_order
|
||||||
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
|
||||||
|
RETURNING id, endpoint_id, model_id, display_name, capabilities, context_window, max_output_tokens, prompt_price_per_million_usd, completion_price_per_million_usd, thinking_price_per_million_usd, is_title_generator, enabled, sort_order, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertLLMModelParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
EndpointID pgtype.UUID `json:"endpoint_id"`
|
||||||
|
ModelID string `json:"model_id"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
Capabilities []byte `json:"capabilities"`
|
||||||
|
ContextWindow int32 `json:"context_window"`
|
||||||
|
MaxOutputTokens int32 `json:"max_output_tokens"`
|
||||||
|
PromptPricePerMillionUsd pgtype.Numeric `json:"prompt_price_per_million_usd"`
|
||||||
|
CompletionPricePerMillionUsd pgtype.Numeric `json:"completion_price_per_million_usd"`
|
||||||
|
ThinkingPricePerMillionUsd pgtype.Numeric `json:"thinking_price_per_million_usd"`
|
||||||
|
IsTitleGenerator bool `json:"is_title_generator"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertLLMModel(ctx context.Context, arg InsertLLMModelParams) (LlmModel, error) {
|
||||||
|
row := q.db.QueryRow(ctx, insertLLMModel,
|
||||||
|
arg.ID,
|
||||||
|
arg.EndpointID,
|
||||||
|
arg.ModelID,
|
||||||
|
arg.DisplayName,
|
||||||
|
arg.Capabilities,
|
||||||
|
arg.ContextWindow,
|
||||||
|
arg.MaxOutputTokens,
|
||||||
|
arg.PromptPricePerMillionUsd,
|
||||||
|
arg.CompletionPricePerMillionUsd,
|
||||||
|
arg.ThinkingPricePerMillionUsd,
|
||||||
|
arg.IsTitleGenerator,
|
||||||
|
arg.Enabled,
|
||||||
|
arg.SortOrder,
|
||||||
|
)
|
||||||
|
var i LlmModel
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.EndpointID,
|
||||||
|
&i.ModelID,
|
||||||
|
&i.DisplayName,
|
||||||
|
&i.Capabilities,
|
||||||
|
&i.ContextWindow,
|
||||||
|
&i.MaxOutputTokens,
|
||||||
|
&i.PromptPricePerMillionUsd,
|
||||||
|
&i.CompletionPricePerMillionUsd,
|
||||||
|
&i.ThinkingPricePerMillionUsd,
|
||||||
|
&i.IsTitleGenerator,
|
||||||
|
&i.Enabled,
|
||||||
|
&i.SortOrder,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listLLMModels = `-- name: ListLLMModels :many
|
||||||
|
SELECT id, endpoint_id, model_id, display_name, capabilities, context_window, max_output_tokens, prompt_price_per_million_usd, completion_price_per_million_usd, thinking_price_per_million_usd, is_title_generator, enabled, sort_order, created_at, updated_at FROM llm_models
|
||||||
|
WHERE ($1::boolean = false) OR enabled = true
|
||||||
|
ORDER BY sort_order, display_name
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListLLMModels(ctx context.Context, dollar_1 bool) ([]LlmModel, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listLLMModels, dollar_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []LlmModel
|
||||||
|
for rows.Next() {
|
||||||
|
var i LlmModel
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.EndpointID,
|
||||||
|
&i.ModelID,
|
||||||
|
&i.DisplayName,
|
||||||
|
&i.Capabilities,
|
||||||
|
&i.ContextWindow,
|
||||||
|
&i.MaxOutputTokens,
|
||||||
|
&i.PromptPricePerMillionUsd,
|
||||||
|
&i.CompletionPricePerMillionUsd,
|
||||||
|
&i.ThinkingPricePerMillionUsd,
|
||||||
|
&i.IsTitleGenerator,
|
||||||
|
&i.Enabled,
|
||||||
|
&i.SortOrder,
|
||||||
|
&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 updateLLMModel = `-- name: UpdateLLMModel :exec
|
||||||
|
UPDATE llm_models
|
||||||
|
SET display_name = COALESCE($2, display_name),
|
||||||
|
capabilities = COALESCE($3, capabilities),
|
||||||
|
context_window = COALESCE($4, context_window),
|
||||||
|
max_output_tokens = COALESCE($5, max_output_tokens),
|
||||||
|
prompt_price_per_million_usd = COALESCE($6, prompt_price_per_million_usd),
|
||||||
|
completion_price_per_million_usd = COALESCE($7, completion_price_per_million_usd),
|
||||||
|
thinking_price_per_million_usd = COALESCE($8, thinking_price_per_million_usd),
|
||||||
|
is_title_generator = COALESCE($9, is_title_generator),
|
||||||
|
enabled = COALESCE($10, enabled),
|
||||||
|
sort_order = COALESCE($11, sort_order),
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateLLMModelParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
Capabilities []byte `json:"capabilities"`
|
||||||
|
ContextWindow int32 `json:"context_window"`
|
||||||
|
MaxOutputTokens int32 `json:"max_output_tokens"`
|
||||||
|
PromptPricePerMillionUsd pgtype.Numeric `json:"prompt_price_per_million_usd"`
|
||||||
|
CompletionPricePerMillionUsd pgtype.Numeric `json:"completion_price_per_million_usd"`
|
||||||
|
ThinkingPricePerMillionUsd pgtype.Numeric `json:"thinking_price_per_million_usd"`
|
||||||
|
IsTitleGenerator bool `json:"is_title_generator"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateLLMModel(ctx context.Context, arg UpdateLLMModelParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateLLMModel,
|
||||||
|
arg.ID,
|
||||||
|
arg.DisplayName,
|
||||||
|
arg.Capabilities,
|
||||||
|
arg.ContextWindow,
|
||||||
|
arg.MaxOutputTokens,
|
||||||
|
arg.PromptPricePerMillionUsd,
|
||||||
|
arg.CompletionPricePerMillionUsd,
|
||||||
|
arg.ThinkingPricePerMillionUsd,
|
||||||
|
arg.IsTitleGenerator,
|
||||||
|
arg.Enabled,
|
||||||
|
arg.SortOrder,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: templates.sql
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const deletePromptTemplate = `-- name: DeletePromptTemplate :exec
|
||||||
|
DELETE FROM prompt_templates WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeletePromptTemplate(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deletePromptTemplate, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPromptTemplate = `-- name: GetPromptTemplate :one
|
||||||
|
SELECT id, name, content, scope, owner_id, created_at, updated_at FROM prompt_templates WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetPromptTemplate(ctx context.Context, id pgtype.UUID) (PromptTemplate, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getPromptTemplate, id)
|
||||||
|
var i PromptTemplate
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Content,
|
||||||
|
&i.Scope,
|
||||||
|
&i.OwnerID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertPromptTemplate = `-- name: InsertPromptTemplate :one
|
||||||
|
INSERT INTO prompt_templates (id, name, content, scope, owner_id)
|
||||||
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
|
RETURNING id, name, content, scope, owner_id, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertPromptTemplateParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
OwnerID pgtype.UUID `json:"owner_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertPromptTemplate(ctx context.Context, arg InsertPromptTemplateParams) (PromptTemplate, error) {
|
||||||
|
row := q.db.QueryRow(ctx, insertPromptTemplate,
|
||||||
|
arg.ID,
|
||||||
|
arg.Name,
|
||||||
|
arg.Content,
|
||||||
|
arg.Scope,
|
||||||
|
arg.OwnerID,
|
||||||
|
)
|
||||||
|
var i PromptTemplate
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Content,
|
||||||
|
&i.Scope,
|
||||||
|
&i.OwnerID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listPromptTemplatesForUser = `-- name: ListPromptTemplatesForUser :many
|
||||||
|
SELECT id, name, content, scope, owner_id, created_at, updated_at FROM prompt_templates
|
||||||
|
WHERE scope = 'system' OR (scope = 'user' AND owner_id = $1)
|
||||||
|
ORDER BY scope, name
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListPromptTemplatesForUser(ctx context.Context, ownerID pgtype.UUID) ([]PromptTemplate, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listPromptTemplatesForUser, ownerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []PromptTemplate
|
||||||
|
for rows.Next() {
|
||||||
|
var i PromptTemplate
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Content,
|
||||||
|
&i.Scope,
|
||||||
|
&i.OwnerID,
|
||||||
|
&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 updatePromptTemplate = `-- name: UpdatePromptTemplate :exec
|
||||||
|
UPDATE prompt_templates SET name = $2, content = $3, updated_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdatePromptTemplateParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdatePromptTemplate(ctx context.Context, arg UpdatePromptTemplateParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updatePromptTemplate, arg.ID, arg.Name, arg.Content)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.31.1
|
||||||
|
// source: usage.sql
|
||||||
|
|
||||||
|
package chatsqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const insertUsage = `-- name: InsertUsage :exec
|
||||||
|
INSERT INTO llm_usage (
|
||||||
|
conversation_id, message_id, user_id, endpoint_id, model_id,
|
||||||
|
prompt_tokens, completion_tokens, thinking_tokens, cost_usd
|
||||||
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertUsageParams struct {
|
||||||
|
ConversationID pgtype.UUID `json:"conversation_id"`
|
||||||
|
MessageID int64 `json:"message_id"`
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
EndpointID pgtype.UUID `json:"endpoint_id"`
|
||||||
|
ModelID pgtype.UUID `json:"model_id"`
|
||||||
|
PromptTokens int32 `json:"prompt_tokens"`
|
||||||
|
CompletionTokens int32 `json:"completion_tokens"`
|
||||||
|
ThinkingTokens int32 `json:"thinking_tokens"`
|
||||||
|
CostUsd pgtype.Numeric `json:"cost_usd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertUsage(ctx context.Context, arg InsertUsageParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, insertUsage,
|
||||||
|
arg.ConversationID,
|
||||||
|
arg.MessageID,
|
||||||
|
arg.UserID,
|
||||||
|
arg.EndpointID,
|
||||||
|
arg.ModelID,
|
||||||
|
arg.PromptTokens,
|
||||||
|
arg.CompletionTokens,
|
||||||
|
arg.ThinkingTokens,
|
||||||
|
arg.CostUsd,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const summarizeUsageByDay = `-- name: SummarizeUsageByDay :many
|
||||||
|
SELECT date_trunc('day', created_at) AS day,
|
||||||
|
SUM(prompt_tokens)::int AS prompt_tokens,
|
||||||
|
SUM(completion_tokens)::int AS completion_tokens,
|
||||||
|
SUM(thinking_tokens)::int AS thinking_tokens,
|
||||||
|
SUM(cost_usd)::numeric AS cost_usd
|
||||||
|
FROM llm_usage
|
||||||
|
WHERE created_at >= $1 AND created_at < $2
|
||||||
|
GROUP BY day
|
||||||
|
ORDER BY day
|
||||||
|
`
|
||||||
|
|
||||||
|
type SummarizeUsageByDayParams struct {
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
CreatedAt_2 pgtype.Timestamptz `json:"created_at_2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SummarizeUsageByDayRow struct {
|
||||||
|
Day pgtype.Interval `json:"day"`
|
||||||
|
PromptTokens int32 `json:"prompt_tokens"`
|
||||||
|
CompletionTokens int32 `json:"completion_tokens"`
|
||||||
|
ThinkingTokens int32 `json:"thinking_tokens"`
|
||||||
|
CostUsd pgtype.Numeric `json:"cost_usd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SummarizeUsageByDay(ctx context.Context, arg SummarizeUsageByDayParams) ([]SummarizeUsageByDayRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, summarizeUsageByDay, arg.CreatedAt, arg.CreatedAt_2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []SummarizeUsageByDayRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i SummarizeUsageByDayRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.Day,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&i.CostUsd,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const summarizeUsageByModel = `-- name: SummarizeUsageByModel :many
|
||||||
|
SELECT model_id,
|
||||||
|
SUM(prompt_tokens)::int AS prompt_tokens,
|
||||||
|
SUM(completion_tokens)::int AS completion_tokens,
|
||||||
|
SUM(thinking_tokens)::int AS thinking_tokens,
|
||||||
|
SUM(cost_usd)::numeric AS cost_usd
|
||||||
|
FROM llm_usage
|
||||||
|
WHERE created_at >= $1 AND created_at < $2
|
||||||
|
GROUP BY model_id
|
||||||
|
ORDER BY cost_usd DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
type SummarizeUsageByModelParams struct {
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
CreatedAt_2 pgtype.Timestamptz `json:"created_at_2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SummarizeUsageByModelRow struct {
|
||||||
|
ModelID pgtype.UUID `json:"model_id"`
|
||||||
|
PromptTokens int32 `json:"prompt_tokens"`
|
||||||
|
CompletionTokens int32 `json:"completion_tokens"`
|
||||||
|
ThinkingTokens int32 `json:"thinking_tokens"`
|
||||||
|
CostUsd pgtype.Numeric `json:"cost_usd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SummarizeUsageByModel(ctx context.Context, arg SummarizeUsageByModelParams) ([]SummarizeUsageByModelRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, summarizeUsageByModel, arg.CreatedAt, arg.CreatedAt_2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []SummarizeUsageByModelRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i SummarizeUsageByModelRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ModelID,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&i.CostUsd,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const summarizeUsageByUser = `-- name: SummarizeUsageByUser :many
|
||||||
|
SELECT user_id,
|
||||||
|
SUM(prompt_tokens)::int AS prompt_tokens,
|
||||||
|
SUM(completion_tokens)::int AS completion_tokens,
|
||||||
|
SUM(thinking_tokens)::int AS thinking_tokens,
|
||||||
|
SUM(cost_usd)::numeric AS cost_usd
|
||||||
|
FROM llm_usage
|
||||||
|
WHERE created_at >= $1 AND created_at < $2
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY cost_usd DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
type SummarizeUsageByUserParams struct {
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
CreatedAt_2 pgtype.Timestamptz `json:"created_at_2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SummarizeUsageByUserRow struct {
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
PromptTokens int32 `json:"prompt_tokens"`
|
||||||
|
CompletionTokens int32 `json:"completion_tokens"`
|
||||||
|
ThinkingTokens int32 `json:"thinking_tokens"`
|
||||||
|
CostUsd pgtype.Numeric `json:"cost_usd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SummarizeUsageByUser(ctx context.Context, arg SummarizeUsageByUserParams) ([]SummarizeUsageByUserRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, summarizeUsageByUser, arg.CreatedAt, arg.CreatedAt_2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []SummarizeUsageByUserRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i SummarizeUsageByUserRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.UserID,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&i.CostUsd,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const summarizeUserDaily = `-- name: SummarizeUserDaily :many
|
||||||
|
SELECT date_trunc('day', created_at) AS day,
|
||||||
|
SUM(prompt_tokens)::int AS prompt_tokens,
|
||||||
|
SUM(completion_tokens)::int AS completion_tokens,
|
||||||
|
SUM(thinking_tokens)::int AS thinking_tokens,
|
||||||
|
SUM(cost_usd)::numeric AS cost_usd
|
||||||
|
FROM llm_usage
|
||||||
|
WHERE user_id = $1 AND created_at >= $2 AND created_at < $3
|
||||||
|
GROUP BY day
|
||||||
|
ORDER BY day
|
||||||
|
`
|
||||||
|
|
||||||
|
type SummarizeUserDailyParams struct {
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
CreatedAt_2 pgtype.Timestamptz `json:"created_at_2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SummarizeUserDailyRow struct {
|
||||||
|
Day pgtype.Interval `json:"day"`
|
||||||
|
PromptTokens int32 `json:"prompt_tokens"`
|
||||||
|
CompletionTokens int32 `json:"completion_tokens"`
|
||||||
|
ThinkingTokens int32 `json:"thinking_tokens"`
|
||||||
|
CostUsd pgtype.Numeric `json:"cost_usd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SummarizeUserDaily(ctx context.Context, arg SummarizeUserDailyParams) ([]SummarizeUserDailyRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, summarizeUserDaily, arg.UserID, arg.CreatedAt, arg.CreatedAt_2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []SummarizeUserDailyRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i SummarizeUserDailyRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.Day,
|
||||||
|
&i.PromptTokens,
|
||||||
|
&i.CompletionTokens,
|
||||||
|
&i.ThinkingTokens,
|
||||||
|
&i.CostUsd,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
@@ -50,3 +50,13 @@ sql:
|
|||||||
sql_package: pgx/v5
|
sql_package: pgx/v5
|
||||||
emit_pointers_for_null_types: true
|
emit_pointers_for_null_types: true
|
||||||
emit_json_tags: true
|
emit_json_tags: true
|
||||||
|
- engine: postgresql
|
||||||
|
queries: internal/chat/queries
|
||||||
|
schema: migrations
|
||||||
|
gen:
|
||||||
|
go:
|
||||||
|
package: chatsqlc
|
||||||
|
out: internal/chat/sqlc
|
||||||
|
sql_package: pgx/v5
|
||||||
|
emit_pointers_for_null_types: true
|
||||||
|
emit_json_tags: true
|
||||||
|
|||||||
Reference in New Issue
Block a user