mirror of
https://github.com/zhigang1992/graphql-engine.git
synced 2026-04-28 20:15:01 +08:00
Co-authored-by: Aravind Shankar <aravind@hasura.io>
This commit is contained in:
committed by
GitHub
parent
491a50b1e9
commit
9b66724b41
@@ -11,6 +11,8 @@ The order and collapsed state of columns is now persisted across page navigation
|
||||
|
||||
### Bug fixes and improvements
|
||||
|
||||
- console: query support for actions (#4318)
|
||||
- cli: query support for actions (#4318)
|
||||
- cli: add retry_conf in event trigger for squashing migrations (close #4296) (#4324)
|
||||
- cli: allow customization of server api paths (close #4016)
|
||||
- cli: clean up migration files created during a failed migrate api (close #4312) (#4319)
|
||||
|
||||
@@ -22,7 +22,7 @@ const handlePayload = (payload) => {
|
||||
if (actions) {
|
||||
try {
|
||||
actions.forEach(a => {
|
||||
actionSdl += getActionDefinitionSdl(a.name, a.definition.arguments, a.definition.output_type) + '\n';
|
||||
actionSdl += getActionDefinitionSdl(a.name, a.definition.type, a.definition.arguments, a.definition.output_type) + '\n';
|
||||
})
|
||||
} catch (e) {
|
||||
actionSdlError = e;
|
||||
@@ -42,7 +42,7 @@ const handlePayload = (payload) => {
|
||||
if (toDeriveOperation) {
|
||||
try {
|
||||
const derivation = deriveAction(toDeriveOperation, introspectionSchema, actionName);
|
||||
const derivedActionSdl = getActionDefinitionSdl(derivation.action.name, derivation.action.arguments, derivation.action.output_type);
|
||||
const derivedActionSdl = getActionDefinitionSdl(derivation.action.name, derivation.action.type, derivation.action.arguments, derivation.action.output_type);
|
||||
const derivedTypesSdl = getTypesSdl(derivation.types);
|
||||
sdl = `${derivedActionSdl}\n\n${derivedTypesSdl}\n\n${sdl}`
|
||||
} catch (e) {
|
||||
|
||||
@@ -21,7 +21,6 @@ require (
|
||||
github.com/gofrs/uuid v3.2.0+incompatible
|
||||
github.com/gorilla/sessions v1.2.0 // indirect
|
||||
github.com/gosimple/slug v1.9.0 // indirect
|
||||
github.com/graphql-go/graphql v0.7.8
|
||||
github.com/jinzhu/configor v1.1.1 // indirect
|
||||
github.com/jinzhu/gorm v1.9.11 // indirect
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||
|
||||
@@ -151,8 +151,6 @@ github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=
|
||||
github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=
|
||||
github.com/graphql-go/graphql v0.7.8 h1:769CR/2JNAhLG9+aa8pfLkKdR0H+r5lsQqling5WwpU=
|
||||
github.com/graphql-go/graphql v0.7.8/go.mod h1:k6yrAYQaSP59DC5UVxbgxESlmVyojThKdORUqGDGmrI=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
|
||||
|
||||
|
||||
@@ -5,13 +5,9 @@ import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/graphql-go/graphql/language/ast"
|
||||
"github.com/graphql-go/graphql/language/kinds"
|
||||
"github.com/graphql-go/graphql/language/parser"
|
||||
"github.com/hasura/graphql-engine/cli"
|
||||
cliextension "github.com/hasura/graphql-engine/cli/metadata/actions/cli_extension"
|
||||
"github.com/hasura/graphql-engine/cli/metadata/actions/editor"
|
||||
"github.com/hasura/graphql-engine/cli/metadata/actions/printer"
|
||||
"github.com/hasura/graphql-engine/cli/metadata/actions/types"
|
||||
"github.com/hasura/graphql-engine/cli/plugins"
|
||||
"github.com/hasura/graphql-engine/cli/util"
|
||||
@@ -61,54 +57,21 @@ func (a *ActionConfig) Create(name string, introSchema interface{}, deriveFrom s
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error in reading %s file", graphqlFileName)
|
||||
}
|
||||
doc, err := parser.Parse(parser.ParseParams{
|
||||
Source: graphqlFileContent,
|
||||
})
|
||||
// Read actions.yaml
|
||||
oldAction, err := a.GetActionsFileContent()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to parse graphql")
|
||||
return errors.Wrapf(err, "error in reading %s file", actionsFileName)
|
||||
}
|
||||
currentActionNames := make([]string, 0)
|
||||
// Check if the action already exists, if yes throw error
|
||||
for _, def := range doc.Definitions {
|
||||
switch obj := def.(type) {
|
||||
case *ast.ObjectDefinition:
|
||||
if obj.Kind == kinds.ObjectDefinition && obj.Name.Kind == kinds.Name && obj.Name.Value == "Mutation" {
|
||||
for _, field := range obj.Fields {
|
||||
currentActionNames = append(currentActionNames, field.Name.Value)
|
||||
}
|
||||
}
|
||||
case *ast.TypeExtensionDefinition:
|
||||
if obj.Kind == kinds.TypeExtensionDefinition && obj.Definition.Name.Kind == kinds.Name && obj.Definition.Name.Value == "Mutation" {
|
||||
for _, field := range obj.Definition.Fields {
|
||||
currentActionNames = append(currentActionNames, field.Name.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, currAction := range currentActionNames {
|
||||
if currAction == name {
|
||||
// check if action already present
|
||||
for _, currAction := range oldAction.Actions {
|
||||
if currAction.Name == name {
|
||||
return fmt.Errorf("action %s already exists in %s", name, graphqlFileName)
|
||||
}
|
||||
}
|
||||
|
||||
// add extend type mutation
|
||||
for index, def := range doc.Definitions {
|
||||
switch obj := def.(type) {
|
||||
case *ast.ObjectDefinition:
|
||||
if obj.Kind == kinds.ObjectDefinition && obj.Name.Kind == kinds.Name && obj.Name.Value == "Mutation" {
|
||||
newObj := &ast.TypeExtensionDefinition{
|
||||
Kind: kinds.TypeExtensionDefinition,
|
||||
Definition: obj,
|
||||
}
|
||||
doc.Definitions[index] = newObj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var defaultSDL string
|
||||
if introSchema == nil {
|
||||
defaultSDL = `
|
||||
extend type Mutation {
|
||||
defaultSDL = `type Mutation {
|
||||
# Define your action as a mutation here
|
||||
` + name + ` (arg1: SampleInput!): SampleOutput
|
||||
}
|
||||
@@ -136,54 +99,8 @@ input SampleInput {
|
||||
}
|
||||
defaultSDL = sdlToResp.SDL.Complete
|
||||
}
|
||||
newDoc, err := parser.Parse(parser.ParseParams{
|
||||
Source: defaultSDL,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error in parsing default sdl")
|
||||
}
|
||||
doc.Definitions = append(newDoc.Definitions, doc.Definitions...)
|
||||
inputDupData := map[string][]int{}
|
||||
objDupData := map[string][]int{}
|
||||
for index, def := range doc.Definitions {
|
||||
switch obj := def.(type) {
|
||||
case *ast.ObjectDefinition:
|
||||
if obj.GetName().Value != "Mutation" {
|
||||
// check if name already exists
|
||||
_, ok := objDupData[obj.GetName().Value]
|
||||
if !ok {
|
||||
objDupData[obj.GetName().Value] = []int{index}
|
||||
} else {
|
||||
objDupData[obj.GetName().Value] = append(objDupData[obj.GetName().Value], index)
|
||||
}
|
||||
}
|
||||
case *ast.InputObjectDefinition:
|
||||
_, ok := inputDupData[obj.GetName().Value]
|
||||
if !ok {
|
||||
inputDupData[obj.GetName().Value] = []int{index}
|
||||
} else {
|
||||
inputDupData[obj.GetName().Value] = append(inputDupData[obj.GetName().Value], index)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, indexes := range inputDupData {
|
||||
if len(indexes) > 0 {
|
||||
indexes = indexes[:len(indexes)-1]
|
||||
}
|
||||
for _, index := range indexes {
|
||||
doc.Definitions = append(doc.Definitions[:index], doc.Definitions[index+1:]...)
|
||||
}
|
||||
}
|
||||
for _, indexes := range objDupData {
|
||||
if len(indexes) > 0 {
|
||||
indexes = indexes[:len(indexes)-1]
|
||||
}
|
||||
for _, index := range indexes {
|
||||
doc.Definitions = append(doc.Definitions[:index], doc.Definitions[index+1:]...)
|
||||
}
|
||||
}
|
||||
defaultText := printer.Print(doc).(string)
|
||||
data, err := editor.CaptureInputFromEditor(editor.GetPreferredEditorFromEnvironment, defaultText)
|
||||
graphqlFileContent = defaultSDL + "\n" + graphqlFileContent
|
||||
data, err := editor.CaptureInputFromEditor(editor.GetPreferredEditorFromEnvironment, graphqlFileContent)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error in getting input from editor")
|
||||
}
|
||||
@@ -196,12 +113,7 @@ input SampleInput {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error in converting sdl to metadata")
|
||||
}
|
||||
// Read actions.yaml
|
||||
oldAction, err := a.GetActionsFileContent()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error in reading %s file", actionsFileName)
|
||||
}
|
||||
currentActionNames = make([]string, 0)
|
||||
currentActionNames := make([]string, 0)
|
||||
for actionIndex, action := range sdlFromResp.Actions {
|
||||
for _, currAction := range currentActionNames {
|
||||
if currAction == action.Name {
|
||||
@@ -213,6 +125,7 @@ input SampleInput {
|
||||
if action.Name == oldActionObj.Name {
|
||||
sdlFromResp.Actions[actionIndex].Permissions = oldAction.Actions[oldActionIndex].Permissions
|
||||
sdlFromResp.Actions[actionIndex].Definition.Kind = oldAction.Actions[oldActionIndex].Definition.Kind
|
||||
sdlFromResp.Actions[actionIndex].Definition.Type = oldAction.Actions[oldActionIndex].Definition.Type
|
||||
sdlFromResp.Actions[actionIndex].Definition.Handler = oldAction.Actions[oldActionIndex].Definition.Handler
|
||||
sdlFromResp.Actions[actionIndex].Definition.ForwardClientHeaders = oldAction.Actions[oldActionIndex].Definition.ForwardClientHeaders
|
||||
sdlFromResp.Actions[actionIndex].Definition.Headers = oldAction.Actions[oldActionIndex].Definition.Headers
|
||||
@@ -500,12 +413,6 @@ func (a *ActionConfig) Export(metadata yaml.MapSlice) (map[string][]byte, error)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error in converting metadata to sdl")
|
||||
}
|
||||
doc, err := parser.Parse(parser.ParseParams{
|
||||
Source: sdlToResp.SDL.Complete,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error in parsing sdl")
|
||||
}
|
||||
common.SetExportDefault()
|
||||
commonByt, err := yaml.Marshal(common)
|
||||
if err != nil {
|
||||
@@ -513,7 +420,7 @@ func (a *ActionConfig) Export(metadata yaml.MapSlice) (map[string][]byte, error)
|
||||
}
|
||||
return map[string][]byte{
|
||||
filepath.Join(a.MetadataDir, actionsFileName): commonByt,
|
||||
filepath.Join(a.MetadataDir, graphqlFileName): []byte(printer.Print(doc).(string)),
|
||||
filepath.Join(a.MetadataDir, graphqlFileName): []byte(sdlToResp.SDL.Complete),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,952 +0,0 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"reflect"
|
||||
|
||||
"github.com/graphql-go/graphql/language/ast"
|
||||
"github.com/graphql-go/graphql/language/visitor"
|
||||
)
|
||||
|
||||
func getMapValue(m map[string]interface{}, key string) interface{} {
|
||||
tokens := strings.Split(key, ".")
|
||||
valMap := m
|
||||
for _, token := range tokens {
|
||||
v, ok := valMap[token]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case []interface{}:
|
||||
return v
|
||||
case map[string]interface{}:
|
||||
valMap = v
|
||||
continue
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
return valMap
|
||||
}
|
||||
func getMapSliceValue(m map[string]interface{}, key string) []interface{} {
|
||||
tokens := strings.Split(key, ".")
|
||||
valMap := m
|
||||
for _, token := range tokens {
|
||||
v, ok := valMap[token]
|
||||
if !ok {
|
||||
return []interface{}{}
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case []interface{}:
|
||||
return v
|
||||
default:
|
||||
return []interface{}{}
|
||||
}
|
||||
}
|
||||
return []interface{}{}
|
||||
}
|
||||
func getMapValueString(m map[string]interface{}, key string) string {
|
||||
tokens := strings.Split(key, ".")
|
||||
valMap := m
|
||||
for _, token := range tokens {
|
||||
v, ok := valMap[token]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case map[string]interface{}:
|
||||
valMap = v
|
||||
continue
|
||||
case string:
|
||||
return v
|
||||
default:
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func getDescription(raw interface{}) string {
|
||||
var desc string
|
||||
|
||||
switch node := raw.(type) {
|
||||
case ast.DescribableNode:
|
||||
if sval := node.GetDescription(); sval != nil {
|
||||
desc = sval.Value
|
||||
}
|
||||
case map[string]interface{}:
|
||||
desc = getMapValueString(node, "Description.Value")
|
||||
}
|
||||
if desc != "" {
|
||||
sep := ""
|
||||
if strings.ContainsRune(desc, '\n') {
|
||||
sep = "\n"
|
||||
}
|
||||
desc = join([]string{`"""`, desc, `"""`}, sep)
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
func toSliceString(slice interface{}) []string {
|
||||
if slice == nil {
|
||||
return []string{}
|
||||
}
|
||||
res := []string{}
|
||||
switch reflect.TypeOf(slice).Kind() {
|
||||
case reflect.Slice:
|
||||
s := reflect.ValueOf(slice)
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
elem := s.Index(i)
|
||||
elemInterface := elem.Interface()
|
||||
if elem, ok := elemInterface.(string); ok {
|
||||
res = append(res, elem)
|
||||
}
|
||||
}
|
||||
return res
|
||||
default:
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
func join(str []string, sep string) string {
|
||||
ss := []string{}
|
||||
// filter out empty strings
|
||||
for _, s := range str {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
ss = append(ss, s)
|
||||
}
|
||||
return strings.Join(ss, sep)
|
||||
}
|
||||
|
||||
func wrap(start, maybeString, end string) string {
|
||||
if maybeString == "" {
|
||||
return maybeString
|
||||
}
|
||||
return start + maybeString + end
|
||||
}
|
||||
|
||||
// Given array, print each item on its own line, wrapped in an indented "{ }" block.
|
||||
func block(maybeArray interface{}) string {
|
||||
s := toSliceString(maybeArray)
|
||||
if len(s) == 0 {
|
||||
return "{}"
|
||||
}
|
||||
return indent("{\n"+join(s, "\n")) + "\n}"
|
||||
}
|
||||
|
||||
func indent(maybeString interface{}) string {
|
||||
if maybeString == nil {
|
||||
return ""
|
||||
}
|
||||
switch str := maybeString.(type) {
|
||||
case string:
|
||||
return strings.Replace(str, "\n", "\n ", -1)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var printDocASTReducer = map[string]visitor.VisitFunc{
|
||||
"Name": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.Name:
|
||||
return visitor.ActionUpdate, node.Value
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, getMapValue(node, "Value")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"Variable": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.Variable:
|
||||
return visitor.ActionUpdate, fmt.Sprintf("$%v", node.Name)
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, "$" + getMapValueString(node, "Name")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
|
||||
// Document
|
||||
"Document": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.Document:
|
||||
definitions := toSliceString(node.Definitions)
|
||||
return visitor.ActionUpdate, join(definitions, "\n\n") + "\n"
|
||||
case map[string]interface{}:
|
||||
definitions := toSliceString(getMapValue(node, "Definitions"))
|
||||
return visitor.ActionUpdate, join(definitions, "\n\n") + "\n"
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"OperationDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.OperationDefinition:
|
||||
op := string(node.Operation)
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
|
||||
varDefs := wrap("(", join(toSliceString(node.VariableDefinitions), ", "), ")")
|
||||
directives := join(toSliceString(node.Directives), " ")
|
||||
selectionSet := fmt.Sprintf("%v", node.SelectionSet)
|
||||
// Anonymous queries with no directives or variable definitions can use
|
||||
// the query short form.
|
||||
str := ""
|
||||
if name == "" && directives == "" && varDefs == "" && op == ast.OperationTypeQuery {
|
||||
str = selectionSet
|
||||
} else {
|
||||
str = join([]string{
|
||||
op,
|
||||
join([]string{name, varDefs}, ""),
|
||||
directives,
|
||||
selectionSet,
|
||||
}, " ")
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
|
||||
op := getMapValueString(node, "Operation")
|
||||
name := getMapValueString(node, "Name")
|
||||
|
||||
varDefs := wrap("(", join(toSliceString(getMapValue(node, "VariableDefinitions")), ", "), ")")
|
||||
directives := join(toSliceString(getMapValue(node, "Directives")), " ")
|
||||
selectionSet := getMapValueString(node, "SelectionSet")
|
||||
str := ""
|
||||
if name == "" && directives == "" && varDefs == "" && op == ast.OperationTypeQuery {
|
||||
str = selectionSet
|
||||
} else {
|
||||
str = join([]string{
|
||||
op,
|
||||
join([]string{name, varDefs}, ""),
|
||||
directives,
|
||||
selectionSet,
|
||||
}, " ")
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"VariableDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.VariableDefinition:
|
||||
variable := fmt.Sprintf("%v", node.Variable)
|
||||
ttype := fmt.Sprintf("%v", node.Type)
|
||||
defaultValue := fmt.Sprintf("%v", node.DefaultValue)
|
||||
|
||||
return visitor.ActionUpdate, variable + ": " + ttype + wrap(" = ", defaultValue, "")
|
||||
case map[string]interface{}:
|
||||
|
||||
variable := getMapValueString(node, "Variable")
|
||||
ttype := getMapValueString(node, "Type")
|
||||
defaultValue := getMapValueString(node, "DefaultValue")
|
||||
|
||||
return visitor.ActionUpdate, variable + ": " + ttype + wrap(" = ", defaultValue, "")
|
||||
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"SelectionSet": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.SelectionSet:
|
||||
str := block(node.Selections)
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
selections := getMapValue(node, "Selections")
|
||||
str := block(selections)
|
||||
return visitor.ActionUpdate, str
|
||||
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"Field": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.Argument:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
value := fmt.Sprintf("%v", node.Value)
|
||||
return visitor.ActionUpdate, name + ": " + value
|
||||
case map[string]interface{}:
|
||||
|
||||
alias := getMapValueString(node, "Alias")
|
||||
name := getMapValueString(node, "Name")
|
||||
args := toSliceString(getMapValue(node, "Arguments"))
|
||||
directives := toSliceString(getMapValue(node, "Directives"))
|
||||
selectionSet := getMapValueString(node, "SelectionSet")
|
||||
|
||||
str := join(
|
||||
[]string{
|
||||
wrap("", alias, ": ") + name + wrap("(", join(args, ", "), ")"),
|
||||
join(directives, " "),
|
||||
selectionSet,
|
||||
},
|
||||
" ",
|
||||
)
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"Argument": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.FragmentSpread:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
directives := toSliceString(node.Directives)
|
||||
return visitor.ActionUpdate, "..." + name + wrap(" ", join(directives, " "), "")
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
value := getMapValueString(node, "Value")
|
||||
return visitor.ActionUpdate, name + ": " + value
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
|
||||
// Fragments
|
||||
"FragmentSpread": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.InlineFragment:
|
||||
typeCondition := fmt.Sprintf("%v", node.TypeCondition)
|
||||
directives := toSliceString(node.Directives)
|
||||
selectionSet := fmt.Sprintf("%v", node.SelectionSet)
|
||||
return visitor.ActionUpdate, "... on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
directives := toSliceString(getMapValue(node, "Directives"))
|
||||
return visitor.ActionUpdate, "..." + name + wrap(" ", join(directives, " "), "")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"InlineFragment": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case map[string]interface{}:
|
||||
typeCondition := getMapValueString(node, "TypeCondition")
|
||||
directives := toSliceString(getMapValue(node, "Directives"))
|
||||
selectionSet := getMapValueString(node, "SelectionSet")
|
||||
return visitor.ActionUpdate,
|
||||
join([]string{
|
||||
"...",
|
||||
wrap("on ", typeCondition, ""),
|
||||
join(directives, " "),
|
||||
selectionSet,
|
||||
}, " ")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"FragmentDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.FragmentDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
typeCondition := fmt.Sprintf("%v", node.TypeCondition)
|
||||
directives := toSliceString(node.Directives)
|
||||
selectionSet := fmt.Sprintf("%v", node.SelectionSet)
|
||||
return visitor.ActionUpdate, "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
typeCondition := getMapValueString(node, "TypeCondition")
|
||||
directives := toSliceString(getMapValue(node, "Directives"))
|
||||
selectionSet := getMapValueString(node, "SelectionSet")
|
||||
return visitor.ActionUpdate, "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
|
||||
// Value
|
||||
"IntValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.IntValue:
|
||||
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, getMapValueString(node, "Value")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"FloatValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.FloatValue:
|
||||
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, getMapValueString(node, "Value")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"StringValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.StringValue:
|
||||
return visitor.ActionUpdate, `"` + fmt.Sprintf("%v", node.Value) + `"`
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, `"` + getMapValueString(node, "Value") + `"`
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"BooleanValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.BooleanValue:
|
||||
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, getMapValueString(node, "Value")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"EnumValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.EnumValue:
|
||||
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, getMapValueString(node, "Value")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"ListValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.ListValue:
|
||||
return visitor.ActionUpdate, "[" + join(toSliceString(node.Values), ", ") + "]"
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, "[" + join(toSliceString(getMapValue(node, "Values")), ", ") + "]"
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"ObjectValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.ObjectValue:
|
||||
return visitor.ActionUpdate, "{" + join(toSliceString(node.Fields), ", ") + "}"
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, "{" + join(toSliceString(getMapValue(node, "Fields")), ", ") + "}"
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"ObjectField": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.ObjectField:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
value := fmt.Sprintf("%v", node.Value)
|
||||
return visitor.ActionUpdate, name + ": " + value
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
value := getMapValueString(node, "Value")
|
||||
return visitor.ActionUpdate, name + ": " + value
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
|
||||
// Directive
|
||||
"Directive": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.Directive:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
args := toSliceString(node.Arguments)
|
||||
return visitor.ActionUpdate, "@" + name + wrap("(", join(args, ", "), ")")
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
args := toSliceString(getMapValue(node, "Arguments"))
|
||||
return visitor.ActionUpdate, "@" + name + wrap("(", join(args, ", "), ")")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
|
||||
// Type
|
||||
"Named": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.Named:
|
||||
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Name)
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, getMapValueString(node, "Name")
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"List": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.List:
|
||||
return visitor.ActionUpdate, "[" + fmt.Sprintf("%v", node.Type) + "]"
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, "[" + getMapValueString(node, "Type") + "]"
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"NonNull": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.NonNull:
|
||||
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Type) + "!"
|
||||
case map[string]interface{}:
|
||||
return visitor.ActionUpdate, getMapValueString(node, "Type") + "!"
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
|
||||
// Type System Definitions
|
||||
"SchemaDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.SchemaDefinition:
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
"schema",
|
||||
join(directives, " "),
|
||||
block(node.OperationTypes),
|
||||
}, " ")
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
operationTypes := toSliceString(getMapValue(node, "OperationTypes"))
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
"schema",
|
||||
join(directives, " "),
|
||||
block(operationTypes),
|
||||
}, " ")
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"OperationTypeDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.OperationTypeDefinition:
|
||||
str := fmt.Sprintf("%v: %v", node.Operation, node.Type)
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
operation := getMapValueString(node, "Operation")
|
||||
ttype := getMapValueString(node, "Type")
|
||||
str := fmt.Sprintf("%v: %v", operation, ttype)
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"ScalarDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.ScalarDefinition:
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
"scalar",
|
||||
fmt.Sprintf("%v", node.Name),
|
||||
join(directives, " "),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
"scalar",
|
||||
name,
|
||||
join(directives, " "),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"ObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.ObjectDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
interfaces := toSliceString(node.Interfaces)
|
||||
fields := node.Fields
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
"type",
|
||||
name,
|
||||
wrap("implements ", join(interfaces, " & "), ""),
|
||||
join(directives, " "),
|
||||
block(fields),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
interfaces := toSliceString(getMapValue(node, "Interfaces"))
|
||||
fields := getMapValue(node, "Fields")
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
"type",
|
||||
name,
|
||||
wrap("implements ", join(interfaces, " & "), ""),
|
||||
join(directives, " "),
|
||||
block(fields),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"FieldDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.FieldDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
ttype := fmt.Sprintf("%v", node.Type)
|
||||
args := toSliceString(node.Arguments)
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
hasArgDesc := false
|
||||
for _, arg := range node.Arguments {
|
||||
if arg.Description != nil && arg.Description.Value != "" {
|
||||
hasArgDesc = true
|
||||
break
|
||||
}
|
||||
}
|
||||
var argsStr string
|
||||
if hasArgDesc {
|
||||
argsStr = wrap("(", indent("\n"+join(args, "\n")), "\n)")
|
||||
} else {
|
||||
argsStr = wrap("(", join(args, ", "), ")")
|
||||
}
|
||||
str := name + argsStr + ": " + ttype + wrap(" ", join(directives, " "), "")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
ttype := getMapValueString(node, "Type")
|
||||
args := toSliceString(getMapValue(node, "Arguments"))
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
hasArgDesc := false
|
||||
for _, arg := range args {
|
||||
if strings.HasPrefix(strings.TrimSpace(arg), `"""`) {
|
||||
hasArgDesc = true
|
||||
break
|
||||
}
|
||||
}
|
||||
var argsStr string
|
||||
if hasArgDesc {
|
||||
argsStr = wrap("(", indent("\n"+join(args, "\n")), "\n)")
|
||||
} else {
|
||||
argsStr = wrap("(", join(args, ", "), ")")
|
||||
}
|
||||
str := name + argsStr + ": " + ttype + wrap(" ", join(directives, " "), "")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"InputValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.InputValueDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
ttype := fmt.Sprintf("%v", node.Type)
|
||||
defaultValue := fmt.Sprintf("%v", node.DefaultValue)
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
name + ": " + ttype,
|
||||
wrap("= ", defaultValue, ""),
|
||||
join(directives, " "),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("\n%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
ttype := getMapValueString(node, "Type")
|
||||
defaultValue := getMapValueString(node, "DefaultValue")
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
name + ": " + ttype,
|
||||
wrap("= ", defaultValue, ""),
|
||||
join(directives, " "),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("\n%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"InterfaceDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.InterfaceDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
fields := node.Fields
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
"interface",
|
||||
name,
|
||||
join(directives, " "),
|
||||
block(fields),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
fields := getMapValue(node, "Fields")
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
"interface",
|
||||
name,
|
||||
join(directives, " "),
|
||||
block(fields),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"UnionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.UnionDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
types := toSliceString(node.Types)
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
"union",
|
||||
name,
|
||||
join(directives, " "),
|
||||
"= " + join(types, " | "),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
types := toSliceString(getMapValue(node, "Types"))
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
"union",
|
||||
name,
|
||||
join(directives, " "),
|
||||
"= " + join(types, " | "),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"EnumDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.EnumDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
values := node.Values
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
"enum",
|
||||
name,
|
||||
join(directives, " "),
|
||||
block(values),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
values := getMapValue(node, "Values")
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
"enum",
|
||||
name,
|
||||
join(directives, " "),
|
||||
block(values),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"EnumValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.EnumValueDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
name,
|
||||
join(directives, " "),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("\n%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
name,
|
||||
join(directives, " "),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("\n%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"InputObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.InputObjectDefinition:
|
||||
name := fmt.Sprintf("%v", node.Name)
|
||||
fields := node.Fields
|
||||
directives := []string{}
|
||||
for _, directive := range node.Directives {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||
}
|
||||
str := join([]string{
|
||||
"input",
|
||||
name,
|
||||
join(directives, " "),
|
||||
block(fields),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
fields := getMapValue(node, "Fields")
|
||||
directives := []string{}
|
||||
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||
}
|
||||
str := join([]string{
|
||||
"input",
|
||||
name,
|
||||
join(directives, " "),
|
||||
block(fields),
|
||||
}, " ")
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"TypeExtensionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.TypeExtensionDefinition:
|
||||
definition := fmt.Sprintf("%v", node.Definition)
|
||||
str := "extend " + definition
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
definition := getMapValueString(node, "Definition")
|
||||
str := "extend " + definition
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
"DirectiveDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||
switch node := p.Node.(type) {
|
||||
case *ast.DirectiveDefinition:
|
||||
args := toSliceString(node.Arguments)
|
||||
hasArgDesc := false
|
||||
for _, arg := range node.Arguments {
|
||||
if arg.Description != nil && arg.Description.Value != "" {
|
||||
hasArgDesc = true
|
||||
break
|
||||
}
|
||||
}
|
||||
var argsStr string
|
||||
if hasArgDesc {
|
||||
argsStr = wrap("(", indent("\n"+join(args, "\n")), "\n)")
|
||||
} else {
|
||||
argsStr = wrap("(", join(args, ", "), ")")
|
||||
}
|
||||
str := fmt.Sprintf("directive @%v%v on %v", node.Name, argsStr, join(toSliceString(node.Locations), " | "))
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
case map[string]interface{}:
|
||||
name := getMapValueString(node, "Name")
|
||||
locations := toSliceString(getMapValue(node, "Locations"))
|
||||
args := toSliceString(getMapValue(node, "Arguments"))
|
||||
hasArgDesc := false
|
||||
for _, arg := range args {
|
||||
if strings.HasPrefix(strings.TrimSpace(arg), `"""`) {
|
||||
hasArgDesc = true
|
||||
break
|
||||
}
|
||||
}
|
||||
var argsStr string
|
||||
if hasArgDesc {
|
||||
argsStr = wrap("(", indent("\n"+join(args, "\n")), "\n)")
|
||||
} else {
|
||||
argsStr = wrap("(", join(args, ", "), ")")
|
||||
}
|
||||
str := fmt.Sprintf("directive @%v%v on %v", name, argsStr, join(locations, " | "))
|
||||
if desc := getDescription(node); desc != "" {
|
||||
str = fmt.Sprintf("%s\n%s", desc, str)
|
||||
}
|
||||
return visitor.ActionUpdate, str
|
||||
}
|
||||
return visitor.ActionNoChange, nil
|
||||
},
|
||||
}
|
||||
|
||||
func Print(astNode ast.Node) (printed interface{}) {
|
||||
defer func() interface{} {
|
||||
if r := recover(); r != nil {
|
||||
return fmt.Sprintf("%v", astNode)
|
||||
}
|
||||
return printed
|
||||
}()
|
||||
printed = visitor.Visit(astNode, &visitor.VisitorOptions{
|
||||
LeaveKindMap: printDocASTReducer,
|
||||
}, nil)
|
||||
return printed
|
||||
}
|
||||
@@ -29,6 +29,7 @@ type Common struct {
|
||||
func (c *Common) SetExportDefault() {
|
||||
for index := range c.Actions {
|
||||
c.Actions[index].Definition.Arguments = nil
|
||||
c.Actions[index].Definition.Type = ""
|
||||
c.Actions[index].Definition.OutputType = ""
|
||||
}
|
||||
|
||||
@@ -55,8 +56,18 @@ type Action struct {
|
||||
Permissions []yaml.MapSlice `json:"-" yaml:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
type ActionType string
|
||||
|
||||
const (
|
||||
// For query type
|
||||
ActionTypeQuery ActionType = "query"
|
||||
// For mutation type
|
||||
ActionTypeMutation = "mutation"
|
||||
)
|
||||
|
||||
type ActionDef struct {
|
||||
Kind string `json:"kind" yaml:"kind"`
|
||||
Type ActionType `json:"type" yaml:"type,omitempty"`
|
||||
Handler string `json:"handler" yaml:"handler"`
|
||||
Arguments []yaml.MapSlice `json:"arguments" yaml:"arguments,omitempty"`
|
||||
OutputType string `json:"output_type" yaml:"output_type,omitempty"`
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
resetDerivedActionParentOperation,
|
||||
} from './reducer';
|
||||
import { createAction } from '../ServerIO';
|
||||
import { getActionDefinitionFromSdl } from '../../../../shared/utils/sdlUtils';
|
||||
|
||||
const AddAction = ({
|
||||
handler,
|
||||
@@ -82,6 +83,15 @@ const AddAction = ({
|
||||
!actionParseTimer &&
|
||||
!typedefParseTimer;
|
||||
|
||||
let actionType;
|
||||
if (!actionDefinitionError) {
|
||||
// TODO optimise
|
||||
const { type, error } = getActionDefinitionFromSdl(actionDefinitionSdl);
|
||||
if (!error) {
|
||||
actionType = type;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Helmet title={'Add Action - Actions | Hasura'} />
|
||||
@@ -110,12 +120,18 @@ const AddAction = ({
|
||||
service="create-action"
|
||||
/>
|
||||
<hr />
|
||||
<KindEditor
|
||||
value={kind}
|
||||
onChange={kindOnChange}
|
||||
className={styles.add_mar_bottom_mid}
|
||||
/>
|
||||
<hr />
|
||||
{
|
||||
actionType === "query" ? null : (
|
||||
<React.Fragment>
|
||||
<KindEditor
|
||||
value={kind}
|
||||
onChange={kindOnChange}
|
||||
className={styles.add_mar_bottom_mid}
|
||||
/>
|
||||
<hr />
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
<HeadersConfEditor
|
||||
forwardClientHeaders={forwardClientHeaders}
|
||||
toggleForwardClientHeaders={toggleForwardClientHeaders}
|
||||
|
||||
@@ -7,7 +7,7 @@ import SDLEditor from '../../../../Common/AceEditor/SDLEditor';
|
||||
|
||||
const editorLabel = 'Action definition';
|
||||
const editorTooltip =
|
||||
'Define the action as mutation using GraphQL SDL. You can use the custom types already defined by you or define new types in the new types definition editor below.';
|
||||
'Define the action as a query or a mutation using GraphQL SDL. You can use the custom types already defined by you or define new types in the new types definition editor below.';
|
||||
|
||||
const ActionDefinitionEditor = ({
|
||||
value,
|
||||
|
||||
@@ -31,6 +31,7 @@ export const generateActionDefinition = ({
|
||||
outputType,
|
||||
kind = 'synchronous',
|
||||
handler,
|
||||
actionType,
|
||||
headers,
|
||||
forwardClientHeaders,
|
||||
}) => {
|
||||
@@ -39,6 +40,7 @@ export const generateActionDefinition = ({
|
||||
kind,
|
||||
output_type: outputType,
|
||||
handler,
|
||||
type: actionType,
|
||||
headers: transformHeaders(headers),
|
||||
forward_client_headers: forwardClientHeaders,
|
||||
};
|
||||
@@ -290,3 +292,4 @@ export const getOverlappingTypeConfirmation = (
|
||||
|
||||
return isOk;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class Landing extends React.Component {
|
||||
// imgUrl={`${globals.assetsPath}/common/img/remote_schema.png`} // TODO: update image & description
|
||||
imgUrl={actionsArchDiagram}
|
||||
imgAlt="Actions"
|
||||
description="Actions are custom mutations that are resolved via HTTP handlers. Actions can be used to carry out complex data validations, data enrichment from external sources or execute just about any custom business logic."
|
||||
description="Actions are custom queries or mutations that are resolved via HTTP handlers. Actions can be used to carry out complex data validations, data enrichment from external sources or execute just about any custom business logic."
|
||||
/>
|
||||
<hr className={styles.clear_fix} />
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
toggleForwardClientHeaders as toggleFCH,
|
||||
} from './reducer';
|
||||
import { saveAction, deleteAction } from '../ServerIO';
|
||||
import { getActionDefinitionFromSdl } from '../../../../shared/utils/sdlUtils';
|
||||
|
||||
const ActionEditor = ({
|
||||
currentAction,
|
||||
@@ -85,6 +86,15 @@ const ActionEditor = ({
|
||||
!actionDefinitionTimer &&
|
||||
!typeDefinitionTimer;
|
||||
|
||||
let actionType;
|
||||
if (!actionDefinitionError) {
|
||||
// TODO optimise
|
||||
const { type, error } = getActionDefinitionFromSdl(actionDefinitionSdl);
|
||||
if (!error) {
|
||||
actionType = type;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Helmet title={`Modify Action - ${actionName} - Actions | Hasura`} />
|
||||
@@ -112,8 +122,18 @@ const ActionEditor = ({
|
||||
service="create-action"
|
||||
/>
|
||||
<hr />
|
||||
<KindEditor value={kind} onChange={kindOnChange} />
|
||||
<hr />
|
||||
{
|
||||
actionType === "query" ? null : (
|
||||
<React.Fragment>
|
||||
<KindEditor
|
||||
value={kind}
|
||||
onChange={kindOnChange}
|
||||
className={styles.add_mar_bottom_mid}
|
||||
/>
|
||||
<hr />
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
<HeadersConfEditor
|
||||
forwardClientHeaders={forwardClientHeaders}
|
||||
toggleForwardClientHeaders={toggleForwardClientHeaders}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
getActionName,
|
||||
getActionOutputType,
|
||||
getActionComment,
|
||||
getActionType
|
||||
} from '../utils';
|
||||
import { getActionTypes } from '../Common/utils';
|
||||
|
||||
@@ -18,6 +19,7 @@ export const getModifyState = (currentAction, allTypes) => {
|
||||
actionDefinition: {
|
||||
sdl: getActionDefinitionSdl(
|
||||
getActionName(currentAction),
|
||||
getActionType(currentAction),
|
||||
getActionArguments(currentAction),
|
||||
getActionOutputType(currentAction),
|
||||
getActionComment(currentAction)
|
||||
|
||||
@@ -119,6 +119,7 @@ export const createAction = () => (dispatch, getState) => {
|
||||
outputType,
|
||||
error: actionDefError,
|
||||
comment: actionDescription,
|
||||
type: actionType
|
||||
} = getActionDefinitionFromSdl(rawState.actionDefinition.sdl);
|
||||
if (actionDefError) {
|
||||
return dispatch(
|
||||
@@ -140,6 +141,7 @@ export const createAction = () => (dispatch, getState) => {
|
||||
handler: rawState.handler,
|
||||
kind: rawState.kind,
|
||||
types,
|
||||
actionType,
|
||||
name: actionName,
|
||||
arguments: args,
|
||||
outputType,
|
||||
@@ -235,6 +237,7 @@ export const saveAction = currentAction => (dispatch, getState) => {
|
||||
name: actionName,
|
||||
arguments: args,
|
||||
outputType,
|
||||
type: actionType,
|
||||
error: actionDefError,
|
||||
comment: actionDescription,
|
||||
} = getActionDefinitionFromSdl(rawState.actionDefinition.sdl);
|
||||
@@ -258,6 +261,7 @@ export const saveAction = currentAction => (dispatch, getState) => {
|
||||
handler: rawState.handler,
|
||||
kind: rawState.kind,
|
||||
types,
|
||||
actionType,
|
||||
name: actionName,
|
||||
arguments: args,
|
||||
outputType,
|
||||
|
||||
@@ -26,6 +26,10 @@ export const getActionArguments = action => {
|
||||
return action.action_defn.arguments;
|
||||
};
|
||||
|
||||
export const getActionType = action => {
|
||||
return action.action_defn.type
|
||||
};
|
||||
|
||||
export const getAllActions = getState => {
|
||||
return getState().actions.common.actions;
|
||||
};
|
||||
|
||||
@@ -114,6 +114,7 @@ class GraphiQLWrapper extends Component {
|
||||
const { action, types } = derivedOperationMetadata;
|
||||
const actionsSdl = getActionDefinitionSdl(
|
||||
action.name,
|
||||
action.type,
|
||||
action.arguments,
|
||||
action.output_type
|
||||
);
|
||||
|
||||
@@ -9,7 +9,12 @@ import {
|
||||
} from 'graphql';
|
||||
import { wrapTypename, getAstTypeMetadata } from './wrappingTypeUtils';
|
||||
import { inbuiltTypes } from './hasuraCustomTypeUtils';
|
||||
import { getTypeFields, getUnderlyingType } from './graphqlSchemaUtils';
|
||||
import {
|
||||
getTypeFields,
|
||||
getUnderlyingType,
|
||||
getOperationType,
|
||||
} from './graphqlSchemaUtils';
|
||||
import { isValidOperationName } from './sdlUtils';
|
||||
|
||||
export const validateOperation = (operationString, clientSchema) => {
|
||||
// parse operation string
|
||||
@@ -27,16 +32,16 @@ export const validateOperation = (operationString, clientSchema) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (operationAst.definitions.find(d => d.kind === 'FragmentDefinition')) {
|
||||
if (operationAst.definitions.some(d => d.kind === 'FragmentDefinition')) {
|
||||
throw Error('fragments are not supported');
|
||||
}
|
||||
|
||||
if (operationAst.definitions.find(d => d.operation !== 'mutation')) {
|
||||
throw Error('queries cannot be derived into actions');
|
||||
if (operationAst.definitions.some(d => !isValidOperationName(d.operation))) {
|
||||
throw Error('subscriptions cannot be derived into actions');
|
||||
}
|
||||
|
||||
operationAst.definitions = operationAst.definitions.filter(
|
||||
d => d.operation === 'mutation'
|
||||
operationAst.definitions = operationAst.definitions.filter(d =>
|
||||
isValidOperationName(d.operation)
|
||||
);
|
||||
|
||||
// throw error if the AST is empty
|
||||
@@ -88,6 +93,8 @@ const deriveAction = (
|
||||
throw e;
|
||||
}
|
||||
|
||||
const operation = operationAst.definitions[0].operation;
|
||||
|
||||
const variables = operationAst.definitions[0].variableDefinitions;
|
||||
|
||||
// get operation name
|
||||
@@ -108,7 +115,7 @@ const deriveAction = (
|
||||
};
|
||||
|
||||
const allHasuraTypes = clientSchema._typeMap;
|
||||
const operationType = clientSchema._mutationType; // TODO better handling for queries
|
||||
const operationType = getOperationType(clientSchema, operation);
|
||||
|
||||
const actionArguments = [];
|
||||
const newTypes = {};
|
||||
@@ -232,6 +239,7 @@ const deriveAction = (
|
||||
types: Object.values(newTypes),
|
||||
action: {
|
||||
name: actionName,
|
||||
type: operation,
|
||||
arguments: actionArguments,
|
||||
output_type: actionOutputTypename,
|
||||
},
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import { isWrappingType, isListType, isNonNullType } from 'graphql';
|
||||
|
||||
export const getOperationType = (schema, operation) => {
|
||||
if (operation === 'query') {
|
||||
return schema._queryType;
|
||||
}
|
||||
if (operation === 'subscription') {
|
||||
return schema._subscriptionType
|
||||
}
|
||||
return schema._mutationType;
|
||||
};
|
||||
|
||||
export const getMutationType = schema => {
|
||||
return schema._mutationType;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,28 @@ import {
|
||||
hydrateTypeRelationships,
|
||||
} from './hasuraCustomTypeUtils';
|
||||
|
||||
export const isValidOperationName = operationName => {
|
||||
return operationName === 'query' || operationName === 'mutation';
|
||||
};
|
||||
|
||||
const isValidOperationType = operationType => {
|
||||
return operationType === 'Mutation' || operationType === 'Query';
|
||||
};
|
||||
|
||||
const getActionTypeFromOperationType = operationType => {
|
||||
if (operationType === 'Query') {
|
||||
return 'query';
|
||||
}
|
||||
return 'mutation';
|
||||
};
|
||||
|
||||
const getOperationTypeFromActionType = operationType => {
|
||||
if (operationType === 'query') {
|
||||
return 'Query';
|
||||
}
|
||||
return 'Mutation';
|
||||
};
|
||||
|
||||
const getAstEntityDescription = def => {
|
||||
return def.description ? def.description.value.trim() : null;
|
||||
};
|
||||
@@ -118,7 +140,7 @@ export const getTypesFromSdl = sdl => {
|
||||
return typeDefinition;
|
||||
};
|
||||
|
||||
const getActionFromMutationAstDef = astDef => {
|
||||
const getActionFromOperationAstDef = astDef => {
|
||||
const definition = {
|
||||
name: '',
|
||||
arguments: [],
|
||||
@@ -146,7 +168,6 @@ const getActionFromMutationAstDef = astDef => {
|
||||
};
|
||||
|
||||
export const getActionDefinitionFromSdl = sdl => {
|
||||
const schemaAst = sdlParse(sdl);
|
||||
const definition = {
|
||||
name: '',
|
||||
arguments: [],
|
||||
@@ -154,18 +175,30 @@ export const getActionDefinitionFromSdl = sdl => {
|
||||
comment: '',
|
||||
error: null,
|
||||
};
|
||||
let schemaAst;
|
||||
try {
|
||||
schemaAst = sdlParse(sdl);
|
||||
} catch {
|
||||
definition.error = 'Invalid SDL';
|
||||
return definition;
|
||||
}
|
||||
|
||||
if (schemaAst.definitions.length > 1) {
|
||||
definition.error = 'Action must be defined under a single "Mutation" type';
|
||||
definition.error =
|
||||
'Action must be defined under a single "Mutation" type or a "Query" type';
|
||||
return definition;
|
||||
}
|
||||
|
||||
const sdlDef = schemaAst.definitions[0];
|
||||
|
||||
if (sdlDef.name.value !== 'Mutation') {
|
||||
definition.error = 'Action must be defined under a "Mutation" type';
|
||||
if (!isValidOperationType(sdlDef.name.value)) {
|
||||
definition.error =
|
||||
'Action must be defined under a "Mutation" or a "Query" type';
|
||||
return definition;
|
||||
}
|
||||
|
||||
const actionType = getActionTypeFromOperationType(sdlDef.name.value);
|
||||
|
||||
if (sdlDef.fields.length > 1) {
|
||||
const definedActions = sdlDef.fields
|
||||
.map(f => `"${f.name.value}"`)
|
||||
@@ -176,7 +209,8 @@ export const getActionDefinitionFromSdl = sdl => {
|
||||
|
||||
return {
|
||||
...definition,
|
||||
...getActionFromMutationAstDef(sdlDef.fields[0]),
|
||||
type: actionType,
|
||||
...getActionFromOperationAstDef(sdlDef.fields[0]),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -250,9 +284,15 @@ export const getTypesSdl = _types => {
|
||||
return sdl;
|
||||
};
|
||||
|
||||
export const getActionDefinitionSdl = (name, args, outputType, description) => {
|
||||
export const getActionDefinitionSdl = (
|
||||
name,
|
||||
actionType,
|
||||
args,
|
||||
outputType,
|
||||
description
|
||||
) => {
|
||||
return getObjectTypeSdl({
|
||||
name: 'Mutation',
|
||||
name: getOperationTypeFromActionType(actionType),
|
||||
fields: [
|
||||
{
|
||||
name,
|
||||
@@ -276,27 +316,31 @@ export const getServerTypesFromSdl = (sdl, existingTypes) => {
|
||||
|
||||
export const getAllActionsFromSdl = sdl => {
|
||||
const ast = sdlParse(sdl);
|
||||
ast.definitions = ast.definitions.filter(d => d.name.value === 'Mutation');
|
||||
const actions = [];
|
||||
|
||||
ast.definitions.forEach(d => {
|
||||
d.fields.forEach(f => {
|
||||
const action = getActionFromMutationAstDef(f);
|
||||
actions.push({
|
||||
name: action.name,
|
||||
definition: {
|
||||
arguments: action.arguments,
|
||||
output_type: action.outputType,
|
||||
},
|
||||
ast.definitions
|
||||
.filter(d => isValidOperationType(d.name.value))
|
||||
.forEach(d => {
|
||||
d.fields.forEach(f => {
|
||||
const action = getActionFromOperationAstDef(f);
|
||||
actions.push({
|
||||
name: action.name,
|
||||
definition: {
|
||||
type: getActionTypeFromOperationType(d.name.value),
|
||||
arguments: action.arguments,
|
||||
output_type: action.outputType,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return actions;
|
||||
};
|
||||
|
||||
export const getAllTypesFromSdl = sdl => {
|
||||
const ast = sdlParse(sdl);
|
||||
ast.definitions = ast.definitions.filter(d => d.name.value !== 'Mutation');
|
||||
ast.definitions = ast.definitions.filter(
|
||||
d => !isValidOperationType(d.name.value)
|
||||
);
|
||||
const types = ast.definitions.map(d => {
|
||||
return getTypeFromAstDef(d);
|
||||
});
|
||||
@@ -308,6 +352,7 @@ export const getSdlComplete = (allActions, allTypes) => {
|
||||
allActions.forEach(a => {
|
||||
sdl += `extend ${getActionDefinitionSdl(
|
||||
a.action_name,
|
||||
a.action_defn.type,
|
||||
a.action_defn.arguments,
|
||||
a.action_defn.output_type,
|
||||
a.comment
|
||||
|
||||
Reference in New Issue
Block a user