From a3a932cfa9a78f441d2cd882883b18ede2fb0577 Mon Sep 17 00:00:00 2001 From: Edward Sammut Alessi Date: Wed, 20 Dec 2023 11:10:41 +0100 Subject: [PATCH] Add NullID nullable type (#627) * Add NullID nullable type * Replace *string with *graphql.ID --- nullable_types.go | 25 +++++++++++++ nullable_types_test.go | 85 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/nullable_types.go b/nullable_types.go index 276f60b95..7816d1b4f 100644 --- a/nullable_types.go +++ b/nullable_types.go @@ -5,6 +5,31 @@ import ( "math" ) +// NullID is an ID that can be null. Use it in input structs to +// differentiate a value explicitly set to null from an omitted value. +// When the value is defined (either null or a value) Set is true. +type NullID struct { + Value *ID + Set bool +} + +func (NullID) ImplementsGraphQLType(name string) bool { + return name == "ID" +} + +func (s *NullID) UnmarshalGraphQL(input interface{}) error { + s.Set = true + + if input == nil { + return nil + } + + s.Value = new(ID) + return s.Value.UnmarshalGraphQL(input) +} + +func (s *NullID) Nullable() {} + // NullString is a string that can be null. Use it in input structs to // differentiate a value explicitly set to null from an omitted value. // When the value is defined (either null or a value) Set is true. diff --git a/nullable_types_test.go b/nullable_types_test.go index 6cb375cba..9aaf43f75 100644 --- a/nullable_types_test.go +++ b/nullable_types_test.go @@ -8,6 +8,91 @@ import ( "github.com/graph-gophers/graphql-go/decode" ) +func TestNullID_ImplementsUnmarshaler(t *testing.T) { + defer func() { + if err := recover(); err != nil { + t.Error(err) + } + }() + + // assert *NullID implements decode.Unmarshaler interface + var _ decode.Unmarshaler = (*graphql.NullID)(nil) +} + +func TestNullID_UnmarshalGraphQL(t *testing.T) { + type args struct { + input interface{} + } + + good := graphql.ID("1234") + ref := graphql.NullID{ + Value: &good, + Set: true, + } + + t.Run("invalid", func(t *testing.T) { + tests := []struct { + name string + args args + wantErr string + }{ + { + name: "boolean", + args: args{input: true}, + wantErr: "wrong type for ID: bool", + }, + { + name: "int", + args: args{input: 1}, + wantErr: "wrong type for ID: int", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gt := &graphql.NullID{} + if err := gt.UnmarshalGraphQL(tt.args.input); err != nil { + if err.Error() != tt.wantErr { + t.Errorf("UnmarshalGraphQL() error = %v, want = %s", err, tt.wantErr) + } + + return + } + + t.Error("UnmarshalGraphQL() expected error not raised") + }) + } + }) + + tests := []struct { + name string + args args + wantEq graphql.NullID + }{ + { + name: "string", + args: args{ + input: string(good), + }, + wantEq: ref, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gt := new(graphql.NullID) + if err := gt.UnmarshalGraphQL(tt.args.input); err != nil { + t.Errorf("UnmarshalGraphQL() error = %v", err) + return + } + + if *gt.Value != *tt.wantEq.Value { + t.Errorf("UnmarshalGraphQL() got = %v, want = %v", *gt.Value, *tt.wantEq.Value) + } + }) + } +} + func TestNullInt_ImplementsUnmarshaler(t *testing.T) { defer func() { if err := recover(); err != nil {