a8m / documentdb

Go driver for Microsoft Azure DocumentDB
MIT License
33 stars 25 forks source link

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.