dgo

package module
v250.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 1, 2025 License: Apache-2.0 Imports: 19 Imported by: 18

README

dgo GoDoc

Official Dgraph Go client which communicates with the server using gRPC.

Before using this client, we highly recommend that you go through dgraph.io/tour and dgraph.io/docs to understand how to run and work with Dgraph.

Use Github Issues for reporting issues about this repository.

Table of contents

Supported Versions

Depending on the version of Dgraph that you are connecting to, you will have to use a different version of this client and their corresponding import paths.

Dgraph version dgo version dgo import path
dgraph 23.X.Y dgo 230.X.Y "github.com/dgraph-io/dgo/v230"
dgraph 24.X.Y dgo 240.X.Y "github.com/dgraph-io/dgo/v240"
dgraph 25.X.Y dgo 240.X.Y "github.com/dgraph-io/dgo/v240"
dgraph 25.X.Y dgo 250.X.Y "github.com/dgraph-io/dgo/v250"

New APIs in v25

Connection Strings

The dgo package supports connecting to a Dgraph cluster using connection strings. Dgraph connections strings take the form dgraph://{username:password@}host:port?args.

username and password are optional. If username is provided, a password must also be present. If supplied, these credentials are used to log into a Dgraph cluster through the ACL mechanism.

Valid connection string args:

Arg Value Description
apikey <key> a Dgraph Cloud API Key
bearertoken <token> an access token
sslmode disable | require | verify-ca TLS option, the default is disable. If verify-ca is set, the TLS certificate configured in the Dgraph cluster must be from a valid certificate authority.

Some example connection strings:

Value Explanation
dgraph://localhost:9080 Connect to localhost, no ACL, no TLS
dgraph://sally:supersecret@dg.example.com:443?sslmode=verify-ca Connect to remote server, use ACL and require TLS and a valid certificate from a CA
dgraph://foo-bar.grpc.us-west-2.aws.cloud.dgraph.io:443?sslmode=verify-ca&apikey=<your-api-connection-key> Connect to a Dgraph Cloud cluster
dgraph://foo-bar.grpc.hypermode.com?sslmode=verify-ca&bearertoken=<some access token> Connect to a Dgraph cluster protected by a secure gateway

Using the Open function with a connection string:

// open a connection to an ACL-enabled, non-TLS cluster and login as groot
client, err := dgo.Open("dgraph://groot:password@localhost:8090")
// Check error
defer client.Close()
// Use the clients
Advanced Client Creation

For more control, you can create a client using the NewClient function.

client, err := dgo.NewClient("localhost:9181",
  // add Dgraph ACL credentials
  dgo.WithACLCreds("groot", "password"),
  // add insecure transport credentials
  dgo.WithGrpcOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
)
// Check error
defer client.Close()
// Use the client

You can connect to multiple alphas using NewRoundRobinClient.

client, err := dgo.NewRoundRobinClient([]string{"localhost:9181", "localhost:9182", "localhost:9183"},
  // add Dgraph ACL credentials
  dgo.WithACLCreds("groot", "password"),
  // add insecure transport credentials
  dgo.WithGrpcOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
)
// Check error
defer client.Close()
// Use the client
Dropping All Data

In order to drop all data in the Dgraph Cluster and start fresh, use the DropAll function.

err := client.DropAll(context.TODO())
// Handle error
Set Schema

To set the schema, use the SetSchema function.

sch := `
  name: string @index(exact) .
  email: string @index(exact) @unique .
  age: int .
`
err := client.SetSchema(context.TODO(), dgo.RootNamespace, sch)
// Handle error
Running a Mutation

To run a mutation, use the RunDQL function.

mutationDQL := `{
  set {
    _:alice <name> "Alice" .
    _:alice <email> "alice@example.com" .
    _:alice <age> "29" .
  }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, mutationDQL)
// Handle error
// Print map of blank UIDs
fmt.Printf("%+v\n", resp.Uids)
Running a Query

To run a query, use the same RunDQL function.

queryDQL := `{
  alice(func: eq(name, "Alice")) {
    name
    email
    age
  }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, queryDQL)
// Handle error
fmt.Printf("%s\n", resp.Json)
Running a Query With Variables

To run a query with variables, using RunDQLWithVars.

queryDQL = `query Alice($name: string) {
  alice(func: eq(name, $name)) {
    name
    email
    age
  }
}`
vars := map[string]string{"$name": "Alice"}
resp, err := client.RunDQLWithVars(context.TODO(), dgo.RootNamespace, queryDQL, vars)
// Handle error
fmt.Printf("%s\n", resp.Json)
Running a Best Effort Query

To run a BestEffort query, use the same RunDQL function with TxnOption.

queryDQL := `{
  alice(func: eq(name, "Alice")) {
    name
    email
    age
  }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, queryDQL, dgo.WithBestEffort())
// Handle error
fmt.Printf("%s\n", resp.Json)
Running a ReadOnly Query

To run a ReadOnly query, use the same RunDQL function with TxnOption.

queryDQL := `{
  alice(func: eq(name, "Alice")) {
    name
    email
    age
  }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, queryDQL, dgo.WithReadOnly())
// Handle error
fmt.Printf("%s\n", resp.Json)
Running a Query with RDF Response

To get the query response in RDF format instead of JSON format, use the following TxnOption.

queryDQL := `{
  alice(func: eq(name, "Alice")) {
    name
    email
    age
  }
}`
resp, err = client.RunDQL(context.TODO(), dgo.RootNamespace, queryDQL, dgo.WithResponseFormat(api_v2.RespFormat_RDF))
// Handle error
fmt.Printf("%s\n", resp.Rdf)
Running an Upsert

The RunDQL function also allows you to run upserts as well.

upsertQuery := `upsert {
  query {
    user as var(func: eq(email, "alice@example.com"))
  }
  mutation {
    set {
      uid(user) <age> "30" .
      uid(user) <name> "Alice Sayum" .
    }
  }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, upsertQuery)
// Handle error
fmt.Printf("%s\n", resp.Json)
fmt.Printf("%+v\n", resp.Uids)
Running a Conditional Upsert
upsertQuery := `upsert {
  query {
    user as var(func: eq(email, "alice@example.com"))
  }
  mutation @if(eq(len(user), 1)) {
    set {
      uid(user) <age> "30" .
      uid(user) <name> "Alice Sayum" .
    }
  }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, upsertQuery)
// Handle error
fmt.Printf("%s\n", resp.Json)
Creating a New Namespace

Dgraph v25 supports creating namespaces using grpc API. You can create one using the dgo client.

_, err := client.CreateNamespace(context.TODO())
// Handle error
Dropping a Namespace

To drop a namespace:

_, err := client.DropNamespace(context.TODO())
// Handle error
List All Namespaces
namespaces, err := client.ListNamespaces(context.TODO())
// Handle error
fmt.Printf("%+v\n", namespaces)

Existing APIs

Creating a Client

dgraphClient object can be initialized by passing it a list of api.DgraphClient clients as variadic arguments. Connecting to multiple Dgraph servers in the same cluster allows for better distribution of workload.

The following code snippet shows just one connection.

conn, err := grpc.Dial("localhost:9080", grpc.WithInsecure())
// Check error
defer conn.Close()
dgraphClient := dgo.NewDgraphClient(api.NewDgraphClient(conn))
Login into a namespace

If your server has Access Control Lists enabled (Dgraph v1.1 or above), the client must be logged in for accessing data. If you do not use the WithACLCreds option with NewClient or a connection string with username:password, use the Login endpoint.

Calling login will obtain and remember the access and refresh JWT tokens. All subsequent operations via the logged in client will send along the stored access token.

err := dgraphClient.Login(ctx, "user", "passwd")
// Check error

If your server additionally has namespaces (Dgraph v21.03 or above), use the LoginIntoNamespace API.

err := dgraphClient.LoginIntoNamespace(ctx, "user", "passwd", 0x10)
// Check error
Altering the database

To set the schema, create an instance of api.Operation and use the Alter endpoint.

op := &api.Operation{
  Schema: `name: string @index(exact) .`,
}
err := dgraphClient.Alter(ctx, op)
// Check error

Operation contains other fields as well, including DropAttr and DropAll. DropAll is useful if you wish to discard all the data, and start from a clean slate, without bringing the instance down. DropAttr is used to drop all the data related to a predicate.

Starting Dgraph version 20.03.0, indexes can be computed in the background. You can set RunInBackground field of the api.Operation to true before passing it to the Alter function. You can find more details here.

op := &api.Operation{
  Schema:          `name: string @index(exact) .`,
  RunInBackground: true
}
err := dgraphClient.Alter(ctx, op)
Creating a transaction

To create a transaction, call dgraphClient.NewTxn(), which returns a *dgo.Txn object. This operation incurs no network overhead.

It is a good practice to call txn.Discard(ctx) using a defer statement after it is initialized. Calling txn.Discard(ctx) after txn.Commit(ctx) is a no-op. Furthermore, txn.Discard(ctx) can be called multiple times with no additional side-effects.

txn := dgraphClient.NewTxn()
defer txn.Discard(ctx)

Read-only transactions can be created by calling c.NewReadOnlyTxn(). Read-only transactions are useful to increase read speed because they can circumvent the usual consensus protocol. Read-only transactions cannot contain mutations and trying to call txn.Commit() will result in an error. Calling txn.Discard() will be a no-op.

Running a mutation

txn.Mutate(ctx, mu) runs a mutation. It takes in a context.Context and a *api.Mutation object. You can set the data using JSON or RDF N-Quad format.

To use JSON, use the fields SetJson and DeleteJson, which accept a string representing the nodes to be added or removed respectively (either as a JSON map or a list). To use RDF, use the fields SetNquads and DelNquads, which accept a string representing the valid RDF triples (one per line) to added or removed respectively. This protobuf object also contains the Set and Del fields which accept a list of RDF triples that have already been parsed into our internal format. As such, these fields are mainly used internally and users should use the SetNquads and DelNquads instead if they are planning on using RDF.

We define a Person struct to represent a Person and marshal an instance of it to use with Mutation object.

type Person struct {
  Uid   string   `json:"uid,omitempty"`
  Name  string   `json:"name,omitempty"`
  DType []string `json:"dgraph.type,omitempty"`
}

p := Person{
  Uid:   "_:alice",
  Name:  "Alice",
  DType: []string{"Person"},
}

pb, err := json.Marshal(p)
// Check error

mu := &api.Mutation{
  SetJson: pb,
}
res, err := txn.Mutate(ctx, mu)
// Check error

For a more complete example, see Example.

Sometimes, you only want to commit a mutation, without querying anything further. In such cases, you can use mu.CommitNow = true to indicate that the mutation must be immediately committed.

Mutation can be run using txn.Do as well.

mu := &api.Mutation{
  SetJson: pb,
}
req := &api.Request{CommitNow:true, Mutations: []*api.Mutation{mu}}
res, err := txn.Do(ctx, req)
// Check error
Running a query

You can run a query by calling txn.Query(ctx, q). You will need to pass in a DQL query string. If you want to pass an additional map of any variables that you might want to set in the query, call txn.QueryWithVars(ctx, q, vars) with the variables map as third argument.

Let's run the following query with a variable $a:

q := `query all($a: string) {
    all(func: eq(name, $a)) {
      name
    }
  }`

resp, err := txn.QueryWithVars(ctx, q, map[string]string{"$a": "Alice"})
fmt.Printf("%s\n", resp.Json)

You can also use txn.Do function to run a query.

req := &api.Request{
  Query: q,
  Vars: map[string]string{"$a": "Alice"},
}
resp, err := txn.Do(ctx, req)
// Check error
fmt.Printf("%s\n", resp.Json)

When running a schema query for predicate name, the schema response is found in the Json field of api.Response as shown below:

q := `schema(pred: [name]) {
  type
  index
  reverse
  tokenizer
  list
  count
  upsert
  lang
}`

resp, err := txn.Query(ctx, q)
// Check error
fmt.Printf("%s\n", resp.Json)
Query with RDF response

You can get query result as a RDF response by calling txn.QueryRDF. The response would contain a Rdf field, which has the RDF encoded result.

Note: If you are querying only for uid values, use a JSON format response.

// Query the balance for Alice and Bob.
const q = `
{
  all(func: anyofterms(name, "Alice Bob")) {
    name
    balance
  }
}
`
resp, err := txn.QueryRDF(context.Background(), q)
// check error

// <0x17> <name> "Alice" .
// <0x17> <balance> 100 .
fmt.Println(resp.Rdf)

txn.QueryRDFWithVars is also available when you need to pass values for variables used in the query.

Running an Upsert: Query + Mutation

The txn.Do function allows you to run upserts consisting of one query and one mutation. Variables can be defined in the query and used in the mutation. You could also use txn.Do to perform a query followed by a mutation.

To know more about upsert, we highly recommend going through the docs at Upsert Block.

query = `
  query {
      user as var(func: eq(email, "wrong_email@dgraph.io"))
  }`
mu := &api.Mutation{
  SetNquads: []byte(`uid(user) <email> "correct_email@dgraph.io" .`),
}
req := &api.Request{
  Query: query,
  Mutations: []*api.Mutation{mu},
  CommitNow:true,
}

// Update email only if matching uid found.
_, err := dg.NewTxn().Do(ctx, req)
// Check error
Running Conditional Upsert

The upsert block also allows specifying a conditional mutation block using an @if directive. The mutation is executed only when the specified condition is true. If the condition is false, the mutation is silently ignored.

See more about Conditional Upsert Here.

query = `
  query {
      user as var(func: eq(email, "wrong_email@dgraph.io"))
  }`
mu := &api.Mutation{
  Cond: `@if(eq(len(user), 1))`, // Only mutate if "wrong_email@dgraph.io" belongs to single user.
  SetNquads: []byte(`uid(user) <email> "correct_email@dgraph.io" .`),
}
req := &api.Request{
  Query: query,
  Mutations: []*api.Mutation{mu},
  CommitNow:true,
}

// Update email only if exactly one matching uid is found.
_, err := dg.NewTxn().Do(ctx, req)
// Check error
Committing a transaction

A transaction can be committed using the txn.Commit(ctx) method. If your transaction consisted solely of calls to txn.Query or txn.QueryWithVars, and no calls to txn.Mutate, then calling txn.Commit is not necessary.

An error will be returned if other transactions running concurrently modify the same data that was modified in this transaction. It is up to the user to retry transactions when they fail.

txn := dgraphClient.NewTxn()
// Perform some queries and mutations.

err := txn.Commit(ctx)
if err == y.ErrAborted {
  // Retry or handle error
}
Setting Metadata Headers

Metadata headers such as authentication tokens can be set through the context of gRPC methods. Below is an example of how to set a header named "auth-token".

// The following piece of code shows how one can set metadata with
// auth-token, to allow Alter operation, if the server requires it.
md := metadata.New(nil)
md.Append("auth-token", "the-auth-token-value")
ctx := metadata.NewOutgoingContext(context.Background(), md)
dg.Alter(ctx, &op)

Development

Running tests

Make sure you have dgraph installed in your GOPATH before you run the tests. The dgo test suite requires that a Dgraph cluster with ACL enabled be running locally. To start such a cluster, you may use the docker compose file located in the testing directory t.

docker compose -f t/docker-compose.yml up -d
# wait for cluster to be healthy
go test -v ./...
docker compose -f t/docker-compose.yml down

Documentation

Overview

Package dgo is used to interact with a Dgraph server. Queries, mutations, and most other types of admin tasks can be run from the client.

Example (GetSchema)
dg, cancel := getDgraphClient()
defer cancel()

op := &api.Operation{}
op.Schema = `
		name: string @index(exact) .
		age: int .
		married: bool .
		loc: geo .
		dob: datetime .
	`

ctx := context.Background()
err := dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

// Ask for the type of name and age.
resp, err := dg.NewTxn().Query(ctx, `schema(pred: [name, age]) {type}`)
if err != nil {
	log.Fatal(err)
}

// resp.Json contains the schema query response.
fmt.Println(string(resp.Json))
Output:

{"schema":[{"predicate":"age","type":"int"},{"predicate":"name","type":"string"}]}
Example (SetObject)
/*
 * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
 * SPDX-License-Identifier: Apache-2.0
 */

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"time"

	"github.com/dgraph-io/dgo/v250/protos/api"
)

type School struct {
	Name  string   `json:"name,omitempty"`
	DType []string `json:"dgraph.type,omitempty"`
}

type loc struct {
	Type   string    `json:"type,omitempty"`
	Coords []float64 `json:"coordinates,omitempty"`
}

// If omitempty is not set, then edges with empty values (0 for int/float, "" for string,
// false for bool) would be created for values not specified explicitly.

type Person struct {
	Uid      string     `json:"uid,omitempty"`
	Name     string     `json:"name,omitempty"`
	Age      int        `json:"age,omitempty"`
	Dob      *time.Time `json:"dob,omitempty"`
	Married  bool       `json:"married,omitempty"`
	Raw      []byte     `json:"raw_bytes,omitempty"`
	Friends  []Person   `json:"friend,omitempty"`
	Location loc        `json:"loc,omitempty"`
	School   []School   `json:"school,omitempty"`
	DType    []string   `json:"dgraph.type,omitempty"`
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()

	dob := time.Date(1980, 01, 01, 23, 0, 0, 0, time.UTC)
	// While setting an object if a struct has a Uid then its properties
	//  in the graph are updated else a new node is created.
	// In the example below new nodes for Alice, Bob and Charlie and
	//  school are created (since they don't have a Uid).
	p := Person{
		Uid:     "_:alice",
		Name:    "Alice",
		Age:     26,
		Married: true,
		DType:   []string{"Person"},
		Location: loc{
			Type:   "Point",
			Coords: []float64{1.1, 2},
		},
		Dob: &dob,
		Raw: []byte("raw_bytes"),
		Friends: []Person{{
			Name:  "Bob",
			Age:   24,
			DType: []string{"Person"},
		}, {
			Name:  "Charlie",
			Age:   29,
			DType: []string{"Person"},
		}},
		School: []School{{
			Name:  "Crown Public School",
			DType: []string{"Institution"},
		}},
	}

	op := &api.Operation{}
	op.Schema = `
		name: string @index(exact) .
		age: int .
		married: bool .
		loc: geo .
		dob: datetime .
		Friend: [uid] .
		type: string .
		coords: float .

		type Person {
			name: string
			age: int
			married: bool
			Friend: [Person]
			loc: Loc
		}

		type Institution {
			name: string
		}

		type Loc {
			type: string
			coords: float
		}
	`

	ctx := context.Background()
	if err := dg.Alter(ctx, op); err != nil {
		log.Fatal(err)
	}

	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

	mu.SetJson = pb
	response, err := dg.NewTxn().Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}

	// Assigned uids for nodes which were created would be returned in the response.Uids map.
	variables := map[string]string{"$id1": response.Uids["alice"]}
	q := `query Me($id1: string){
		me(func: uid($id1)) {
			name
			dob
			age
			loc
			raw_bytes
			married
			dgraph.type
			friend @filter(eq(name, "Bob")){
				name
				age
				dgraph.type
			}
			school {
				name
				dgraph.type
			}
		}
	}`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}

	out, _ := json.MarshalIndent(r, "", "\t")
	fmt.Printf("%s\n", out)
}
Output:

{
	"me": [
		{
			"name": "Alice",
			"age": 26,
			"dob": "1980-01-01T23:00:00Z",
			"married": true,
			"raw_bytes": "cmF3X2J5dGVz",
			"friend": [
				{
					"name": "Bob",
					"age": 24,
					"loc": {},
					"dgraph.type": [
						"Person"
					]
				}
			],
			"loc": {
				"type": "Point",
				"coordinates": [
					1.1,
					2
				]
			},
			"school": [
				{
					"name": "Crown Public School",
					"dgraph.type": [
						"Institution"
					]
				}
			],
			"dgraph.type": [
				"Person"
			]
		}
	]
}

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrFinished is returned when an operation is performed on
	// already committed or discarded transaction
	ErrFinished = errors.New("Transaction has already been committed or discarded")
	// ErrReadOnly is returned when a write/update is performed on a readonly transaction
	ErrReadOnly = errors.New("Readonly transaction cannot run mutations or be committed")
	// ErrAborted is returned when an operation is performed on an aborted transaction.
	ErrAborted = errors.New("Transaction has been aborted. Please retry")
)

Functions

func DeleteEdges

func DeleteEdges(mu *api.Mutation, uid string, predicates ...string)

DeleteEdges sets the edges corresponding to predicates on the node with the given uid for deletion. This helper function doesn't run the mutation on the server. Txn needs to be committed in order to execute the mutation.

Example
dg, cancel := getDgraphClient()
defer cancel()
op := &api.Operation{}
op.Schema = `
		age: int .
		married: bool .
		name: string @lang .
		location: string .
		Friends: [uid] .

		type Person {
			name
			age
			married
			Friends
		}

		type Institution {
			name
		}
	`

ctx := context.Background()
err := dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

type School struct {
	Uid   string   `json:"uid"`
	Name  string   `json:"name@en,omitempty"`
	DType []string `json:"dgraph.type,omitempty"`
}

type Person struct {
	Uid      string    `json:"uid,omitempty"`
	Name     string    `json:"name,omitempty"`
	Age      int       `json:"age,omitempty"`
	Married  bool      `json:"married,omitempty"`
	Friends  []Person  `json:"friends,omitempty"`
	Location string    `json:"location,omitempty"`
	Schools  []*School `json:"schools,omitempty"`
	DType    []string  `json:"dgraph.type,omitempty"`
}

// Lets add some data first.
p := Person{
	Uid:      "_:alice",
	Name:     "Alice",
	Age:      26,
	Married:  true,
	DType:    []string{"Person"},
	Location: "Riley Street",
	Friends: []Person{{
		Name:  "Bob",
		Age:   24,
		DType: []string{"Person"},
	}, {
		Name:  "Charlie",
		Age:   29,
		DType: []string{"Person"},
	}},
	Schools: []*School{{
		Name:  "Crown Public School",
		DType: []string{"Institution"},
	}},
}

mu := &api.Mutation{}
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
mu.CommitNow = true
response, err := dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

alice := response.Uids["alice"]

variables := make(map[string]string)
variables["$alice"] = alice
const q = `
		query Me($alice: string){
			me(func: uid($alice)) {
				name
				age
				location
				married
				dgraph.type
				friends {
					name
					age
					dgraph.type
				}
				schools {
					name@en
					dgraph.type
				}
			}
		}
	`

resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

// Now lets delete the friend and location edge from Alice
mu = &api.Mutation{}
dgo.DeleteEdges(mu, alice, "friends", "location")

mu.CommitNow = true
_, err = dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

resp, err = dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me []Person `json:"me"`
}

var r Root
if err := json.Unmarshal(resp.Json, &r); err != nil {
	log.Fatal(err)
}
out, _ := json.MarshalIndent(r.Me, "", "\t")
fmt.Printf("%s\n", out)
Output:

[
	{
		"name": "Alice",
		"age": 26,
		"married": true,
		"schools": [
			{
				"uid": "",
				"name@en": "Crown Public School",
				"dgraph.type": [
					"Institution"
				]
			}
		],
		"dgraph.type": [
			"Person"
		]
	}
]

func DialCloud deprecated

func DialCloud(endpoint, key string) (*grpc.ClientConn, error)

DialCloud creates a new TLS connection to a Dgraph Cloud backend

It requires the backend endpoint as well as the api token
Usage:
	conn, err := dgo.DialCloud("CLOUD_ENDPOINT","API_TOKEN")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	dgraphClient := dgo.NewDgraphClient(api.NewDgraphClient(conn))

Deprecated: Use dgo.NewClient or dgo.Open instead.

Types

type ClientOption

type ClientOption func(*clientOptions) error

ClientOption is a function that modifies the client options.

func WithACLCreds

func WithACLCreds(username, password string) ClientOption

WithACLCreds will use the provided username and password for ACL authentication. If namespace is not provided, it logs into the galaxy namespace.

func WithBearerToken

func WithBearerToken(token string) ClientOption

WithBearerToken uses the provided token and presents it as a Bearer Token in the HTTP Authorization header for authentication against a Dgraph Cluster. This can be used to connect to Hypermode Cloud.

func WithDgraphAPIKey

func WithDgraphAPIKey(apiKey string) ClientOption

WithDgraphAPIKey will use the provided API key for authentication for Dgraph Cloud.

func WithGrpcOption

func WithGrpcOption(opt grpc.DialOption) ClientOption

WithGrpcOption will add a grpc.DialOption to the client. This is useful for setting custom grpc options.

func WithNamespace

func WithNamespace(nsID uint64) ClientOption

WithNamespace logs into the given namespace.

func WithSkipTLSVerify

func WithSkipTLSVerify() ClientOption

func WithSystemCertPool

func WithSystemCertPool() ClientOption

WithSystemCertPool will use the system cert pool and setup a TLS connection with Dgraph cluster.

type Dgraph

type Dgraph struct {
	// contains filtered or unexported fields
}

Dgraph is a transaction-aware client to a Dgraph cluster.

func NewClient

func NewClient(endpoint string, opts ...ClientOption) (*Dgraph, error)

NewClient creates a new Dgraph client for a single endpoint. If ACL connection options are present, an login attempt is made using the supplied credentials.

func NewDgraphClient deprecated

func NewDgraphClient(clients ...api.DgraphClient) *Dgraph

NewDgraphClient creates a new Dgraph (client) for interacting with Alphas. The client is backed by multiple connections to the same or different servers in a cluster.

A single Dgraph (client) is thread safe for sharing with multiple goroutines.

Deprecated: Use dgo.NewClient or dgo.Open instead.

func NewRoundRobinClient

func NewRoundRobinClient(endpoints []string, opts ...ClientOption) (*Dgraph, error)

NewRoundRobinClient creates a new Dgraph client for a list of endpoints. It will round robin among the provided endpoints. If ACL connection options are present, an login attempt is made using the supplied credentials.

func Open

func Open(connStr string) (*Dgraph, error)

Open creates a new Dgraph client by parsing a connection string of the form: dgraph://<optional-login>:<optional-password>@<host>:<port>?<optional-params> For example `dgraph://localhost:9080?sslmode=require`

Parameters: - apikey: a Dgraph Cloud API key for authentication - bearertoken: a token for bearer authentication - sslmode: SSL connection mode (options: disable, require, verify-ca)

  • disable: No TLS (default)
  • require: Use TLS but skip certificate verification
  • verify-ca: Use TLS and verify the certificate against system CA

If credentials are provided, Open connects to the gRPC endpoint and authenticates the user. An error can be returned if the Dgraph cluster is not yet ready to accept requests--the text of the error in this case will contain the string "Please retry".

func (*Dgraph) AllocateNamespaces

func (d *Dgraph) AllocateNamespaces(ctx context.Context, howMany uint64) (uint64, uint64, error)

AllocateNamespaces allocates a given number of namespaces in the Graph and returns a start and end namespaces, end excluded. The namespaces in the range [start, end) can then be used by the client. Dgraph ensures that these namespaces are NOT allocated anywhere else throughout the operation of this cluster. This is useful in bulk loader or live loader or similar applications.

func (*Dgraph) AllocateTimestamps

func (d *Dgraph) AllocateTimestamps(ctx context.Context, howMany uint64) (uint64, uint64, error)

AllocateTimestamps gets a sequence of timestamps allocated from Dgraph. These timestamps can be used in bulk loader and similar applications.

func (*Dgraph) AllocateUIDs

func (d *Dgraph) AllocateUIDs(ctx context.Context, howMany uint64) (uint64, uint64, error)

AllocateUIDs allocates a given number of Node UIDs in the Graph and returns a start and end UIDs, end excluded. The UIDs in the range [start, end) can then be used by the client in the mutations going forward. Note that, each node in a Graph is assigned a UID in Dgraph. Dgraph ensures that these UIDs are not allocated anywhere else throughout the operation of this cluster. This is useful in bulk loader or live loader or similar applications.

func (*Dgraph) Alter

func (d *Dgraph) Alter(ctx context.Context, op *api.Operation) error

Alter can be used to do the following by setting various fields of api.Operation:

  1. Modify the schema.
  2. Drop a predicate.
  3. Drop the database.

Use DropAll, DropData, DropPredicate, DropType, SetSchema instead for better readability.

Example (DropAll)
dg, cancel := getDgraphClient()
defer cancel()
op := api.Operation{DropAll: true}
ctx := context.Background()
if err := dg.Alter(ctx, &op); err != nil {
	log.Fatal(err)
}

func (*Dgraph) Close

func (d *Dgraph) Close()

Close shutdown down all the connections to the Dgraph Cluster.

func (*Dgraph) CreateNamespace

func (d *Dgraph) CreateNamespace(ctx context.Context) (uint64, error)

CreateNamespace creates a new namespace with the given name and password for groot user.

func (*Dgraph) DropAll

func (d *Dgraph) DropAll(ctx context.Context) error

func (*Dgraph) DropData

func (d *Dgraph) DropData(ctx context.Context) error

func (*Dgraph) DropNamespace

func (d *Dgraph) DropNamespace(ctx context.Context, nsID uint64) error

DropNamespace deletes the namespace with the given name.

func (*Dgraph) DropPredicate

func (d *Dgraph) DropPredicate(ctx context.Context, predicate string) error

func (*Dgraph) DropType

func (d *Dgraph) DropType(ctx context.Context, typeName string) error

func (*Dgraph) GetAPIClients

func (d *Dgraph) GetAPIClients() []api.DgraphClient

GetAPIClients returns the api.DgraphClient that is useful for advanced cases when grpc API that are not exposed in dgo needs to be used.

func (*Dgraph) GetJwt

func (d *Dgraph) GetJwt() api.Jwt

GetJwt returns back the JWT for the dgraph client.

Deprecated

func (*Dgraph) ListNamespaces

func (d *Dgraph) ListNamespaces(ctx context.Context) (map[uint64]*api.Namespace, error)

ListNamespaces returns a map of namespace names to their details.

func (*Dgraph) Login

func (d *Dgraph) Login(ctx context.Context, userid string, password string) error

Login logs in the current client using the provided credentials into default namespace (0). Valid for the duration the client is alive.

func (*Dgraph) LoginIntoNamespace

func (d *Dgraph) LoginIntoNamespace(ctx context.Context,
	userid string, password string, namespace uint64) error

LoginIntoNamespace logs in the current client using the provided credentials. Valid for the duration the client is alive.

func (*Dgraph) NewReadOnlyTxn

func (d *Dgraph) NewReadOnlyTxn() *Txn

NewReadOnlyTxn sets the txn to readonly transaction.

func (*Dgraph) NewTxn

func (d *Dgraph) NewTxn() *Txn

NewTxn creates a new transaction.

func (*Dgraph) Relogin

func (d *Dgraph) Relogin(ctx context.Context) error

Relogin relogin the current client using the refresh token. This can be used when the access-token gets expired.

func (*Dgraph) RunDQL

func (d *Dgraph) RunDQL(ctx context.Context, q string, opts ...TxnOption) (
	*api.Response, error)

RunDQL runs a DQL query in the given namespace. A DQL query could be a mutation or a query or an upsert which is a combination of mutations and queries.

func (*Dgraph) RunDQLWithVars

func (d *Dgraph) RunDQLWithVars(ctx context.Context, q string,
	vars map[string]string, opts ...TxnOption) (*api.Response, error)

RunDQLWithVars is like RunDQL with variables.

func (*Dgraph) SetSchema

func (d *Dgraph) SetSchema(ctx context.Context, schema string) error

type Txn

type Txn struct {
	// contains filtered or unexported fields
}

Txn is a single atomic transaction. A transaction lifecycle is as follows:

  1. Created using NewTxn.
  2. Various Query and Mutate calls made.
  3. Commit or Discard used. If any mutations have been made, It's important that at least one of these methods is called to clean up resources. Discard is a no-op if Commit has already been called, so it's safe to defer a call to Discard immediately after NewTxn.

func (*Txn) BestEffort

func (txn *Txn) BestEffort() *Txn

BestEffort enables best effort in read-only queries. This will ask the Dgraph Alpha to try to get timestamps from memory in a best effort to reduce the number of outbound requests to Zero. This may yield improved latencies in read-bound datasets.

This method will panic if the transaction is not read-only. Returns the transaction itself.

func (*Txn) Commit

func (txn *Txn) Commit(ctx context.Context) error

Commit commits any mutations that have been made in the transaction. Once Commit has been called, the lifespan of the transaction is complete.

Errors could be returned for various reasons. Notably, ErrAborted could be returned if transactions that modify the same data are being run concurrently. It's up to the user to decide if they wish to retry. In this case, the user should create a new transaction.

func (*Txn) Discard

func (txn *Txn) Discard(ctx context.Context) error

Discard cleans up the resources associated with an uncommitted transaction that contains mutations. It is a no-op on transactions that have already been committed or don't contain mutations. Therefore, it is safe (and recommended) to call as a deferred function immediately after a new transaction is created.

In some cases, the transaction can't be discarded, e.g. the grpc connection is unavailable. In these cases, the server will eventually do the transaction clean up itself without any intervention from the client.

Example
dg, cancel := getDgraphClient()
defer cancel()

ctx, toCancel := context.WithTimeout(context.Background(), 30*time.Second)
defer toCancel()
err := dg.Alter(ctx, &api.Operation{
	DropAll: true,
})
if err != nil {
	log.Fatal("The drop all operation should have succeeded")
}

err = dg.Alter(ctx, &api.Operation{
	Schema: `name: string @index(exact) .`,
})
if err != nil {
	log.Fatal("The alter should have succeeded")
}

txn := dg.NewTxn()
_, err = txn.Mutate(ctx, &api.Mutation{
	SetNquads: []byte(`_:a <name> "Alice" .`),
})
if err != nil {
	log.Fatal("The mutation should have succeeded")
}
if err := txn.Discard(ctx); err != nil {
	log.Fatal(err)
}

// now query the cluster and make sure that the data has made no effect
queryTxn := dg.NewReadOnlyTxn()
query := `
		{
			q (func: eq(name, "Alice")) {
				name
				dgraph.type
			}
		}
	`
resp, err := queryTxn.Query(ctx, query)
if err != nil {
	log.Fatal("The query should have succeeded")
}

fmt.Print(string(resp.Json))
Output:

{"q":[]}

func (*Txn) Do

func (txn *Txn) Do(ctx context.Context, req *api.Request) (*api.Response, error)

Do executes a query followed by one or more than one mutations.

func (*Txn) Mutate

func (txn *Txn) Mutate(ctx context.Context, mu *api.Mutation) (*api.Response, error)

Mutate allows data stored on Dgraph instances to be modified. The fields in api.Mutation come in pairs, set and delete. Mutations can either be encoded as JSON or as RDFs.

If CommitNow is set, then this call will result in the transaction being committed. In this case, an explicit call to Commit doesn't need to be made subsequently.

If the mutation fails, then the transaction is discarded and all future operations on it will fail.

Example
type School struct {
	Name  string   `json:"name,omitempty"`
	DType []string `json:"dgraph.type,omitempty"`
}

type loc struct {
	Type   string    `json:"type,omitempty"`
	Coords []float64 `json:"coordinates,omitempty"`
}

// If omitempty is not set, then edges with empty values (0 for int/float, "" for string,
// false for bool) would be created for values not specified explicitly.

type Person struct {
	Uid      string   `json:"uid,omitempty"`
	Name     string   `json:"name,omitempty"`
	Age      int      `json:"age,omitempty"`
	Married  bool     `json:"married,omitempty"`
	Raw      []byte   `json:"raw_bytes,omitempty"`
	Friends  []Person `json:"friends,omitempty"`
	Location loc      `json:"loc,omitempty"`
	School   []School `json:"school,omitempty"`
	DType    []string `json:"dgraph.type,omitempty"`
}

dg, cancel := getDgraphClient()
defer cancel()
// While setting an object if a struct has a Uid then its properties in the
// graph are updated else a new node is created.
// In the example below new nodes for Alice, Bob and Charlie and school
// are created (since they don't have a Uid).
p := Person{
	Uid:     "_:alice",
	Name:    "Alice",
	Age:     26,
	Married: true,
	DType:   []string{"Person"},
	Location: loc{
		Type:   "Point",
		Coords: []float64{1.1, 2},
	},
	Raw: []byte("raw_bytes"),
	Friends: []Person{{
		Name:  "Bob",
		Age:   24,
		DType: []string{"Person"},
	}, {
		Name:  "Charlie",
		Age:   29,
		DType: []string{"Person"},
	}},
	School: []School{{
		Name:  "Crown Public School",
		DType: []string{"Institution"},
	}},
}

op := &api.Operation{}
op.Schema = `
		name: string @index(exact) .
		age: int .
		married: bool .
		Friends: [uid] .
		loc: geo .
		type: string .
		coords: float .

		type Person {
			name
			age
			married
			Friends
			loc
		  }

		type Institution {
			name
		}
	`

ctx := context.Background()
if err := dg.Alter(ctx, op); err != nil {
	log.Fatal(err)
}

mu := &api.Mutation{
	CommitNow: true,
}
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
response, err := dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

// Assigned uids for nodes which were created would be returned in the response.Uids map.
puid := response.Uids["alice"]
const q = `
		query Me($id: string){
			me(func: uid($id)) {
				name
				age
				loc
				raw_bytes
				married
				dgraph.type
				friends @filter(eq(name, "Bob")) {
					name
					age
					dgraph.type
				}
				school {
					name
					dgraph.type
				}
			}
		}
	`

variables := make(map[string]string)
variables["$id"] = puid
resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me []Person `json:"me"`
}

var r Root
err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}

out, _ := json.MarshalIndent(r, "", "\t")
fmt.Printf("%s\n", out)
Output:

{
	"me": [
		{
			"name": "Alice",
			"age": 26,
			"married": true,
			"raw_bytes": "cmF3X2J5dGVz",
			"friends": [
				{
					"name": "Bob",
					"age": 24,
					"loc": {},
					"dgraph.type": [
						"Person"
					]
				}
			],
			"loc": {
				"type": "Point",
				"coordinates": [
					1.1,
					2
				]
			},
			"school": [
				{
					"name": "Crown Public School",
					"dgraph.type": [
						"Institution"
					]
				}
			],
			"dgraph.type": [
				"Person"
			]
		}
	]
}
Example (Bytes)
dg, cancel := getDgraphClient()
defer cancel()
type Person struct {
	Uid   string   `json:"uid,omitempty"`
	Name  string   `json:"name,omitempty"`
	Bytes []byte   `json:"bytes,omitempty"`
	DType []string `json:"dgraph.type,omitempty"`
}

op := &api.Operation{}
op.Schema = `
		name: string @index(exact) .
		bytes: string .

		type Person {
			name
			bytes
		}
	`

ctx := context.Background()
err := dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

p := Person{
	Name:  "Alice-new",
	DType: []string{"Person"},
	Bytes: []byte("raw_bytes"),
}

mu := &api.Mutation{
	CommitNow: true,
}
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
_, err = dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

q := `
		{
			q(func: eq(name, "Alice-new")) {
				name
				bytes
				dgraph.type
			}
		}
	`

resp, err := dg.NewTxn().Query(ctx, q)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me []Person `json:"q"`
}

var r Root
err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Me: %+v\n", r.Me)
Output:

Me: [{Uid: Name:Alice-new Bytes:[114 97 119 95 98 121 116 101 115] DType:[Person]}]
Example (DeleteNode)
dg, cancel := getDgraphClient()
defer cancel()
// In this test we check S * * deletion.
type Person struct {
	Uid     string    `json:"uid,omitempty"`
	Name    string    `json:"name,omitempty"`
	Age     int       `json:"age,omitempty"`
	Married bool      `json:"married,omitempty"`
	Friends []*Person `json:"friends,omitempty"`
	DType   []string  `json:"dgraph.type,omitempty"`
}

p := Person{
	Uid:     "_:alice",
	Name:    "Alice",
	Age:     26,
	Married: true,
	DType:   []string{"Person"},
	Friends: []*Person{
		{
			Uid:   "_:bob",
			Name:  "Bob",
			Age:   24,
			DType: []string{"Person"},
		},
		{
			Uid:   "_:charlie",
			Name:  "Charlie",
			Age:   29,
			DType: []string{"Person"},
		},
	},
}

op := &api.Operation{}
op.Schema = `
		age: int .
		married: bool .
		friends: [uid] .

		type Person {
			name: string
			age: int
			married: bool
			friends: [Person]
		}
	`

ctx := context.Background()
err := dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

mu := &api.Mutation{
	CommitNow: true,
}
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
response, err := dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

alice := response.Uids["alice"]
bob := response.Uids["bob"]
charlie := response.Uids["charlie"]

variables := make(map[string]string)
variables["$alice"] = alice
variables["$bob"] = bob
variables["$charlie"] = charlie
const q = `
		query Me($alice: string, $bob: string, $charlie: string){
			me(func: uid($alice)) {
				name
				age
				married
				dgraph.type
				friends {
					uid
					name
					age
					dgraph.type
				}
			}

			me2(func: uid($bob)) {
				name
				age
				dgraph.type
			}

			me3(func: uid($charlie)) {
				name
				age
				dgraph.type
			}
		}
	`

resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me  []Person `json:"me"`
	Me2 []Person `json:"me2"`
	Me3 []Person `json:"me3"`
}

var r Root
if err := json.Unmarshal(resp.Json, &r); err != nil {
	log.Fatal(err)
}

// Now lets try to delete Alice. This won't delete Bob and Charlie
// but just remove the connection between Alice and them.

// The JSON for deleting a node should be of the form {"uid": "0x123"}.
// If you wanted to delete multiple nodes you could supply an array of objects
// like [{"uid": "0x321"}, {"uid": "0x123"}] to DeleteJson.

d := map[string]string{"uid": alice}
pb, err = json.Marshal(d)
if err != nil {
	log.Fatal(err)
}

mu = &api.Mutation{
	CommitNow:  true,
	DeleteJson: pb,
}

_, err = dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

resp, err = dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}

out, _ := json.MarshalIndent(r, "", "\t")
fmt.Printf("%s\n", out)
Output:

{
	"me": [],
	"me2": [
		{
			"name": "Bob",
			"age": 24,
			"dgraph.type": [
				"Person"
			]
		}
	],
	"me3": [
		{
			"name": "Charlie",
			"age": 29,
			"dgraph.type": [
				"Person"
			]
		}
	]
}
Example (DeletePredicate)
dg, cancel := getDgraphClient()
defer cancel()
type Person struct {
	Uid     string   `json:"uid,omitempty"`
	Name    string   `json:"name,omitempty"`
	Age     int      `json:"age,omitempty"`
	Married bool     `json:"married,omitempty"`
	Friends []Person `json:"friends,omitempty"`
	DType   []string `json:"dgraph.type,omitempty"`
}

p := Person{
	Uid:     "_:alice",
	Name:    "Alice",
	Age:     26,
	Married: true,
	DType:   []string{"Person"},
	Friends: []Person{
		{
			Name:  "Bob",
			Age:   24,
			DType: []string{"Person"},
		},
		{
			Name:  "Charlie",
			Age:   29,
			DType: []string{"Person"},
		},
	},
}

op := &api.Operation{}
op.Schema = `
		name: string .
		age: int .
		married: bool .
		friends: [uid] .

		type Person {
			name: string
			age: int
			married: bool
			friends: [Person]
		}
	`

ctx := context.Background()
err := dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

mu := &api.Mutation{
	CommitNow: true,
}
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
response, err := dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

alice := response.Uids["alice"]

variables := make(map[string]string)
variables["$id"] = alice
const q = `
		query Me($id: string){
			me(func: uid($id)) {
				name
				age
				married
				dgraph.type
				friends {
					uid
					name
					age
					dgraph.type
				}
			}
		}
	`

resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me []Person `json:"me"`
}
var r Root
err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}

op = &api.Operation{DropAttr: "friends"}
err = dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

op = &api.Operation{DropAttr: "married"}
err = dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

// Also lets run the query again to verify that predicate data was deleted.
resp, err = dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

r = Root{}
err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}

// Alice should have no friends and only two attributes now.
fmt.Printf("%+v\n", r)
Output:

{Me:[{Uid: Name:Alice Age:26 Married:false Friends:[] DType:[Person]}]}
Example (Facets)
dg, cancel := getDgraphClient()
defer cancel()
// Doing a dropAll isn't required by the user. We do it here so that
// we can verify that the example runs as expected.
op := api.Operation{DropAll: true}
ctx := context.Background()
if err := dg.Alter(ctx, &op); err != nil {
	log.Fatal(err)
}

op = api.Operation{}
op.Schema = `
		name: string @index(exact) .
		age: int .
		married: bool .
		NameOrigin: string .
		Since: string .
		Family: string .
		Age: bool .
		Close: bool .
		Friends: [uid] .

		type Person {
			name
			age
			married
			NameOrigin
			Since
			Family
			Age
			Close
			Friends
		  }

		type Institution {
			name
			Since
		  }
	`

err := dg.Alter(ctx, &op)
if err != nil {
	log.Fatal(err)
}

// This example shows example for SetObject using facets.
type School struct {
	Name  string    `json:"name,omitempty"`
	Since time.Time `json:"school|since,omitempty"`
	DType []string  `json:"dgraph.type,omitempty"`
}

type Person struct {
	Uid        string   `json:"uid,omitempty"`
	Name       string   `json:"name,omitempty"`
	NameOrigin string   `json:"name|origin,omitempty"`
	Friends    []Person `json:"friends,omitempty"`

	// These are facets on the friend edge.
	Since  *time.Time `json:"friends|since,omitempty"`
	Family string     `json:"friends|family,omitempty"`
	Age    float64    `json:"friends|age,omitempty"`
	Close  bool       `json:"friends|close,omitempty"`

	School []School `json:"school,omitempty"`
	DType  []string `json:"dgraph.type,omitempty"`
}

ti := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
p := Person{
	Uid:        "_:alice",
	Name:       "Alice",
	NameOrigin: "Indonesia",
	DType:      []string{"Person"},
	Friends: []Person{
		{
			Name:   "Bob",
			Since:  &ti,
			Family: "yes",
			Age:    13,
			Close:  true,
			DType:  []string{"Person"},
		},
		{
			Name:   "Charlie",
			Family: "maybe",
			Age:    16,
			DType:  []string{"Person"},
		},
	},
	School: []School{{
		Name:  "Wellington School",
		Since: ti,
		DType: []string{"Institution"},
	}},
}

mu := &api.Mutation{}
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
mu.CommitNow = true
response, err := dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

auid := response.Uids["alice"]
variables := make(map[string]string)
variables["$id"] = auid

const q = `
		query Me($id: string){
			me(func: uid($id)) {
				name @facets
				dgraph.type
				friends @filter(eq(name, "Bob")) @facets {
					name
					dgraph.type
				}
				school @facets {
					name
					dgraph.type
				}

			}
		}
	`

resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me []Person `json:"me"`
}

var r Root
err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}

out, _ := json.MarshalIndent(r.Me, "", "\t")
fmt.Printf("%s\n", out)
Output:

[
	{
		"name": "Alice",
		"name|origin": "Indonesia",
		"friends": [
			{
				"name": "Bob",
				"friends|since": "2009-11-10T23:00:00Z",
				"friends|family": "yes",
				"friends|age": 13,
				"friends|close": true,
				"dgraph.type": [
					"Person"
				]
			}
		],
		"school": [
			{
				"name": "Wellington School",
				"school|since": "2009-11-10T23:00:00Z",
				"dgraph.type": [
					"Institution"
				]
			}
		],
		"dgraph.type": [
			"Person"
		]
	}
]
Example (List)
dg, cancel := getDgraphClient()
defer cancel() // This example shows example for SetObject for predicates with list type.
type Person struct {
	Uid         string   `json:"uid"`
	Address     []string `json:"address"`
	PhoneNumber []int64  `json:"phone_number"`
	DType       []string `json:"dgraph.type,omitempty"`
}

p := Person{
	Uid:         "_:person",
	Address:     []string{"Redfern", "Riley Street"},
	PhoneNumber: []int64{9876, 123},
	DType:       []string{"Person"},
}

op := &api.Operation{}
op.Schema = `
		address: [string] .
		phone_number: [int] .

		type Person {
			Address
			phone_number
		  }
	`

ctx := context.Background()
err := dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

mu := &api.Mutation{}
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
mu.CommitNow = true
response, err := dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

variables := map[string]string{"$id": response.Uids["person"]}
const q = `
		query Me($id: string){
			me(func: uid($id)) {
				address
				phone_number
				dgraph.type
			}
		}
	`

resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me []Person `json:"me"`
}

var r Root
err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}

// List items aren't guaranteed to be in the same order.
fmt.Println(string(resp.Json))
// {"me":[{"address":["Riley Street","Redfern"],"phone_number":[9876,123]}]}
Example (Upsert)
dg, cancel := getDgraphClient()
defer cancel()

ctx, toCancel := context.WithTimeout(context.Background(), 30*time.Second)
defer toCancel()

// Warn: Cleaning up the database
if err := dg.Alter(ctx, &api.Operation{DropAll: true}); err != nil {
	log.Fatal("The drop all operation should have succeeded")
}

op := &api.Operation{}
op.Schema = `
		name: string .
		email: string @index(exact) .`
if err := dg.Alter(ctx, op); err != nil {
	log.Fatal(err)
}

m1 := `
		_:n1 <name> "user" .
		_:n1 <email> "user@dgraphO.io" .
	`
mu := &api.Mutation{
	SetNquads: []byte(m1),
	CommitNow: true,
}
if _, err := dg.NewTxn().Mutate(ctx, mu); err != nil {
	log.Fatal(err)
}

req := &api.Request{CommitNow: true}
req.Query = `
		query {
  			me(func: eq(email, "user@dgraphO.io")) {
	    		v as uid
  			}
		}
	`
m2 := `uid(v) <email> "user@dgraph.io" .`
mu.SetNquads = []byte(m2)
req.Mutations = []*api.Mutation{mu}

// Update email only if matching uid found.
if _, err := dg.NewTxn().Do(ctx, req); err != nil {
	log.Fatal(err)
}

query := `
		{
			me(func: eq(email, "user@dgraph.io")) {
				name
				email
				dgraph.type
			}
		}
	`
resp, err := dg.NewTxn().Query(ctx, query)
if err != nil {
	log.Fatal(err)
}

// resp.Json contains the updated value.
fmt.Println(string(resp.Json))
Output:

{"me":[{"name":"user","email":"user@dgraph.io"}]}
Example (UpsertJSON)
dg, cancel := getDgraphClient()
defer cancel()

// Warn: Cleaning up the database
ctx := context.Background()
if err := dg.Alter(ctx, &api.Operation{DropAll: true}); err != nil {
	log.Fatal(err)
}

type Person struct {
	Uid     string   `json:"uid,omitempty"`
	Name    string   `json:"name,omitempty"`
	Age     int      `json:"age,omitempty"`
	Email   string   `json:"email,omitempty"`
	Friends []Person `json:"friends,omitempty"`
	DType   []string `json:"dgraph.type,omitempty"`
}

op := &api.Operation{Schema: `email: string @index(exact) @upsert .`}
if err := dg.Alter(context.Background(), op); err != nil {
	log.Fatal(err)
}

// Create and query the user using Upsert block
req := &api.Request{CommitNow: true}
req.Query = `
		{
			me(func: eq(email, "user@dgraph.io")) {
				...fragmentA
			}
		}

		fragment fragmentA {
			v as uid
		}
	`
pb, err := json.Marshal(Person{Uid: "uid(v)", Name: "Wrong", Email: "user@dgraph.io"})
if err != nil {
	log.Fatal(err)
}
mu := &api.Mutation{SetJson: pb}
req.Mutations = []*api.Mutation{mu}
if _, err := dg.NewTxn().Do(ctx, req); err != nil {
	log.Fatal(err)
}

// Fix the name and add age
pb, err = json.Marshal(Person{Uid: "uid(v)", Name: "user", Age: 35})
if err != nil {
	log.Fatal(err)
}
mu.SetJson = pb
req.Mutations = []*api.Mutation{mu}
if _, err := dg.NewTxn().Do(ctx, req); err != nil {
	log.Fatal(err)
}

q := `
  		{
			Me(func: has(email)) {
				age
				name
				email
				dgraph.type
			}
		}
	`
resp, err := dg.NewReadOnlyTxn().Query(ctx, q)
if err != nil {
	log.Fatal("The query should have succeeded")
}

type Root struct {
	Me []Person `json:"me"`
}
var r Root
if err := json.Unmarshal(resp.Json, &r); err != nil {
	log.Fatal(err)
}
fmt.Println(string(resp.Json))

// Delete the user now
mu.SetJson = nil
dgo.DeleteEdges(mu, "uid(v)", "age", "name", "email")
req.Mutations = []*api.Mutation{mu}
if _, err := dg.NewTxn().Do(ctx, req); err != nil {
	log.Fatal(err)
}

resp, err = dg.NewReadOnlyTxn().Query(ctx, q)
if err != nil {
	log.Fatal("The query should have succeeded")
}
if err := json.Unmarshal(resp.Json, &r); err != nil {
	log.Fatal(err)
}

fmt.Println(string(resp.Json))
Output:

{"Me":[{"age":35,"name":"user","email":"user@dgraph.io"}]}
{"Me":[]}

func (*Txn) Query

func (txn *Txn) Query(ctx context.Context, q string) (*api.Response, error)

Query sends a query to one of the connected Dgraph instances. If no mutations need to be made in the same transaction, it's convenient to chain the method, e.g. NewTxn().Query(ctx, "...").

Example (Besteffort)
dg, cancel := getDgraphClient()
defer cancel()

// NOTE: Best effort only works with read-only queries.
txn := dg.NewReadOnlyTxn().BestEffort()
resp, err := txn.Query(context.Background(), `{ q(func: uid(0x1)) { uid } }`)
if err != nil {
	log.Fatal(err)
}

fmt.Println(string(resp.Json))
Output:

{"q":[{"uid":"0x1"}]}
Example (Unmarshal)
type School struct {
	Name  string   `json:"name,omitempty"`
	DType []string `json:"dgraph.type,omitempty"`
}

type Person struct {
	Uid     string   `json:"uid,omitempty"`
	Name    string   `json:"name,omitempty"`
	Age     int      `json:"age,omitempty"`
	Married bool     `json:"married,omitempty"`
	Raw     []byte   `json:"raw_bytes,omitempty"`
	Friends []Person `json:"friends,omitempty"`
	School  []School `json:"school,omitempty"`
	DType   []string `json:"dgraph.type,omitempty"`
}

dg, cancel := getDgraphClient()
defer cancel()
op := &api.Operation{}
op.Schema = `
		name: string @index(exact) .
		age: int .
		married: bool .
		Friends: [uid] .

		type Person {
			name
			age
			married
			Friends
		}

		type Institution {
			name
		}
	`

ctx := context.Background()
err := dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

p := Person{
	Uid:   "_:bob",
	Name:  "Bob",
	Age:   24,
	DType: []string{"Person"},
}

txn := dg.NewTxn()
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu := &api.Mutation{
	CommitNow: true,
	SetJson:   pb,
}
response, err := txn.Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}
bob := response.Uids["bob"]

// While setting an object if a struct has a Uid then its properties
// in the graph are updated else a new node is created.
// In the example below new nodes for Alice and Charlie and school are created
// (since they dont have a Uid).  Alice is also connected via the friend edge
// to an existing node Bob.
p = Person{
	Uid:     "_:alice",
	Name:    "Alice",
	Age:     26,
	Married: true,
	DType:   []string{"Person"},
	Raw:     []byte("raw_bytes"),
	Friends: []Person{{
		Uid: bob,
	}, {
		Name:  "Charlie",
		Age:   29,
		DType: []string{"Person"},
	}},
	School: []School{{
		Name:  "Crown Public School",
		DType: []string{"Institution"},
	}},
}

txn = dg.NewTxn()
mu = &api.Mutation{}
pb, err = json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
mu.CommitNow = true
response, err = txn.Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

// Assigned uids for nodes which were created would be returned in the response.Uids map.
puid := response.Uids["alice"]
variables := make(map[string]string)
variables["$id"] = puid
const q = `
		query Me($id: string){
			me(func: uid($id)) {
				name
				age
				loc
				raw_bytes
				married
				dgraph.type
				friends @filter(eq(name, "Bob")) {
					name
					age
					dgraph.type
				}
				school {
					name
					dgraph.type
				}
			}
		}
	`

resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me []Person `json:"me"`
}

var r Root
err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}

out, _ := json.MarshalIndent(r, "", "\t")
fmt.Printf("%s\n", out)
Output:

{
	"me": [
		{
			"name": "Alice",
			"age": 26,
			"married": true,
			"raw_bytes": "cmF3X2J5dGVz",
			"friends": [
				{
					"name": "Bob",
					"age": 24,
					"dgraph.type": [
						"Person"
					]
				}
			],
			"school": [
				{
					"name": "Crown Public School",
					"dgraph.type": [
						"Institution"
					]
				}
			],
			"dgraph.type": [
				"Person"
			]
		}
	]
}
Example (Variables)
dg, cancel := getDgraphClient()
defer cancel()
type Person struct {
	Uid   string   `json:"uid,omitempty"`
	Name  string   `json:"name,omitempty"`
	DType []string `json:"dgraph.type,omitempty"`
}

op := &api.Operation{}
op.Schema = `
		name: string @index(exact) .

		type Person {
			name
		}
	`

ctx := context.Background()
err := dg.Alter(ctx, op)
if err != nil {
	log.Fatal(err)
}

p := Person{
	Name:  "Alice",
	DType: []string{"Person"},
}

mu := &api.Mutation{
	CommitNow: true,
}
pb, err := json.Marshal(p)
if err != nil {
	log.Fatal(err)
}

mu.SetJson = pb
_, err = dg.NewTxn().Mutate(ctx, mu)
if err != nil {
	log.Fatal(err)
}

variables := make(map[string]string)
variables["$a"] = "Alice"
q := `
		query Alice($a: string){
			me(func: eq(name, $a)) {
				name
				dgraph.type
			}
		}
	`

resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
if err != nil {
	log.Fatal(err)
}

type Root struct {
	Me []Person `json:"me"`
}

var r Root
err = json.Unmarshal(resp.Json, &r)
if err != nil {
	log.Fatal(err)
}

fmt.Println(string(resp.Json))
Output:

{"me":[{"name":"Alice","dgraph.type":["Person"]}]}

func (*Txn) QueryRDF

func (txn *Txn) QueryRDF(ctx context.Context, q string) (*api.Response, error)

QueryRDF sends a query to one of the connected Dgraph instances and returns RDF response. If no mutations need to be made in the same transaction, it's convenient to chain the method, e.g. NewTxn().QueryRDF(ctx, "...").

func (*Txn) QueryRDFWithVars

func (txn *Txn) QueryRDFWithVars(ctx context.Context, q string, vars map[string]string) (
	*api.Response, error)

QueryRDFWithVars is like Query and returns RDF, but allows a variable map to be used. This can provide safety against injection attacks.

func (*Txn) QueryWithVars

func (txn *Txn) QueryWithVars(ctx context.Context, q string, vars map[string]string) (
	*api.Response, error)

QueryWithVars is like Query, but allows a variable map to be used. This can provide safety against injection attacks.

type TxnOption

type TxnOption func(*txnOptions) error

TxnOption is a function that modifies the txn options.

func WithBestEffort

func WithBestEffort() TxnOption

WithBestEffort sets the txn to be best effort.

func WithReadOnly

func WithReadOnly() TxnOption

WithReadOnly sets the txn to be read-only.

func WithResponseFormat

func WithResponseFormat(respFormat api.Request_RespFormat) TxnOption

WithResponseFormat sets the response format for queries. By default, the response format is JSON. We can also specify RDF format.

Directories

Path Synopsis
protos
api

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL