diff --git a/gen.go b/gen.go index 657aa845..5485f83c 100644 --- a/gen.go +++ b/gen.go @@ -30,7 +30,6 @@ const ( inputObjectFile string = "input.go" interfacesFile string = "interfaces.go" objectFile string = "object.go" - queryFile string = "query.go" mutationFile string = "mutation.go" payloadFile string = "payload.go" // scalarFile string = "scalar.go" // NOTE: probably not useful @@ -207,6 +206,32 @@ func main() { } schema := graphql.MustParseSchema(graphqlSchema, nil, opts...) schemaAst := schema.ASTSchema() + + inputObjects := map[string]*types.InputObject{} + objects := map[string]*types.ObjectTypeDefinition{} + enums := map[string]*types.EnumTypeDefinition{} + interfaces := map[string]*types.InterfaceTypeDefinition{} + unions := map[string]*types.Union{} + scalars := map[string]*types.ScalarTypeDefinition{} + for name, graphqlType := range schemaAst.Types { + switch v := graphqlType.(type) { + case *types.EnumTypeDefinition: + enums[name] = v + case *types.InputObject: + inputObjects[name] = v + case *types.InterfaceTypeDefinition: + interfaces[name] = v + case *types.ObjectTypeDefinition: + objects[name] = v + case *types.ScalarTypeDefinition: + scalars[name] = v + case *types.Union: + unions[name] = v + default: + panic(fmt.Errorf("Unknown GraphQL type: %v", v)) + } + } + genQueries(objects) genEnums(schemaAst.Enums) err := run() @@ -215,6 +240,15 @@ func main() { } } +func sortedMapKeys[T any](schemaMap map[string]T) []string { + sortedNames := make([]string, 0, len(schemaMap)) + for k := range schemaMap { + sortedNames = append(sortedNames, k) + } + slices.Sort(sortedNames) + return sortedNames +} + func genEnums(schemaEnums []*types.EnumTypeDefinition) { var buf bytes.Buffer @@ -237,6 +271,72 @@ func genEnums(schemaEnums []*types.EnumTypeDefinition) { } } +var queryRenames = map[string]string{ + "CustomActionsTriggerDefinitions": "TriggerDefinitions", +} + +func queryRename(name string) string { + if rename, ok := queryRenames[name]; ok { + return rename + } + return name +} + +func isObjectType(fieldDef *types.FieldDefinition) bool { + var unwrappedType types.Type + + if nonNull, ok := fieldDef.Type.(*types.NonNull); ok { + unwrappedType = nonNull.OfType + } else { + unwrappedType = fieldDef.Type + } + + return unwrappedType.Kind() == "OBJECT" +} + +func genQueries(objects map[string]*types.ObjectTypeDefinition) { + var buf bytes.Buffer + + buf.WriteString(header + "\n\nimport \"fmt\"\n") + + tmpl := template.New("queries") + tmpl.Funcs(sprig.TxtFuncMap()) + tmpl.Funcs(templFuncMap) + template.Must(tmpl.ParseFiles("./templates/queries.tpl")) + + if err := tmpl.ExecuteTemplate(&buf, "account_get_query", objects["Account"]); err != nil { + panic(err) + } + if err := tmpl.ExecuteTemplate(&buf, "account_list_query", objects["Account"]); err != nil { + panic(err) + } + + unwantedObjects := []string{"Account", "Error", "Group", "Mutation", "Query", "Warning"} + for _, unwantedObject := range unwantedObjects { + delete(objects, unwantedObject) + } + + for _, objectName := range sortedMapKeys(objects) { + if strings.HasPrefix(objectName, "_") || + strings.HasSuffix(objectName, "Connection") || + strings.HasSuffix(objectName, "Edge") || + strings.HasSuffix(objectName, "Payload") { + continue + } + if err := tmpl.ExecuteTemplate(&buf, "get_query", objects[objectName]); err != nil { + panic(err) + } + if err := tmpl.ExecuteTemplate(&buf, "list_query", objects[objectName]); err != nil { + panic(err) + } + } + + err := os.WriteFile("query.go", buf.Bytes(), 0o644) + if err != nil { + panic(err) + } +} + func getRootSchema() (*GraphQLSchema, error) { visibility, ok := os.LookupEnv("GRAPHQL_VISIBILITY") if !ok { @@ -294,14 +394,12 @@ func run() error { subSchema = inputObjectSchema case interfacesFile: subSchema = interfaceSchema - case objectFile: - subSchema = objectSchema + // case objectFile: + // subSchema = objectSchema case mutationFile: subSchema = objectSchema case payloadFile: subSchema = objectSchema - case queryFile: - subSchema = objectSchema // case scalarFile: // subSchema = scalarSchema // case unionFile: @@ -480,135 +578,6 @@ type {{.Name}} struct { {{range .InputFields }} {{- end }} } {{- end }}{{ end -}} - `), - // NOTE: "account" == objectSchema.Types[0] - // NOTE: "mutation" == objectSchema.Types[134] - queryFile: t(header + ` - import "fmt" - - {{range .Types | sortByName}} - {{if and (eq .Kind "OBJECT") (not (internal .Name)) }} - {{- if eq .Name "Account" }} - {{- template "account_queries" . }} - {{- else }} - {{- template "non_account_queries" . }} - {{- end}} - {{- end}} - {{- end}} - - {{ define "account_queries" -}} - {{- range .Fields }} {{- if and (len .Args) (not (skip_query .Name)) }} - // {{ if gt (len .Args) 3 -}} List {{- else -}} Get {{- end -}} - {{- .Name | title}} {{ .Description | clean | endSentence }} - func (client *Client) {{ if gt (len .Args) 3 }}List{{ .Name | title | makePlural }}(variables *PayloadVariables) (* - {{- if eq .Name "customActionsExternalActions" }}{{ .Name | title }}Connection, error) { - {{- else}}{{ .Name | title | makeSingular }}Connection, error) { - {{- end -}} - {{- else -}} Get{{ .Name | title }}(value string) (*{{.Name | title | trimSuffix "sVaultsSecret" }}, error) { - {{- end -}} - var q struct { - Account struct { - {{ if gt (len .Args) 3 -}} - {{- .Name | title | makePlural }} {{ if eq .Name "customActionsExternalActions" -}}{{ .Name | title }}{{ else }}{{ .Name | title | makeSingular }}{{ end }}Connection {{ template "graphql_struct_tag_with_args" . }} - {{- else -}} - {{- .Name | title }} {{ .Name | title | makeSingular | trimSuffix "sVaultsSecret" }} {{ template "graphql_struct_tag_with_args" . }} - {{- end -}} - } - } - {{- if gt (len .Args) 3 }} - if variables == nil { - variables = client.InitialPageVariablesPointer() - } - {{ else }} - v := PayloadVariables{ {{ range .Args }} - "{{.Name}}": value, {{ end}} - } - {{- end }} - - {{ if gt (len .Args) 3 -}} - if err := client.Query(&q, *variables, WithName("{{ template "name_to_singular" . }}List")); err != nil { - return nil, err - } - - for q.Account.{{ .Name | title }}.PageInfo.HasNextPage { - (*variables)["after"] = q.Account.{{ .Name | title }}.PageInfo.End - resp, err := client.List{{ .Name | title }}(variables) - if err != nil { - return nil, err - } - q.Account.{{ .Name | title }}.Nodes = append(q.Account.{{ .Name | title }}.Nodes, resp.Nodes...) - q.Account.{{ .Name | title }}.PageInfo = resp.PageInfo - q.Account.{{ .Name | title }}.TotalCount += resp.TotalCount - } - return &q.Account.{{ .Name | title }}, nil - {{ else }} - err := client.Query(&q, v, WithName("{{ template "name_to_singular" . }}{{ if isListType .Name }}List{{else}}Get{{end}}")) - return &q.Account.{{ .Name | title }}, HandleErrors(err, nil) - {{- end }} - } - {{end}}{{- end}}{{- end}} - - {{ define "non_account_queries" -}} - {{- range .Fields }} {{- if and (len .Args) (not (skip_query $.Name)) }} - // {{ if gt (len .Args) 3 }}List{{- else }}Get{{ end }}{{.Name | title}} {{ .Description | clean | endSentence }} - func ( {{- $.Name | first_char_lowered }} *{{ $.Name | title | makeSingular }}) - - {{- if gt (len .Args) 3 }}List{{ .Name | title }}(client *Client, variables *PayloadVariables) (* - {{- if or (hasPrefix "ancestor" .Name) (hasPrefix "child" .Name) }} {{- $.Name }}Connection, error - {{- else if hasPrefix "descendant" .Name }}{{ .Name | title | makeSingular | trimPrefix "Descendant" }}Connection, error - {{- else }}{{ if eq .Name "memberships" }}Team{{end}}{{ .Name | title | makeSingular | trimPrefix "Child" }}Connection, error - {{- end -}} ) { - if {{ $.Name | first_char_lowered }}.Id == "" { - return nil, fmt.Errorf("Unable to get {{ .Name | title }}, invalid {{ $.Name | lower }} id: '%s'", {{ $.Name | first_char_lowered }}.Id) - } - var q struct { - Account struct { - {{ $.Name | title | makeSingular }} struct { - {{- if or (hasPrefix "ancestor" .Name) (hasPrefix "child" .Name) -}} - {{ .Name | title }} {{ $.Name | title | makeSingular }}Connection - {{- else if hasPrefix "descendant" .Name }} - {{ .Name | title }} {{ .Name | title | makeSingular | trimPrefix "Descendant" }}Connection - {{- else -}} - {{ .Name | title }} {{ if eq .Name "memberships" }}Team{{end}}{{ .Name | title | makeSingular }}Connection - {{- end }} ` + "`" + `graphql:"{{.Name}}(after: $after, first: $first)"` + "`" + ` - } ` + "`" + `graphql:"{{$.Name | word_first_char_lowered }}(id: $id)"` + "`" + ` - } - } - if variables == nil { - variables = client.InitialPageVariablesPointer() - } - (*variables)["id"] = {{ $.Name | first_char_lowered }}.Id - if err := client.Query(&q, *variables, WithName("{{ template "name_to_singular" . }}List")); err != nil { - return nil, err - } - - for q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}.PageInfo.HasNextPage { - (*variables)["after"] = q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}.PageInfo.End - connection, err := {{ $.Name | first_char_lowered }}.List{{ .Name | title }}(client, variables) - if err != nil { - return nil, err - } - q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}.Nodes = append(q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}.Nodes, connection.Nodes...) - q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}.PageInfo = q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}.PageInfo - q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}.TotalCount += q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}.TotalCount - } - - return &q.Account.{{ $.Name | title | makeSingular }}.{{ .Name | title }}, nil - - {{- else }}Get{{ .Name | title }}({{ query_args . }}) (*{{.Name | title | makeSingular }}, error) { - var q struct { - Account struct { - {{ .Name | title }} {{ template "name_to_singular" . }} ` + "`" + `graphql:"{{.Name}}(input: $input)"` + "`" + ` - } - } - v := PayloadVariables{"input": *NewIdentifier(identifier)} - if err := client.Query(&q, v, WithName("{{ template "name_to_singular" . }}Get")); err != nil { - return nil, err - } - return &q.Account.{{ .Name | title }}, nil - {{- end -}} - } - {{- end -}}{{- end -}}{{- end -}} `), mutationFile: t(header + ` {{range .Types | sortByName}} @@ -657,27 +626,27 @@ type {{.Name}} struct { {{range .InputFields }} } {{- end}}{{ end }}{{- end}} `), - objectFile: t(header + ` - import "github.com/relvacode/iso8601" - - {{range .Types | sortByName}} - {{if and (eq .Kind "OBJECT") (not (internal .Name)) }} - {{- if ne .Name "Account" }} - {{template "object" .}}{{end}} - {{- end}} - {{- end}} - - {{- define "object" -}} - {{ if not (skip_object .Name) }} - {{ template "type_comment_description" . }} - type {{.Name}} struct { {{ add_special_fields .Name }} - {{ range .Fields }} - {{- if and (not (skip_object_field $.Name .Name)) (not (len .Args)) }} - {{ .Name | title}} {{ get_field_type $.Name . }} {{ template "graphql_struct_tag" . }} {{ template "field_comment_description" . }} - {{- end -}}{{ end }} - } - {{- end }}{{- end -}} - `), + // objectFile: t(header + ` + // import "github.com/relvacode/iso8601" + + // {{range .Types | sortByName}} + // {{if and (eq .Kind "OBJECT") (not (internal .Name)) }} + // {{- if ne .Name "Account" }} + // {{template "object" .}}{{end}} + // {{- end}} + // {{- end}} + + // {{- define "object" -}} + // {{ if not (skip_object .Name) }} + // {{ template "type_comment_description" . }} + // type {{.Name}} struct { {{ add_special_fields .Name }} + // {{ range .Fields }} + // {{- if and (not (skip_object_field $.Name .Name)) (not (len .Args)) }} + // {{ .Name | title}} {{ get_field_type $.Name . }} {{ template "graphql_struct_tag" . }} {{ template "field_comment_description" . }} + // {{- end -}}{{ end }} + // } + // {{- end }}{{- end -}} + // `), // scalarFile: t(header + ` // import ( // "encoding/base64" @@ -959,12 +928,12 @@ func firstCharLowered(s string) string { var templFuncMap = template.FuncMap{ "internal": func(s string) bool { return strings.HasPrefix(s, "__") }, + "queryRename": queryRename, "quote": strconv.Quote, "join": strings.Join, "check_fragments": fragmentsForCheck, "custom_actions_ext_action_fragments": fragmentsForCustomActionsExtAction, "integration_fragments": fragmentsForIntegration, - "get_field_type": getFieldType, "get_input_field_type": getInputFieldType, "add_special_fields": addSpecialFields, "add_special_interfaces_fields": addSpecialInterfacesFields, @@ -975,6 +944,7 @@ var templFuncMap = template.FuncMap{ "skip_query": skipQuery, "skip_interface_field": skipInterfaceField, "example_tag_value": getExampleValue, + "isObjectType": isObjectType, "isListType": isPlural, "renameMutation": renameMutation, "renameMutationReturnType": renameMutationReturnType, @@ -1190,190 +1160,6 @@ func getInputFieldType(inputField GraphQLField) string { return "string" } -func getFieldType(objectName string, inputField GraphQLField) string { - lowercaseFieldName := strings.ToLower(inputField.Name) - switch { - case "type" == lowercaseFieldName: - switch objectName { - case "AlertSource": - return "AlertSourceTypeEnum" - case "AlertSourceUsageCheck", "CustomCheck", "CustomEventCheck", - "GitBranchProtectionCheck", "HasDocumentationCheck", "HasRecentDeployCheck", - "ManualCheck", "PayloadCheck", "RepositoryFileCheck", "RepositoryGrepCheck", - "RepositoryIntegratedCheck", "RepositorySearchCheck", "ServiceConfigurationCheck", - "ServiceDependencyCheck", "ServiceOwnershipCheck", "ServicePropertyCheck", - "TagDefinedCheck", "ToolUsageCheck": - return "CheckType" - case "ApiDocIntegration", "AwsIntegration", "AzureDevopsIntegration", - "AzureDevopsPermissionError", "BitbucketIntegration", "CheckIntegration", - "DatadogIntegration", "DeployIntegration", "FluxIntegration", "GenericIntegration", - "GithubActionsIntegration", "GithubIntegration", "GitlabIntegration", - "InfrastructureResource", "InfrastructureResourceSchema", "Repository", - "IssueTrackingIntegration", "JenkinsIntegration", "KubernetesIntegration", - "NewRelicIntegration", "OctopusDeployIntegration", "OnPremGitlabIntegration", - "OpsgenieIntegration", "PagerdutyIntegration", "PayloadIntegration", - "RelationshipType", "ScimIntegration", "SlackIntegration", "TerraformIntegration": - return "string" - case "Contact": - return "ContactType" - case "FilterPredicate": - return "PredicateTypeEnum" - case "InfrastructureResourceProviderData": - return "DoubleCheckThis" - case "Predicate": - return "PredicateTypeEnum" - default: - return "any" - } - case objectName == "AlertSource" && lowercaseFieldName == "integration": - return "IntegrationId" - case objectName == "AlertSourceService": - switch lowercaseFieldName { - case "alertsource": - return "AlertSource" - case "service": - return "ServiceId" - case "status": - return "AlertSourceStatusTypeEnum" - } - case objectName == "CustomActionsTriggerDefinition": - switch lowercaseFieldName { - case "accesscontrol": - return "CustomActionsTriggerDefinitionAccessControlEnum" - case "action": - return "CustomActionsId" - case "entitytype": - return "CustomActionsEntityTypeEnum" - case "filter": - return "FilterId" - case "owner": - return "TeamId" - } - case objectName == "CustomActionsWebhookAction": - switch lowercaseFieldName { - case "headers": - return "JSON" - case "httpmethod": - return "CustomActionsHttpMethodEnum" - } - case objectName == "Domain": - switch lowercaseFieldName { - case "managedaliases": - return "[]string" - case "owner": - return "EntityOwner" - } - case objectName == "Filter": - switch lowercaseFieldName { - case "connective": - return "ConnectiveEnum" - case "predicates": - return "[]FilterPredicate" - } - case objectName == "FilterPredicate": - switch lowercaseFieldName { - case "casesensitive": - return "*bool" - case "key": - return "PredicateKeyEnum" - } - case objectName == "InfrastructureResource": - switch lowercaseFieldName { - case "data", "rawdata": - return "JSON" - case "id": - return "ID" - case "owner": - return "EntityOwner" - case "providerdata": - return "InfrastructureResourceProviderData" - } - case objectName == "InfrastructureResourceSchema" && lowercaseFieldName == "schema": - return "JSON" - case objectName == "Language" && lowercaseFieldName == "usage": - return "float64" - case objectName == "Repository": - switch lowercaseFieldName { - case "languages": - return "[]Language" - case "owner": - return "TeamId" - } - case objectName == "Scorecard": - switch lowercaseFieldName { - case "owner": - return "EntityOwner" - case "passingchecks", "servicecount", "totalchecks": - return "int" - } - case objectName == "Secret" && lowercaseFieldName == "owner": - return "TeamId" - case objectName == "Repository" && lowercaseFieldName == "owner": - return "TeamId" - case objectName == "Service": - switch lowercaseFieldName { - case "managedaliases": - return "[]string" - case "owner": - return "TeamId" - case "preferredapidocument": - return "*ServiceDocument" - case "preferredapidocumentsource": - return "*ApiDocumentSourceEnum" - } - case objectName == "ServiceDependency": - switch lowercaseFieldName { - case "destinationservice", "sourceservice": - return "ServiceId" - } - case objectName == "ServiceDocument" && lowercaseFieldName == "source": - return "ServiceDocumentSource" - case objectName == "ServiceRepository": - switch lowercaseFieldName { - case "repository": - return "RepositoryId" - case "service": - return "ServiceId" - } - case objectName == "System": - switch lowercaseFieldName { - case "managedaliases": - return "[]string" - case "owner": - return "EntityOwner" - case "parent": - return "Domain" - } - case objectName == "Team": - switch lowercaseFieldName { - case "contacts": - return "Contact" - case "managedaliases": - return "[]string" - case "parentteam": - return "TeamId" - } - case objectName == "TeamMembership": - switch lowercaseFieldName { - case "team": - return "TeamId" - case "user": - return "UserId" - } - case objectName == "Tool": - switch lowercaseFieldName { - case "category": - return "ToolCategory" - case "service": - return "ServiceId" - } - case objectName == "User" && lowercaseFieldName == "role": - return "UserRole" - } - - return getInputFieldType(inputField) -} - func getExampleValueByFieldName(inputField GraphQLInputValue) string { mapFieldTypeToExampleValue := map[string]string{ "DocumentSubtype": "openapi", diff --git a/go.mod b/go.mod index 810ec71f..88f6843a 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gosimple/unidecode v1.0.1 // indirect + github.com/graph-gophers/graphql-go v1.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect diff --git a/go.sum b/go.sum index 57a7a373..4dc4887d 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,7 @@ github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSC github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= @@ -17,6 +18,9 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -28,6 +32,7 @@ github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaC github.com/go-resty/resty/v2 v2.16.2 h1:CpRqTjIzq/rweXUt9+GxzzQdlkqMdt8Lm/fuK/CAbAg= github.com/go-resty/resty/v2 v2.16.2/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -36,6 +41,8 @@ github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo= github.com/gosimple/slug v1.15.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= +github.com/graph-gophers/graphql-go v1.5.0 h1:fDqblo50TEpD0LY7RXk/LFVYEVqo3+tXMNMPSVXA1yc= +github.com/graph-gophers/graphql-go v1.5.0/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= @@ -64,6 +71,7 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opslevel/moredefaults v0.0.0-20240112142637-078c8ff8ba9c h1:m4sNHcfkE02xZy1oxF2QVGfhHulamxw9UlzRM7c45QQ= github.com/opslevel/moredefaults v0.0.0-20240112142637-078c8ff8ba9c/go.mod h1:g2GSXVP6LO+5+AIsnMRPN+BeV86OXuFRTX7HXCDtYeI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -83,8 +91,13 @@ github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= +go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= @@ -98,6 +111,8 @@ golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/templates/queries.tpl b/templates/queries.tpl new file mode 100644 index 00000000..3cf5813f --- /dev/null +++ b/templates/queries.tpl @@ -0,0 +1,138 @@ +{{- define "get_query" }} + {{- if and (eq "OBJECT" .Kind) (not (contains "Connection" .String)) }} + {{- range .Fields }} + {{ if and (isObjectType .) (not (contains "Connection" .Type.String)) }} + {{- if gt (len .Arguments) 0 }} +func ({{ lower $.Name }} *{{ $.Name }}) Get{{ title .Name }}(client *Client + {{- range $index, $arg := .Arguments -}} + , {{ $arg.Name.Name }} {{ trimSuffix "!" $arg.Type.String }} + {{- end -}} + ) (*{{ title .Name }}, error){ + var q struct { + Account struct { + {{ $.Name }} struct { + {{ title .Name }} {{ trimSuffix "!" .Type.String }} `graphql:"{{ .Name }}( + {{- range $index, $arg := .Arguments }} + {{- if gt $index 0 }}, {{ end -}} + {{ $arg.Name.Name }}: ${{ $arg.Name.Name }} + {{- end }})"` + } `graphql:"{{ lower $.Name }}(id: $id)"` + } + } + if {{ lower $.Name }}.Id == "" { + return nil, fmt.Errorf("unable to get {{ title .Name }}, invalid {{ lower $.Name }} id: '%s'", {{ lower $.Name }}.Id) + } + v := PayloadVariables{ {{ range .Arguments }} + "{{.Name.Name}}": {{.Name.Name}}, {{ end }} + } + + err := client.Query(&q, v, WithName("{{ $.Name }}{{ title .Name }}Get")) + return &q.Account.{{ $.Name }}.{{ title .Name }}, HandleErrors(err, nil) +} + {{ end }} + {{ end }} + {{ end }} + {{- end }} +{{- end -}} + +{{- define "list_query" }} + {{- if eq "OBJECT" .Kind }} + {{- range .Fields }} + {{ if and (isObjectType .) (contains "Connection" .Type.String) }} + {{- if gt (len .Arguments) 0 }} +func ({{ lower $.Name }} *{{ $.Name }}) List{{ title .Name | makePlural }}(client *Client, variables *PayloadVariables) (*{{ trimSuffix "!" .Type.String }}, error){ + var q struct { + Account struct { + {{ $.Name }} struct { + {{ title .Name }} {{ trimSuffix "!" .Type.String }} `graphql:"{{ .Name }}(after: $after, first: $first)"` + } `graphql:"{{ lower $.Name }}(id: $id)"` + } + } + if {{ lower $.Name }}.Id == "" { + return nil, fmt.Errorf("unable to get {{ title .Name }}, invalid {{ lower $.Name }} id: '%s'", {{ lower $.Name }}.Id) + } + if variables == nil { + variables = client.InitialPageVariablesPointer() + } + + if err := client.Query(&q, *variables, WithName("{{ title .Name }}List")); err != nil { + return nil, err + } + for q.Account.{{ $.Name }}.{{ title .Name }}.PageInfo.HasNextPage { + (*variables)["after"] = q.Account.{{ $.Name }}.{{ title .Name }}.PageInfo.End + resp, err := {{ lower $.Name }}.List{{ title .Name | makePlural }}(client, variables) + if err != nil { + return nil, err + } + q.Account.{{ $.Name }}.{{ title .Name }}.Nodes = append(q.Account.{{ $.Name }}.{{ title .Name }}.Nodes, resp.Nodes...) + q.Account.{{ $.Name }}.{{ title .Name }}.PageInfo = resp.PageInfo + q.Account.{{ $.Name }}.{{ title .Name }}.TotalCount += resp.TotalCount + } + return &q.Account.{{ $.Name }}.{{ title .Name }}, nil +} + {{ end }} + {{ end }} + {{ end }} + {{- end }} +{{- end -}} + +{{ define "account_get_query" -}} + {{- range .Fields }} + {{ if and (isObjectType .) (not (contains "Connection" .Type.String)) }} +func (client *Client) Get{{ title .Name }}( + {{- range $index, $arg := .Arguments }} + {{- if gt $index 0 }}, {{ end -}} + {{ $arg.Name.Name }} {{ trimSuffix "!" $arg.Type.String }} + {{- end -}} + ) (*{{ trimSuffix "!" .Type.String }}, error){ + var q struct { + Account struct { + {{ title .Name }} {{ trimSuffix "!" .Type.String }} `graphql:"{{ .Name }}( + {{- range $index, $arg := .Arguments }} + {{- if gt $index 0 }}, {{ end -}} + {{ $arg.Name.Name }}: ${{ $arg.Name.Name }} + {{- end }})"` + } + } + v := PayloadVariables{ {{ range .Arguments }} + "{{.Name.Name}}": {{.Name.Name}}, {{ end }} + } + + err := client.Query(&q, v, WithName("{{ title .Name }}Get")) + return &q.Account.{{ title .Name }}, HandleErrors(err, nil) +} + {{ end }} + {{- end }} +{{- end }} + +{{ define "account_list_query" -}} + {{- range .Fields }} + {{- if contains "Connection" .Type.String }} +func (client *Client) List{{ title .Name | queryRename | makePlural }}(variables *PayloadVariables) (*{{ trimSuffix "!" .Type.String }}, error){ + var q struct { + Account struct { + {{ title .Name }} {{ trimSuffix "!" .Type.String }} `graphql:"{{ .Name }}(after: $after, first: $first)"` + } + } + if variables == nil { + variables = client.InitialPageVariablesPointer() + } + + if err := client.Query(&q, *variables, WithName("{{ title .Name | queryRename }}List")); err != nil { + return nil, err + } + for q.Account.{{ title .Name }}.PageInfo.HasNextPage { + (*variables)["after"] = q.Account.{{ title .Name }}.PageInfo.End + resp, err := client.List{{ title .Name | queryRename | makePlural }}(variables) + if err != nil { + return nil, err + } + q.Account.{{ title .Name }}.Nodes = append(q.Account.{{ title .Name }}.Nodes, resp.Nodes...) + q.Account.{{ title .Name }}.PageInfo = resp.PageInfo + q.Account.{{ title .Name }}.TotalCount += resp.TotalCount + } + return &q.Account.{{ title .Name }}, nil +} + {{ end }} + {{- end }} +{{- end }}