-
Notifications
You must be signed in to change notification settings - Fork 1
Quick Start
What this page covers: the minimal end-to-end path — define an entity, describe it once, open a backend, save / find / count, and close — followed by a one-line swap to a completely different database.
📌 Note — already added the dependency? Good. If not, do Installation first.
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.
public class PlayerData {
private UUID uuid;
private String name;
private int score;
public PlayerData() {} // Jackson needs this
public PlayerData(UUID uuid, String name, int score) {
this.uuid = uuid; this.name = name; this.score = score;
}
public UUID getUuid() { return uuid; }
public String getName() { return name; }
public int getScore() { return score; }
// setters omitted for brevity
}
// 2. Describe it once. Note the order: KEY type FIRST, ENTITY type second.
EntityDescriptor<UUID, PlayerData> PLAYERS = EntityDescriptor.builder(UUID.class, PlayerData.class)
.collection("players")
.keyExtractor(PlayerData::getUuid)
.codec(new JacksonJsonCodec<>(PlayerData.class))
.build();
// 3. Pick a backend and open it.
Storage storage = Storages.createSQL(
new SqlConfig("jdbc:mariadb://localhost:3306/mydb", "root", "root"));
storage.init().join();
// 4. Get a typed repository and use it.
Repository<UUID, PlayerData> repo = storage.repository(PLAYERS);
UUID aliceId = UUID.randomUUID();
repo.save(new PlayerData(aliceId, "Alice", 100)).join(); // upsert
Optional<PlayerData> alice = repo.find(aliceId).join(); // -> Optional[Alice]
long total = repo.count().join(); // -> 1
// 5. Release the pool when you're done.
storage.close().join();That's the entire lifecycle: describe → open → use → close. Everything between init() and
close() is backend-agnostic.
⚠️ Gotcha —EntityDescriptor.builder(KeyType.class, EntityType.class)takes the key type first. Both arguments areClass<?>, so the compiler won't catch a flip —builder(PlayerData.class, UUID.class)compiles and then fails confusingly at runtime. Key first, entity second.
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.
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 unchangedOr 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();
⚠️ Gotcha — the typed factories (createSQL,createPostgreSQL,createH2,createMongo,createLocalFile,createInMemory) return the concrete storage type, so capability interfaces are reachable without a cast. The genericStorages.create(StorageConfig)dispatches by config type but always picks the MySQL/MariaDB dialect for anySqlConfig— usecreatePostgreSQL/createH2explicitly when you need those dialects.
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.
| Type | Role |
|---|---|
EntityDescriptor<K, V> |
immutable metadata: collection, key extractor, codec, indexes, versioning |
Storages |
static factory — typed create* builders + generic create(StorageConfig)
|
Storage |
lifecycle (init / close / health) + a factory for repositories |
Repository<K, V> |
typed CRUD for one collection; every method returns a CompletableFuture
|
JacksonJsonCodec<V> |
the serialization strategy attached to the descriptor |
Next steps: dig into the descriptor on Defining Entities, the full CRUD surface on CRUD Operations, and declarative indexes on Indexing & Queries.
-
Defining Entities —
EntityDescriptor.builder, collection rules, valid keys, codecs. -
The Async API — the
CompletableFuturemodel, composition, exceptional completion. -
CRUD Operations —
find/findMany/save/saveAll/delete/exists/count/all. - Choosing a Backend — the capability matrix and per-backend instantiation.
- Installation — coordinates and flavor choice.
EveryDatabase · Home · made by Petrus Pradella
Getting Started
Core Concepts
Working with Data
Backends
Manager Module
- Caching & References
- Typed References (Ref)
- Caching Managers
- Cache Policies & Freshness
- Cross-Process Cache Sync
- One Entity, Many Databases
Operations
Advanced
Reference
Contributing