Files
ai-workflow/inbox/internal/store/sqlite/skills_store.go
T

159 lines
4.5 KiB
Go

package sqlite
import (
"context"
"database/sql"
"fmt"
"slices"
"strings"
"inbox/internal/domain/skill"
)
func (s *Store) UpsertSkill(ctx context.Context, value skill.Definition, changedBy string) (skill.Definition, error) {
if err := value.Validate(); err != nil {
return skill.Definition{}, err
}
return upsertVersionedConfig(ctx, s, value, changedBy, versionedConfigUpsertSpec[skill.Definition]{
entityName: "skill",
idKind: "skill",
loadTx: func(ctx context.Context, tx *sql.Tx) (skill.Definition, error) {
return getSkillByKeyTx(ctx, tx, value.SkillKey)
},
current: func(item skill.Definition) versionedConfigCurrent {
return versionedConfigCurrent{
ID: item.ID,
Version: item.Version,
CreatedAt: item.CreatedAt,
}
},
applyMetadata: func(item *skill.Definition, meta versionedConfigMetadata) {
item.ID = meta.ID
item.Version = meta.Version
item.CreatedAt = meta.CreatedAt
item.UpdatedAt = meta.UpdatedAt
},
writeTx: func(ctx context.Context, tx *sql.Tx, item skill.Definition) error {
_, err := tx.ExecContext(ctx, `
INSERT INTO skills(id, skill_key, name, description, source_type, content_markdown, status, version, created_at, updated_at)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
name = excluded.name,
description = excluded.description,
source_type = excluded.source_type,
content_markdown = excluded.content_markdown,
status = excluded.status,
version = excluded.version,
updated_at = excluded.updated_at
`,
item.ID,
item.SkillKey,
item.Name,
item.Description,
item.SourceType,
item.ContentMarkdown,
item.Status,
item.Version,
item.CreatedAt,
item.UpdatedAt,
)
return err
},
})
}
func (s *Store) ListSkillsByIDs(ctx context.Context, ids []string) (map[string]skill.Definition, error) {
ids = slices.Clone(ids)
if len(ids) == 0 {
return map[string]skill.Definition{}, nil
}
placeholders := make([]string, len(ids))
args := make([]any, len(ids))
for i, id := range ids {
placeholders[i] = "?"
args[i] = id
}
query := fmt.Sprintf(`
SELECT id, skill_key, name, description, source_type, content_markdown, status, version, created_at, updated_at
FROM skills
WHERE id IN (%s)
`, strings.Join(placeholders, ", "))
rows, err := s.db.QueryContext(ctx, query, args...)
if err != nil {
return nil, fmt.Errorf("list skills by ids: %w", err)
}
defer rows.Close()
out := make(map[string]skill.Definition, len(ids))
for rows.Next() {
item, err := scanSkill(rows)
if err != nil {
return nil, err
}
out[item.ID] = item
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate skills: %w", err)
}
return out, nil
}
func (s *Store) GetSkillByKey(ctx context.Context, skillKey string) (skill.Definition, error) {
row := s.db.QueryRowContext(ctx, `
SELECT id, skill_key, name, description, source_type, content_markdown, status, version, created_at, updated_at
FROM skills
WHERE skill_key = ?
`, skillKey)
return scanSkill(row)
}
func (s *Store) ListSkills(ctx context.Context) ([]skill.Definition, error) {
rows, err := s.db.QueryContext(ctx, `
SELECT id, skill_key, name, description, source_type, content_markdown, status, version, created_at, updated_at
FROM skills
ORDER BY name, skill_key
`)
if err != nil {
return nil, fmt.Errorf("list skills: %w", err)
}
defer rows.Close()
var out []skill.Definition
for rows.Next() {
item, err := scanSkill(rows)
if err != nil {
return nil, err
}
out = append(out, item)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate skills: %w", err)
}
return out, nil
}
func (s *Store) DeleteSkillByKey(ctx context.Context, skillKey string) error {
result, err := s.db.ExecContext(ctx, `DELETE FROM skills WHERE skill_key = ?`, skillKey)
if err != nil {
return fmt.Errorf("delete skill: %w", err)
}
return ensureAffected(result, sql.ErrNoRows)
}
func getSkillByKeyTx(ctx context.Context, tx *sql.Tx, skillKey string) (skill.Definition, error) {
row := tx.QueryRowContext(ctx, `
SELECT id, skill_key, name, description, source_type, content_markdown, status, version, created_at, updated_at
FROM skills
WHERE skill_key = ?
`, skillKey)
return scanSkill(row)
}
func scanSkill(s scanner) (skill.Definition, error) {
var item skill.Definition
if err := s.Scan(&item.ID, &item.SkillKey, &item.Name, &item.Description, &item.SourceType, &item.ContentMarkdown, &item.Status, &item.Version, &item.CreatedAt, &item.UpdatedAt); err != nil {
return skill.Definition{}, err
}
return item, nil
}