Move to string to GID

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-01-23 17:29:16 +01:00
parent e6035cd701
commit f6e1e80202
11 changed files with 110 additions and 44 deletions

View File

@@ -19,6 +19,9 @@ omit_panic_handler: true
call_argument_directives_with_null: true call_argument_directives_with_null: true
models: models:
ID:
model:
- "github.com/getprobo/probo/pkg/api/console/v1/types.GIDScalar"
Datetime: Datetime:
model: model:
- "github.com/99designs/gqlgen/graphql.Time" - "github.com/99designs/gqlgen/graphql.Time"

View File

@@ -15,6 +15,7 @@ import (
"github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/introspection" "github.com/99designs/gqlgen/graphql/introspection"
"github.com/getprobo/probo/pkg/api/console/v1/types" "github.com/getprobo/probo/pkg/api/console/v1/types"
"github.com/getprobo/probo/pkg/probo/coredata/gid"
"github.com/getprobo/probo/pkg/probo/coredata/page" "github.com/getprobo/probo/pkg/probo/coredata/page"
gqlparser "github.com/vektah/gqlparser/v2" gqlparser "github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
@@ -104,7 +105,7 @@ type ComplexityRoot struct {
} }
Query struct { Query struct {
Node func(childComplexity int, id string) int Node func(childComplexity int, id gid.GID) int
} }
Task struct { Task struct {
@@ -135,7 +136,7 @@ type OrganizationResolver interface {
Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.FrameworkConnection, error) Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.FrameworkConnection, error)
} }
type QueryResolver interface { type QueryResolver interface {
Node(ctx context.Context, id string) (types.Node, error) Node(ctx context.Context, id gid.GID) (types.Node, error)
} }
type executableSchema struct { type executableSchema struct {
@@ -385,7 +386,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false return 0, false
} }
return e.complexity.Query.Node(childComplexity, args["id"].(string)), true return e.complexity.Query.Node(childComplexity, args["id"].(gid.GID)), true
case "Task.createdAt": case "Task.createdAt":
if e.complexity.Task.CreatedAt == nil { if e.complexity.Task.CreatedAt == nil {
@@ -915,13 +916,13 @@ func (ec *executionContext) field_Query_node_args(ctx context.Context, rawArgs m
func (ec *executionContext) field_Query_node_argsID( func (ec *executionContext) field_Query_node_argsID(
ctx context.Context, ctx context.Context,
rawArgs map[string]any, rawArgs map[string]any,
) (string, error) { ) (gid.GID, error) {
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
if tmp, ok := rawArgs["id"]; ok { if tmp, ok := rawArgs["id"]; ok {
return ec.unmarshalNID2string(ctx, tmp) return ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚋgidᚐGID(ctx, tmp)
} }
var zeroVal string var zeroVal gid.GID
return zeroVal, nil return zeroVal, nil
} }
@@ -999,9 +1000,9 @@ func (ec *executionContext) _Control_id(ctx context.Context, field graphql.Colle
} }
return graphql.Null return graphql.Null
} }
res := resTmp.(string) res := resTmp.(gid.GID)
fc.Result = res fc.Result = res
return ec.marshalNID2string(ctx, field.Selections, res) return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚋgidᚐGID(ctx, field.Selections, res)
} }
func (ec *executionContext) fieldContext_Control_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { func (ec *executionContext) fieldContext_Control_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -1420,9 +1421,9 @@ func (ec *executionContext) _Framework_id(ctx context.Context, field graphql.Col
} }
return graphql.Null return graphql.Null
} }
res := resTmp.(string) res := resTmp.(gid.GID)
fc.Result = res fc.Result = res
return ec.marshalNID2string(ctx, field.Selections, res) return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚋgidᚐGID(ctx, field.Selections, res)
} }
func (ec *executionContext) fieldContext_Framework_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { func (ec *executionContext) fieldContext_Framework_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -1841,9 +1842,9 @@ func (ec *executionContext) _Organization_id(ctx context.Context, field graphql.
} }
return graphql.Null return graphql.Null
} }
res := resTmp.(string) res := resTmp.(gid.GID)
fc.Result = res fc.Result = res
return ec.marshalNID2string(ctx, field.Selections, res) return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚋgidᚐGID(ctx, field.Selections, res)
} }
func (ec *executionContext) fieldContext_Organization_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { func (ec *executionContext) fieldContext_Organization_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -2176,7 +2177,7 @@ func (ec *executionContext) _Query_node(ctx context.Context, field graphql.Colle
ctx = graphql.WithFieldContext(ctx, fc) ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().Node(rctx, fc.Args["id"].(string)) return ec.resolvers.Query().Node(rctx, fc.Args["id"].(gid.GID))
}) })
if err != nil { if err != nil {
ec.Error(ctx, err) ec.Error(ctx, err)
@@ -2342,9 +2343,9 @@ func (ec *executionContext) _Task_id(ctx context.Context, field graphql.Collecte
} }
return graphql.Null return graphql.Null
} }
res := resTmp.(string) res := resTmp.(gid.GID)
fc.Result = res fc.Result = res
return ec.marshalNID2string(ctx, field.Selections, res) return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚋgidᚐGID(ctx, field.Selections, res)
} }
func (ec *executionContext) fieldContext_Task_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { func (ec *executionContext) fieldContext_Task_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -5461,13 +5462,13 @@ func (ec *executionContext) marshalNFrameworkEdge2ᚖgithubᚗcomᚋgetproboᚋp
return ec._FrameworkEdge(ctx, sel, v) return ec._FrameworkEdge(ctx, sel, v)
} }
func (ec *executionContext) unmarshalNID2string(ctx context.Context, v any) (string, error) { func (ec *executionContext) unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚋgidᚐGID(ctx context.Context, v any) (gid.GID, error) {
res, err := graphql.UnmarshalID(v) res, err := types.UnmarshalGIDScalar(v)
return res, graphql.ErrorOnPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
} }
func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { func (ec *executionContext) marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚋgidᚐGID(ctx context.Context, sel ast.SelectionSet, v gid.GID) graphql.Marshaler {
res := graphql.MarshalID(v) res := types.MarshalGIDScalar(v)
if res == graphql.Null { if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow") ec.Errorf(ctx, "the requested element is null which the schema does not allow")

View File

@@ -0,0 +1,44 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package types
import (
"errors"
"io"
"strconv"
"github.com/99designs/gqlgen/graphql"
"github.com/getprobo/probo/pkg/probo/coredata/gid"
)
func MarshalGIDScalar(id gid.GID) graphql.Marshaler {
return graphql.WriterFunc(func(w io.Writer) {
w.Write([]byte(strconv.Quote(id.String())))
})
}
func UnmarshalGIDScalar(v interface{}) (gid.GID, error) {
s, ok := v.(string)
if !ok {
return gid.Nil, errors.New("must be a string")
}
id, err := gid.ParseGID(s)
if err != nil {
return gid.Nil, err
}
return id, nil
}

View File

@@ -5,16 +5,17 @@ package types
import ( import (
"time" "time"
"github.com/getprobo/probo/pkg/probo/coredata/gid"
"github.com/getprobo/probo/pkg/probo/coredata/page" "github.com/getprobo/probo/pkg/probo/coredata/page"
) )
type Node interface { type Node interface {
IsNode() IsNode()
GetID() string GetID() gid.GID
} }
type Control struct { type Control struct {
ID string `json:"id"` ID gid.GID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Tasks *TaskConnection `json:"tasks"` Tasks *TaskConnection `json:"tasks"`
@@ -23,7 +24,7 @@ type Control struct {
} }
func (Control) IsNode() {} func (Control) IsNode() {}
func (this Control) GetID() string { return this.ID } func (this Control) GetID() gid.GID { return this.ID }
type ControlConnection struct { type ControlConnection struct {
Edges []*ControlEdge `json:"edges"` Edges []*ControlEdge `json:"edges"`
@@ -36,7 +37,7 @@ type ControlEdge struct {
} }
type Framework struct { type Framework struct {
ID string `json:"id"` ID gid.GID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Controls *ControlConnection `json:"controls"` Controls *ControlConnection `json:"controls"`
@@ -45,7 +46,7 @@ type Framework struct {
} }
func (Framework) IsNode() {} func (Framework) IsNode() {}
func (this Framework) GetID() string { return this.ID } func (this Framework) GetID() gid.GID { return this.ID }
type FrameworkConnection struct { type FrameworkConnection struct {
Edges []*FrameworkEdge `json:"edges"` Edges []*FrameworkEdge `json:"edges"`
@@ -58,7 +59,7 @@ type FrameworkEdge struct {
} }
type Organization struct { type Organization struct {
ID string `json:"id"` ID gid.GID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Frameworks *FrameworkConnection `json:"frameworks"` Frameworks *FrameworkConnection `json:"frameworks"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
@@ -66,7 +67,7 @@ type Organization struct {
} }
func (Organization) IsNode() {} func (Organization) IsNode() {}
func (this Organization) GetID() string { return this.ID } func (this Organization) GetID() gid.GID { return this.ID }
type PageInfo struct { type PageInfo struct {
HasNextPage bool `json:"hasNextPage"` HasNextPage bool `json:"hasNextPage"`
@@ -79,14 +80,14 @@ type Query struct {
} }
type Task struct { type Task struct {
ID string `json:"id"` ID gid.GID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"` UpdatedAt time.Time `json:"updatedAt"`
} }
func (Task) IsNode() {} func (Task) IsNode() {}
func (this Task) GetID() string { return this.ID } func (this Task) GetID() gid.GID { return this.ID }
type TaskConnection struct { type TaskConnection struct {
Edges []*TaskEdge `json:"edges"` Edges []*TaskEdge `json:"edges"`

View File

@@ -10,6 +10,7 @@ import (
"github.com/getprobo/probo/pkg/api/console/v1/schema" "github.com/getprobo/probo/pkg/api/console/v1/schema"
"github.com/getprobo/probo/pkg/api/console/v1/types" "github.com/getprobo/probo/pkg/api/console/v1/types"
"github.com/getprobo/probo/pkg/probo/coredata/gid"
"github.com/getprobo/probo/pkg/probo/coredata/page" "github.com/getprobo/probo/pkg/probo/coredata/page"
) )
@@ -50,7 +51,7 @@ func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organi
} }
// Node is the resolver for the node field. // Node is the resolver for the node field.
func (r *queryResolver) Node(ctx context.Context, id string) (types.Node, error) { func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
panic(fmt.Errorf("not implemented: Node - node")) panic(fmt.Errorf("not implemented: Node - node"))
} }

View File

@@ -62,7 +62,7 @@ func (c *Controls) LoadByFrameworkID(
ctx context.Context, ctx context.Context,
conn pg.Conn, conn pg.Conn,
scope *Scope, scope *Scope,
frameworkID string, frameworkID gid.GID,
cursor *page.Cursor, cursor *page.Cursor,
) error { ) error {
q := ` q := `

View File

@@ -60,7 +60,7 @@ func (f *Frameworks) LoadByOrganizationID(
ctx context.Context, ctx context.Context,
conn pg.Conn, conn pg.Conn,
scope *Scope, scope *Scope,
organizationID string, organizationID gid.GID,
cursor *page.Cursor, cursor *page.Cursor,
) error { ) error {
q := ` q := `
@@ -115,7 +115,7 @@ func (f *Framework) LoadByID(
ctx context.Context, ctx context.Context,
conn pg.Conn, conn pg.Conn,
scope *Scope, scope *Scope,
frameworkID string, frameworkID gid.GID,
) error { ) error {
q := ` q := `
SELECT SELECT

View File

@@ -27,15 +27,30 @@ type (
GID uuid.UUID GID uuid.UUID
) )
var (
Nil = GID(uuid.Nil)
)
func ParseGID(encoded string) (GID, error) {
gid := GID{}
err := gid.UnmarshalText([]byte(encoded))
if err != nil {
return Nil, err
}
return gid, nil
}
func NewGID(et uint32) (GID, error) { func NewGID(et uint32) (GID, error) {
id, err := uuid.NewV7() id, err := uuid.NewV7()
if err != nil { if err != nil {
return GID(uuid.Nil), err return Nil, err
} }
binary.BigEndian.PutUint32(id[10:14], et) binary.BigEndian.PutUint32(id[10:14], et)
return GID(id), nil return Nil, nil
} }
func (gid GID) Value() (driver.Value, error) { func (gid GID) Value() (driver.Value, error) {

View File

@@ -47,7 +47,7 @@ func (o *Organization) LoadByID(
ctx context.Context, ctx context.Context,
conn pg.Conn, conn pg.Conn,
scope *Scope, scope *Scope,
organizationID string, organizationID gid.GID,
) error { ) error {
q := ` q := `
SELECT SELECT

View File

@@ -58,7 +58,7 @@ func (t *Tasks) LoadByControlID(
ctx context.Context, ctx context.Context,
conn pg.Conn, conn pg.Conn,
scope *Scope, scope *Scope,
controlID string, controlID gid.GID,
cursor *page.Cursor, cursor *page.Cursor,
) error { ) error {
q := ` q := `

View File

@@ -18,6 +18,7 @@ import (
"context" "context"
"github.com/getprobo/probo/pkg/probo/coredata" "github.com/getprobo/probo/pkg/probo/coredata"
"github.com/getprobo/probo/pkg/probo/coredata/gid"
"github.com/getprobo/probo/pkg/probo/coredata/page" "github.com/getprobo/probo/pkg/probo/coredata/page"
"go.gearno.de/kit/pg" "go.gearno.de/kit/pg"
) )
@@ -38,7 +39,7 @@ func NewService(ctx context.Context, pgClient *pg.Client) *Service {
func (s *Service) GetOrganization( func (s *Service) GetOrganization(
ctx context.Context, ctx context.Context,
organizationID string, organizationID gid.GID,
) (*coredata.Organization, error) { ) (*coredata.Organization, error) {
organization := &coredata.Organization{} organization := &coredata.Organization{}
@@ -63,7 +64,7 @@ func (s *Service) GetOrganization(
func (s *Service) ListOrganizationFrameworks( func (s *Service) ListOrganizationFrameworks(
ctx context.Context, ctx context.Context,
organizationID string, organizationID gid.GID,
cursor *page.Cursor, cursor *page.Cursor,
) (*page.Page[*coredata.Framework], error) { ) (*page.Page[*coredata.Framework], error) {
var frameworks coredata.Frameworks var frameworks coredata.Frameworks
@@ -90,7 +91,7 @@ func (s *Service) ListOrganizationFrameworks(
func (s *Service) ListFrameworkControls( func (s *Service) ListFrameworkControls(
ctx context.Context, ctx context.Context,
frameworkID string, frameworkID gid.GID,
cursor *page.Cursor, cursor *page.Cursor,
) (*page.Page[*coredata.Control], error) { ) (*page.Page[*coredata.Control], error) {
var controls coredata.Controls var controls coredata.Controls
@@ -117,7 +118,7 @@ func (s *Service) ListFrameworkControls(
func (s *Service) ListControlTasks( func (s *Service) ListControlTasks(
ctx context.Context, ctx context.Context,
controlID string, controlID gid.GID,
cursor *page.Cursor, cursor *page.Cursor,
) (*page.Page[*coredata.Task], error) { ) (*page.Page[*coredata.Task], error) {
var tasks coredata.Tasks var tasks coredata.Tasks