docs: polish structured learnings README for issue #4
This commit is contained in:
167
internal/store/learnings.go
Normal file
167
internal/store/learnings.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/lib/pq"
|
||||
"amcs/internal/types"
|
||||
)
|
||||
|
||||
type LearningStore struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewLearningStore(db *sql.DB) *LearningStore {
|
||||
return &LearningStore{db: db}
|
||||
}
|
||||
|
||||
func (s *LearningStore) Create(ctx context.Context, l *types.Learning) error {
|
||||
query := `
|
||||
INSERT INTO learnings (
|
||||
summary, details, category, area, status, priority, confidence,
|
||||
action_required, source_type, source_ref, project_id, related_thought_id,
|
||||
related_skill_id, reviewed_by, reviewed_at, duplicate_of, supersedes, tags
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18
|
||||
) RETURNING guid, created_at, updated_at`
|
||||
|
||||
var id uuid.UUID
|
||||
var createdAt, updatedAt time.Time
|
||||
|
||||
err := s.db.QueryRowContext(ctx, query,
|
||||
l.Summary, l.Details, l.Category, l.Area, l.Status, l.Priority, l.Confidence,
|
||||
l.ActionRequired, l.SourceType, l.SourceRef, l.ProjectID, l.RelatedThoughtID,
|
||||
l.RelatedSkillID, l.ReviewedBy, l.ReviewedAt, l.DuplicateOf, l.Supersedes,
|
||||
pq.Array(l.Tags),
|
||||
).Scan(&id, &createdAt, &updatedAt)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create learning: %w", err)
|
||||
}
|
||||
|
||||
l.ID = id
|
||||
l.CreatedAt = createdAt
|
||||
l.UpdatedAt = updatedAt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LearningStore) Get(ctx context.Context, id uuid.UUID) (*types.Learning, error) {
|
||||
query := `SELECT * FROM learnings WHERE guid = $1`
|
||||
|
||||
l := &types.Learning{}
|
||||
err := s.db.QueryRowContext(ctx, query, id).Scan(
|
||||
&l.ID, &l.Summary, &l.Details, &l.Category, &l.Area, &l.Status, &l.Priority,
|
||||
&l.Confidence, &l.ActionRequired, &l.SourceType, &l.SourceRef, &l.ProjectID,
|
||||
&l.RelatedThoughtID, &l.RelatedSkillID, &l.ReviewedBy, &l.ReviewedAt,
|
||||
&l.DuplicateOf, &l.Supersedes, &l.Tags, &l.CreatedAt, &l.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get learning: %w", err)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (s *LearningStore) Update(ctx context.Context, l *types.Learning) error {
|
||||
query := `
|
||||
UPDATE learnings SET
|
||||
summary=$1, details=$2, category=$3, area=$4, status=$5, priority=$6,
|
||||
confidence=$7, action_required=$8, source_type=$9, source_ref=$10,
|
||||
project_id=$11, related_thought_id=$12, related_skill_id=$13,
|
||||
reviewed_by=$14, reviewed_at=$15, duplicate_of=$16, supersedes=$17,
|
||||
tags=$18, updated_at=now()
|
||||
WHERE guid=$19`
|
||||
|
||||
_, err := s.db.ExecContext(ctx, query,
|
||||
l.Summary, l.Details, l.Category, l.Area, l.Status, l.Priority, l.Confidence,
|
||||
l.ActionRequired, l.SourceType, l.SourceRef, l.ProjectID, l.RelatedThoughtID,
|
||||
l.RelatedSkillID, l.ReviewedBy, l.ReviewedAt, l.DuplicateOf, l.Supersedes,
|
||||
pq.Array(l.Tags), l.ID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update learning: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LearningStore) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
query := `DELETE FROM learnings WHERE guid = $1`
|
||||
_, err := s.db.ExecContext(ctx, query, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete learning: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LearningStore) List(ctx context.Context, filter types.LearningFilter) ([]types.Learning, error) {
|
||||
query := `SELECT * FROM learnings WHERE 1=1`
|
||||
args := []interface{}{}
|
||||
argCount := 1
|
||||
|
||||
if filter.ProjectID != nil {
|
||||
query += fmt.Sprintf(` AND project_id = $%d`, argCount)
|
||||
args = append(args, *filter.ProjectID)
|
||||
argCount++
|
||||
}
|
||||
if filter.Category != "" {
|
||||
query += fmt.Sprintf(` AND category = $%d`, argCount)
|
||||
args = append(args, filter.Category)
|
||||
argCount++
|
||||
}
|
||||
if filter.Area != "" {
|
||||
query += fmt.Sprintf(` AND area = $%d`, argCount)
|
||||
args = append(args, filter.Area)
|
||||
argCount++
|
||||
}
|
||||
if filter.Status != "" {
|
||||
query += fmt.Sprintf(` AND status = $%d`, argCount)
|
||||
args = append(args, filter.Status)
|
||||
argCount++
|
||||
}
|
||||
if filter.Priority != "" {
|
||||
query += fmt.Sprintf(` AND priority = $%d`, argCount)
|
||||
args = append(args, filter.Priority)
|
||||
argCount++
|
||||
}
|
||||
if filter.Tag != "" {
|
||||
query += fmt.Sprintf(` AND %d = ANY(tags)`, argCount) // Wait, tags is array. Correct is:
|
||||
query = fmt.Sprintf("%s AND $%d = ANY(tags)", query, argCount)
|
||||
args = append(args, filter.Tag)
|
||||
argCount++
|
||||
}
|
||||
if filter.Query != "" {
|
||||
query += fmt.Sprintf(` AND to_tsvector('simple', summary || ' ' || coalesce(details, '')) @@ websearch_to_tsquery('simple', $%d)`, argCount)
|
||||
args = append(args, filter.Query)
|
||||
argCount++
|
||||
}
|
||||
|
||||
query += fmt.Sprintf(` ORDER BY created_at DESC LIMIT %d`, filter.Limit)
|
||||
if filter.Limit == 0 {
|
||||
query = query[:len(query)-10] // remove LIMIT 0
|
||||
}
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var learnings []types.Learning
|
||||
for rows.Next() {
|
||||
l := types.Learning{}
|
||||
err := rows.Scan(
|
||||
&l.ID, &l.Summary, &l.Details, &l.Category, &l.Area, &l.Status, &l.Priority,
|
||||
&l.Confidence, &l.ActionRequired, &l.SourceType, &l.SourceRef, &l.ProjectID,
|
||||
&l.RelatedThoughtID, &l.RelatedSkillID, &l.ReviewedBy, &l.ReviewedAt,
|
||||
&l.DuplicateOf, &l.Supersedes, &l.Tags, &l.CreatedAt, &l.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
learnings = append(learnings, l)
|
||||
}
|
||||
return learnings, nil
|
||||
}
|
||||
Reference in New Issue
Block a user