Skip to content

Commit ccf4d93

Browse files
authored
feat: GQL variables and operation name (#2993)
## Relevant issue(s) Resolves #1441 Resolves #1395 ## Description This PR adds support for GraphQL variables and operation name. ## Tasks - [x] I made sure the code is well commented, particularly hard-to-understand areas. - [x] I made sure the repository-held documentation is changed accordingly. - [x] I made sure the pull request title adheres to the conventional commit style (the subset used in the project can be found in [tools/configs/chglog/config.yml](tools/configs/chglog/config.yml)). - [x] I made sure to discuss its limitations such as threats to validity, vulnerability to mistake and misuse, robustness to invalidation of assumptions, resource requirements, ... ## How has this been tested? Added tests Specify the platform(s) on which this was tested: - MacOS
1 parent 36fb5b5 commit ccf4d93

File tree

31 files changed

+794
-478
lines changed

31 files changed

+794
-478
lines changed

cli/request.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
package cli
1212

1313
import (
14+
"encoding/json"
1415
"io"
1516
"os"
1617

1718
"github.com/spf13/cobra"
1819

20+
"github.com/sourcenetwork/defradb/client"
1921
"github.com/sourcenetwork/defradb/errors"
2022
)
2123

@@ -26,6 +28,8 @@ const (
2628

2729
func MakeRequestCommand() *cobra.Command {
2830
var filePath string
31+
var operationName string
32+
var variablesJSON string
2933
var cmd = &cobra.Command{
3034
Use: "query [-i --identity] [request]",
3135
Short: "Send a DefraDB GraphQL query request",
@@ -70,8 +74,21 @@ To learn more about the DefraDB GraphQL Query Language, refer to https://docs.so
7074
return errors.New("request cannot be empty")
7175
}
7276

77+
var options []client.RequestOption
78+
if variablesJSON != "" {
79+
var variables map[string]any
80+
err := json.Unmarshal([]byte(variablesJSON), &variables)
81+
if err != nil {
82+
return err
83+
}
84+
options = append(options, client.WithVariables(variables))
85+
}
86+
if operationName != "" {
87+
options = append(options, client.WithOperationName(operationName))
88+
}
89+
7390
store := mustGetContextStore(cmd)
74-
result := store.ExecRequest(cmd.Context(), request)
91+
result := store.ExecRequest(cmd.Context(), request, options...)
7592

7693
var errors []string
7794
for _, err := range result.GQL.Errors {
@@ -88,7 +105,8 @@ To learn more about the DefraDB GraphQL Query Language, refer to https://docs.so
88105
return nil
89106
},
90107
}
91-
108+
cmd.Flags().StringVarP(&operationName, "operation", "o", "", "Name of the operation to execute in the query")
109+
cmd.Flags().StringVarP(&variablesJSON, "variables", "v", "", "JSON encoded variables to use in the query")
92110
cmd.Flags().StringVarP(&filePath, "file", "f", "", "File containing the query request")
93111
return cmd
94112
}

client/db.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,32 @@ type Store interface {
246246
GetAllIndexes(context.Context) (map[CollectionName][]IndexDescription, error)
247247

248248
// ExecRequest executes the given GQL request against the [Store].
249-
ExecRequest(ctx context.Context, request string) *RequestResult
249+
ExecRequest(ctx context.Context, request string, opts ...RequestOption) *RequestResult
250+
}
251+
252+
// GQLOptions contains optional arguments for GQL requests.
253+
type GQLOptions struct {
254+
// OperationName is the name of the operation to exec.
255+
OperationName string
256+
// Variables is a map of names to varible values.
257+
Variables map[string]any
258+
}
259+
260+
// RequestOption sets an optional request setting.
261+
type RequestOption func(*GQLOptions)
262+
263+
// WithOperationName sets the operation name for a GQL request.
264+
func WithOperationName(operationName string) RequestOption {
265+
return func(o *GQLOptions) {
266+
o.OperationName = operationName
267+
}
268+
}
269+
270+
// WithVariables sets the variables for a GQL request.
271+
func WithVariables(variables map[string]any) RequestOption {
272+
return func(o *GQLOptions) {
273+
o.Variables = variables
274+
}
250275
}
251276

252277
// GQLResult represents the immediate results of a GQL request.

client/mocks/db.go

Lines changed: 25 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/website/references/cli/defradb_client_query.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ defradb client query [-i --identity] [request] [flags]
3030
### Options
3131

3232
```
33-
-f, --file string File containing the query request
34-
-h, --help help for query
33+
-f, --file string File containing the query request
34+
-h, --help help for query
35+
-o, --operation string Name of the operation to execute in the query
36+
-v, --variables string JSON encoded variables to use in the query
3537
```
3638

3739
### Options inherited from parent commands

docs/website/references/http/openapi.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,15 @@
316316
},
317317
"graphql_request": {
318318
"properties": {
319+
"operationName": {
320+
"type": "string"
321+
},
319322
"query": {
320323
"type": "string"
324+
},
325+
"variables": {
326+
"additionalProperties": {},
327+
"type": "object"
321328
}
322329
},
323330
"type": "object"

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module github.com/sourcenetwork/defradb
22

33
go 1.22
44

5+
toolchain go1.22.0
6+
57
require (
68
github.com/bits-and-blooms/bitset v1.14.3
79
github.com/bxcodec/faker v2.0.1+incompatible
@@ -45,7 +47,7 @@ require (
4547
github.com/sourcenetwork/badger/v4 v4.2.1-0.20231113215945-a63444ca5276
4648
github.com/sourcenetwork/corelog v0.0.8
4749
github.com/sourcenetwork/go-libp2p-pubsub-rpc v0.0.14
48-
github.com/sourcenetwork/graphql-go v0.7.10-0.20231113214537-a9560c1898dd
50+
github.com/sourcenetwork/graphql-go v0.7.10-0.20240910200541-550a51c57c7d
4951
github.com/sourcenetwork/immutable v0.3.0
5052
github.com/sourcenetwork/sourcehub v0.2.1-0.20240704194128-f43f5e427274
5153
github.com/spf13/cobra v1.8.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,8 +1394,8 @@ github.com/sourcenetwork/corelog v0.0.8 h1:jCo0mFBpWrfhUCGzzN3uUtPGyQv3jnITdPO1s
13941394
github.com/sourcenetwork/corelog v0.0.8/go.mod h1:cMabHgs3kARgYTQeQYSOmaGGP8XMU6sZrHd8LFrL3zA=
13951395
github.com/sourcenetwork/go-libp2p-pubsub-rpc v0.0.14 h1:620zKV4rOn7U5j/WsPkk4SFj0z9/pVV4bBx0BpZQgro=
13961396
github.com/sourcenetwork/go-libp2p-pubsub-rpc v0.0.14/go.mod h1:jUoQv592uUX1u7QBjAY4C+l24X9ArhPfifOqXpDHz4U=
1397-
github.com/sourcenetwork/graphql-go v0.7.10-0.20231113214537-a9560c1898dd h1:lmpW39/8wPJ0khWRhOcj7Bj0HYKbSmQ8rXMJw1cMB8U=
1398-
github.com/sourcenetwork/graphql-go v0.7.10-0.20231113214537-a9560c1898dd/go.mod h1:rkahXkgRH/3vZErN1Bx+qt1+w+CV5fgaJyKKWgISe4U=
1397+
github.com/sourcenetwork/graphql-go v0.7.10-0.20240910200541-550a51c57c7d h1:gpBJx/mKmpelxZfHT4AYhPYFgSy8DKp/Ca+bBzIIy2A=
1398+
github.com/sourcenetwork/graphql-go v0.7.10-0.20240910200541-550a51c57c7d/go.mod h1:rkahXkgRH/3vZErN1Bx+qt1+w+CV5fgaJyKKWgISe4U=
13991399
github.com/sourcenetwork/immutable v0.3.0 h1:gHPtGvLrTBTK5YpDAhMU+u+S8v1F6iYmc3nbZLryMdc=
14001400
github.com/sourcenetwork/immutable v0.3.0/go.mod h1:GD7ceuh/HD7z6cdIwzKK2ctzgZ1qqYFJpsFp+8qYnbI=
14011401
github.com/sourcenetwork/raccoondb v0.2.1-0.20240606193653-1e91e9be9234 h1:8dA9bVC1A0ChJygtsUfNsek3oR0GnwpLoYpmEo4t2mk=

http/client.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,11 +340,22 @@ func (c *Client) GetAllIndexes(ctx context.Context) (map[client.CollectionName][
340340
func (c *Client) ExecRequest(
341341
ctx context.Context,
342342
query string,
343+
opts ...client.RequestOption,
343344
) *client.RequestResult {
344345
methodURL := c.http.baseURL.JoinPath("graphql")
345346
result := &client.RequestResult{}
346347

347-
body, err := json.Marshal(&GraphQLRequest{query})
348+
gqlOptions := &client.GQLOptions{}
349+
for _, o := range opts {
350+
o(gqlOptions)
351+
}
352+
gqlRequest := &GraphQLRequest{
353+
Query: query,
354+
OperationName: gqlOptions.OperationName,
355+
Variables: gqlOptions.Variables,
356+
}
357+
358+
body, err := json.Marshal(gqlRequest)
348359
if err != nil {
349360
result.GQL.Errors = []error{err}
350361
return result

http/handler_store.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,9 @@ func (s *storeHandler) PrintDump(rw http.ResponseWriter, req *http.Request) {
242242
}
243243

244244
type GraphQLRequest struct {
245-
Query string `json:"query"`
245+
Query string `json:"query"`
246+
OperationName string `json:"operationName"`
247+
Variables map[string]any `json:"variables"`
246248
}
247249

248250
type GraphQLResponse struct {
@@ -299,7 +301,14 @@ func (s *storeHandler) ExecRequest(rw http.ResponseWriter, req *http.Request) {
299301
return
300302
}
301303

302-
result := store.ExecRequest(req.Context(), request.Query)
304+
var options []client.RequestOption
305+
if request.OperationName != "" {
306+
options = append(options, client.WithOperationName(request.OperationName))
307+
}
308+
if len(request.Variables) > 0 {
309+
options = append(options, client.WithVariables(request.Variables))
310+
}
311+
result := store.ExecRequest(req.Context(), request.Query, options...)
303312

304313
if result.Subscription == nil {
305314
responseJSON(rw, http.StatusOK, GraphQLResponse{result.GQL.Data, result.GQL.Errors})

internal/core/parser.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type Parser interface {
4545
ExecuteIntrospection(request string) *client.RequestResult
4646

4747
// Parses the given request, returning a strongly typed model of that request.
48-
Parse(*ast.Document) (*request.Request, []error)
48+
Parse(*ast.Document, *client.GQLOptions) (*request.Request, []error)
4949

5050
// NewFilterFromString creates a new filter from a string.
5151
NewFilterFromString(collectionType string, body string) (immutable.Option[request.Filter], error)

0 commit comments

Comments
 (0)