Skip to content

Commit

Permalink
improve docs and template
Browse files Browse the repository at this point in the history
  • Loading branch information
hgiasac committed Mar 5, 2024
1 parent ad8e71b commit 79868b3
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 136 deletions.
28 changes: 25 additions & 3 deletions cmd/ndc-go-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@ the schema will be:
}
```

#### Arguments

Arguments must be defined as struct types. The generator automatically infers argument types in functions to generate schemas and Encoder and Decoder methods. Value fields are treated as required and pointer fields are optional.

```go
type HelloArguments struct {
Greeting string `json:"greeting"` // value argument will be required
Count *int `json:"count"` // pointer arguments are optional
}
```

#### Scalar Types

**Supported types**
Expand All @@ -168,7 +179,7 @@ The basic scalar types supported are:
- `float32`, `float64` (NDC scalar type: `Float`)
- `bool` (NDC scalar type: `Boolean`)
- `time.Time` (NDC scalar type: `DateTime`, represented as an [ISO formatted](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) string in JSON)
- `time.Duration` (NDC scalar type: `Duration`, represented as a duration string in JSON)
- `time.Duration` (NDC scalar type: `Duration`, represented as a int64 nanosecond duration in JSON)
- `github.com/google/uuid.UUID` (NDC scalar type: `UUID`, represented as an UUID string in JSON)

Alias scalar types will be inferred to the origin type in schema.
Expand All @@ -182,7 +193,7 @@ If you want to define a custom scalar type, the type name must have a `Scalar` p

```go
type ScalarFoo struct {
Bar string
bar string
}
// output: Foo
// auto generated
Expand All @@ -204,13 +215,24 @@ type Foo struct {}

> The generator detects comments by the nearby position. It isn't perfectly accurate in some use cases. Prefix name in function is highly recommended.
For custom scalar, you must implement a method to decode `any` value so its data can be set when resolving request query arguments. `UnmarshalJSON` is used when encoding results.
For custom scalar, you must implement a method to decode `any` value so its data can be set when resolving request query arguments. `UnmarshalJSON` is also used when encoding results.

```go
func (c *ScalarFoo) FromValue(value any) (err error) {
c.Bar, err = utils.DecodeString(value)
return
}

func (c *ScalarFoo) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}

c.bar = s

return nil
}
```

### Documentation
Expand Down
78 changes: 72 additions & 6 deletions cmd/ndc-go-sdk/templates/new/functions/hello.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,62 @@ import (
"{{.Module}}/types"
)

// The generator infers the argument type in FunctionHello to generate codes
// Encoder and decoder methods will be generated to types.generated.go and connector.generated.go

// A hello argument
type HelloArguments struct {
Num int `json:"num"`
Str string `json:"str"`
Greeting string `json:"greeting"` // value argument will be required
Count *int `json:"count"` // pointer arguments are optional
}

// A hello result
type HelloResult struct {
Num int `json:"num"`
Str string `json:"str"`
Reply string `json:"reply"`
Count int `json:"count"`
}

// FunctionHello sends a hello message
// Function is an operation type of query, the name of function will be `hello`
//
// Example:
//
// curl http://localhost:8080/query -H 'content-type: application/json' -d \
// '{
// "collection": "hello",
// "arguments": {
// "greeting": {
// "type": "literal",
// "value": "Hello world!"
// }
// },
// "collection_relationships": {},
// "query": {
// "fields": {
// "reply": {
// "type": "column",
// "column": "reply"
// },
// "count": {
// "type": "column",
// "column": "count"
// }
// }
// }
// }'
func FunctionHello(ctx context.Context, state *types.State, arguments *HelloArguments) (*HelloResult, error) {
count := 1
if arguments.Count != nil {
count = *arguments.Count + 1
}
return &HelloResult{
Num: 1,
Str: "world",
Reply: fmt.Sprintf("Hi! %s", arguments.Greeting),
Count: count,
}, nil
}

// Procedure is similar to function. However the data structure of arguments are simpler and can be decode directly with JSON

// A create author argument
type CreateAuthorArguments struct {
Name string `json:"name"`
Expand All @@ -38,6 +74,36 @@ type CreateAuthorResult struct {
}

// ProcedureCreateAuthor creates an author
// Procedure is an operation type of mutation, the name of function will be `createAuthor`
//
// Example:
//
// curl http://localhost:8080/mutation -H 'content-type: application/json' -d \
// '{
// "operations": [
// {
// "type": "procedure",
// "name": "createAuthor",
// "arguments": {
// "name": "John"
// },
// "fields": {
// "type": "object",
// "fields": {
// "id": {
// "type": "column",
// "column": "id"
// },
// "name": {
// "type": "column",
// "column": "name"
// }
// }
// }
// }
// ],
// "collection_relationships": {}
// }'
func ProcedureCreateAuthor(ctx context.Context, state *types.State, arguments *CreateAuthorArguments) (*CreateAuthorResult, error) {
return &CreateAuthorResult{
ID: 1,
Expand Down
81 changes: 49 additions & 32 deletions example/codegen/connector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,79 +131,87 @@ func TestQueryGetTypes(t *testing.T) {
},
"StringPtr": {
"type": "literal",
"value": "hello"
"value": "world"
},
"IntPtr": {
"type": "literal",
"value": 1
"value": 11
},
"Int8Ptr": {
"type": "literal",
"value": 2
"value": 12
},
"Int16Ptr": {
"type": "literal",
"value": 3
"value": 13
},
"Int32Ptr": {
"type": "literal",
"value": 4
"value": 14
},
"Int64Ptr": {
"type": "literal",
"value": 5
"value": 15
},
"UintPtr": {
"type": "literal",
"value": 6
"value": 16
},
"Uint8Ptr": {
"type": "literal",
"value": 7
"value": 17
},
"Uint16Ptr": {
"type": "literal",
"value": 8
"value": 18
},
"Uint32Ptr": {
"type": "literal",
"value": 9
"value": 19
},
"Uint64Ptr": {
"type": "literal",
"value": 10
"value": 20
},
"Float32Ptr": {
"type": "literal",
"value": 1.1
"value": 3.3
},
"Float64Ptr": {
"type": "literal",
"value": 2.2
"value": 4.4
},
"TimePtr": {
"type": "literal",
"value": "2024-03-05T07:00:56Z"
"value": "2024-03-05T07:00:00Z"
},
"DurationPtr": {
"type": "literal",
"value": "10s"
"value": "1m"
},
"CustomScalarPtr": {
"type": "literal",
"value": "a comment"
"value": "a comment pointer"
},
"Object": {
"type": "literal",
"value": {}
"value": {
"id": "b085b0b9-007c-440e-9661-0d8f2de98a5c",
"created_at": "2024-03-05T06:00:00Z"
}
},
"ObjectPtr": {
"type": "literal",
"value": null
"value": {
"Long": 1,
"Lat": 2
}
},
"ArrayObject": {
"type": "literal",
"value": []
"value": [{
"content": "a content"
}]
},
"ArrayObjectPtr": {
"type": "literal",
Expand All @@ -219,11 +227,19 @@ func TestQueryGetTypes(t *testing.T) {
},
"NamedObjectPtr": {
"type": "literal",
"value": null
"value": {
"id": "2",
"duration": 11,
"created_at": "2024-03-05T04:00:00Z"
}
},
"NamedArray": {
"type": "literal",
"value": []
"value": [{
"id": "3",
"duration": 12,
"created_at": "2024-03-05T03:00:00Z"
}]
}
},
"query": {
Expand Down Expand Up @@ -420,11 +436,12 @@ func TestQueryGetTypes(t *testing.T) {
Uint64: 10,
Float32: 1.1,
Float64: 2.2,
Time: time.Date(2023, 3, 5, 7, 0, 56, 0, time.UTC),
Time: time.Date(2024, 3, 5, 7, 0, 56, 0, time.UTC),
Duration: 10 * time.Second,
CustomScalar: commentText,
UUIDPtr: utils.ToPtr(uuid.MustParse("b085b0b9-007c-440e-9661-0d8f2de98a5b")),
BoolPtr: utils.ToPtr(true),
StringPtr: utils.ToPtr("world"),
IntPtr: utils.ToPtr(11),
Int8Ptr: utils.ToPtr(int8(12)),
Int16Ptr: utils.ToPtr(int16(13)),
Expand All @@ -437,15 +454,15 @@ func TestQueryGetTypes(t *testing.T) {
Uint64Ptr: utils.ToPtr(uint64(20)),
Float32Ptr: utils.ToPtr(float32(3.3)),
Float64Ptr: utils.ToPtr(float64(4.4)),
TimePtr: utils.ToPtr(time.Date(2023, 3, 5, 7, 0, 0, 0, time.UTC)),
TimePtr: utils.ToPtr(time.Date(2024, 3, 5, 7, 0, 0, 0, time.UTC)),
DurationPtr: utils.ToPtr(time.Minute),
CustomScalarPtr: &commentTextPtr,
Object: struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"created_at"`
}{
ID: uuid.MustParse("b085b0b9-007c-440e-9661-0d8f2de98a5c"),
CreatedAt: time.Date(2023, 3, 5, 6, 0, 0, 0, time.UTC),
CreatedAt: time.Date(2024, 3, 5, 6, 0, 0, 0, time.UTC),
},
ObjectPtr: &struct {
Long int
Expand All @@ -455,34 +472,34 @@ func TestQueryGetTypes(t *testing.T) {
Lat: 2,
},
ArrayObject: []struct {
Content string "json:\"content\""
Content string `json:"content"`
}{
{
Content: "a content",
},
},
ArrayObjectPtr: &[]struct {
Content string "json:\"content\""
Content string `json:"content"`
}{
{
Content: "a content pointer",
},
},
NamedObject: functions.Author{
ID: "1",
Duration: 10 * time.Minute,
CreatedAt: time.Date(2023, 3, 5, 5, 0, 0, 0, time.UTC),
Duration: 10,
CreatedAt: time.Date(2024, 3, 5, 5, 0, 0, 0, time.UTC),
},
NamedObjectPtr: &functions.Author{
ID: "2",
Duration: 11 * time.Minute,
CreatedAt: time.Date(2023, 3, 5, 4, 0, 0, 0, time.UTC),
Duration: 11,
CreatedAt: time.Date(2024, 3, 5, 4, 0, 0, 0, time.UTC),
},
NamedArray: []functions.Author{
{
ID: "3",
Duration: 12 * time.Minute,
CreatedAt: time.Date(2023, 3, 5, 3, 0, 0, 0, time.UTC),
Duration: 12,
CreatedAt: time.Date(2024, 3, 5, 3, 0, 0, 0, time.UTC),
},
},
},
Expand Down
Loading

0 comments on commit 79868b3

Please sign in to comment.