602 lines
17 KiB
Go
602 lines
17 KiB
Go
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
const dbPath = "/Users/rdarius/.nyxtex/go-coder.db"
|
|
|
|
type Group struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Location string `json:"location"`
|
|
TotalTokens int `json:"total_tokens,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
type Conversation struct {
|
|
ID string `json:"id"`
|
|
Title string `json:"title"`
|
|
GroupID *string `json:"group_id"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
MessageCount int `json:"message_count"`
|
|
TotalTokens int `json:"total_tokens,omitempty"`
|
|
ContextSummary string `json:"-"`
|
|
ContextSummaryOrder int `json:"-"`
|
|
}
|
|
|
|
type Message struct {
|
|
ID int64 `json:"id"`
|
|
ConvID string `json:"conversation_id"`
|
|
Role string `json:"role"`
|
|
Content string `json:"content"`
|
|
Kind string `json:"kind"`
|
|
Name string `json:"name"`
|
|
Agent string `json:"agent"`
|
|
TotalTokens int `json:"total_tokens,omitempty"`
|
|
Order int `json:"order"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type Store struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewStore() (*Store, error) {
|
|
db, err := sql.Open("sqlite", dbPath+"?_busy_timeout=5000&_journal=WAL")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open database: %w", err)
|
|
}
|
|
|
|
if err := db.Ping(); err != nil {
|
|
return nil, fmt.Errorf("failed to ping database: %w", err)
|
|
}
|
|
|
|
store := &Store{db: db}
|
|
if err := store.createTables(); err != nil {
|
|
return nil, fmt.Errorf("failed to create tables: %w", err)
|
|
}
|
|
|
|
return store, nil
|
|
}
|
|
|
|
func generateID() string {
|
|
return uuid.New().String()
|
|
}
|
|
|
|
func (s *Store) createTables() error {
|
|
_, err := s.db.Exec(`
|
|
CREATE TABLE IF NOT EXISTS groups (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
id TEXT PRIMARY KEY,
|
|
title TEXT NOT NULL,
|
|
group_id TEXT,
|
|
context_summary TEXT NOT NULL DEFAULT '',
|
|
context_summary_order INTEGER NOT NULL DEFAULT 0,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
|
|
);
|
|
CREATE TABLE IF NOT EXISTS messages (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
conversation_id TEXT NOT NULL,
|
|
role TEXT NOT NULL CHECK(role IN ('user', 'assistant', 'system')),
|
|
content TEXT NOT NULL,
|
|
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
"order" INTEGER NOT NULL,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE
|
|
);
|
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
version INTEGER PRIMARY KEY,
|
|
applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_messages_conv_order ON messages(conversation_id, "order");
|
|
CREATE INDEX IF NOT EXISTS idx_messages_conv_id ON messages(conversation_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conversations_group_id ON conversations(group_id);
|
|
`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return s.applyMigrations()
|
|
}
|
|
|
|
func (s *Store) applyMigrations() error {
|
|
migrations := []struct {
|
|
version int
|
|
sql string
|
|
}{
|
|
{
|
|
version: 1,
|
|
sql: `ALTER TABLE groups ADD COLUMN location TEXT NOT NULL DEFAULT ''`,
|
|
},
|
|
{
|
|
version: 2,
|
|
sql: `ALTER TABLE messages ADD COLUMN kind TEXT NOT NULL DEFAULT 'message'`,
|
|
},
|
|
{
|
|
version: 3,
|
|
sql: `ALTER TABLE messages ADD COLUMN name TEXT NOT NULL DEFAULT ''`,
|
|
},
|
|
{
|
|
version: 4,
|
|
sql: `ALTER TABLE messages ADD COLUMN agent TEXT NOT NULL DEFAULT ''`,
|
|
},
|
|
{
|
|
version: 5,
|
|
sql: `ALTER TABLE messages ADD COLUMN total_tokens INTEGER NOT NULL DEFAULT 0`,
|
|
},
|
|
{
|
|
version: 6,
|
|
sql: `ALTER TABLE conversations ADD COLUMN context_summary TEXT NOT NULL DEFAULT ''`,
|
|
},
|
|
{
|
|
version: 7,
|
|
sql: `ALTER TABLE conversations ADD COLUMN context_summary_order INTEGER NOT NULL DEFAULT 0`,
|
|
},
|
|
}
|
|
|
|
for _, m := range migrations {
|
|
applied, err := s.isMigrationApplied(m.version)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !applied {
|
|
if m.version == 5 {
|
|
exists, err := s.columnExists("messages", "total_tokens")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
_, err = s.db.Exec(
|
|
"INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)",
|
|
m.version, time.Now().UTC(),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to record migration %d: %w", m.version, err)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
if m.version == 6 {
|
|
exists, err := s.columnExists("conversations", "context_summary")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
_, err = s.db.Exec(
|
|
"INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)",
|
|
m.version, time.Now().UTC(),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to record migration %d: %w", m.version, err)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
if m.version == 7 {
|
|
exists, err := s.columnExists("conversations", "context_summary_order")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
_, err = s.db.Exec(
|
|
"INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)",
|
|
m.version, time.Now().UTC(),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to record migration %d: %w", m.version, err)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
_, err = s.db.Exec(m.sql)
|
|
if err != nil {
|
|
return fmt.Errorf("migration %d failed: %w", m.version, err)
|
|
}
|
|
_, err = s.db.Exec(
|
|
"INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)",
|
|
m.version, time.Now().UTC(),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to record migration %d: %w", m.version, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Store) isMigrationApplied(version int) (bool, error) {
|
|
var count int
|
|
err := s.db.QueryRow(
|
|
"SELECT COUNT(*) FROM schema_migrations WHERE version = ?", version,
|
|
).Scan(&count)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return count > 0, nil
|
|
}
|
|
|
|
func (s *Store) columnExists(tableName, columnName string) (bool, error) {
|
|
rows, err := s.db.Query(fmt.Sprintf("PRAGMA table_info(%s)", tableName))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var cid int
|
|
var name, colType string
|
|
var notNull int
|
|
var dfltValue sql.NullString
|
|
var pk int
|
|
for rows.Next() {
|
|
if err := rows.Scan(&cid, &name, &colType, ¬Null, &dfltValue, &pk); err != nil {
|
|
return false, err
|
|
}
|
|
if name == columnName {
|
|
return true, nil
|
|
}
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return false, err
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (s *Store) CreateGroup(name string) (*Group, error) {
|
|
id := generateID()
|
|
now := time.Now().UTC()
|
|
_, err := s.db.Exec(
|
|
"INSERT INTO groups (id, name, created_at, updated_at) VALUES (?, ?, ?, ?)",
|
|
id, name, now, now,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create group: %w", err)
|
|
}
|
|
return &Group{
|
|
ID: id,
|
|
Name: name,
|
|
Location: "",
|
|
TotalTokens: 0,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Store) GetGroup(id string) (*Group, error) {
|
|
var group Group
|
|
err := s.db.QueryRow(
|
|
`SELECT g.id, g.name, g.location, g.created_at, g.updated_at,
|
|
COALESCE((
|
|
SELECT SUM(m.total_tokens)
|
|
FROM conversations c
|
|
JOIN messages m ON c.id = m.conversation_id
|
|
WHERE c.group_id = g.id
|
|
), 0) AS total_tokens
|
|
FROM groups g
|
|
WHERE g.id = ?`, id,
|
|
).Scan(&group.ID, &group.Name, &group.Location, &group.CreatedAt, &group.UpdatedAt, &group.TotalTokens)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
return nil, fmt.Errorf("failed to get group: %w", err)
|
|
}
|
|
return &group, nil
|
|
}
|
|
|
|
func (s *Store) ListGroups() ([]Group, error) {
|
|
rows, err := s.db.Query(
|
|
`SELECT g.id, g.name, g.location, g.created_at, g.updated_at,
|
|
COALESCE((
|
|
SELECT SUM(m.total_tokens)
|
|
FROM conversations c
|
|
JOIN messages m ON c.id = m.conversation_id
|
|
WHERE c.group_id = g.id
|
|
), 0) AS total_tokens
|
|
FROM groups g
|
|
ORDER BY g.updated_at DESC`,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list groups: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var groups []Group
|
|
for rows.Next() {
|
|
var g Group
|
|
if err := rows.Scan(&g.ID, &g.Name, &g.Location, &g.CreatedAt, &g.UpdatedAt, &g.TotalTokens); err != nil {
|
|
return nil, fmt.Errorf("failed to scan group: %w", err)
|
|
}
|
|
groups = append(groups, g)
|
|
}
|
|
return groups, nil
|
|
}
|
|
|
|
func (s *Store) UpdateGroupTitle(id, name string) error {
|
|
_, err := s.db.Exec(
|
|
"UPDATE groups SET name = ?, updated_at = ? WHERE id = ?",
|
|
name, time.Now().UTC(), id,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) DeleteGroup(id string) error {
|
|
_, err := s.db.Exec("DELETE FROM groups WHERE id = ?", id)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) SetGroupLocation(id, location string) error {
|
|
_, err := s.db.Exec(
|
|
"UPDATE groups SET location = ?, updated_at = ? WHERE id = ?",
|
|
location, time.Now().UTC(), id,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) UpdateConversationGroup(id, groupID string) error {
|
|
_, err := s.db.Exec(
|
|
"UPDATE conversations SET group_id = ?, updated_at = ? WHERE id = ? AND (group_id IS NULL OR group_id = '')",
|
|
groupID, time.Now().UTC(), id,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) HasGroupLocation(id string) (bool, error) {
|
|
var count int
|
|
err := s.db.QueryRow(
|
|
"SELECT COUNT(*) FROM groups WHERE id = ? AND location != ''", id,
|
|
).Scan(&count)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return count > 0, nil
|
|
}
|
|
|
|
func (s *Store) CreateConversation(title string, groupID *string) (*Conversation, error) {
|
|
id := generateID()
|
|
now := time.Now().UTC()
|
|
var groupIDVal interface{} = nil
|
|
if groupID != nil {
|
|
groupIDVal = *groupID
|
|
}
|
|
_, err := s.db.Exec(
|
|
"INSERT INTO conversations (id, title, group_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?)",
|
|
id, title, groupIDVal, now, now,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create conversation: %w", err)
|
|
}
|
|
return &Conversation{
|
|
ID: id,
|
|
Title: title,
|
|
GroupID: groupID,
|
|
TotalTokens: 0,
|
|
ContextSummary: "",
|
|
ContextSummaryOrder: 0,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Store) GetConversation(id string) (*Conversation, error) {
|
|
var conv Conversation
|
|
var groupID sql.NullString
|
|
err := s.db.QueryRow(
|
|
`SELECT c.id, c.title, c.group_id, c.created_at, c.updated_at,
|
|
COALESCE((SELECT COUNT(*) FROM messages m WHERE m.conversation_id = c.id), 0) AS message_count,
|
|
COALESCE((SELECT SUM(m.total_tokens) FROM messages m WHERE m.conversation_id = c.id), 0) AS total_tokens,
|
|
COALESCE(c.context_summary, '') AS context_summary,
|
|
COALESCE(c.context_summary_order, 0) AS context_summary_order
|
|
FROM conversations c
|
|
WHERE c.id = ?`, id,
|
|
).Scan(&conv.ID, &conv.Title, &groupID, &conv.CreatedAt, &conv.UpdatedAt, &conv.MessageCount, &conv.TotalTokens, &conv.ContextSummary, &conv.ContextSummaryOrder)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
return nil, fmt.Errorf("failed to get conversation: %w", err)
|
|
}
|
|
if groupID.Valid {
|
|
conv.GroupID = &groupID.String
|
|
}
|
|
return &conv, nil
|
|
}
|
|
|
|
func (s *Store) ListConversations() ([]Conversation, error) {
|
|
rows, err := s.db.Query(`
|
|
SELECT c.id, c.title, c.group_id, c.created_at, c.updated_at,
|
|
COALESCE((SELECT COUNT(*) FROM messages m WHERE m.conversation_id = c.id), 0) AS message_count,
|
|
COALESCE((SELECT SUM(m.total_tokens) FROM messages m WHERE m.conversation_id = c.id), 0) AS total_tokens,
|
|
COALESCE(c.context_summary, '') AS context_summary,
|
|
COALESCE(c.context_summary_order, 0) AS context_summary_order
|
|
FROM conversations c
|
|
ORDER BY c.updated_at DESC
|
|
`)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list conversations: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var conversations []Conversation
|
|
for rows.Next() {
|
|
var conv Conversation
|
|
var groupID sql.NullString
|
|
if err := rows.Scan(&conv.ID, &conv.Title, &groupID, &conv.CreatedAt, &conv.UpdatedAt, &conv.MessageCount, &conv.TotalTokens, &conv.ContextSummary, &conv.ContextSummaryOrder); err != nil {
|
|
return nil, fmt.Errorf("failed to scan conversation: %w", err)
|
|
}
|
|
if groupID.Valid {
|
|
conv.GroupID = &groupID.String
|
|
}
|
|
conversations = append(conversations, conv)
|
|
}
|
|
return conversations, nil
|
|
}
|
|
|
|
type GroupedConversations struct {
|
|
Groups []GroupWithConversations `json:"groups"`
|
|
Ungrouped []Conversation `json:"ungrouped"`
|
|
}
|
|
|
|
type GroupWithConversations struct {
|
|
Group
|
|
Conversations []Conversation `json:"conversations"`
|
|
}
|
|
|
|
func (s *Store) ListGroupedConversations() (*GroupedConversations, error) {
|
|
groups, err := s.ListGroups()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
grouped := &GroupedConversations{
|
|
Groups: make([]GroupWithConversations, 0),
|
|
Ungrouped: make([]Conversation, 0),
|
|
}
|
|
|
|
for _, g := range groups {
|
|
rows, err := s.db.Query(`
|
|
SELECT c.id, c.title, c.group_id, c.created_at, c.updated_at,
|
|
COALESCE((SELECT COUNT(*) FROM messages m WHERE m.conversation_id = c.id), 0) AS message_count,
|
|
COALESCE((SELECT SUM(m.total_tokens) FROM messages m WHERE m.conversation_id = c.id), 0) AS total_tokens,
|
|
COALESCE(c.context_summary, '') AS context_summary,
|
|
COALESCE(c.context_summary_order, 0) AS context_summary_order
|
|
FROM conversations c
|
|
WHERE c.group_id = ?
|
|
ORDER BY c.updated_at DESC
|
|
`, g.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list conversations for group %s: %w", g.ID, err)
|
|
}
|
|
|
|
var convs []Conversation
|
|
for rows.Next() {
|
|
var conv Conversation
|
|
var groupID sql.NullString
|
|
if err := rows.Scan(&conv.ID, &conv.Title, &groupID, &conv.CreatedAt, &conv.UpdatedAt, &conv.MessageCount, &conv.TotalTokens, &conv.ContextSummary, &conv.ContextSummaryOrder); err != nil {
|
|
rows.Close()
|
|
return nil, fmt.Errorf("failed to scan conversation: %w", err)
|
|
}
|
|
convs = append(convs, conv)
|
|
}
|
|
rows.Close()
|
|
|
|
grouped.Groups = append(grouped.Groups, GroupWithConversations{
|
|
Group: g,
|
|
Conversations: convs,
|
|
})
|
|
}
|
|
|
|
ungroupedRows, err := s.db.Query(`
|
|
SELECT c.id, c.title, c.group_id, c.created_at, c.updated_at,
|
|
COALESCE((SELECT COUNT(*) FROM messages m WHERE m.conversation_id = c.id), 0) AS message_count,
|
|
COALESCE((SELECT SUM(m.total_tokens) FROM messages m WHERE m.conversation_id = c.id), 0) AS total_tokens,
|
|
COALESCE(c.context_summary, '') AS context_summary,
|
|
COALESCE(c.context_summary_order, 0) AS context_summary_order
|
|
FROM conversations c
|
|
WHERE c.group_id IS NULL
|
|
ORDER BY c.updated_at DESC
|
|
`)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list ungrouped conversations: %w", err)
|
|
}
|
|
defer ungroupedRows.Close()
|
|
|
|
for ungroupedRows.Next() {
|
|
var conv Conversation
|
|
var groupID sql.NullString
|
|
if err := ungroupedRows.Scan(&conv.ID, &conv.Title, &groupID, &conv.CreatedAt, &conv.UpdatedAt, &conv.MessageCount, &conv.TotalTokens, &conv.ContextSummary, &conv.ContextSummaryOrder); err != nil {
|
|
return nil, fmt.Errorf("failed to scan ungrouped conversation: %w", err)
|
|
}
|
|
grouped.Ungrouped = append(grouped.Ungrouped, conv)
|
|
}
|
|
|
|
return grouped, nil
|
|
}
|
|
|
|
func (s *Store) UpdateConversationTitle(id, title string) error {
|
|
_, err := s.db.Exec(
|
|
"UPDATE conversations SET title = ?, updated_at = ? WHERE id = ?",
|
|
title, time.Now().UTC(), id,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) UpdateConversationContextSummary(id, summary string, summaryOrder int) error {
|
|
_, err := s.db.Exec(
|
|
"UPDATE conversations SET context_summary = ?, context_summary_order = ?, updated_at = ? WHERE id = ?",
|
|
summary, summaryOrder, time.Now().UTC(), id,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) DeleteConversation(id string) error {
|
|
_, err := s.db.Exec("DELETE FROM conversations WHERE id = ?", id)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) AddMessage(convID, role, content string, order int, totalTokens int) error {
|
|
return s.AddMessageWithMeta(convID, role, content, order, "message", "", "", totalTokens)
|
|
}
|
|
|
|
func (s *Store) AddMessageWithMeta(convID, role, content string, order int, kind, name, agent string, totalTokens int) error {
|
|
if kind == "" {
|
|
kind = "message"
|
|
}
|
|
_, err := s.db.Exec(
|
|
"INSERT INTO messages (conversation_id, role, content, total_tokens, kind, name, agent, \"order\", created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
convID, role, content, totalTokens, kind, name, agent, order, time.Now().UTC(),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to add message: %w", err)
|
|
}
|
|
_, err = s.db.Exec(
|
|
"UPDATE conversations SET updated_at = ? WHERE id = ?",
|
|
time.Now().UTC(), convID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) GetMessages(convID string) ([]Message, error) {
|
|
rows, err := s.db.Query(
|
|
"SELECT id, conversation_id, role, content, COALESCE(kind, 'message'), COALESCE(name, ''), COALESCE(agent, ''), COALESCE(total_tokens, 0), \"order\", created_at FROM messages WHERE conversation_id = ? ORDER BY \"order\" ASC",
|
|
convID,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get messages: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
messages := make([]Message, 0)
|
|
for rows.Next() {
|
|
var msg Message
|
|
if err := rows.Scan(&msg.ID, &msg.ConvID, &msg.Role, &msg.Content, &msg.Kind, &msg.Name, &msg.Agent, &msg.TotalTokens, &msg.Order, &msg.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("failed to scan message: %w", err)
|
|
}
|
|
messages = append(messages, msg)
|
|
}
|
|
return messages, nil
|
|
}
|
|
|
|
func (s *Store) DeleteMessages(convID string) error {
|
|
_, err := s.db.Exec("DELETE FROM messages WHERE conversation_id = ?", convID)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) Close() error {
|
|
return s.db.Close()
|
|
}
|