From 86b48da2915fc5c87688d9ef108bc283d9fbd5d7 Mon Sep 17 00:00:00 2001 From: gearnode Date: Wed, 22 Jan 2025 16:50:28 +0100 Subject: [PATCH] Add task resolver Signed-off-by: gearnode --- pkg/api/console/v1/types/task.go | 30 +++++++++++ pkg/api/console/v1/v1_resolver.go | 9 +++- pkg/probo/coredata/task.go | 87 +++++++++++++++++++++++++++++-- pkg/probo/probo.go | 21 ++++++++ 4 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 pkg/api/console/v1/types/task.go diff --git a/pkg/api/console/v1/types/task.go b/pkg/api/console/v1/types/task.go new file mode 100644 index 000000000..137606d74 --- /dev/null +++ b/pkg/api/console/v1/types/task.go @@ -0,0 +1,30 @@ +package types + +import ( + "github.com/getprobo/probo/pkg/probo/coredata" + "github.com/getprobo/probo/pkg/probo/coredata/page" +) + +func NewTaskConnection(p *page.Page[*coredata.Task]) *TaskConnection { + var edges = make([]*TaskEdge, len(p.Data)) + + for i := range edges { + edges[i] = NewTaskEdge(p.Data[i]) + } + + return &TaskConnection{ + Edges: edges, + PageInfo: NewPageInfo(p), + } +} + +func NewTaskEdge(f *coredata.Task) *TaskEdge { + return &TaskEdge{ + Cursor: f.CursorKey(), + Node: NewTask(f), + } +} + +func NewTask(e *coredata.Task) *Task { + return &Task{} +} diff --git a/pkg/api/console/v1/v1_resolver.go b/pkg/api/console/v1/v1_resolver.go index 1b9e5f11f..47545e35c 100644 --- a/pkg/api/console/v1/v1_resolver.go +++ b/pkg/api/console/v1/v1_resolver.go @@ -15,7 +15,14 @@ import ( // Tasks is the resolver for the tasks field. func (r *controlResolver) Tasks(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.TaskConnection, error) { - panic(fmt.Errorf("not implemented: Tasks - tasks")) + cursor := types.NewCursor(first, after, last, before) + + page, err := r.svc.ListControlTasks(ctx, obj.ID, cursor) + if err != nil { + return nil, fmt.Errorf("cannot list framework controls: %w", err) + } + + return types.NewTaskConnection(page), nil } // Controls is the resolver for the controls field. diff --git a/pkg/probo/coredata/task.go b/pkg/probo/coredata/task.go index 784ff8b26..7bf7c4c8d 100644 --- a/pkg/probo/coredata/task.go +++ b/pkg/probo/coredata/task.go @@ -1,12 +1,89 @@ package coredata -import "time" +import ( + "context" + "fmt" + "maps" + "time" + + "github.com/getprobo/probo/pkg/probo/coredata/page" + "github.com/jackc/pgx/v5" + "go.gearno.de/crypto/uuid" + "go.gearno.de/kit/pg" +) type ( Task struct { - ID string - ContentID string - CreatedAt time.Time - UpdatedAt time.Time + ID uuid.UUID + ControlID string + ContentRef string + CreatedAt time.Time + UpdatedAt time.Time } + + Tasks []*Task ) + +func (t Task) CursorKey() page.CursorKey { + return page.NewCursorKey(t.ID, t.CreatedAt) +} + +func (t *Task) scan(r pgx.Row) error { + return r.Scan( + &t.ID, + &t.ControlID, + &t.ContentRef, + &t.CreatedAt, + &t.UpdatedAt, + ) +} + +func (t *Tasks) LoadByControlID( + ctx context.Context, + conn pg.Conn, + controlID string, + cursor *page.Cursor, +) error { + q := ` +SELECT + task_id, + control_id, + content_ref, + created_at, + updated_at +FROM + tasks +WHERE + control_id = @control_id + AND %s +` + + q = fmt.Sprintf(q, cursor.SQLFragment()) + + args := pgx.NamedArgs{"control_id": controlID} + maps.Copy(args, cursor.SQLArguments()) + + r, err := conn.Query(ctx, q, args) + if err != nil { + return err + } + defer r.Close() + + tasks := Tasks{} + for r.Next() { + task := &Task{} + if err := task.scan(r); err != nil { + return err + } + + tasks = append(tasks, task) + } + + if err := r.Err(); err != nil { + return err + } + + *t = tasks + + return nil +} diff --git a/pkg/probo/probo.go b/pkg/probo/probo.go index 726bd35ee..c0ba3607f 100644 --- a/pkg/probo/probo.go +++ b/pkg/probo/probo.go @@ -81,3 +81,24 @@ func (s *Service) ListFrameworkControls( return page.NewPage(controls, cursor), nil } + +func (s *Service) ListControlTasks( + ctx context.Context, + controlID string, + cursor *page.Cursor, +) (*page.Page[*coredata.Task], error) { + var tasks coredata.Tasks + + err := s.pg.WithConn( + ctx, + func(conn pg.Conn) error { + return tasks.LoadByControlID(ctx, conn, controlID, cursor) + }, + ) + + if err != nil { + return nil, err + } + + return page.NewPage(tasks, cursor), nil +}