Last active
April 2, 2023 10:11
-
-
Save dacr/9063bf7c788c4f0872b33e9547f93af4 to your computer and use it in GitHub Desktop.
learning arangodb serialization / deserialization using the java client driver / published by https://github.com/dacr/code-examples-manager #6f65b437-59bf-49fd-acf1-ec32ae86d3fc/117bdc4db208752a098cda491263c2d19175ca4a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// summary : learning arangodb serialization / deserialization using the java client driver | |
// keywords : arangodb, graphdb, javadriver, @testable, serdes, serialization, deserialization | |
// publish : gist, corporate | |
// authors : David Crosson | |
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2) | |
// id : 6f65b437-59bf-49fd-acf1-ec32ae86d3fc | |
// created-on : 2021-03-05T09:25:00Z | |
// managed-by : https://github.com/dacr/code-examples-manager | |
// execution : scala ammonite script (http://ammonite.io/) - run as follow 'amm scriptname.sc' | |
import $ivy.`com.fasterxml.jackson.core:jackson-databind:2.12.2` | |
import $ivy.`com.arangodb:arangodb-java-driver:6.9.1` | |
import $ivy.`com.arangodb:jackson-dataformat-velocypack:1.0.0` | |
import $ivy.`com.whisk::docker-testkit-impl-spotify:0.9.9` | |
import $ivy.`org.json4s::json4s-jackson:3.6.11` | |
import $ivy.`org.json4s::json4s-ext:3.6.11` | |
import $ivy.`org.scalatest::scalatest:3.2.6` | |
import $ivy.`org.slf4j:slf4j-simple:1.7.30` | |
import $ivy.`javax.activation:activation:1.1.1` | |
import org.scalatest._ | |
import matchers.should.Matchers | |
import wordspec.AnyWordSpec | |
import OptionValues._ | |
import com.arangodb._ | |
import com.arangodb.mapping.ArangoJack | |
import com.arangodb.entity.DocumentField.Type | |
import com.arangodb.entity._ | |
import com.arangodb.model.{AqlQueryOptions, CollectionCreateOptions, DocumentCreateOptions, StreamTransactionOptions, TransactionOptions} | |
import com.arangodb.util.MapBuilder | |
import com.fasterxml.jackson.annotation.JsonIgnoreProperties | |
import com.whisk.docker.{DockerContainer, DockerKit, DockerPortMapping, DockerReadyChecker} | |
import org.json4s.{DefaultFormats, FieldSerializer, Formats} | |
import org.json4s.jackson.Serialization.{read, write} | |
import org.json4s.FieldSerializer._ | |
import java.io.Serializable | |
import scala.jdk.CollectionConverters._ | |
import scala.beans.BeanProperty | |
// ================================================================================================== | |
// Provided DockerTestKit allow to have control over the used scalatest release | |
trait DockerTestKit extends BeforeAndAfterAll with org.scalatest.concurrent.ScalaFutures with DockerKit { | |
self: Suite => | |
import org.scalatest.time.{Span, Seconds, Millis} | |
def dockerInitPatienceInterval = | |
PatienceConfig(scaled(Span(20, Seconds)), scaled(Span(10, Millis))) | |
def dockerPullImagesPatienceInterval = | |
PatienceConfig(scaled(Span(1200, Seconds)), scaled(Span(250, Millis))) | |
override def beforeAll(): Unit = { | |
super.beforeAll(); | |
startAllOrFail() | |
} | |
override def afterAll(): Unit = { | |
stopAllQuietly(); | |
super.afterAll() | |
} | |
} | |
// ================================================================================================== | |
trait DockerArangoDBService extends com.whisk.docker.impl.spotify.DockerKitSpotify { | |
val arangoUsername = "root" | |
val arangoPassword = "changeit" | |
val mappedArangoPort = 9529 | |
lazy val arangoContainer = { | |
val env = Array( | |
s"ARANGO_ROOT_PASSWORD=$arangoPassword", | |
) | |
DockerContainer("arangodb:3.7.3") | |
.withEnv(env: _*) | |
.withPortMapping(8529 -> DockerPortMapping(Some(mappedArangoPort), "127.0.0.1")) | |
.withReadyChecker(DockerReadyChecker.LogLineContains("is ready for business")) | |
} | |
override def dockerContainers: List[DockerContainer] = arangoContainer :: Nil | |
} | |
// ================================================================================================== | |
@JsonIgnoreProperties(ignoreUnknown = true) | |
class Someone( | |
@BeanProperty var name: String, | |
@BeanProperty var age: Int, | |
) extends Serializable { | |
def this() = this(name = "", age = 0) | |
} | |
trait ArangoDocument { | |
val key: Option[String] | |
} | |
trait ArangoEdgeDocument extends ArangoDocument { | |
val from: String | |
val to: String | |
} | |
case class SomeoneAlt(key: Option[String], name: String, age: Int) extends ArangoDocument | |
trait Pet extends ArangoDocument { | |
val name:String | |
val birthYear:Int | |
} | |
case class Dog(key: Option[String], name:String, birthYear:Int) extends Pet | |
case class Cat(key: Option[String], name:String, birthYear:Int, lifeCount:Int) extends Pet | |
case class Animals(animals:List[Pet]) | |
trait ArangoDatabaseAccessForTest extends DockerArangoDBService { | |
val documentRenamer = FieldSerializer[ArangoDocument]( | |
renameTo("key", "_key"),renameFrom("_key", "key") | |
) | |
val edgeFromRenamer = FieldSerializer[ArangoEdgeDocument]( | |
renameTo("from", "_from"), renameFrom("_from", "from") | |
) | |
val edgeToRenamer = FieldSerializer[ArangoEdgeDocument]( | |
renameTo("to", "_to"), renameFrom("_to", "to") | |
) | |
implicit val formats = DefaultFormats.lossless + documentRenamer + edgeFromRenamer + edgeToRenamer | |
def uuid = java.util.UUID.randomUUID().toString | |
// raw queries just return json strings | |
def rawQueryCursor(query: String, vars: (String, Object)*)(implicit db: ArangoDatabase): ArangoCursor[String] = { | |
db.query(query, vars.toMap.asJava, null, classOf[String]) | |
} | |
def rawQuery(query: String, vars: (String, Object)*)(implicit db: ArangoDatabase): Iterable[String] = { | |
db.query(query, vars.toMap.asJava, null, classOf[String]).asListRemaining().asScala | |
} | |
// normal queries returns json4s mapped json | |
def query[T](query: String, vars: (String, Object)*)(implicit db: ArangoDatabase, formats: Formats, mf: Manifest[T]): Iterable[T] = { | |
db.query(query, vars.toMap.asJava, null, classOf[String]).asListRemaining().asScala.map(read[T]) | |
} | |
def withArango(testCode: ArangoDB => Any): Unit = { | |
val arango = { | |
new ArangoDB.Builder() | |
.host("127.0.0.1", mappedArangoPort) | |
.serializer(new ArangoJack) | |
.user(arangoUsername) | |
.password(arangoPassword) | |
.build() | |
} | |
try { | |
testCode(arango) | |
} finally { | |
arango.shutdown() | |
} | |
} | |
def withArangoAndDatabaseCleanup(testCode: (ArangoDB, String) => Any): Unit = { | |
withArango { arango => | |
val databaseName = "random-" + java.util.UUID.randomUUID().toString | |
try { | |
testCode(arango, databaseName) | |
} finally { | |
val db: ArangoDatabase = arango.db(databaseName) | |
if (db.exists()) db.drop() | |
} | |
} | |
} | |
def withDatabase(testCode: ArangoDatabase => Any): Unit = { | |
withArango { arango => | |
val databaseName = s"test-database-$uuid" | |
val db: ArangoDatabase = arango.db(databaseName) | |
if (db.exists()) db.drop() | |
arango.createDatabase(databaseName) | |
try { | |
testCode(db) | |
} finally { | |
db.drop() | |
} | |
} | |
} | |
def withCollection(testCode: ArangoCollection => Any): Unit = { | |
withDatabase { db => | |
def collectionName = s"test-collection-$uuid".replaceAll("-", "_") | |
val collection = db.collection(collectionName) | |
if (!collection.exists) collection.create() | |
try { | |
testCode(collection) | |
} finally { | |
collection.drop() | |
} | |
} | |
} | |
} | |
class ArangoDbLearningTest extends AnyWordSpec with Matchers with ArangoDatabaseAccessForTest with DockerTestKit { | |
override def suiteName: String = "ArangoDbLearningTest" | |
"ArangoDb serialization deserialization (serdes)" can { | |
// ----------------------------------------------------------------------------------------------------------------- | |
"when using no serdes, just raw strings" should { | |
"insert and get a document using raw json strings" in withCollection { collection => | |
val result = collection.insertDocument("""{"name":"joe","age":42}""") | |
val doc = collection.getDocument(result.getKey, classOf[String]) | |
info("using classOf[String] tells the driver to just work with raw json strings") | |
doc should include regex """"name":"joe"""" | |
doc should include regex """"age":42""" | |
} | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
"when using unstructured documents" should { | |
"insert and get a unstructured document by using the BaseDocument approach" in withCollection { collection => | |
info("using classOf[BaseDocument] tells the driver to use this generic data structure") | |
val doc = new BaseDocument() | |
doc.setKey("a") | |
doc.addAttribute("name", "joe") | |
doc.addAttribute("age", 42) | |
collection.insertDocument(doc) | |
collection.documentExists("a") shouldBe true | |
val gottenDoc = collection.getDocument("a", classOf[BaseDocument]) | |
gottenDoc.getAttribute("name") shouldBe "joe" | |
gottenDoc.getAttribute("age") shouldBe 42 | |
} | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
"when using java beans based documents (and so velocitypack)" should { | |
"insert and get a javabean document" in withCollection { collection => | |
val doc = new Someone("joe", 42) | |
val result = collection.insertDocument(doc) | |
val gottenDoc = collection.getDocument(result.getKey, classOf[Someone]) | |
gottenDoc.name shouldBe doc.name | |
gottenDoc.age shouldBe doc.age | |
//gottenDoc shouldEqual doc // issue here ! | |
} | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
"when using an third party JSON library while relying on scala simplificication mechanisms" should { | |
"insert and get a JSON4S AST based document" in withCollection { collection => | |
info("As the driver is able to work with raw json string, json4s json library integration becomes obvious") | |
val doc = SomeoneAlt(Some("a"), "joe", 42) | |
collection.insertDocument(write(doc)) | |
val gottenDoc = read[SomeoneAlt](collection.getDocument("a", classOf[String])) | |
gottenDoc shouldEqual doc | |
info("note here that this code can be simplified thanks to advanced scala features such as implicits") | |
} | |
} | |
} | |
} | |
org.scalatest.tools.Runner.main(Array("-oDF", "-s", classOf[ArangoDbLearningTest].getName)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment