Skip to content

diegogub/aranGO

Repository files navigation

aranGO

go get github.com/diegogub/aranGO

Golang driver for ArangoDB.

Here are the things you can do until now:

  • Databases : create
  • Collections : drop, create, list, truncate
  • Documents : save, replace,patch, query (simple query,AQL,Transactions)
  • Edges : Relate documents, save, patch, replace
  • Execute transactions
  • Execute AQL
  • Replication config

Additional Features

Any ideas for the driver or bug fixes please feel free to create a issue or pull-request to dev :)

Documentation

https://gowalker.org/github.com/diegogub/aranGO

Basic Usage

import ara "github.com/diegogub/aranGO"

type DocTest struct {
  ara.Document // Must include arango Document in every struct you want to save id, key, rev after saving it
  Name     string
  Age      int
  Likes    []string
}

Connect and create collections

    //change false to true if you want to see every http request
    //Connect(host, user, password string, log bool) (*Session, error) {
    s,err := ara.Connect("http://localhost:8529","diego","test",false) 
    if err != nil{
        panic(err)
    }

    // CreateDB(name string,users []User) error
    s.CreateDB("test",nil)

    // create Collections test if exist
    if !s.DB("test").ColExist("docs1"){
        // CollectionOptions has much more options, here we just define name , sync
        docs1 := NewCollectionOptions("docs1",true)
        s.DB("test").CreateCollection(docs1)
    }

    if !s.DB("test").ColExist("docs2"){
        docs2 := NewCollectionOptions("docs2",true)
        s.DB("test").CreateCollection(docs2)
    }

    if !s.DB("test").ColExist("ed"){
        edges := NewCollectionOptions("ed",true)
        edges.IsEdge() // set to Edge
        s.DB("test").CreateCollection(edges)
    }

Create and Relate documents

  var d1,d2 DocTest
  d1.Name = "Diego"
  d1.Age = 22
  d1.Likes = []string { "arangodb", "golang", "linux" }
  
  d2.Name = "Facundo"
  d2.Age = 25
  d2.Likes = []string { "php", "linux", "python" }


  err =s.DB("test").Col("docs1").Save(&d1)
  err =s.DB("test").Col("docs1").Save(&d2)
  if err != nil {
    panic(err)
  }

  // could also check error in document
  /*
  if d1.Error {
    panic(d1.Message)
  }
  */

  // update document
  d1.Age = 23
  err =s.DB("test").Col("docs1").Replace(d1.Key,d1)
  if err != nil {
    panic(err)
  }
  
  // Relate documents
  s.DB("test").Col("ed").Relate(d1.Id,d2.Id,map[string]interface{}{ "is" : "friend" })

AQL

// query query 
  q := ara.NewQuery("FOR i in docs1 RETURN i")
  c ,err:=s.DB("test").Execute(q)
  if err != nil {
    panic(err)
  }
  var doc DocTest

  for c.FetchOne(&doc){
    log.Println(doc)
  }

Transactions

// saving document with transaction
func TranSave(db *ara.Database,doc interface{},col string,counter string) (*ara.Transaction,error){
  if  col == "" || counter == ""{
    return nil,errors.New("Collection or counter must not be nil")
  }

  write := []string { col }
  q := `function(params){
                var db = require('internal').db;
                try {
                  var c = db.`+col+`.document('c');
                }catch(error){
                  var tmp = db.`+col+`.save( { '_key' : 'c' , '`+counter+`' : 0 });
                }
                var c = db.`+col+`.document('c');
                var co = c.`+counter+` || 0;
                co = co + 1 ;
                // update counter
                db.`+col+`.update(c, { '`+counter+`' : co }) ;
                params.doc.s = -1 * co ;
                params.doc.created = new Date().toISOString();
                var res = db.`+col+`.save(params.doc) ;
                return res._key
        }
  `
  t := ara.NewTransaction(q,write,nil)
  t.Params = map[string]interface{}{ "doc" : doc }

  err := t.Execute(db)

  return t,err
}

Models

To be a model, any struct must implement Modeler Interface.

type Modeler interface {
    // Returns current model key
    GetKey() string
    // Returns collection where I should save the model
    GetCollection() string
    // Error
    GetError() (string, bool)
}

Implement Modeler and add tags to struct..

type DocTest struct {
  ara.Document // Must include arango Document in every struct you want to save id, key, rev after saving it
// required tag for strings.
  Name     string `required:"-"`
// unique tag validate within collection users, if username is unique
  Username string `unique:"users"`
// enum tag checks string value
  Type     string `enum:"A,M,S"`
// Next release I will be implementing some other tags to validate int
and arrays
  Age      int
  Likes    []string
}

func (d *DocTest) GetKey() string{
  return d.Key
}

func (d *DocTest) GetCollection() string {
  return "testcollection"
}

func (d *DocTest) GetError()(string,error){
    // default error bool and messages. Could be any kind of error
    return d.Message,d.Error
}

// pass ArangoDB database as context
ctx, err :=  NewContext(db)

// save model, returns map of errors or empty map
e := ctx.Save(d1)

// check errors, also Error is saved in Context struct
if len(e) > 1 {
  panic(e)
}

// get other document
d2.Key = "d2key"
ctx.Get(d2)
log.Println(d2)

We can implement hooks to execute when saving,updating or deleting model..

// execute before saving
func (d *DocTest) PreSave(c *ara.Context) {
   var e error
  // Any extra validation
  // ......
  // ......
  if e != nil {
    // errors should be set into context struct
    c.Err["presave"] = "failed to validate doctest"
  }

  return
}