Skip to content

Quick Start

Petrus Pradella edited this page Jun 19, 2026 · 4 revisions

Quick Start

Basic Usage

  • The entire lifecycle of the project is: describe → open → use → close.
  • Everything between init() and close() is backend-agnostic.
  • We use POJO (Plain Old Java Object) as entity contracts.
import br.com.finalcraft.everydatabase.*;
import br.com.finalcraft.everydatabase.codec.JacksonJsonCodec;
import br.com.finalcraft.everydatabase.modules.sql.SqlConfig;

import java.util.Optional;
import java.util.UUID;

// 1. A plain entity — no-arg constructor + accessors so Jackson can (de)serialise it.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PlayerEntity { // POJO (Plain Old Java Object)
  private UUID uuid;
  private String name;
  private int score;
  private SomeInnerData innerData; // Another POJO
}

// 2. Create an EntityDescriptor for the Entity.
EntityDescriptor<UUID, PlayerEntity> PLAYER_DESCRIPTOR = EntityDescriptor.builder(UUID.class, PlayerEntity.class)
  .collection("player")
  .keyExtractor(PlayerEntity::getUuid)
  .codec(new JacksonJsonCodec<>(PlayerEntity.class))
  .build();

// 3. Pick a storage backend and open it.
Storage storage = Storages.createSQL(
  new SqlConfig(
    "jdbc:mariadb://localhost:3306/mydb",
    "root",
    "root")
);

storage.init().join();

// 4. Create a typed repository on that database.
Repository<UUID, PlayerEntity> repo = storage.repository(PLAYERS);

UUID aliceId = UUID.randomUUID();
repo.save(
  new PlayerEntity(aliceId, "Alice", 100)
).join(); // upsert

Optional<PlayerEntity> alice = repo.find(aliceId).join(); // -> Optional[Alice]
long total = repo.count().join();                         // -> 1

// 5. Release the pool when you're done or the applicaiton ends.
storage.close().join();

Why .join() everywhere?

Every I/O call returns a CompletableFuture — there are no blocking variants. .join() simply waits for the result, which keeps these examples short. In real code you usually compose instead of blocking:

repo.find(aliceId)
  .thenApply(opt -> opt.map(PlayerData::getScore).orElse(0))
  .thenAccept(score -> System.out.println("score = " + score));

Errors surface as the exceptional completion of the future (as the cause of a CompletionException when you .join()). The full async model — composition, exception handling, the executor — is on The Async API.


Swapping the backend is one line

Everything from storage.repository(PLAYERS) downward is identical regardless of engine. To move the same code onto MongoDB, change only how you open the storage:

import br.com.finalcraft.everydatabase.modules.mongo.MongoConfig;

Storage storage = Storages.createMongo(
  new MongoConfig(
    "mongodb://localhost:27017",
    "mydb")
);

storage.init().join();

// ...repository(PLAYERS), save, find, count — all unchanged

Or an embedded H2 file, or pure in-memory for a test:

Storage h2  = Storages.createH2(new SqlConfig("jdbc:h2:file:./data/storage", "", ""));
Storage mem = Storages.createInMemory();

See Choosing a Backend for the capability matrix and per-backend setup, and the per-engine config (SqlConfig, MongoConfig, LocalFileConfig) on each backend's page.


See also

  • Defining EntitiesEntityDescriptor.builder, collection rules, valid keys, codecs.
  • The Async API — the CompletableFuture model, composition, exceptional completion.
  • CRUD Operationsfind / findMany / save / saveAll / delete / exists / count / all.
  • Choosing a Backend — the capability matrix and per-backend instantiation.
  • Installation — coordinates and flavor choice.

Clone this wiki locally