Files
Control-Center/go-backend/internal/repository/project_repository.go
Joshua e8ced74429
All checks were successful
Dev Build / build-test (pull_request) Successful in 2m23s
CUB-123: integrate gateway, wire PostgreSQL repositories, add SSE streaming
- Create repository/ package with pgx-backed CRUD for agents, sessions, tasks, projects
- Define AgentRepo/SessionRepo/TaskRepo/ProjectRepo interfaces
- Update handler to use repository interfaces instead of in-memory stores
- Add SSE broker with GET /api/events endpoint (text/event-stream)
- Add gateway client that polls OpenClaw for agent states
- Add GATEWAY_URL and GATEWAY_POLL_INTERVAL config fields
- Seed 5 demo agents (Otto, Rex, Dex, Hex, Pip) on empty DB
- Update router to wire SSE broker
- All 21 handler tests pass with mock repos
2026-05-08 19:58:06 -04:00

95 lines
2.4 KiB
Go

package repository
import (
"context"
"time"
"code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/models"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
// ProjectRepository provides PostgreSQL-backed CRUD for projects.
type ProjectRepository struct {
pool *pgxpool.Pool
}
// NewProjectRepository returns a repository wired to the given connection pool.
func NewProjectRepository(pool *pgxpool.Pool) *ProjectRepository {
return &ProjectRepository{pool: pool}
}
// Create inserts a new project. The current projects table only stores
// a single agent_id, so we use the first entry from AgentIDs if present.
func (r *ProjectRepository) Create(ctx context.Context, p models.Project) (models.Project, error) {
now := time.Now().UTC()
if p.CreatedAt.IsZero() {
p.CreatedAt = now
}
if p.UpdatedAt.IsZero() {
p.UpdatedAt = now
}
var agentID *string
if len(p.AgentIDs) > 0 {
agentID = &p.AgentIDs[0]
}
err := r.pool.QueryRow(ctx, `
INSERT INTO projects (name, description, status, agent_id, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, name, description, status, agent_id, created_at, updated_at
`, p.Name, p.Description, string(p.Status), agentID, p.CreatedAt, p.UpdatedAt).Scan(
&p.ID, &p.Name, &p.Description, &p.Status, &agentID,
&p.CreatedAt, &p.UpdatedAt,
)
if err != nil {
return p, err
}
if agentID != nil {
p.AgentIDs = []string{*agentID}
} else {
p.AgentIDs = []string{}
}
return p, nil
}
// List returns all projects ordered by name.
func (r *ProjectRepository) List(ctx context.Context) ([]models.Project, error) {
rows, err := r.pool.Query(ctx, `
SELECT id, name, description, status, agent_id, created_at, updated_at
FROM projects
ORDER BY name
`)
if err != nil {
return nil, err
}
defer rows.Close()
return pgx.CollectRows(rows, func(row pgx.CollectableRow) (models.Project, error) {
var p models.Project
var agentID *string
if err := row.Scan(&p.ID, &p.Name, &p.Description, &p.Status,
&agentID, &p.CreatedAt, &p.UpdatedAt); err != nil {
return p, err
}
if agentID != nil {
p.AgentIDs = []string{*agentID}
} else {
p.AgentIDs = []string{}
}
return p, nil
})
}
// Count returns the total number of projects.
func (r *ProjectRepository) Count(ctx context.Context) (int, error) {
var n int
err := r.pool.QueryRow(ctx, `SELECT COUNT(*) FROM projects`).Scan(&n)
return n, err
}