blob: 4f434d7c089a1a42562946c4c77043b4365cbed0 [file] [log] [blame]
giolekvac76b21b2020-04-18 19:28:43 +04001package schema
2
3import (
4 "bytes"
giolekvafb52e0d2020-04-23 22:52:13 +04005 "errors"
giolekvac76b21b2020-04-18 19:28:43 +04006 "fmt"
7 "io/ioutil"
8 "net/http"
9 "strings"
10
11 "github.com/golang/glog"
12 "github.com/itaysk/regogo"
giolekvafb52e0d2020-04-23 22:52:13 +040013 "github.com/vektah/gqlparser"
giolekvac76b21b2020-04-18 19:28:43 +040014 "github.com/vektah/gqlparser/ast"
giolekvac76b21b2020-04-18 19:28:43 +040015)
16
17const jsonContentType = "application/json"
giolekvafb52e0d2020-04-23 22:52:13 +040018const textContentType = "text/plain"
giolekvac76b21b2020-04-18 19:28:43 +040019
giolekvafb52e0d2020-04-23 22:52:13 +040020const getSchemaQuery = `{ "query": "{ getGQLSchema() { generatedSchema } }" }`
21const runQuery = `{ "query": "%s" }`
giolekvac76b21b2020-04-18 19:28:43 +040022
giolekvafb52e0d2020-04-23 22:52:13 +040023type DgraphClient struct {
24 gqlAdddress string
25 schemaAddress string
giolekvac76b21b2020-04-18 19:28:43 +040026 gqlSchema string
giolekvafb52e0d2020-04-23 22:52:13 +040027 schema *ast.Schema
giolekvac76b21b2020-04-18 19:28:43 +040028}
29
giolekvafb52e0d2020-04-23 22:52:13 +040030func NewDgraphClient(gqlAddress, schemaAddress string) (GraphQLClient, error) {
31 ret := &DgraphClient{
32 gqlAdddress: gqlAddress,
33 schemaAddress: schemaAddress,
34 gqlSchema: ""}
giolekvac76b21b2020-04-18 19:28:43 +040035 if err := ret.fetchSchema(); err != nil {
36 return nil, err
37 }
38 return ret, nil
39}
40
giolekvafb52e0d2020-04-23 22:52:13 +040041func (s *DgraphClient) Schema() *ast.Schema {
giolekvac76b21b2020-04-18 19:28:43 +040042 return s.schema
43}
44
giolekvafb52e0d2020-04-23 22:52:13 +040045func (s *DgraphClient) AddSchema(gqlSchema string) error {
giolekvac76b21b2020-04-18 19:28:43 +040046 return s.SetSchema(s.gqlSchema + gqlSchema)
47}
48
giolekvafb52e0d2020-04-23 22:52:13 +040049func (s *DgraphClient) SetSchema(gqlSchema string) error {
giolekvac76b21b2020-04-18 19:28:43 +040050 glog.Info("Setting GraphQL schema:")
51 glog.Info(gqlSchema)
giolekvafb52e0d2020-04-23 22:52:13 +040052 resp, err := http.Post(
53 s.schemaAddress+"/schema",
54 textContentType,
55 bytes.NewReader([]byte(gqlSchema)))
giolekvac76b21b2020-04-18 19:28:43 +040056 if err != nil {
57 return err
58 }
giolekvacba39b82020-04-18 20:56:05 +040059 glog.Infof("Response status code: %d", resp.StatusCode)
giolekvac76b21b2020-04-18 19:28:43 +040060 respBody, err := ioutil.ReadAll(resp.Body)
61 if err != nil {
62 return err
63 }
64 glog.Infof("Result: %s", string(respBody))
65 s.gqlSchema = gqlSchema
66 return s.fetchSchema()
67}
68
giolekvafb52e0d2020-04-23 22:52:13 +040069func (s *DgraphClient) fetchSchema() error {
giolekvac76b21b2020-04-18 19:28:43 +040070 glog.Infof("Getting GraphQL schema with query: %s", getSchemaQuery)
giolekvafb52e0d2020-04-23 22:52:13 +040071 resp, err := http.Post(
72 s.schemaAddress,
73 jsonContentType,
74 bytes.NewReader([]byte(getSchemaQuery)))
giolekvac76b21b2020-04-18 19:28:43 +040075 if err != nil {
76 return err
77 }
78 glog.Infof("Response status code: %d", resp.StatusCode)
79 respBody, err := ioutil.ReadAll(resp.Body)
80 if err != nil {
81 return err
82 }
83 glog.Infof("Result: %s", string(respBody))
giolekvafb52e0d2020-04-23 22:52:13 +040084 gqlSchema, err := regogo.Get(
85 string(respBody),
86 "input.data.getGQLSchema.generatedSchema")
giolekvac76b21b2020-04-18 19:28:43 +040087 if err != nil {
88 return err
89 }
giolekvafb52e0d2020-04-23 22:52:13 +040090 schema, gqlErr := gqlparser.LoadSchema(&ast.Source{Input: gqlSchema.String()})
giolekvac76b21b2020-04-18 19:28:43 +040091 if gqlErr != nil {
92 return gqlErr
93 }
94 s.schema = schema
95 return nil
96}
giolekvafb52e0d2020-04-23 22:52:13 +040097
98func (s *DgraphClient) RunQuery(query string) (string, error) {
99 _, gqlErr := gqlparser.LoadQuery(s.Schema(), query)
100 if gqlErr != nil {
101 return "", errors.New(gqlErr.Error())
102 }
103 glog.Infof("Running GraphQL query: %s", query)
104 queryJson := fmt.Sprintf(runQuery, sanitizeQuery(query))
105 resp, err := http.Post(
106 s.gqlAdddress,
107 jsonContentType,
108 bytes.NewReader([]byte(queryJson)))
109 if err != nil {
110 return "", err
111 }
112 respBody, err := ioutil.ReadAll(resp.Body)
113 if err != nil {
114 return "", err
115 }
116 respStr := string(respBody)
117 glog.Infof("Result: %s", string(respStr))
118 // errStr, err := regogo.Get(respStr, "input.errors")
119 // if err == nil {
120 // return "", errors.New(errStr.JSON())
121 // }
122 data, err := regogo.Get(respStr, "input.data")
123 if err != nil {
124 return "", err
125 }
126 return data.JSON(), nil
127}
128
129func sanitizeSchema(schema string) string {
130 return strings.ReplaceAll(
131 strings.ReplaceAll(schema, "\n", " "), "\t", " ")
132}
133
134func sanitizeQuery(query string) string {
135 return strings.ReplaceAll(query, "\"", "\\\"")
136}