MikArt

Getting Started

Install Tava, choose an adapter, define a schema, and run a small query.

Tava is published as small modules. Import the BOM, add tava-core, then add only the adapters your application actually opens.

build.gradle.kts
dependencies {
    implementation(platform("eu.mikart.tava:tava-bom:1.0.0"))

    implementation("eu.mikart.tava:tava-core")
    implementation("eu.mikart.tava:tava-postgres")
}

Java version

Tava is compiled for Java 21. Configure your application toolchain before adding the modules.

Install

dependencies {
    implementation(platform("eu.mikart.tava:tava-bom:1.0.0"))
    implementation("eu.mikart.tava:tava-core")
    implementation("eu.mikart.tava:tava-postgres")
}

Pick An Adapter

Every adapter returns the same SPI type, so application code opens Tava the same way regardless of backend.

OpenTava.java
import eu.mikart.tava.Tava;
import eu.mikart.tava.postgres.Postgres;

try (Tava tava = Tava.open(Postgres.connect(jdbcUrl, user, password))) {
    System.out.println(tava.adapterName());
}

For local tests, H2 and SQLite keep the setup short:

LocalDatabase.java
import eu.mikart.tava.Tava;
import eu.mikart.tava.h2.H2;
import eu.mikart.tava.sqlite.Sqlite;

try (Tava h2 = Tava.open(H2.memory("tests"))) {
    // Fast in-memory JDBC adapter.
}

try (Tava sqlite = Tava.open(Sqlite.memory("tests"))) {
    // Shared in-memory SQLite database kept alive until Tava closes.
}

Define A Record

Records are the most compact way to define typed entities. Tava derives the entity name, field names, nullability, logical types, uniqueness, identity fields, and generated values from annotations and Java component types.

Account.java
import eu.mikart.tava.schema.GeneratedValue;
import eu.mikart.tava.schema.annotation.Entity;
import eu.mikart.tava.schema.annotation.Field;
import eu.mikart.tava.schema.annotation.Generated;
import eu.mikart.tava.schema.annotation.Identity;
import eu.mikart.tava.schema.annotation.Required;
import eu.mikart.tava.schema.annotation.Unique;

import java.time.Instant;
import java.util.UUID;

@Entity("accounts")
public record Account(
        @Identity UUID id,
        @Required @Unique @Field(length = 255) String email,
        int score,
        @Generated(GeneratedValue.NOW) Instant createdAt
) {}

Apply The Schema

Schema changes are planned before they are applied. Unsupported changes fail. Lossy or destructive changes require an explicit opt-in.

ApplySchema.java
import eu.mikart.tava.schema.Schema;

Schema schema = Schema.builder()
        .record(Account.class)
        .build();

try (Tava tava = Tava.open(Postgres.connect(jdbcUrl, user, password))) {
    var plan = tava.plan(schema);
    plan.changes().forEach(change ->
            System.out.println(change.risk() + " " + change.description()));

    plan.apply();
}

Insert And Query

UseEntity.java
import eu.mikart.tava.query.Predicate;
import eu.mikart.tava.query.Query;
import eu.mikart.tava.query.Sort;

var accounts = tava.entity(Account.class);

Account saved = accounts.insert(new Account(
        UUID.randomUUID(),
        "ada@example.com",
        7,
        null
));

var page = accounts.find(Query.builder()
        .where(Predicate.eq("email", saved.email()))
        .sort(Sort.desc("createdAt"))
        .limit(25)
        .build());

Last updated on

Last updated on

On this page