ndgo provides dgraph dgo txn abstractions and helpers.
- Reduce txn related boilerplate, thus making code more readable,
- Make using ratel like queries easier,
- Get query execution times the easy way, even for multi-query txns,
- Be low level - don't do magic, keep dgo things exposed for them to be usable, if necessary,
- No performance overhead compared to dgo, if possible.
go get -u github.com/ppp225/ndgo
import (
"github.com/ppp225/ndgo/v5"
)
Run transactions the same way one would do in ratel:
q := QueryDQL(fmt.Sprintf(`
{
%s(func: eq(%s, "%s")) {
uid
name
}
}
`, "favActor", "name", "Keanu Reeves"))
resp, err := q.Run(txn)
Or marshal structs:
jsonBytes, err := json.Marshal(myObj)
if err != nil {
return nil, err
}
resp, err := txn.Setb(jsonBytes, nil)
Or don't:
resp, err := txn.Seti(myObj, myObj2, myObj3)
Do Upserts:
q := `{ a as var(func: eq(name, "Keanu")) }`
myObj := personStruct{
UID: "uid(a)",
Type: "Person",
Name: "Keanu",
}
resp, err := txn.DoSeti(q, myObj)
See TestBasic
and TestComplex
and TestTxnUpsert
in ndgo_test.go
for a complete example.
dg := NewDgraphClient()
txn := ndgo.NewTxn(ctx, dg.NewTxn()) // or dg.NewReadOnlyTxn(), you can use any available dgo.txn options. You can also use ndgo.NewTxnWithoutContext(txn)
defer txn.Discard()
...
err = txn.Commit()
resp, err := txn.Mutate(*api.Mutation)
resp, err := txn.Setb(jsonBytes, rdfBytes)
resp, err := txn.Seti(myObjs...)
resp, err := txn.Setnq(nquads)
resp, err := txn.Deleteb(jsonBytes, deleteRdfBytes)
resp, err := txn.Deletei(myObjs...)
resp, err := txn.Deletenq(nquads)
resp, err := txn.Query(queryString)
resp, err := txn.QueryWithVars(queryWithVarsString, vars...)
resp, err := txn.Do(req *api.Request)
resp, err := txn.DoSetb(queryString, jsonBytes)
resp, err := txn.DoSeti(queryString, myObjs...)
resp, err := txn.DoSetnq(queryString, nquads)
dbms := txn.GetDatabaseTime()
nwms := txn.GetNetworkTime()
Define and run txns through json, rdf or predefined helpers
set := ndgo.SetJSON(fmt.Sprintf(`
{
"name": "%s",
"age": "%s"
}`, "L", "25"))
// or
set := ndgo.SetRDF(`<_:new> <name> "L" .
<_:new> <age> "25" .`)
// or
set := ndgo.Query{}.SetPred("_:new", name, "L") +
ndgo.Query{}.SetPred("_:new", age, "25")
resp, err := set.Run(txn)
del := ndgo.DeleteJSON(fmt.Sprintf(`
{
"uid": "%s"
}
`, uid))
// or
del := ndgo.Query{}.DeleteNode("0x420") +
ndgo.Query{}.DeleteEdge("0x420", "edgeName", "0x42") +
ndgo.Query{}.DeletePred("0x42", "name")
resp, err := del.Run(txn)
q := ndgo.QueryDQL(fmt.Sprintf(`
{
%s(func: eq(%s, "%s")) {
uid
}
}
`, "favActor", "name", "Keanu Reeves"))
response, err := q.Run(txn)
You can chain queries and JSON mutations with Join, RDF mutations with + operator, assuming they are the same type:
q1 := ndgo.QueryDQL(`{q1(func:eq(name,"a")){uid}})`
q2 := ndgo.QueryDQL(`{q2(func:eq(name,"b")){uid}})`
resp, err := q1.Join(q2).Run(txn)
Note that query blocks have to be named uniquely.
Sometimes, when querying dgraph, we want just 1 resulting element, instead of a nested array.
// Instead of having this:
type Queries struct {
Q []struct {
UID string `json:"uid"`
} `json:"q"`
}
// We can have:
type MyObj struct {
UID string `json:"uid"`
}
resp, _ := ndgo.QueryDQL(`{q(func:uid(0x123)){uid}}`).Run(txn)
// query block name -------^ must be one letter and only one query block must be in the query for this helper to work!
var result MyObj
if err := json.Unmarshal(ndgo.Unsafe{}.FlattenRespToObject(resp.GetJson()), &result); err != nil {
panic(err) // will fail, if result has more than 1 element!
}
var resultSlice []MyObj
if err := json.Unmarshal(ndgo.Unsafe{}.FlattenRespToArray(resp.GetJson()), &resultSlice); err != nil {
panic(err) // will fail, if multiple query blocks are used in Query, but can have multiple results!
}
log.Print(result)
log.Print(resultSlice)
- add more upsert things
This project uses semantic versioning, see the changelog for details.