Skip to content

Commit

Permalink
Support ndc spec v0.1.2 (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
hgiasac authored Apr 5, 2024
1 parent 9c3db01 commit e5c75fc
Show file tree
Hide file tree
Showing 18 changed files with 1,668 additions and 310 deletions.
42 changes: 41 additions & 1 deletion cmd/ndc-go-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ Commands:

generate
Generate schema and implementation for the connector from functions.

test snapshots
Generate test snapshots.
```

### Initialize connector project
Expand Down Expand Up @@ -292,6 +295,43 @@ func ProcedureCreateAuthor(ctx context.Context, state *types.State, arguments *C
// }
```

### Example
## Example

See [example/codegen](../../example/codegen).

## Test Snapshots

The tool supports test snapshots generation for query and mutation requests and responses that are compatible with [ndc-test replay](https://github.com/hasura/ndc-spec/tree/main/ndc-test#custom-tests) command. See generated snapshots at [the codegen example](../../example/codegen/testdata).

```bash
Usage: hasura-ndc-go test snapshots

Generate test snapshots.

Flags:
-h, --help Show context-sensitive help.
--log-level="info" Log level.

--schema=STRING NDC schema file path. Use either endpoint or schema path
--endpoint=STRING The endpoint of the connector. Use either endpoint or schema path
--dir=STRING The directory of test snapshots.
--depth=10 The selection depth of nested fields in result types.
--seed=SEED Using a fixed seed will produce the same output on every run.
--query=QUERY,... Specify individual queries to be generated. Separated by commas, or 'all' for all queries
--mutation=MUTATION,... Specify individual mutations to be generated. Separated by commas, or 'all' for all mutations
--strategy="none" Decide the strategy to do when the snapshot file exists.
```

The command accepts either a connector `--endpoint` or a JSON `--schema` file.

**Endpoint**

```bash
hasura-ndc-go test snapshots --endpoint http://localhost:8080 --dir testdata
```

**NDC Schema**

```bash
hasura-ndc-go test snapshots --schema schema.generated.json --dir testdata
```
32 changes: 30 additions & 2 deletions cmd/ndc-go-sdk/command/internal/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,41 @@ package internal

import (
"encoding/json"
"fmt"
"os"
"slices"
)

// Decide the strategy to do when the written file exists
type WriteFileStrategy string

const (
WriteFileStrategyNone WriteFileStrategy = "none"
WriteFileStrategyOverride WriteFileStrategy = "override"
)

var enumValues_WriteFileStrategy = []WriteFileStrategy{
WriteFileStrategyNone,
WriteFileStrategyOverride,
}

// ParseWriteFileStrategy parses a WriteFileStrategy enum from string
func ParseWriteFileStrategy(input string) (WriteFileStrategy, error) {
result := WriteFileStrategy(input)
if !slices.Contains(enumValues_WriteFileStrategy, result) {
return WriteFileStrategy(""), fmt.Errorf("failed to parse WriteFileStrategy, expect one of %v, got: %s", enumValues_WriteFileStrategy, input)
}

return result, nil
}

// WritePrettyFileJSON writes JSON data with indent
func WritePrettyFileJSON(fileName string, data any) error {
func WritePrettyFileJSON(fileName string, data any, strategy WriteFileStrategy) error {
if _, err := os.Stat(fileName); err == nil {
return nil
switch strategy {
case WriteFileStrategyNone, "":
return nil
}
}
rawBytes, err := json.MarshalIndent(data, "", " ")
if err != nil {
Expand Down
48 changes: 37 additions & 11 deletions cmd/ndc-go-sdk/command/test_snapshots.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"os"
"path"
"slices"
"time"

"github.com/hasura/ndc-sdk-go/cmd/ndc-go-sdk/command/internal"
Expand All @@ -16,11 +17,14 @@ import (

// GenTestSnapshotArguments represents arguments for test snapshot generation
type GenTestSnapshotArguments struct {
Schema string `help:"NDC schema file path. Use either endpoint or schema path"`
Endpoint string `help:"The endpoint of the connector. Use either endpoint or schema path"`
Dir string `help:"The directory of test snapshots."`
Depth uint `help:"The selection depth of nested fields in result types." default:"10"`
Seed *int64 `help:"Using a fixed seed will produce the same output on every run."`
Schema string `help:"NDC schema file path. Use either endpoint or schema path"`
Endpoint string `help:"The endpoint of the connector. Use either endpoint or schema path"`
Dir string `help:"The directory of test snapshots."`
Depth uint `help:"The selection depth of nested fields in result types." default:"10"`
Seed *int64 `help:"Using a fixed seed will produce the same output on every run."`
Query []string `help:"Specify individual queries to be generated. Separated by commas, or 'all' for all queries"`
Mutation []string `help:"Specify individual mutations to be generated. Separated by commas, or 'all' for all mutations"`
Strategy internal.WriteFileStrategy `help:"Decide the strategy to do when the snapshot file exists. Accept: none, override" enum:"none,override" default:"none"`
}

// genTestSnapshotsCommand
Expand Down Expand Up @@ -102,7 +106,9 @@ func (cmd *genTestSnapshotsCommand) fetchSchema() error {
}

func (cmd *genTestSnapshotsCommand) genFunction(fn *schema.FunctionInfo) error {

if !cmd.hasQuery(fn.Name) {
return nil
}
args, err := cmd.genQueryArguments(fn.Arguments)
if err != nil {
return fmt.Errorf("failed to generate arguments for %s function: %s", fn.Name, err)
Expand Down Expand Up @@ -138,11 +144,11 @@ func (cmd *genTestSnapshotsCommand) genFunction(fn *schema.FunctionInfo) error {
return err
}

if err := internal.WritePrettyFileJSON(path.Join(snapshotDir, "request.json"), queryReq); err != nil {
if err := internal.WritePrettyFileJSON(path.Join(snapshotDir, "request.json"), queryReq, cmd.args.Strategy); err != nil {
return err
}

return internal.WritePrettyFileJSON(path.Join(snapshotDir, "expected.json"), queryResp)
return internal.WritePrettyFileJSON(path.Join(snapshotDir, "expected.json"), queryResp, cmd.args.Strategy)
}

func (cmd *genTestSnapshotsCommand) genQueryArguments(arguments schema.FunctionInfoArguments) (schema.QueryRequestArguments, error) {
Expand All @@ -161,6 +167,9 @@ func (cmd *genTestSnapshotsCommand) genQueryArguments(arguments schema.FunctionI
}

func (cmd *genTestSnapshotsCommand) genProcedure(proc *schema.ProcedureInfo) error {
if !cmd.hasMutation(proc.Name) {
return nil
}
args, err := cmd.genOperationArguments(proc.Arguments)
if err != nil {
return fmt.Errorf("failed to generate arguments for %s procedure: %s", proc.Name, err)
Expand Down Expand Up @@ -197,11 +206,11 @@ func (cmd *genTestSnapshotsCommand) genProcedure(proc *schema.ProcedureInfo) err
return err
}

if err := internal.WritePrettyFileJSON(path.Join(snapshotDir, "request.json"), mutationReq); err != nil {
if err := internal.WritePrettyFileJSON(path.Join(snapshotDir, "request.json"), mutationReq, cmd.args.Strategy); err != nil {
return err
}

return internal.WritePrettyFileJSON(path.Join(snapshotDir, "expected.json"), mutationResp)
return internal.WritePrettyFileJSON(path.Join(snapshotDir, "expected.json"), mutationResp, cmd.args.Strategy)
}

func (cmd *genTestSnapshotsCommand) genOperationArguments(arguments schema.ProcedureInfoArguments) ([]byte, error) {
Expand Down Expand Up @@ -236,7 +245,7 @@ func (cmd *genTestSnapshotsCommand) genNestFieldAndValueInternal(rawType schema.
if err != nil {
return nil, nil, false, err
}
if isScalar {
if innerType == nil || isScalar {
return nil, []any{data}, isScalar, nil
}
return schema.NewNestedArray(innerType), []any{data}, isScalar, nil
Expand All @@ -262,8 +271,25 @@ func (cmd *genTestSnapshotsCommand) genNestFieldAndValueInternal(rawType schema.
fields[key] = schema.NewColumnField(key, innerType)
values[key] = value
}
if len(fields) == 0 {
return nil, values, false, nil
}
return schema.NewNestedObject(fields), values, false, nil
default:
return nil, nil, false, err
}
}

func (cmd genTestSnapshotsCommand) hasQuery(name string) bool {
if (len(cmd.args.Query) == 0 && len(cmd.args.Mutation) == 0) || slices.Contains(cmd.args.Query, "all") {
return true
}
return slices.Contains(cmd.args.Query, name)
}

func (cmd genTestSnapshotsCommand) hasMutation(name string) bool {
if (len(cmd.args.Query) == 0 && len(cmd.args.Mutation) == 0) || slices.Contains(cmd.args.Mutation, "all") {
return true
}
return slices.Contains(cmd.args.Mutation, name)
}
Loading

0 comments on commit e5c75fc

Please sign in to comment.