Skip to content

Instantly share code, notes, and snippets.

@crajah
Created November 7, 2020 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crajah/10d88c5826bb2acbda6e45955a52aab5 to your computer and use it in GitHub Desktop.
Save crajah/10d88c5826bb2acbda6e45955a52aab5 to your computer and use it in GitHub Desktop.
Scala Arango DB Connector
package parallelai.loop.api.dao
import java.net.URL
import com.outr.arango.CollectionType._
import com.outr.arango._
import com.outr.arango.query._
import com.outr.arango.transaction.Transaction
import io.youi.net.URL
import parallelai.loop.api.model.dto.Long
import parallelai.loop.api.model.graph.{EdgeEntity, Entity, EntityModel, Site, User, UserToken}
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Random
//import scala.concurrent.ExecutionContext.Implicits.global
import scala.reflect.ClassTag
import scala.reflect.runtime.universe._
class ArangoDAO[D <: Entity[D] : ClassTag]
(implicit givenPrefix: Option[String] = None, config: ArangoConfig)
extends Graph(
databaseName = config.database_name,
baseURL = config.base_url,
credentials = config.credentials
) { self: Entity[D] =>
init()(scala.concurrent.ExecutionContext.Implicits.global)
val collection = self.entityType match {
case Vertex => vertex[D]
case Edge => edge[D]
}
// if (typeOf[D] == typeOf[EdgeEntity[D, _, _]]) { edge[D] } else { vertex[D] }
def findT(id: Id[D])(implicit ec: ExecutionContext): Future[Option[D]] = collection.get(id)
def findAllT(from: Int, size: Int)(implicit ec: ExecutionContext): Future[List[D]] = {
val query =
aql"""
FOR item in ${collection}
SORT item._ts_epoch_ms DESC
LIMIT ${from}, ${size}
RETURN item
"""
collection.query(query).results
}
def findAllMatchingPairsT(terms: Map[String, List[String]])(from: Int, size: Int)(implicit ec: ExecutionContext): Future[List[D]] = {
val filterTerms: Set[String] = terms.keySet.flatMap { k =>
terms(k).map { v =>
s"FILTER item.${k} == ${v}"
}
}
val query =
aql"""
FOR item in ${collection}
SORT item._ts_epoch_ms DESC
${filterTerms.mkString(" ")}
LIMIT ${from}, ${size}
RETURN item
"""
collection.query(query).results
}
def findAllMatchingT(field: String, values: String*)(from: Int, size: Int)(implicit ec: ExecutionContext): Future[List[D]] =
findAllMatchingPairsT(Map(field -> values.toList))(from, size)
def findAllWithMatchingPairsT(terms: Map[String, List[String]])(from: Int, size: Int)(implicit ec: ExecutionContext): Future[List[D]] =
findAllMatchingPairsT(terms)(from, size)
def findAnyMatchingPairsT(terms: Map[String, List[String]])(from: Int, size: Int)(implicit ec: ExecutionContext): Future[List[D]] = {
val searchTerms = terms.keySet.map { k =>
val v = terms(k)
s"${v} ANY IN item.${k}"
}.mkString(" OR ")
val query =
aql"""
FOR item in ${collection}
SEARCH ${searchTerms}
SORT item._ts_epoch_ms DESC
LIMIT ${from}, ${size}
RETURN item
"""
collection.query(query).results
}
def insertT(item: D)(implicit ec: ExecutionContext): Future[D] = collection.upsertOne(item).map { insertedDoc =>
insertedDoc.`new` match {
case Some(jsonObj) => collection.model.serialization.fromJson(jsonObj)
case None => throw new UnknownError(s"Arango: Failed inserting item with id ${item._id} into ${collection.name}. Item is ${item}")
}
}
def insertT(item: List[D])(implicit ec: ExecutionContext): Future[List[D]] = collection.upsert(item).map {
listOfInstertedDocs => listOfInstertedDocs.map { insertedDoc =>
insertedDoc.`new` match {
case Some(jsonObj) => collection.model.serialization.fromJson(jsonObj)
case None => throw new UnknownError(s"Arango: Failed inserting item with id ${insertedDoc._id} into ${collection.name}. Items are ${item}")
}
}
}
def deleteT(id: Id[D])(implicit ec: ExecutionContext): Future[Id[D]] = collection.deleteOne(id)
def deleteT(id: List[Id[D]])(implicit ec: ExecutionContext): Future[List[Id[D]]] = collection.delete(id)
def deleteAllT()(implicit ec: ExecutionContext): Future[Unit] = collection.truncate()
}
object TTT extends App {
import scala.concurrent.ExecutionContext.Implicits.global
implicit val config = ArangoConfig(database_name = "test", base_url = URL(port = 8529), credentials = None)
val userDAO = new ArangoDAO[User](None, config)
for {
u <- userDAO.insertT(User(user_token = UserToken( token = Random.nextString(20), // THE ID
user_id = Random.nextString(5),
emailVerified = Random.nextBoolean(),
expiry = (System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 10))
)))
_ <- Future.successful(println(u))
v <- userDAO.findT(u._id)
_ <- Future.successful(println(v))
} yield ()
}
//Entity for Reference
import com.outr.arango._
import parallelai.loop.api.model.dto.Long
import scala.reflect.ClassTag
import scala.reflect.runtime.universe._
trait Entity[D <: Entity[D]] extends Document[D] {
def _ts_epoch_ms: Long
def _rev: Option[String]
sealed trait EntityType
case object Vertex extends EntityType
case object Edge extends EntityType
def entityType: EntityType = Vertex
}
trait EdgeEntity[D <: Entity[D], F, T] extends Entity[D] {
override def entityType: EntityType = Edge
}
abstract class EntityModel[D <: Entity[D] : TypeTag : ClassTag] extends DocumentModel[D] {
override val collectionName: String = "" + typeOf[D].typeSymbol.name
override protected def generateId(): String = {
def getType[V: ClassTag : TypeTag]() = typeOf[D].typeSymbol.name.toString.toLowerCase
s"loop|${getType[D]()}|${System.currentTimeMillis()}"
}
def $id: Id[D] = id(generateId())
}
// Example Case class
package parallelai.loop.api.model.graph
import com.outr.arango.{Id, Index, Serialization}
import parallelai.loop.api.model.dto.Long
import parallelai.loop.api.model.graph.User._
case class User
(
_id: Id[User] = $id,
_rev: Option[String] = None,
_ts_epoch_ms: Long = Long(),
user_token: UserToken
) extends Entity[User]
object User extends EntityModel[User] {
override implicit val serialization: Serialization[User] = Serialization.auto[User]
override def indexes: List[Index] = Nil
}
case class UserToken
(
token: String, // THE ID
user_id: String,
emailVerified: Boolean,
expiry: Long
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment