fill out the easy parts of the codegen
This commit is contained in:
+1
-8
@@ -1,16 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/Khan/genql/generate"
|
"github.com/Khan/genql/generate"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := generate.Generate()
|
generate.Main()
|
||||||
if err != nil {
|
|
||||||
fmt.Println(fmt.Errorf("genql failed: %v", err))
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,10 @@ func GetViewer(ctx context.Context) (*GetViewerResponse, error) {
|
|||||||
http.MethodPost,
|
http.MethodPost,
|
||||||
`https://api.github.com/graphql`,
|
`https://api.github.com/graphql`,
|
||||||
strings.NewReader(`
|
strings.NewReader(`
|
||||||
"GetViewer gets the current user's name."
|
|
||||||
query GetViewer {
|
query GetViewer {
|
||||||
Viewer: viewer {
|
Viewer: viewer {
|
||||||
Name: name
|
Name: name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`))
|
`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"GetViewer gets the current user's name."
|
# GetViewer gets the current user's name.
|
||||||
query GetViewer {
|
query GetViewer {
|
||||||
Viewer: viewer {
|
Viewer: viewer {
|
||||||
Name: name
|
Name: name
|
||||||
|
|||||||
+92
-11
@@ -2,41 +2,122 @@ package generate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/vektah/gqlparser"
|
"github.com/vektah/gqlparser/ast"
|
||||||
|
"github.com/vektah/gqlparser/formatter"
|
||||||
|
"github.com/vektah/gqlparser/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = gqlparser.LoadSchema
|
|
||||||
|
|
||||||
// TODO: package template into the binary using one of those asset thingies
|
// TODO: package template into the binary using one of those asset thingies
|
||||||
const tmplFilename = "generate/operation.go.tmpl"
|
const tmplFilename = "generate/operation.go.tmpl"
|
||||||
|
|
||||||
|
var tmpl = template.Must(template.ParseFiles(tmplFilename))
|
||||||
|
|
||||||
type TemplateParams struct {
|
type TemplateParams struct {
|
||||||
// The name of the package into which to generate the operation-helpers.
|
// The name of the package into which to generate the operation-helpers.
|
||||||
PackageName string
|
PackageName string
|
||||||
|
// The list of operations for which to generate code.
|
||||||
|
Operations []OperationParams
|
||||||
|
}
|
||||||
|
|
||||||
|
type OperationParams struct {
|
||||||
// The type-name for the operation's response type.
|
// The type-name for the operation's response type.
|
||||||
ResponseName string
|
ResponseName string
|
||||||
// The body of the operation's response type (e.g. struct { ... }).
|
// The body of the operation's response type (e.g. struct { ... }).
|
||||||
ResponseType string
|
ResponseType string
|
||||||
// The documentation for the operation, from GraphQL.
|
// The type of the operation (query, mutation, or subscription).
|
||||||
OperationDoc string
|
OperationType ast.Operation
|
||||||
// The name of the operation, from GraphQL.
|
// The name of the operation, from GraphQL.
|
||||||
OperationName string
|
OperationName string
|
||||||
|
// The documentation for the operation, from GraphQL.
|
||||||
|
OperationDoc string
|
||||||
// The endpoint to which to send queries.
|
// The endpoint to which to send queries.
|
||||||
Endpoint string
|
Endpoint string
|
||||||
// The body of the operation to send.
|
// The body of the operation to send.
|
||||||
Operation string
|
Operation string
|
||||||
}
|
}
|
||||||
|
|
||||||
var tmpl = template.Must(template.ParseFiles(tmplFilename))
|
func Generate(specFilename, generatedFilename string) error {
|
||||||
|
text, err := ioutil.ReadFile(specFilename)
|
||||||
func Generate() error {
|
|
||||||
var data TemplateParams
|
|
||||||
err := tmpl.Execute(os.Stdout, data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("template did not render: %v", err)
|
return fmt.Errorf("could not open query-spec file %v: %v",
|
||||||
|
specFilename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
document, graphqlError := parser.ParseQuery(
|
||||||
|
&ast.Source{Name: specFilename, Input: string(text)})
|
||||||
|
if graphqlError != nil { // ParseQuery returns type *graphql.Error, yuck
|
||||||
|
return fmt.Errorf("could not parse query-spec file %v: %v",
|
||||||
|
specFilename, graphqlError)
|
||||||
|
}
|
||||||
|
|
||||||
|
var out io.Writer
|
||||||
|
if generatedFilename == "-" {
|
||||||
|
out = os.Stdout
|
||||||
|
} else {
|
||||||
|
out, err = os.OpenFile(generatedFilename, os.O_RDWR|os.O_CREATE, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not open generated file %v: %v",
|
||||||
|
generatedFilename, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: configure these
|
||||||
|
packageName := "example"
|
||||||
|
endpoint := "https://api.github.com/graphql"
|
||||||
|
|
||||||
|
operations := make([]OperationParams, len(document.Operations))
|
||||||
|
for i, operation := range document.Operations {
|
||||||
|
var builder strings.Builder
|
||||||
|
f := formatter.NewFormatter(&builder)
|
||||||
|
f.FormatQueryDocument(&ast.QueryDocument{
|
||||||
|
Operations: ast.OperationList{operation},
|
||||||
|
// TODO: handle fragments
|
||||||
|
})
|
||||||
|
operations[i] = OperationParams{
|
||||||
|
OperationType: operation.Operation,
|
||||||
|
OperationName: operation.Name,
|
||||||
|
OperationDoc: "TODO",
|
||||||
|
|
||||||
|
// TODO: configure this
|
||||||
|
ResponseName: operation.Name + "Response",
|
||||||
|
ResponseType: "struct{} // TODO",
|
||||||
|
|
||||||
|
Endpoint: endpoint,
|
||||||
|
// The newline just makes it format a little nicer
|
||||||
|
Operation: "\n" + builder.String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data := TemplateParams{
|
||||||
|
PackageName: packageName,
|
||||||
|
Operations: operations,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tmpl.Execute(out, data)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not render template: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Main() {
|
||||||
|
var err error
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if len(os.Args) != 3 {
|
||||||
|
err = fmt.Errorf("usage: %s queries.graphql generated.go", os.Args[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = Generate(os.Args[1], os.Args[2])
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
{{range .Operations}}
|
||||||
type {{.ResponseName}} = {{.ResponseType}}
|
type {{.ResponseName}} = {{.ResponseType}}
|
||||||
|
|
||||||
// {{.OperationDoc}}
|
// {{.OperationDoc}}
|
||||||
@@ -20,7 +21,7 @@ func {{.OperationName}}(ctx context.Context) (*{{.ResponseName}}, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -40,3 +41,4 @@ func {{.OperationName}}(ctx context.Context) (*{{.ResponseName}}, error) {
|
|||||||
|
|
||||||
return &retval, nil
|
return &retval, nil
|
||||||
}
|
}
|
||||||
|
{{end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user