Getting Started

Connect to ArangoDB, define an entity, and run your first type-safe query.

1. Add dependencies

plugins {
    kotlin("jvm")
    id("com.google.devtools.ksp") // For type-safe property generation
}

dependencies {
    implementation("io.peekandpoke.ultra:karango-core:0.107.2")
    ksp("io.peekandpoke.ultra:karango-ksp:0.107.2")
}

2. Define your entity

Annotate data classes with @Vault. KSP generates type-safe property accessors at compile time.

import io.peekandpoke.ultra.vault.Vault

@Vault
data class Person(
    val name: String,
    val age: Int,
    val email: String? = null,
)

3. Create a repository

import io.peekandpoke.karango.vault.EntityRepository
import io.peekandpoke.karango.vault.KarangoDriver
import io.peekandpoke.ultra.reflection.kType

class PersonsRepo(driver: KarangoDriver) : EntityRepository<Person>(
    name = "persons",          // ArangoDB collection name
    storedType = kType(),      // Type reference for serialization
    driver = driver,
)

4. Configure the connection

import io.peekandpoke.karango.config.ArangoDbConfig

val config = ArangoDbConfig(
    host = "localhost",
    port = 8529,
    user = "root",
    password = "",
    database = "my_app",
)

With Kontainer (dependency injection):

import io.peekandpoke.karango.karango

kontainer {
    karango(config)

    // Register your repositories
    singleton(PersonsRepo::class)
}

5. Basic CRUD

// Insert
val stored = repo.insert(Person("Alice", 30, "alice@example.com"))
// stored._id = "persons/abc123"
// stored._key = "abc123"
// stored() -> Person(name="Alice", age=30, ...)

// Find by ID
val found = repo.findById(stored._id)

// Update
repo.save(found!!.map { it.copy(age = 31) })

// Delete
repo.remove(found)

// Find all
val everyone = repo.findAll().toList()

6. Your first query

// Type-safe query with the Karango DSL
val results = repo.findList {
    FOR(repo) { person ->
        FILTER(person.age GTE 18)
        SORT(person.name.ASC)
        RETURN(person)
    }
}

// results: List<Stored<Person>>

The person.age and person.name accessors are generated by KSP — they're compile-time checked. If you rename a field in the data class, the compiler catches every query that references it.