Main repo for zio-arangodb
ArangoDB supports 3 type of API's:
- Velocypack over Velocystream (sockets)
- Velocypack over HTTP
- JSON over HTTP
This library is built on top of ZIO and is designed in a way it can (potentially) implement all protocols. Current version supports JSON over HTTP only using zio-http as underlying client.
Experimental: trying to support zio-schema, instead of using JSON encoder/decoder you would be able to use any type that has the typeclass Schema
Install:
import sbt._
object Dependencies {
val zioArangoV = "0.0.3"
}
object Libraries {
val zioArangoHttp = "io.funkode" %% "zio-arangodb-http" % zioArangoV
}Example of usage:
import io.funkode.arangodb.*
import io.funkode.arangodb.http.*
import zio.*
import zio.Console.*
import zio.http.Client
import zio.http.Middleware.*
import zio.json.*
object Main extends ZIOAppDefault:
import model.* // arango API types
import JsonCodecs.given // json codecs for arango API types
val testDb = DatabaseName("test")
def app =
for
db <- ArangoClientJson.database(testDb).createIfNotExist()
dbInfo <- db.info
_ <- printLine(s"""Database info: $dbInfo""")
collections <- db.collections(true)
_ <- printLine(s"""Database collections: ${collections.map(_.name).mkString(", ")}""")
_ <- printLine(s"""Press any key to exit""")
_ <- readLine
yield ()
def run = app.provide(
ArangoConfiguration.default, // check reference.conf (HOCON)
ArangoClientJson.live, // JSON over HTTP
Client.default, // zio-http client
Scope.default
)To do IT testing you can use ArangoClientJson.testcontainers instead of live.
It will add an ArangoContainer layer running on a random port and a client already configured against the instance
Example from it tests (check code for more examples):
import io.funkode.arangodb.*
import io.funkode.arangodb.http.*
import io.funkode.arangodb.model.*
import io.funkode.velocypack.VPack
import zio.*
import zio.http.Client
import zio.json.*
import zio.test.*
object ArangoDatabaseIT extends ZIOSpecDefault:
import JsonCodecs.given
import VPack.*
import docker.ArangoContainer
override def spec: Spec[TestEnvironment, Any] =
suite("ArangoDB client should")(
test("Create and drop a database") {
for
container <- ZIO.service[ArangoContainer]
_ <- Console.printLine(s"ArangoDB container running on port ${container.container.getFirstMappedPort.nn}")
databaseApi <- ArangoClientJson.database("pets").create()
dataInfo <- databaseApi.info
deleteResult <- databaseApi.drop
yield assertTrue(dataInfo.name == testDatabase.name) &&
assertTrue(!dataInfo.isSystem) &&
assertTrue(deleteResult)
}).provideShared(
Scope.default,
ArangoConfiguration.default,
Client.default,
ArangoClientJson.testContainers
)ServerInfo API link
High level methods:
def databases: List[DatabaseName]- list of server databasesdef version(details: Boolean = false): ServerVersion- server version, license type, etc
Example of usage:
for
databases <- ArangoClientJson.serverInfo().databases
yield databasesDatabase API link
High level methods:
def name: DatabaseName- name of current databasedef info: DatabaseInfo- get database infodef create(users: List[DatabaseCreate.User]): ArangoDatabase- create this database, will fail if already existdef createIfNotExist(users: List[DatabaseCreate.User]): ArangoDatabasedef drop: Boolean- drop current databasedef collections: List[CollectionInfo]- list of database collectionsdef graphs: List[GraphInfo]- list of database graphsdef collection(name: CollectionName): ArangoCollection- access to collection API
Example of usage:
val testDb = DatabaseName("test")
for
dbApi <- ArangoClientJson.database(testDb).createIfNotExist()
databaseInfo <- dbApi.info
collections <- dbApi.collections()
yield (databaseInfo, collections)Collection API link
High level methods:
def database: DatabaseName- current database namedef name: CollectionName- current collection namedef info: CollectionInfo- collection infodef create(setup: CollectionCreate => CollectionCreate)- create collectiondef createIfNotExist(setup: CollectionCreate => CollectionCreate)- create collection if not existdef drop(isSystem: Boolean = false): DeleteResult- drop collection
Example of usage:
for
collection <- ArangoClientJson.collection("pets").createIfNotExist
collectionInfo <- collection.info
yield collectionInfoDocuments API link
High level methods:
def database: DatabaseName- current database namedef collection: CollectionName- current collection namedef count: Long- number of documents for this collectiondef insert[T](document: T, ...): Document[T]- insert new document, retrievesDocument[T]which has internal id, key and revisiondef create[T](documents: List[T], ...): List[Document[T]]- insert list of documentsdef replace[T](documents: List[T], ...): List[Document[T]]- replace list of documentsdef update[T, P](patch: List[P], ...): List[Document[T]]- patch list of documentsdef remove[T, K](keys: List[K], ...): List[Document[T]]- remove list of documents by key
Example of usage:
for
documents <- ArangoClientJson.collection(petsCollection).createIfNotExist().documents
document <- documents.insert(pet1, true, true)
yield document`
Document API link
High level methods:
def database: DatabaseName- current database namedef handle: DocumentHandle- current document handle (collection and key)def read[T: Decoder]: T- retrieve current documentdef head: ArangoMessage.Header- retrieve document metadata headersdef remove[T: Decoder]: Document[T]- delete documentdef update[T, P](patch: P): Document[T]- patch documentdef replate[T](document: T): Document[T]- replace document
Example of usage:
for
collection <- ArangoClientJson.collection(petsCollection).createIfNotExist()
document = collection.document(petKey)
pet <- document.read[Pet]
yield petQuery API link
High level methods:
def database: DatabaseName- current database namebatchSize(value: Long): ArangoQuery- setup batch size and return new querycount(value: Boolean): ArangoQuery- set if query returns counttransaction(id: TransactionId): ArangoQuery- setup transaction id for the querydef execute[T: Decoder]: QueryResults[T]- execute query and return results (no pagination)def cursor[T: Decoder]: ArangoCursor[T]- execute query and return results with cursordef stream[T: Decoder]: ZStream[Any, ArangoError, T]- execute query and return streamed results
Examples of usage:
for
db <- ArangoClientJson.database(DatabaseName("test"))
queryCountries =
db
.query(
Query("FOR c IN @@col SORT c RETURN c")
.bindVar("@col", VString("countries"))
)
.count(true)
.batchSize(2) // setup the batch size
// query with cursor
cursor <- queryCountries.cursor[Country]
firstResults = cursor.body
// cursor has a next method to get next batch
more <- cursor.next
secondResults = more.body
// another approach is to use directly streams
firstStreamResults <- queryCountries.stream[Country].run(ZSink.take(4))
streamResultsCount <- queryCountries.stream[Country].run(ZSink.count)
streamedResults <- queryCountries.stream[Country]
yield streamedResultsGraph API link
High level methods:
def name: GraphName- graph namedef create: GraphInfo- create graphdef info: GraphInfo- graph infodef vertexCollections: List[CollectionName]- retrieves vertex collectionsdef addVertexCollection: GrahInfo- add a vertex collectiondef removeVertexCollection: GrahInfo- remove a vertex collectiondef collection: ArangoGraphCollection- access to graph collection apidef vertex(handle: DocumentHandle): ArangoGraphVertex- access to vertex apidef edge(handle: DocumentHandle): ArangoGraphEdge- access to edge api
Example of usage:
val politics = GraphName("politics")
val allies = CollectionName("allies")
val countries = CollectionName("countries")
val graphEdgeDefinitions = List(GraphEdgeDefinition(allies, List(countries), List(countries)))
for
graph <- ArangoClientJson.graph(politics)
graphCreated <- graph.create(graphEdgeDefinitions)
alliesCol = ArangoClientJson.db.collection(allies)
_ <- alliesCol.documents.create(alliesOfEs)
queryAlliesOfSpain =
ArangoClientJson.db
.query(
Query("FOR c IN OUTBOUND @startVertex @@edge RETURN c")
.bindVar("startVertex", VString(es.unwrap))
.bindVar("@edge", VString(allies.unwrap))
)
resultQuery <- queryAlliesOfSpain.execute[Country].map(_.result)
yield resultQueryStart ArangoDB with docker:
make startDockerArangoRun local test versus running ArangoDB instance (default port 8529):
make run