Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(alpha): support RDF response via http query request (#8004) #8639

Merged
merged 1 commit into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ GOPATH ?= $(shell go env GOPATH)
######################
DGRAPH_VERSION ?= local

.PHONY: all
.PHONY: all
all: dgraph

.PHONY: dgraph
Expand Down
24 changes: 23 additions & 1 deletion dgraph/cmd/alpha/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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('}'))
Expand Down
72 changes: 62 additions & 10 deletions dgraph/cmd/alpha/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand All @@ -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
}

Expand Down Expand Up @@ -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 <name> "Bob \"<the builder>\"" .
_:bob <balance> "110" .
_:alice <balance> "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)
}