SkillAgentSearch skills...

Dgman

Dgraph schema manager, with mutate and query helpers

Install / Use

/learn @dolan-in/Dgman
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Build Status Codecov Go Reference

Dgman is a schema manager for Dgraph using the Go Dgraph client (dgo), which manages Dgraph types, schema, and indexes from Go tags in struct definitions, allowing ORM-like convenience for developing Dgraph clients in Go.

Features

  • Create types (Dgraph v24.1+), schemas, and indexes from struct tags.
  • Detect conflicts from existing schema and defined schema.
  • Mutate Helpers (Mutate, MutateOrGet, Upsert).
  • Autoinject node type from struct.
  • Field unique checking (e.g: emails, username).
  • Query helpers.
  • Delete helpers (Delete n-quads generator, Delete Query, Delete Node, Delete Edge).

Roadmap

  • Support for Dgraph v25's new namespace mechanism and other dgo v25 features.

Table of Contents

Installation

Using go modules:

go get -u github.com/dolan-in/dgman/v2

Usage

import(
	"github.com/dolan-in/dgman/v2"
)

Schema Definition

Schemas are defined using Go structs which defines the predicate name from the json tag, indices and directives using the dgraph tag. To define a dgraph node struct, json fields uid and dgraph.type is required.

Node Types

Node types will be inferred from the struct name.

If you need to define a custom name for the node type, you can define it on the dgraph tag on the dgraph.type field.

type CustomNodeType struct {
	UID 	string 		`json:"uid,omitempty"`
	Name 	string 		`json:"name,omitempty"`
	DType	[]string 	`json:"dgraph.type" dgraph:"MyNodeType"`
}

CreateSchema

Using the CreateSchema function, it will install the schema, and detect schema and index conflicts within the passed structs and with the currently existing schema in the specified Dgraph database.

// User is a node, nodes have a uid and a dgraph.type json field
type User struct {
	UID           string     `json:"uid,omitempty"`
	Name          string     `json:"name,omitempty" dgraph:"index=term"`         // use term index
	Username      string     `json:"username,omitempty" dgraph:"index=hash"`     // use hash index
	Email         string     `json:"email,omitempty" dgraph:"index=hash upsert"` // use hash index, use upsert directive
	Password      string     `json:"password,omitempty" dgraph:"type=password"` // password type
	Height        *int       `json:"height,omitempty"`
	Description   string     `json:"description" dgraph:"lang"` // multi language support on predicate
	DescriptionEn string     `json:"description@en"`            // will not be parsed as schema
	Dob           *time.Time `json:"dob,omitempty"`             // will be inferred as dateTime schema type
	Status        EnumType   `json:"status,omitempty" dgraph="type=int"`
	Created       time.Time  `json:"created,omitempty" dgraph:"index=day"`     // will be inferred as dateTime schema type, with day index
	Mobiles       []string   `json:"mobiles,omitempty"`                        // will be inferred as using the  [string] schema type, slices with primitive types will all be inferred as lists
	Schools       []School   `json:"schools,omitempty" dgraph:"count reverse"` // defines an edge to other nodes, add count index, add reverse edges
	DType         []string   `json:"dgraph.type,omitempty"`
}

// School is another node, that will be connected to User node using the schools predicate
type School struct {
	UID      string 	`json:"uid,omitempty"`
	Name     string 	`json:"name,omitempty"`
	Location *GeoLoc 	`json:"location,omitempty" dgraph:"type=geo"` // for geo schema type, need to specify explicitly
	DType    []string   `json:"dgraph.type,omitempty"`
}

type GeoLoc struct {
	Type  string    `json:"type"`
	Coord []float64 `json:"coordinates"`
}

func main() {
	d, err := grpc.Dial("localhost:9080", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}

	c := dgo.NewDgraphClient(api.NewDgraphClient(d))

	// create the schema, 
	// it will only install non-existing schema in the specified database
	schema, err := dgman.CreateSchema(c, &User{})
	if err != nil {
		panic(err)
	}
	// Check the generated schema
	fmt.Println(schema)
}

On an empty database, the above code will return the generated type and schema string used to create the schema, logging the conflicting schemas in the process:

2018/12/14 02:23:48 conflicting schema name, already defined as "name: string @index(term) .", trying to define "name: string ."
status: int .
mobiles: [string] .
email: string @index(hash) @upsert .
password: string .
height: int .
dob: datetime .
schools: [uid] @count @reverse .
name: string @index(term) .
username: string @index(hash) .
created: datetime @index(day) .
location: geo .

type School {
        location
        name
}
type User {
        status
        created
        username
        password
        height
        dob
        name
        email
        mobiles
        schools
}

When schema conflicts is detected with the existing schema already installed in the database, it will only log the differences. You would need to manually correct the conflicts by dropping or updating the schema manually.

This may be useful to prevent unnecessary or unwanted re-indexing of your data.

MutateSchema

To overwrite/update index definitions, you can use the MutateSchema function, which will update the schema indexes.

	// update the schema indexes
	schema, err := dgman.MutateSchema(c, &User{})
	if err != nil {
		panic(err)
	}
	// Check the generated schema
	fmt.Println(schema)

Mutate Helpers

Mutate

Using the Mutate function, before sending a mutation, it will marshal a struct into JSON, injecting the Dgraph node type ("dgraph.type" predicate), and do unique checking on the specified fields.

If you need unique checking for a particular field of a node with a certain node type, e.g: Email of users, you can add unique in the dgraph tag on the struct definition.


type User struct {
	UID 			string 		`json:"uid,omitempty"`
	Name 			string 		`json:"name,omitempty" dgraph:"index=term"`
	Email 			string 		`json:"email,omitempty" dgraph:"index=hash unique"`
	Username 		string 		`json:"username,omitempty" dgraph:"index=term unique"`
	DType			[]string	`json:"dgraph.type"`
}
...

	user := User{
		Name: "Alexander",
		Email: "alexander@gmail.com",
		Username: "alex123",
	}

	// Create a transaction with context.Background() as the context
	// can be shorthened to dgman.NewTxn(c)
	tx := dgman.NewTxnContext(context.Background(), c).
		SetCommitNow() // set transaction to CommitNow: true, which will autocommit, leaving the transaction to only can be used once

	uids, err := tx.Mutate(&user)
	if err != nil {
		panic(err)
	}

	// UID will be set
	fmt.Println(user.UID)
	// list of created UIDs
	fmt.Println(uids)

	// try to create user with a duplicate email
	duplicateEmail := User{
		Name: "Alexander",
		Email: "alexander@gmail.com",
		Username: "alexa",
	}

	// will return a dgman.UniqueError
	tx = dgman.NewTxn(c)
	_, err = tx.Mutate(&duplicateEmail)
	if err != nil {
		if uniqueErr, ok := err.(*dgman.UniqueError); ok {
			// check the duplicate field
			fmt.Println(uniqueErr.Field, uniqueErr.Value)
		}
	}

The above mutation will result in the following json, with dgraph.type automatically injected:

{"name":"Alexander","email":"alexander@gmail.com","username":"alex123","dgraph.type":["User"]}
Updating a Node

If you want to update an existing node, just set the UID on the struct node data being passed to Mutate. It will also do unique checking on predicates set to be unique.

type User struct {
	UID 			string 		`json:"uid,omitempty"`
	Name 			string 		`json:"name,omitempty"`
	Email 			string 		`json:"email,omitempty" dgraph:"index=hash unique"`
	Username 		string 		`json:"username,omitempty" dgraph:"index=term unique"`
	Dob				time.Time	`json:"dob" dgraph:"index=day"`
	DType			[]string	`json:"dgraph.type"`
}

...

	users := []*User{
		{
			Name: "Alexander",
			Email: "alexander@gmail.com",
			Username: "alex123",
		},
		{
			Name: "Fergusso",
			Email: "fergusso@gmail.com",
			Username: "fergusso123",
		},
	}

	tx := dgman.NewTxn(c).SetCommitNow()
	_, err := tx.Mutate(&users)
	if err != nil {
		panic(err)
	}
	
	// try to update the user with existing username
	alexander := users[0]
	alexander.Username = "fergusso123"
	// UID should have a value
	fmt.Println(alexander.UID)

	// will return a dgman.UniqueError
	tx := dgman.NewTxn(c).SetCommitNow()
	_, err = tx.Mutate(&alexander)
	if err != nil {
		if uniqueErr, ok := err.(*dgman.UniqueError); ok {
			// will return duplicate error for username
			fmt.Println(u

Related Skills

View on GitHub
GitHub Stars65
CategoryDevelopment
Updated1mo ago
Forks15

Languages

Go

Security Score

100/100

Audited on Feb 19, 2026

No findings