package httpapi import ( "context" "encoding/json" "github.com/dtoro/oikos/internal/httpapi/gen" "github.com/google/uuid" ) // ─── Classifications ─────────────────────────────────────────────────── func (s *Server) ListClassifications(ctx context.Context, req gen.ListClassificationsRequestObject) (gen.ListClassificationsResponseObject, error) { limit := clampLimit(req.Params.Limit) var route *string if req.Params.Route != nil { r := string(*req.Params.Route) route = &r } rows, err := s.pool.Query(ctx, ` SELECT c.entity_id, c.signal_entity_id, c.target_entity_id, c.action, c.recommended_action, c.risk_class, c.route, c.blast_radius, c.pattern_confidence, c.skill_id, c.autonomy_check, c.reasoning, c.correlation_id, c.created_at, e.slug, COALESCE(se.slug, '') AS signal_slug, COALESCE(te.slug, '') AS target_slug FROM classifications c LEFT JOIN entities e ON e.id = c.entity_id LEFT JOIN entities se ON se.id = c.signal_entity_id LEFT JOIN entities te ON te.id = c.target_entity_id WHERE ($1::text IS NULL OR c.route = $1) AND ($2::text IS NULL OR e.slug > $2) ORDER BY e.slug LIMIT $3`, route, req.Params.Cursor, limit+1) if err != nil { return nil, err } defer rows.Close() items := []gen.Classification{} for rows.Next() { var cls gen.Classification var recActionJSON []byte var reasoningJSON []byte var blastRadius []uuid.UUID var signalSlug, targetSlug string if err := rows.Scan(&cls.Id, &cls.SignalId, &targetSlug, &cls.Action, &recActionJSON, &cls.RiskClass, &cls.Route, &blastRadius, &cls.PatternConfidence, &cls.SkillId, &cls.AutonomyCheck, &reasoningJSON, &cls.CorrelationId, &cls.CreatedAt, &cls.Target, &signalSlug, &targetSlug); err != nil { return nil, err } if targetSlug != "" { cls.Target = &targetSlug } var reasoning map[string]any if json.Unmarshal(reasoningJSON, &reasoning) == nil { cls.Reasoning = reasoning } if len(blastRadius) > 0 { br := make([]string, len(blastRadius)) for i, id := range blastRadius { br[i] = id.String() } cls.BlastRadius = &br } items = append(items, cls) } if rows.Err() != nil { return nil, rows.Err() } var next *string if len(items) > limit { items = items[:limit] if items[len(items)-1].Target != nil { next = items[len(items)-1].Target } } if items == nil { items = []gen.Classification{} } return gen.ListClassifications200JSONResponse{Items: items, NextCursor: next}, nil }