diff --git a/cmd/hasura-ndc-go/command/internal/connector_handler.go b/cmd/hasura-ndc-go/command/internal/connector_handler.go index c8b00d5..c7f38ce 100644 --- a/cmd/hasura-ndc-go/command/internal/connector_handler.go +++ b/cmd/hasura-ndc-go/command/internal/connector_handler.go @@ -122,7 +122,10 @@ func (dch DataConnectorHandler) execQuery(ctx context.Context, state *`) functionKeys[i] = fn.Name op := OperationInfo(fn) resultType, isNullable := unwrapNullableType(op.ResultType.Type) - chb.writeOperationValidation(sb, &op, "queryFields", resultType) + schemaName := resultType.SchemaName(false) + _, isScalar := chb.RawSchema.Scalars[schemaName] + + chb.writeOperationValidation(sb, &op, "queryFields", resultType, isScalar) var argumentParamStr string if fn.ArgumentsType != nil { @@ -154,21 +157,21 @@ func (dch DataConnectorHandler) execQuery(ctx context.Context, state *`) argumentParamStr = ", &args" } - switch t := resultType.(type) { + if isScalar { + sb.WriteString(fmt.Sprintf("\n return %s(ctx, state%s)\n", fn.OriginName, argumentParamStr)) + continue + } + switch resultType.(type) { case *ArrayType: chb.writeOperationResult(sb, fn.OriginName, OperationFunction, argumentParamStr, isNullable) sb.WriteString("\n result, err := utils.EvalNestedColumnArrayIntoSlice(selection, rawResult)") writeErrorCheck(sb, 2, 4) sb.WriteString(" return result, nil\n") case *NamedType: - if _, ok := chb.RawSchema.Scalars[t.NativeType.SchemaName]; ok { - sb.WriteString(fmt.Sprintf("\n return %s(ctx, state%s)\n", fn.OriginName, argumentParamStr)) - } else { - chb.writeOperationResult(sb, fn.OriginName, OperationFunction, argumentParamStr, isNullable) - sb.WriteString("\n result, err := utils.EvalNestedColumnObject(selection, rawResult)") - writeErrorCheck(sb, 2, 4) - sb.WriteString(" return result, nil\n") - } + chb.writeOperationResult(sb, fn.OriginName, OperationFunction, argumentParamStr, isNullable) + sb.WriteString("\n result, err := utils.EvalNestedColumnObject(selection, rawResult)") + writeErrorCheck(sb, 2, 4) + sb.WriteString(" return result, nil\n") } } @@ -213,7 +216,9 @@ func (dch DataConnectorHandler) Mutation(ctx context.Context, state *`) procedureKeys[i] = fn.Name op := OperationInfo(fn) resultType, isNullable := unwrapNullableType(op.ResultType.Type) - chb.writeOperationValidation(sb, &op, "operation.Fields", resultType) + schemaName := resultType.SchemaName(false) + _, isScalar := chb.RawSchema.Scalars[schemaName] + chb.writeOperationValidation(sb, &op, "operation.Fields", resultType, isScalar) var argumentParamStr string if fn.ArgumentsType != nil { @@ -235,15 +240,15 @@ func (dch DataConnectorHandler) Mutation(ctx context.Context, state *`) sb.WriteString("\n span.AddEvent(\"execute_procedure\")") - switch t := resultType.(type) { - case *ArrayType: - chb.writeOperationResult(sb, fn.OriginName, OperationProcedure, argumentParamStr, isNullable) - sb.WriteString("\n result, err := utils.EvalNestedColumnArrayIntoSlice(selection, rawResult)\n") - writeErrorCheck(sb, 2, 4) - case *NamedType: - if _, ok := chb.RawSchema.Scalars[t.NativeType.SchemaName]; ok { - chb.writeOperationExecution(sb, fn.OriginName, argumentParamStr, "result") - } else { + if isScalar { + chb.writeOperationExecution(sb, fn.OriginName, argumentParamStr, "result") + } else { + switch resultType.(type) { + case *ArrayType: + chb.writeOperationResult(sb, fn.OriginName, OperationProcedure, argumentParamStr, isNullable) + sb.WriteString("\n result, err := utils.EvalNestedColumnArrayIntoSlice(selection, rawResult)\n") + writeErrorCheck(sb, 2, 4) + case *NamedType: chb.writeOperationResult(sb, fn.OriginName, OperationProcedure, argumentParamStr, isNullable) sb.WriteString("\n result, err := utils.EvalNestedColumnObject(selection, rawResult)\n") writeErrorCheck(sb, 2, 4) @@ -261,12 +266,21 @@ func (dch DataConnectorHandler) Mutation(ctx context.Context, state *`) chb.writeOperationNameEnums(sb, procedureEnumsName, procedureKeys) } -func (chb connectorHandlerBuilder) writeOperationValidation(sb *strings.Builder, fn *OperationInfo, selector string, resultType Type) { +func (chb connectorHandlerBuilder) writeOperationValidation(sb *strings.Builder, fn *OperationInfo, selector string, resultType Type, isScalar bool) { _, _ = sb.WriteString("\n case \"") _, _ = sb.WriteString(fn.Name) _, _ = sb.WriteString("\":\n") - switch t := resultType.(type) { + if isScalar { + sb.WriteString("\n if len(") + sb.WriteString(selector) + sb.WriteString(`) > 0 { + return nil, schema.UnprocessableContentError("cannot evaluate selection fields for scalar", nil) + }`) + return + } + + switch resultType.(type) { case *ArrayType: sb.WriteString("\n selection, err := ") sb.WriteString(selector) @@ -277,15 +291,6 @@ func (chb connectorHandlerBuilder) writeOperationValidation(sb *strings.Builder, }) }`) case *NamedType: - if _, ok := chb.RawSchema.Scalars[t.NativeType.SchemaName]; ok { - sb.WriteString("\n if len(") - sb.WriteString(selector) - sb.WriteString(`) > 0 { - return nil, schema.UnprocessableContentError("cannot evaluate selection fields for scalar", nil) - }`) - return - } - sb.WriteString("\n selection, err := ") sb.WriteString(selector) sb.WriteString(`.AsObject() diff --git a/example/codegen/functions/prefix.go b/example/codegen/functions/prefix.go index f9d1ce1..866eec5 100644 --- a/example/codegen/functions/prefix.go +++ b/example/codegen/functions/prefix.go @@ -9,6 +9,7 @@ import ( "github.com/google/uuid" "github.com/hasura/ndc-codegen-example/types" "github.com/hasura/ndc-codegen-example/types/arguments" + "github.com/hasura/ndc-sdk-go/utils" ) // A foo scalar @@ -85,6 +86,11 @@ func FunctionGetBool(ctx context.Context, state *types.State) (bool, error) { return true, nil } +// FunctionGetInts return a slice of scalar ints +func FunctionGetInts(ctx context.Context, state *types.State) ([]*int, error) { + return []*int{utils.ToPtr(1), utils.ToPtr(2), utils.ToPtr(3)}, nil +} + func FunctionGetTypes(ctx context.Context, state *types.State, arguments *arguments.GetTypesArguments) (*arguments.GetTypesArguments, error) { return arguments, nil } @@ -143,7 +149,8 @@ func FunctionGetCustomHeaders(ctx context.Context, state *types.State, arguments if arguments.Headers == nil { arguments.Headers = make(map[string]string) } - arguments.Headers["X-Test-ResponseHeader"] = "I set this in the code" + + arguments.Headers["X-Test-ResponseHeader"] = arguments.Input.Name result := HelloResult{} if arguments.Input != nil { result.Text = types.Text(arguments.Input.Name) diff --git a/example/codegen/functions/types.generated.go b/example/codegen/functions/types.generated.go index ec1d4cc..cb7804f 100644 --- a/example/codegen/functions/types.generated.go +++ b/example/codegen/functions/types.generated.go @@ -311,6 +311,13 @@ func (dch DataConnectorHandler) execQuery(ctx context.Context, state *types.Stat } return result, nil + case "getInts": + + if len(queryFields) > 0 { + return nil, schema.UnprocessableContentError("cannot evaluate selection fields for scalar", nil) + } + return FunctionGetInts(ctx, state) + case "getTypes": selection, err := queryFields.AsObject() @@ -413,7 +420,7 @@ func (dch DataConnectorHandler) execQuery(ctx context.Context, state *types.Stat } } -var enumValues_FunctionName = []string{"getAuthor", "getAuthor2", "getBool", "getCustomHeaders", "getGenericWithoutDecodingMethod", "getTypes", "hello", "getArticles"} +var enumValues_FunctionName = []string{"getAuthor", "getAuthor2", "getBool", "getCustomHeaders", "getGenericWithoutDecodingMethod", "getInts", "getTypes", "hello", "getArticles"} // MutationExists check if the mutation name exists func (dch DataConnectorHandler) MutationExists(name string) bool { diff --git a/example/codegen/go.mod b/example/codegen/go.mod index 52d9a12..499a999 100644 --- a/example/codegen/go.mod +++ b/example/codegen/go.mod @@ -5,7 +5,7 @@ go 1.21 require ( github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 - github.com/hasura/ndc-sdk-go v1.5.1 + github.com/hasura/ndc-sdk-go v1.6.0 go.opentelemetry.io/otel v1.28.0 go.opentelemetry.io/otel/trace v1.28.0 golang.org/x/sync v0.8.0 diff --git a/example/codegen/schema.generated.go b/example/codegen/schema.generated.go index d1fd4ac..a010f79 100644 --- a/example/codegen/schema.generated.go +++ b/example/codegen/schema.generated.go @@ -891,6 +891,12 @@ func GetConnectorSchema() *schema.SchemaResponse { }, }, }, + { + Name: "getInts", + Description: toPtr("return a slice of scalar ints"), + ResultType: schema.NewArrayType(schema.NewNullableType(schema.NewNamedType("Int32"))).Encode(), + Arguments: map[string]schema.ArgumentInfo{}, + }, { Name: "getTypes", ResultType: schema.NewNullableType(schema.NewNamedType("GetTypesArguments")).Encode(), diff --git a/example/codegen/testdata/query/getCustomHeaders/expected.json b/example/codegen/testdata/query/getCustomHeaders/expected.json index f75ec28..b348a75 100644 --- a/example/codegen/testdata/query/getCustomHeaders/expected.json +++ b/example/codegen/testdata/query/getCustomHeaders/expected.json @@ -11,7 +11,7 @@ "text": "oK022ZdXnL" }, "headers": { - "X-Test-ResponseHeader": "I set this in the code", + "X-Test-ResponseHeader": "oK022ZdXnL", "foo": "bar" } } diff --git a/example/codegen/testdata/query/getInts/expected.json b/example/codegen/testdata/query/getInts/expected.json new file mode 100644 index 0000000..603bca3 --- /dev/null +++ b/example/codegen/testdata/query/getInts/expected.json @@ -0,0 +1,9 @@ +[ + { + "rows": [ + { + "__value": [1, 2, 3] + } + ] + } +] diff --git a/example/codegen/testdata/query/getInts/request.json b/example/codegen/testdata/query/getInts/request.json new file mode 100644 index 0000000..c7192a0 --- /dev/null +++ b/example/codegen/testdata/query/getInts/request.json @@ -0,0 +1,13 @@ +{ + "arguments": {}, + "collection": "getInts", + "collection_relationships": {}, + "query": { + "fields": { + "__value": { + "column": "__value", + "type": "column" + } + } + } +} \ No newline at end of file