feat(chat): sqlc queries for conversations/messages/attachments/templates/endpoints/models/usage

This commit is contained in:
2026-05-04 09:52:06 +08:00
parent ca5a018cd4
commit a1d0fbc3d3
17 changed files with 1929 additions and 0 deletions
+32
View File
@@ -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);
+28
View File
@@ -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;
+21
View File
@@ -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;
+47
View File
@@ -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';
+37
View File
@@ -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;
+19
View File
@@ -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;
+49
View File
@@ -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;
+235
View File
@@ -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
}
+181
View File
@@ -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
}
+32
View File
@@ -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,
}
}
+138
View File
@@ -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
}
+265
View File
@@ -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
}
+232
View File
@@ -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"`
}
+227
View File
@@ -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
}
+125
View File
@@ -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
}
+251
View File
@@ -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
}
+10
View File
@@ -50,3 +50,13 @@ sql:
sql_package: pgx/v5
emit_pointers_for_null_types: 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