From d1531c1fba3670f03bb6a54fdcc08887b6605804 Mon Sep 17 00:00:00 2001 From: gearnode Date: Wed, 22 Jan 2025 16:33:25 +0100 Subject: [PATCH] Add control resolver Signed-off-by: gearnode --- pkg/api/console/v1/types/control.go | 30 ++++++++++ pkg/api/console/v1/v1_resolver.go | 9 ++- pkg/probo/coredata/control.go | 87 ++++++++++++++++++++++++++++- pkg/probo/probo.go | 21 +++++++ 4 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 pkg/api/console/v1/types/control.go diff --git a/pkg/api/console/v1/types/control.go b/pkg/api/console/v1/types/control.go new file mode 100644 index 000000000..a815d8339 --- /dev/null +++ b/pkg/api/console/v1/types/control.go @@ -0,0 +1,30 @@ +package types + +import ( + "github.com/getprobo/probo/pkg/probo/coredata" + "github.com/getprobo/probo/pkg/probo/coredata/page" +) + +func NewControlConnection(p *page.Page[*coredata.Control]) *ControlConnection { + var edges = make([]*ControlEdge, len(p.Data)) + + for i := range edges { + edges[i] = NewControlEdge(p.Data[i]) + } + + return &ControlConnection{ + Edges: edges, + PageInfo: NewPageInfo(p), + } +} + +func NewControlEdge(f *coredata.Control) *ControlEdge { + return &ControlEdge{ + Cursor: f.CursorKey(), + Node: NewControl(f), + } +} + +func NewControl(e *coredata.Control) *Control { + return &Control{} +} diff --git a/pkg/api/console/v1/v1_resolver.go b/pkg/api/console/v1/v1_resolver.go index 84ebfd671..88937de71 100644 --- a/pkg/api/console/v1/v1_resolver.go +++ b/pkg/api/console/v1/v1_resolver.go @@ -20,7 +20,14 @@ func (r *controlResolver) Tasks(ctx context.Context, obj *types.Control, first * // Controls is the resolver for the controls field. func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.ControlConnection, error) { - panic(fmt.Errorf("not implemented: Controls - controls")) + cursor := types.NewCursor(first, after, last, before) + + page, err := r.svc.ListFrameworkControls(ctx, obj.ID, cursor) + if err != nil { + return nil, fmt.Errorf("cannot list framework controls: %w", err) + } + + return types.NewControlConnection(page, cursor), nil } // Frameworks is the resolver for the frameworks field. diff --git a/pkg/probo/coredata/control.go b/pkg/probo/coredata/control.go index 3e8f135f3..95f1397ca 100644 --- a/pkg/probo/coredata/control.go +++ b/pkg/probo/coredata/control.go @@ -1,13 +1,94 @@ 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 ( Control struct { - ID string + ID uuid.UUID FrameworkID string - ContentID string + Name string + Description string + ContentRef string CreatedAt time.Time UpdatedAt time.Time } + + Controls []*Control ) + +func (c *Control) CursorKey() page.CursorKey { + return page.NewCursorKey(c.ID, c.CreatedAt) +} + +func (c *Control) scan(r pgx.Row) error { + return r.Scan( + &c.ID, + &c.FrameworkID, + &c.Name, + &c.Description, + &c.ContentRef, + &c.CreatedAt, + &c.UpdatedAt, + ) +} + +func (c *Controls) LoadByFrameworkID( + ctx context.Context, + conn pg.Conn, + frameworkID string, + cursor *page.Cursor, +) error { + q := ` +SELECT + control_id, + framework_id, + name, + description, + content_ref, + created_at, + updated_at +FROM + controls +WHERE + framework_id = @framework_id + AND % +` + q = fmt.Sprintf(q, cursor.SQLFragment()) + + args := pgx.NamedArgs{"framework_id": frameworkID} + maps.Copy(args, cursor.SQLArguments()) + + r, err := conn.Query(ctx, q, args) + if err != nil { + return err + } + defer r.Close() + + controls := Controls{} + for r.Next() { + control := &Control{} + if err := control.scan(r); err != nil { + return err + } + + controls = append(controls, control) + } + + if err := r.Err(); err != nil { + return err + } + + *c = controls + + return nil +} diff --git a/pkg/probo/probo.go b/pkg/probo/probo.go index 0875114f5..726bd35ee 100644 --- a/pkg/probo/probo.go +++ b/pkg/probo/probo.go @@ -60,3 +60,24 @@ func (s *Service) ListOrganizationFrameworks( return page.NewPage(frameworks, cursor), nil } + +func (s *Service) ListFrameworkControls( + ctx context.Context, + frameworkID string, + cursor *page.Cursor, +) (*page.Page[*coredata.Control], error) { + var controls coredata.Controls + + err := s.pg.WithConn( + ctx, + func(conn pg.Conn) error { + return controls.LoadByFrameworkID(ctx, conn, frameworkID, cursor) + }, + ) + + if err != nil { + return nil, err + } + + return page.NewPage(controls, cursor), nil +}