/documentdb

Go driver for Microsoft Azure DocumentDB

Primary LanguageGoMIT LicenseMIT

DocumentDB Go Build status

Go driver for Microsoft Azure DocumentDB

Table of contents:

Get Started

Installation

$ go get github.com/a8m/documentdb

Add to your project

import (
	"github.com/a8m/documentdb"
)

func main() {
	config := documentdb.NewConfig(&documentdb.Key{
		Key: "master-key",
	})
	client := documentdb.New("connection-url", config)

	// Start using DocumentDB
	dbs, err := client.ReadDatabases()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(dbs)
}

Databases

ReadDatabase

func main() {
	// ...
	db, err := client.ReadDatabase("self_link")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(db.Self, db.Id)
}

QueryDatabases

func main() {
	// ...
	dbs, err := client.QueryDatabases("SELECT * FROM ROOT r")
	if err != nil {
		log.Fatal(err)
	}
	for _, db := range dbs {
		fmt.Println("DB Name:", db.Id)
	}
}

ReadDatabases

func main() {
	// ...
	dbs, err := client.ReadDatabases()
	if err != nil {
		log.Fatal(err)
	}
	for _, db := range dbs {
		fmt.Println("DB Name:", db.Id)
	}
}

CreateDatabase

func main() {
	// ...
	db, err := client.CreateDatabase(`{ "id": "test" }`)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(db)

	// or ...
	var db documentdb.Database
	db.Id = "test"
	db, err = client.CreateDatabase(&db)
}

ReplaceDatabase

func main() {
	// ...
	db, err := client.ReplaceDatabase("self_link", `{ "id": "test" }`)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(db)

	// or ...
	var db documentdb.Database
	db, err = client.ReplaceDatabase("self_link", &db)
}

DeleteDatabase

func main() {
	// ...
	err := client.DeleteDatabase("self_link")
	if err != nil {
		log.Fatal(err)
	}
}

Collections

ReadCollection

func main() {
	// ...
	coll, err := client.ReadCollection("self_link")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(coll.Self, coll.Id)
}

QueryCollections

func main() {
	// ...
	colls, err := client.QueryCollections("db_self_link", "SELECT * FROM ROOT r")
	if err != nil {
		log.Fatal(err)
	}
	for _, coll := range colls {
		fmt.Println("Collection Name:", coll.Id)
	}
}

ReadCollections

func main() {
	// ...
	colls, err := client.ReadCollections("db_self_link")
	if err != nil {
		log.Fatal(err)
	}
	for _, coll := range colls {
		fmt.Println("Collection Name:", coll.Id)
	}
}

CreateCollection

func main() {
	// ...
	coll, err := client.CreateCollection("db_self_link", `{"id": "my_test"}`)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Collection Name:", coll.Id)

	// or ...
	var coll documentdb.Collection
	coll.Id = "test"
	coll, err = client.CreateCollection("db_self_link", &coll)
}

DeleteCollection

func main() {
	// ...
	err := client.DeleteCollection("self_link")
	if err != nil {
		log.Fatal(err)
	}
}

Documents

ReadDocument

type Document struct {
	documentdb.Document
	// Your external fields
	Name    string `json:"name,omitempty"`
	Email   string `json:"email,omitempty"`
}

func main() {
	// ...
	var doc Document
	err = client.ReadDocument("self_link", &doc)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Document Name:", doc.Name)
}

QueryDocuments

type User struct {
	documentdb.Document
	// Your external fields
	Name    string `json:"name,omitempty"`
	Email   string `json:"email,omitempty"`
}

func main() {
	// ...
	var users []User
	_, err = client.QueryDocuments(
        "coll_self_link", 
        documentdb.NewQuery("SELECT * FROM ROOT r WHERE r.name=@name", documentdb.P{"@name", "john"}),
        &users,
    )
	if err != nil {
		log.Fatal(err)
	}
	for _, user := range users {
		fmt.Print("Name:", user.Name, "Email:", user.Email)
	}
}

QueryDocuments with partition key

type User struct {
	documentdb.Document
	// Your external fields
	Name    string `json:"name,omitempty"`
	Email   string `json:"email,omitempty"`
}

func main() {
	// ...
	var users []User
	_, err = client.QueryDocuments(
        "coll_self_link", 
		documentdb.NewQuery(
			"SELECT * FROM ROOT r WHERE r.name=@name AND r.company_id = @company_id", 
			documentdb.P{"@name", "john"}, 
			documentdb.P{"@company_id", "1234"},
		),
		&users,
		documentdb.PartitionKey("1234")
    )
	if err != nil {
		log.Fatal(err)
	}
	for _, user := range users {
		fmt.Print("Name:", user.Name, "Email:", user.Email)
	}
}

ReadDocuments

type User struct {
	documentdb.Document
	// Your external fields
	Name    string `json:"name,omitempty"`
	Email   string `json:"email,omitempty"`
}

func main() {
	// ...
	var users []User
	err = client.ReadDocuments("coll_self_link", &users)
	if err != nil {
		log.Fatal(err)
	}
	for _, user := range users {
		fmt.Print("Name:", user.Name, "Email:", user.Email)
	}
}

CreateDocument

type User struct {
	documentdb.Document
	// Your external fields
	Name    string `json:"name,omitempty"`
	Email   string `json:"email,omitempty"`
}

func main() {
	// ...
	var user User
	// Note: If the `id` is missing(or empty) in the payload it will generate
	// random document id(i.e: uuid4)
	user.Id = "uuid"
	user.Name = "Ariel"
	user.Email = "ariel@test.com"
	err := client.CreateDocument("coll_self_link", &doc)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Print("Name:", user.Name, "Email:", user.Email)
}

ReplaceDocument

type User struct {
	documentdb.Document
	// Your external fields
	IsAdmin bool   `json:"isAdmin,omitempty"`
}

func main() {
	// ...
	var user User
	user.Id = "uuid"
	user.IsAdmin = false
	err := client.ReplaceDocument("doc_self_link", &user)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Print("Is Admin:", user.IsAdmin)
}

DeleteDocument

func main() {
	// ...
	err := client.DeleteDocument("doc_self_link")
	if err != nil {
		log.Fatal(err)
	}
}

ExecuteStoredProcedure

func main() {
	// ...
	var docs []Document
	err := client.ExecuteStoredProcedure("sporc_self", [...]interface{}{p1, p2}, &docs)
	if err != nil {
		log.Fatal(err)
	}
	// ...
}

Iterator

DocumentIterator

func main() {
	// ...
	var docs []Document

	iterator := documentdb.NewIterator(
		client, documentdb.NewDocumentIterator("coll_self_link", nil, &docs, documentdb.PartitionKey("1"), documentdb.Limit(1)),
	)

	for iterator.Next() {
		if err := iterator.Error(); err != nil {
			log.Fatal(err)
		}
		fmt.Println(len(docs))
	}    

	// ...
}

Authentication with Azure AD

You can authenticate with Cosmos DB using Azure AD and a service principal, including full RBAC support. To configure Cosmos DB to use Azure AD, take a look at the Cosmos DB documentation.

To use this library with a service principal:

import (
	"github.com/Azure/go-autorest/autorest/adal"
	"github.com/a8m/documentdb"
)

func main() {
	// Azure AD application (service principal) client credentials
	tenantId := "tenant-id"
	clientId := "client-id"
	clientSecret := "client-secret"

	// Azure AD endpoint may be different for sovereign clouds
	oauthConfig, err := adal.NewOAuthConfig("https://login.microsoftonline.com/", tenantId)
	if err != nil {
		log.Fatal(err)
	}
	spt, err := adal.NewServicePrincipalToken(*oauthConfig, clientId, clientSecret, "https://cosmos.azure.com") // Always "https://cosmos.azure.com"
	if err != nil {
		log.Fatal(err)
	}

	config := documentdb.NewConfigWithServicePrincipal(spt)
	client := documentdb.New("connection-url", config)
}

Examples

License

Distributed under the MIT license, which is available in the file LICENSE.