arangolite

package module
v0.0.0-...-37702a8 Latest Latest
Warning

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

Go to latest
Published: Mar 15, 2017 License: MIT Imports: 15 Imported by: 0

README

Arangolite Build Status Coverage Status Code Climate

Arangolite is a lightweight ArangoDB driver for Go.

It focuses entirely on pure AQL querying. See AranGO for a more ORM-like experience.

Arangolite also features a LoopBack heavily inspired filtering system, in a separated package so you don't need to import it if you don't use it.

Installation

To install Arangolite:

go get github.com/solher/arangolite

Basic Usage

package main

import (
  "encoding/json"
  "fmt"

  "github.com/solher/arangolite"
)

type Node struct {
  arangolite.Document
}

func main() {
  db := arangolite.New().
    LoggerOptions(false, false, false).
    Connect("http://localhost:8000", "_system", "root", "rootPassword")

  _, _ = db.Run(&arangolite.CreateDatabase{
		Name: "testDB",
		Users: []map[string]interface{}{
			{"username": "root", "passwd": "rootPassword"},
			{"username": "user", "passwd": "password"},
		},
	})

  db.SwitchDatabase("testDB").SwitchUser("user", "password")

  _, _ = db.Run(&arangolite.CreateCollection{Name: "nodes"})

  key := "48765564346"

  q := arangolite.NewQuery(`
    FOR n
    IN nodes
    FILTER n._key == %s
    RETURN n
  `, key).Cache(true).BatchSize(500) // The caching feature is unavailable prior to ArangoDB 2.7

  // The Run method returns all the query results of every batches
  // available in the cursor as a slice of byte.
  r, _ := db.Run(q)

  nodes := []Node{}
  json.Unmarshal(r, &nodes)

  // The RunAsync method returns a Result struct allowing to handle batches as they
  // are retrieved from the database.
  async, _ := db.RunAsync(q)

  nodes = []Node{}
  decoder := json.NewDecoder(async.Buffer())

  for async.HasMore() {
    batch := []Node{}
    decoder.Decode(&batch)
    nodes = append(nodes, batch...)
  }

  fmt.Printf("%v", nodes)
}

// OUTPUT EXAMPLE:
// [
//   {
//     "_id": "nodes/48765564346",
//     "_rev": "48765564346",
//     "_key": "48765564346"
//   }
// ]

Document and Edge

// Document represents a basic ArangoDB document
// Fields are pointers to allow null values in ArangoDB
type Document struct {
  ID  *string `json:"_id,omitempty"`
  Rev *string `json:"_rev,omitempty"`
  Key *string `json:"_key,omitempty"`
}

// Edge represents a basic ArangoDB edge
// Fields are pointers to allow null values in ArangoDB
type Edge struct {
  Document
  From *string `json:"_from,omitempty"`
  To   *string `json:"_to,omitempty"`
}

Transactions

Overview

Arangolite provides an abstraction layer to the Javascript ArangoDB transactions.

The only limitation is that no Javascript processing can be manually added inside the transaction. The queries can only be connected in a raw way, using the Go templating conventions.

Usage
func main() {
  db := arangolite.New()
  db.Connect("http://localhost:8000", "testDB", "user", "password")

  t := arangolite.NewTransaction([]string{"nodes"}, nil).
  AddQuery("nodes", `
    FOR n
    IN nodes
    RETURN n
  `).AddQuery("ids", `
    FOR n
    IN {{.nodes}}
    RETURN n._id
  `).Return("ids")

  r, _ := db.Run(t)

  ids := []string{}
  json.Unmarshal(r, &ids)

  fmt.Printf("%v", ids)
}

Graphs

Overview

AQL may be used for querying graph data. But to manage graphs, aroangolite offers a few specific requests:

  • CreateGraph to create a graph
  • ListGraphs to list available graphs
  • GetGraph to get an existing graph
  • DropGraph to delete a graph
Usage
  db.Run(&arangolite.CreateCollection{Name: "CollectionName"})
  db.Run(&arangolite.CreateCollection{Name: "RelationshipCollectionName", Type: 3})

  // check graph existence
  _, err := db.Run(&arangolite.GetGraph{Name: "GraphName"})

  // if graph does not exist, create a new one
  if err != nil {
    from := make([]string, 1)
    from[0] = "FirstCollectionName"
    to := make([]string, 1)
    to[0] = "SecondCollectionName"

    edgeDefinition := arangolite.EdgeDefinition{Collection: "EdgeCollectionName", From: from, To: to}
    edgeDefinitions := make([]arangolite.EdgeDefinition, 1)
    edgeDefinitions[0] = edgeDefinition
    db.Run(&arangolite.CreateGraph{Name: "GraphName", EdgeDefinitions: edgeDefinitions})
  }

  // grab the graph
  graphBytes, _ := config.DB().Run(&arangolite.GetGraph{Name: "GraphName"})
  graph := &arangolite.GraphData{}
  json.Unmarshal(graphBytes, &graph)
  fmt.Printf("Graph: %+v", graph)

  // list existing graphs
  listBytes, _ :=  db.Run(&arangolite.ListGraphs{})
  list := &arangolite.GraphList{}
  json.Unmarshal(listBytes, &list)
  fmt.Printf("Graph list: %+v", list)

  // destroy the graph we just created, and the related collections
  db.Run(&arangolite.DropGraph{Name: "GraphName", DropCollections: true})

Filters

Overview

In a similar way than in LoopBack, the filtering system is API client oriented.

Its goal is to provide an easy way of converting JSON filters passed through query strings into an actual AQL query:

// Filter defines a way of filtering AQL queries.
type Filter struct {
  Offset  int                      `json:"offset"`
  Limit   int                      `json:"limit"`
  Sort    []string                 `json:"sort"`
  Where   []map[string]interface{} `json:"where"`
  Options []string                 `json:"options"`
}
Options Field

The Options field implementation is left to the developer. It is not translated into AQL during the filtering.

Its main goal is to allow a filtering similar to the Include one in traditional ORMs, as a relation can be a join or a edge in ArangoDB.

Of course, the Options field can also be used as a more generic option selector (e.g., Options: "Basic" to only return the basic info about a resource).

Translation example

JSON:

{
  "offset": 1,
  "limit": 2,
  "sort": ["age desc", "money"],
  "where": [
    {"firstName": "Pierre"},
    {
      "or": [
        {"birthPlace": ["Paris", "Los Angeles"]},
        {"age": {"gte": 18}}
      ]
    },
    {
      "like": {
        "text": "lastName",
        "search": "R%",
        "case_insensitive": true
      }
    }
  ]
  },
  "options": ["details"]
}

AQL:

LIMIT 1, 2
SORT var.age DESC, var.money ASC
FILTER var.firstName == 'Pierre' && (var.birthPlace IN ['Paris', 'Los Angeles'] || var.age >= 18) && LIKE(var.lastName, 'R%', true)
Operators
  • and: Logical AND operator.
  • or: Logical OR operator.
  • not: Logical NOT operator.
  • gt, gte: Numerical greater than (>); greater than or equal (>=).
  • lt, lte: Numerical less than (<); less than or equal (<=).
  • eq, neq: Equal (==); non equal (!=).
  • like: LIKE(text, search, case_insensitive) function support
Usage
func main() {
  db := arangolite.New(true)
  db.Connect("http://localhost:8000", "testDB", "user", "password")

  filter, err := filters.FromJSON(`{"limit": 2}`)
  if err != nil {
    panic(err)
  }

  aqlFilter, err := filters.ToAQL("n", filter)
  if err != nil {
    panic(err)
  }

  r, _ := db.Run(arangolite.NewQuery(`
    FOR n
    IN nodes
    %s
    RETURN n
  `, aqlFilter))

  nodes := []Node{}
  json.Unmarshal(r, &nodes)

  fmt.Printf("%v", nodes)
}

// OUTPUT EXAMPLE:
// [
//   {
//     "_id": "nodes/47473545749",
//     "_rev": "47473545749",
//     "_key": "47473545749"
//   },
//   {
//     "_id": "nodes/47472824853",
//     "_rev": "47472824853",
//     "_key": "47472824853"
//   }
// ]

Contributing

Currently, very few methods of the ArangoDB HTTP API are implemented in Arangolite. Fortunately, it is really easy to add your own. There are two ways:

  • Using the Send method, passing a struct representing the request you want to send.
func (db *DB) Send(description, method, path string, req interface{}) ([]byte, error) {}
  • Implementing the Runnable interface. You can then use the regular Run method.
// Runnable defines requests runnable by the Run and RunAsync methods.
// Queries, transactions and everything in the requests.go file are Runnable.
type Runnable interface {
	Description() string // Description shown in the logger
	Generate() []byte // The body of the request
	Path() string // The path where to send the request
	Method() string // The HTTP method to use
}

Please pull request when you implement some new features so everybody can use it.

License

MIT

Documentation

Overview

Package arangolite provides a lightweight ArangoDB driver.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CollectionInfo

type CollectionInfo struct {
	Id       string `json:"id"`
	Name     string `json:"name"`
	IsSystem bool   `json:"isSystem"`
	Status   int    `json:"status"`
	Type     int    `json:"type"`
}

type CollectionInfoList

type CollectionInfoList struct {
	Collections []CollectionInfo `json:"collections"`
	Error       bool             `json:"error"`
	Code        int              `json:"code"`
}

type CreateCollection

type CreateCollection struct {
	JournalSize    int                    `json:"journalSize,omitempty"`
	KeyOptions     map[string]interface{} `json:"keyOptions,omitempty"`
	Name           string                 `json:"name"`
	WaitForSync    *bool                  `json:"waitForSync,omitempty"`
	DoCompact      *bool                  `json:"doCompact,omitempty"`
	IsVolatile     *bool                  `json:"isVolatile,omitempty"`
	ShardKeys      []string               `json:"shardKeys,omitempty"`
	NumberOfShards int                    `json:"numberOfShards,omitempty"`
	IsSystem       *bool                  `json:"isSystem,omitempty"`
	Type           int                    `json:"type,omitempty"`
	IndexBuckets   int                    `json:"indexBuckets,omitempty"`
}

CreateCollection creates a collection in database.

func (*CreateCollection) Description

func (r *CreateCollection) Description() string

func (*CreateCollection) Generate

func (r *CreateCollection) Generate() []byte

func (*CreateCollection) Method

func (r *CreateCollection) Method() string

func (*CreateCollection) Path

func (r *CreateCollection) Path() string

type CreateDatabase

type CreateDatabase struct {
	Username string                   `json:"username,omitempty"`
	Name     string                   `json:"name"`
	Extra    json.RawMessage          `json:"extra,omitempty"`
	Passwd   string                   `json:"passwd,omitempty"`
	Active   *bool                    `json:"active,omitempty"`
	Users    []map[string]interface{} `json:"users,omitempty"`
}

CreateDatabase creates a new database.

func (*CreateDatabase) Description

func (r *CreateDatabase) Description() string

func (*CreateDatabase) Generate

func (r *CreateDatabase) Generate() []byte

func (*CreateDatabase) Method

func (r *CreateDatabase) Method() string

func (*CreateDatabase) Path

func (r *CreateDatabase) Path() string

type CreateGraph

type CreateGraph struct {
	Name              string           `json:"name"`
	EdgeDefinitions   []EdgeDefinition `json:"edgeDefinitions,omitempty"`
	OrphanCollections []string         `json:"orphanCollections,omitempty"`
}

CreateGraph creates a collection in database.

func (*CreateGraph) Description

func (c *CreateGraph) Description() string

func (*CreateGraph) Generate

func (c *CreateGraph) Generate() []byte

func (*CreateGraph) Method

func (c *CreateGraph) Method() string

func (*CreateGraph) Path

func (c *CreateGraph) Path() string

type CreateHashIndex

type CreateHashIndex struct {
	CollectionName string   `json:"-"`
	Fields         []string `json:"fields,omitempty"`
	Unique         *bool    `json:"unique,omitempty"`
	Type           string   `json:"type,omitempty"`
	Sparse         *bool    `json:"sparse,omitempty"`
}

CreateHashIndex creates a hash index in database.

func (*CreateHashIndex) Description

func (r *CreateHashIndex) Description() string

func (*CreateHashIndex) Generate

func (r *CreateHashIndex) Generate() []byte

func (*CreateHashIndex) Method

func (r *CreateHashIndex) Method() string

func (*CreateHashIndex) Path

func (r *CreateHashIndex) Path() string

type DB

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

DB represents an access to an ArangoDB database.

func New

func New() *DB

New returns a new DB object.

func (*DB) Connect

func (db *DB) Connect(url, database, username, password string) *DB

Connect initialize a DB object with the database url and credentials.

func (*DB) LoggerOptions

func (db *DB) LoggerOptions(enabled, printQuery, printResult bool) *DB

LoggerOptions sets the Arangolite logger options.

func (*DB) Run

func (db *DB) Run(q Runnable) ([]byte, error)

Run runs the Runnable synchronously and returns the JSON array of all elements of every batch returned by the database.

func (*DB) RunAsync

func (db *DB) RunAsync(q Runnable) (*Result, error)

RunAsync runs the Runnable asynchronously and returns an async Result object.

func (*DB) Send

func (db *DB) Send(description, method, path string, req interface{}) ([]byte, error)

Send runs a low level request in the database. The description param is shown in the logger. The req param is serialized in the body. The purpose of this method is to be a fallback in case the user wants to do something which is not implemented in the requests.go file.

func (*DB) SwitchDatabase

func (db *DB) SwitchDatabase(database string) *DB

SwitchDatabase change the current database.

func (*DB) SwitchUser

func (db *DB) SwitchUser(username, password string) *DB

SwitchUser change the current user.

type Document

type Document struct {
	// The document handle. Format: ':collection/:key'
	ID *string `json:"_id,omitempty"`
	// The document's revision token. Changes at each update.
	Rev *string `json:"_rev,omitempty"`
	// The document's unique key.
	Key *string `json:"_key,omitempty"`
}

Document represents a basic ArangoDB document Fields are pointers to allow null values in ArangoDB

type DropCollection

type DropCollection struct {
	Name string
}

DropCollection deletes a collection in database.

func (*DropCollection) Description

func (r *DropCollection) Description() string

func (*DropCollection) Generate

func (r *DropCollection) Generate() []byte

func (*DropCollection) Method

func (r *DropCollection) Method() string

func (*DropCollection) Path

func (r *DropCollection) Path() string

type DropDatabase

type DropDatabase struct {
	Name string
}

DropDatabase deletes a database.

func (*DropDatabase) Description

func (r *DropDatabase) Description() string

func (*DropDatabase) Generate

func (r *DropDatabase) Generate() []byte

func (*DropDatabase) Method

func (r *DropDatabase) Method() string

func (*DropDatabase) Path

func (r *DropDatabase) Path() string

type DropGraph

type DropGraph struct {
	Name            string
	DropCollections bool
}

DropGraph deletes an existing graph.

func (*DropGraph) Description

func (d *DropGraph) Description() string

func (*DropGraph) Generate

func (d *DropGraph) Generate() []byte

func (*DropGraph) Method

func (d *DropGraph) Method() string

func (*DropGraph) Path

func (d *DropGraph) Path() string

type Edge

type Edge struct {
	Document
	// Reference to another document. Format: ':collection/:key'
	// Required: true
	From *string `json:"_from,omitempty"`
	// Reference to another document. Format: ':collection/:key'
	// Required: true
	To *string `json:"_to,omitempty"`
}

Edge represents a basic ArangoDB edge Fields are pointers to allow null values in ArangoDB

type EdgeDefinition

type EdgeDefinition struct {
	Collection string   `json:"collection"`
	From       []string `json:"from"`
	To         []string `json:"to"`
}

EdgeDefinition is a definition of the graph edges

type ErrDuplicate

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

ErrDuplicate throwned when error message contains "duplicate name" string.

func (*ErrDuplicate) Error

func (e *ErrDuplicate) Error() string

type ErrNotFound

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

ErrNotFound throwned when error message contains "not found" or "unknown collection" string.

func (*ErrNotFound) Error

func (e *ErrNotFound) Error() string

type ErrUnique

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

ErrUnique throwned when error message contains "unique constraint violated" string.

func (*ErrUnique) Error

func (e *ErrUnique) Error() string

type GetCacheProperties

type GetCacheProperties struct{}

GetCacheProperties retrieves the current query cache properties.

func (*GetCacheProperties) Description

func (r *GetCacheProperties) Description() string

func (*GetCacheProperties) Generate

func (r *GetCacheProperties) Generate() []byte

func (*GetCacheProperties) Method

func (r *GetCacheProperties) Method() string

func (*GetCacheProperties) Path

func (r *GetCacheProperties) Path() string

type GetCollectionInfo

type GetCollectionInfo struct {
	CollectionName string
	IncludeSystem  bool
}

CollectionInfo gets information about the collection

func (*GetCollectionInfo) Description

func (c *GetCollectionInfo) Description() string

func (*GetCollectionInfo) Generate

func (c *GetCollectionInfo) Generate() []byte

func (*GetCollectionInfo) Method

func (c *GetCollectionInfo) Method() string

func (*GetCollectionInfo) Path

func (c *GetCollectionInfo) Path() string

type GetGraph

type GetGraph struct {
	Name string
}

GetGraph gets a graph from the graph module.

func (*GetGraph) Description

func (g *GetGraph) Description() string

func (*GetGraph) Generate

func (g *GetGraph) Generate() []byte

func (*GetGraph) Method

func (g *GetGraph) Method() string

func (*GetGraph) Path

func (g *GetGraph) Path() string

type Graph

type Graph struct {
	Name string `json:"name"`
	//An array of definitions for the edges
	EdgeDefinitions []EdgeDefinition `json:"edgeDefinitions,omitempty"`
	//An array of additional vertex collections.
	OrphanCollections []string `json:"orphanCollections,omitempty"`
	ID                string   `json:"_id,omitempty"`
	Rev               string   `json:"_rev,omitempty"`
}

Graph represents a graph definition.

type GraphData

type GraphData struct {
	Graph Graph `json:"graph"`
}

GraphData is a container for data returned by a GET GRAPH request

type GraphList

type GraphList struct {
	Graphs []Graph `json:"graphs"`
}

GraphList is a container for data returned by a LIST GRAPHS request

type ImportCollection

type ImportCollection struct {
	CollectionName string
	Data           []byte
	OnDuplicate    string
}

ImportCollection imports data to a collection

func (*ImportCollection) Description

func (c *ImportCollection) Description() string

func (*ImportCollection) Generate

func (c *ImportCollection) Generate() []byte

func (*ImportCollection) Method

func (c *ImportCollection) Method() string

func (*ImportCollection) Path

func (c *ImportCollection) Path() string

type ListCollections

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

ListCollections lists all collections from the current DB

func (*ListCollections) Description

func (c *ListCollections) Description() string

func (*ListCollections) Generate

func (c *ListCollections) Generate() []byte

func (*ListCollections) Method

func (c *ListCollections) Method() string

func (*ListCollections) Path

func (c *ListCollections) Path() string

type ListGraphs

type ListGraphs struct{}

ListGraph lists all graphs known by the graph module.

func (*ListGraphs) Description

func (l *ListGraphs) Description() string

func (*ListGraphs) Generate

func (l *ListGraphs) Generate() []byte

func (*ListGraphs) Method

func (l *ListGraphs) Method() string

func (*ListGraphs) Path

func (l *ListGraphs) Path() string

type Query

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

Query represents an AQL query.

func NewQuery

func NewQuery(aql string, params ...interface{}) *Query

NewQuery returns a new Query object.

func (*Query) BatchSize

func (q *Query) BatchSize(size int) *Query

BatchSize sets the batch size of the query

func (*Query) Bind

func (q *Query) Bind(name string, value interface{}) *Query

Bind sets the name and value of a bind parameter Binding parameters prevents AQL injection

func (*Query) Cache

func (q *Query) Cache(enable bool) *Query

Cache enables/disables the caching of the query. Unavailable prior to ArangoDB 2.7

func (*Query) Description

func (q *Query) Description() string

func (*Query) Generate

func (q *Query) Generate() []byte

func (*Query) Method

func (q *Query) Method() string

func (*Query) Path

func (q *Query) Path() string

type Result

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

Result defines a query result, allowing the user to retrieve asynchronously every batch returned by the database.

func NewResult

func NewResult(c chan interface{}) *Result

NewResult returns a new Result object.

func (*Result) Buffer

func (r *Result) Buffer() *bytes.Buffer

Buffer returns the Result buffer.

func (*Result) HasMore

func (r *Result) HasMore() bool

HasMore indicates if another batch is available to get. If true, the content can be read from the buffer.

type Runnable

type Runnable interface {
	Description() string // Description shown in the logger
	Generate() []byte    // The body of the request
	Path() string        // The path where to send the request
	Method() string      // The HTTP method to use
}

Runnable defines requests runnable by the Run and RunAsync methods. Queries, transactions and everything in the requests.go file are Runnable.

type SetCacheProperties

type SetCacheProperties struct {
	Mode       string `json:"mode,omitempty"`
	MaxResults int    `json:"maxResults,omitempty"`
}

SetCacheProperties sets the query cache properties.

func (*SetCacheProperties) Description

func (r *SetCacheProperties) Description() string

func (*SetCacheProperties) Generate

func (r *SetCacheProperties) Generate() []byte

func (*SetCacheProperties) Method

func (r *SetCacheProperties) Method() string

func (*SetCacheProperties) Path

func (r *SetCacheProperties) Path() string

type Transaction

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

Transaction represents an ArangoDB transaction.

func NewTransaction

func NewTransaction(readCol, writeCol []string) *Transaction

NewTransaction returns a new Transaction object.

func (*Transaction) AddQuery

func (t *Transaction) AddQuery(resultVar, aql string, params ...interface{}) *Transaction

AddQuery adds a new AQL query to the transaction. The result will be set in a temp variable named after the value of "resultVar". To use it from elsewhere in the transaction, use the Go templating convention.

e.g. NewTransaction([]string{}, []string{}).

AddQuery("var1", "FOR d IN documents RETURN d").
AddQuery("var2", "FOR d IN {{.var1}} RETURN d._id").Run(db)

func (*Transaction) Bind

func (t *Transaction) Bind(name string, value interface{}) *Transaction

Bind sets the name and value of a bind parameter Binding parameters prevents AQL injection Example: transaction := arangolite.NewTransaction([]string{}, []string{}).

AddQuery("var1", "FOR d IN nodes FILTER d._key == @key RETURN d._id").
AddQuery("var2", "FOR n IN nodes FILTER n._id == {{.var1}}[0] RETURN n._key").Return("var2")

transaction.Bind("key", 123)

func (*Transaction) Description

func (t *Transaction) Description() string

func (*Transaction) Generate

func (t *Transaction) Generate() []byte

func (*Transaction) Method

func (t *Transaction) Method() string

func (*Transaction) Path

func (t *Transaction) Path() string

func (*Transaction) Return

func (t *Transaction) Return(resultVar string) *Transaction

Return sets the final "resultVar" that is returned at the end of the transaction.

type TruncateCollection

type TruncateCollection struct {
	Name string
}

TruncateCollection deletes a collection in database.

func (*TruncateCollection) Description

func (r *TruncateCollection) Description() string

func (*TruncateCollection) Generate

func (r *TruncateCollection) Generate() []byte

func (*TruncateCollection) Method

func (r *TruncateCollection) Method() string

func (*TruncateCollection) Path

func (r *TruncateCollection) Path() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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