diff --git a/Makefile b/Makefile index 65dd39fe28a..a88c8241c17 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ GOPATH ?= $(shell go env GOPATH) ###################### DGRAPH_VERSION ?= local -.PHONY: all +.PHONY: all all: dgraph .PHONY: dgraph diff --git a/dgraph/cmd/alpha/http.go b/dgraph/cmd/alpha/http.go index 923a4d6f3f3..8ebde0f59b0 100644 --- a/dgraph/cmd/alpha/http.go +++ b/dgraph/cmd/alpha/http.go @@ -244,6 +244,18 @@ func queryHandler(w http.ResponseWriter, r *http.Request) { } } + // If rdf is set true, then response will be in rdf format. + respFormat := r.URL.Query().Get("respFormat") + switch respFormat { + case "", "json": + req.RespFormat = api.Request_JSON + case "rdf": + req.RespFormat = api.Request_RDF + default: + x.SetStatus(w, x.ErrorInvalidRequest, fmt.Sprintf("invalid value [%v] for parameter respFormat", respFormat)) + return + } + // Core processing happens here. resp, err := (&edgraph.Server{}).QueryNoGrpc(ctx, &req) if err != nil { @@ -273,7 +285,17 @@ func queryHandler(w http.ResponseWriter, r *http.Request) { x.Check2(out.Write(js)) } x.Check2(out.WriteRune('{')) - writeEntry("data", resp.Json) + if respFormat == "rdf" { + // In Json, []byte marshals into a base64 data. We instead Marshal it as a string. + // json.Marshal is therefore necessary here. We also do not want to escape <,>. + var buf bytes.Buffer + encoder := json.NewEncoder(&buf) + encoder.SetEscapeHTML(false) + x.Check(encoder.Encode(string(resp.Rdf))) + writeEntry("data", buf.Bytes()) + } else { + writeEntry("data", resp.Json) + } x.Check2(out.WriteRune(',')) writeEntry("extensions", js) x.Check2(out.WriteRune('}')) diff --git a/dgraph/cmd/alpha/http_test.go b/dgraph/cmd/alpha/http_test.go index a063cbc2f48..ea01f7c75fd 100644 --- a/dgraph/cmd/alpha/http_test.go +++ b/dgraph/cmd/alpha/http_test.go @@ -164,11 +164,12 @@ func queryWithGz(queryText, contentType, debug, timeout string, gzReq, gzResp bo } type queryInp struct { - body string - typ string - debug string - ts uint64 - hash string + body string + typ string + debug string + ts uint64 + hash string + respFmt string } type tsInfo struct { @@ -191,6 +192,9 @@ func queryWithTsForResp(inp queryInp) (string, *tsInfo, *http.Response, error) { params = append(params, fmt.Sprintf("startTs=%v", strconv.FormatUint(inp.ts, 10))) params = append(params, fmt.Sprintf("hash=%s", inp.hash)) } + if inp.respFmt != "" { + params = append(params, fmt.Sprintf("respFormat=%s", inp.respFmt)) + } url := addr + "/query?" + strings.Join(params, "&") _, body, resp, err := runWithRetriesForResp("POST", inp.typ, url, inp.body) @@ -205,12 +209,9 @@ func queryWithTsForResp(inp queryInp) (string, *tsInfo, *http.Response, error) { startTs := r.Extensions.Txn.StartTs hash := r.Extensions.Txn.Hash - // Remove the extensions. - r2 := res{ - Data: r.Data, - } + // Remove the extensions + r2 := res{Data: r.Data} output, err := json.Marshal(r2) - return string(output), &tsInfo{ts: startTs, hash: hash}, resp, err } @@ -985,3 +986,54 @@ func TestQueryBackwardCompatibleWithGraphqlPlusMinusHeader(t *testing.T) { require.NoError(t, err) require.Equal(t, "2", resp.Header.Get(x.DgraphCostHeader)) } + +func TestQueryRdfData(t *testing.T) { + require.NoError(t, dropAll()) + require.NoError(t, alterSchema(`name: string @index(term) .`)) + + // empty RDF response + q1 := ` + { + balances(func: anyofterms(name, "Alice Bob")) { + name + balance + } + }` + resp, _, err := queryWithTs(queryInp{body: q1, typ: "application/dql", respFmt: "rdf"}) + require.NoError(t, err) + require.Equal(t, `{"data":""}`, resp) + + m1 := ` + { + set { + _:bob "Bob \"\"" . + _:bob "110" . + _:alice "60" . + } + }` + _, err = mutationWithTs(mutationInp{body: m1, typ: "application/rdf", commitNow: true}) + require.NoError(t, err) + + // json query + resp, _, err = queryWithTs(queryInp{body: q1, typ: "application/dql"}) + require.NoError(t, err) + require.Equal(t, `{"data":{"balances":[{"name":"Bob \"\u003cthe builder\u003e\"","balance":"110"}]}}`, resp) + + // rdf query + resp, _, err = queryWithTs(queryInp{body: q1, typ: "application/dql", respFmt: "rdf"}) + require.NoError(t, err) + var r2 struct { + Data string `json:"data"` + } + require.NoError(t, json.Unmarshal([]byte(resp), &r2)) + + // we apply the same RDF mutation and it should work + require.NoError(t, dropAll()) + require.NoError(t, alterSchema(`name: string @index(term) .`)) + _, err = mutationWithTs(mutationInp{body: `{set {` + r2.Data + `}}`, typ: "application/rdf", commitNow: true}) + require.NoError(t, err) + + resp, _, err = queryWithTs(queryInp{body: q1, typ: "application/dql"}) + require.NoError(t, err) + require.Equal(t, `{"data":{"balances":[{"name":"Bob \"\u003cthe builder\u003e\"","balance":"110"}]}}`, resp) +}