-
Notifications
You must be signed in to change notification settings - Fork 1
API Cheat Sheet
What this page covers: a one-screen index of the public surface — every factory, every
Repository method, the descriptor builder, the query/index API, the capability interfaces, and the
manager add-on. Skim it to find the call you need, then click through for the details. Signatures are
real; semantics are paraphrased — the linked guide pages and the Javadoc are canonical.
📌 Note — every I/O call returns a
CompletableFuture. Examples use.join()for brevity, but you compose withthenApply/thenCompose; there are no blocking variants. See The Async API.
EntityDescriptor<UUID, PlayerData> PLAYERS = EntityDescriptor.builder(UUID.class, PlayerData.class)
.collection("players")
.keyExtractor(PlayerData::getUuid)
.codec(new JacksonJsonCodec<>(PlayerData.class))
.build();
Storage storage = Storages.createH2(new SqlConfig("jdbc:h2:mem:demo", "", ""));
storage.init().join();
Repository<UUID, PlayerData> repo = storage.repository(PLAYERS);
repo.save(new PlayerData(id, "Alice", 100)).join();
Optional<PlayerData> alice = repo.find(id).join();
storage.close().join();Typed builders return concrete types, so capability interfaces are reachable without a cast.
| Call | Returns | Notes |
|---|---|---|
Storages.createSQL(SqlConfig) |
SqlStorage |
MySQL / MariaDB dialect |
Storages.createPostgreSQL(SqlConfig) |
PostgreSqlStorage |
PostgreSQL dialect |
Storages.createH2(SqlConfig) |
H2SqlStorage |
jdbc:h2:mem: / file: / tcp:
|
Storages.createMongo(MongoConfig) |
MongoStorage |
tx needs a replica set |
Storages.createLocalFile(LocalFileConfig) |
LocalFileStorage |
one file per entity |
Storages.createInMemory() |
InMemoryStorage |
ephemeral |
Storages.create(StorageConfig) |
Storage |
dispatches by config type |
⚠️ Gotcha —Storages.create(SqlConfig)always picks the MySQL/MariaDB dialect. For PostgreSQL or H2 callcreatePostgreSQL/createH2explicitly. See Gotchas & Pitfalls and Choosing a Backend.
CompletableFuture<Void> init(); // idempotent
CompletableFuture<Void> close(); // idempotent
CompletableFuture<Boolean> health();
<K, V> Repository<K, V> repository(EntityDescriptor<K, V> descriptor); // cached per collectionrepository(sameDescriptor) returns the same object each time. See Architecture Overview.
| Method | Returns | Notes |
|---|---|---|
find(K key) |
CompletableFuture<Optional<V>> |
empty when absent |
findMany(Collection<K> keys) |
CompletableFuture<List<V>> |
missing keys omitted |
save(V entity) |
CompletableFuture<Void> |
upsert (insert or replace) |
saveAll(Collection<V> entities) |
CompletableFuture<Void> |
batched |
delete(K key) |
CompletableFuture<Boolean> |
true if it existed |
exists(K key) |
CompletableFuture<Boolean> |
|
count() |
CompletableFuture<Long> |
|
versions(Collection<K> keys) |
CompletableFuture<Map<K, Long>> |
cheap key+version read; 0 if unversioned/H2; powers cache-sync polling |
all() |
CompletableFuture<Stream<V>> |
|
findBy(String fieldPath, Object value) |
CompletableFuture<List<V>> |
declared index only |
query(Query query) |
CompletableFuture<List<V>> |
declared indexes only |
See CRUD Operations and Indexing & Queries.
EntityDescriptor.builder(Class<K> keyType, Class<V> type) // keyType is FIRST
.collection(String name) // must match ^[a-zA-Z][a-zA-Z0-9_]*$
.keyExtractor(Function<V, K> getKey)
.codec(Codec<V> codec)
.index(IndexHint hint) // repeatable
.versioned() // entity implements Versioned
.version(Function<V, Long> get, BiConsumer<V, Long> set) // explicit accessors
.build();
⚠️ Gotcha — the builder takeskeyTypefirst, then the entity type — both areClass, so a flip compiles.EntityDescriptor.builder(UUID.class, Player.class), never the reverse. See Defining Entities.
| Factory | Field type | Annotation equivalent |
|---|---|---|
IndexHint.string(path) |
STRING |
@Indexed on a String
|
IndexHint.integer(path) |
INT |
@Indexed on an int/Integer
|
IndexHint.bigInt(path) |
LONG |
@Indexed on a long/Long
|
IndexHint.decimal(path) |
DOUBLE |
@Indexed on a double
|
IndexHint.bool(path) |
BOOLEAN |
@Indexed on a boolean
|
IndexHint.timestamp(path) |
TIMESTAMP |
@Indexed on a date/Instant
|
Order helpers: IndexHint.descending(path), hint.asDescending() / .asAscending().
@Indexed(path = "...", type = String.class, order = IndexHint.Order.DESCENDING) on a field is merged
by build(). See Indexing & Queries.
Query.eq(String fieldPath, Object value)
Query.range(String fieldPath, Object fromInclusive, Object toInclusive) // inclusive; null = open end
Query.in(String fieldPath, Object... values) // also Collection<?> overload
query.and(Query other) // AND only — no native ORrepo.query(Query.eq("world", "world_nether")
.and(Query.range("score", 1000, null))).join(); // world == … AND score >= 1000
⚠️ Gotcha — querying an undeclared field throwsIllegalArgumentExceptionon every backend, LocalFile included. Union two queries client-side for OR. See Indexing & Queries.
new JacksonJsonCodec<>(Type.class) // compact JSON (the database default)
JacksonJsonCodec.pretty(Type.class) // indented JSON (human-readable LocalFile)
new JacksonYamlCodec<>(Type.class) // YAML — LocalFile onlyCodec<V>: encode / decode / contentType() / isJsonCodec() / fileExtension(). SQL, Mongo and
InMemory require a JSON codec; only LocalFile accepts YAML. See Codecs.
if (storage instanceof TransactionalStorage tx) {
tx.inTransaction(scope -> { // scope.repository(d) / scope.rollback()
Repository<UUID, Account> accounts = scope.repository(ACCOUNTS);
return accounts.save(updated);
}).join();
}
if (storage instanceof SchemaAwareStorage schema) {
schema.register(new V001_CreateAuditLog()).migrate().join();
}| Interface | Method | Backends |
|---|---|---|
tx.TransactionalStorage |
inTransaction(scope -> future) |
SQL (incl. H2), Mongo (replica set), InMemory (no isolation) |
schema.SchemaAwareStorage |
register(...).migrate() |
SQL, Mongo, LocalFile |
changefeed.ChangeFeedStorage |
subscribe(listener) + originId()
|
Mongo, PostgreSQL, InMemory (others poll) |
Migration base classes: SqlMigration (override upScript()), MongoMigration (override
executeOnDatabase(MongoDatabase)), LocalFileMigration (override executeOnStorage(LocalFileStorage));
MigrationContext.getNativeClient(Type.class). See Transactions and Schema Migrations.
@OptimisticLock private Long lockVersion; // preferred — auto-wired at build()
// or: .versioned() (entity implements Versioned)
// or: .version(Account::getLockVersion, Account::setLockVersion)Version starts at 0, +1 per update; mismatch → OptimisticLockException (surfaces as the cause of
a CompletionException). Enforced by MySQL/MariaDB, PostgreSQL, Mongo; H2 silently degrades; LocalFile
and InMemory don't enforce it. See Optimistic Locking.
TransferReport report = StorageTransfer.builder()
.from(src).to(dst)
.descriptor(PLAYERS) // or descriptor(srcDesc, dstDesc) to rename/recodec
.batchSize(500) // default 500
.errorPolicy(ErrorPolicy.FAIL_FAST) // or CONTINUE / SKIP_EXISTING
.applyTargetMigrations(true)
.failIfTargetCollectionNotEmpty(true)
.verifyCounts(true)
.build().execute().join();
report.success(); report.errors(); report.totalEntities(); report.durationMs();The future does not complete exceptionally for expected failures — they collect in
report.errors(). See Moving Data Between Backends.
StorageLogConfig.defaults(); // WARN floor — routine silent, failures visible
StorageLogConfig.silent(); // only the unsuppressible ERROR floor
StorageLogConfig.verbose(); // DEBUG
StorageLogConfig.trace();
cfg.level(StorageLogTopic.WRITE, StorageLogLevel.DEBUG)
.mute(StorageLogTopic.INDEX)
.includeKeys(true); // includeKeys / includeValues / includeQueryValues — default false
StorageLogSinks.installDefault(event -> logger.info(event.format())); // host bridgeTopics: LIFECYCLE SCHEMA INDEX MIGRATION WRITE DELETE READ QUERY TRANSACTION
TRANSFER HEALTH. CLI: -Deverydatabase.log.level=info|debug|trace. See Logging & Diagnostics.
RefRegistry refRegistry = new RefRegistry(); // per-context; no global default
JacksonJsonCodec<Guild> codec = refRegistry.codec(Guild.class); // ref-aware, bound to 'refRegistry'
CachingManager<UUID, Guild> guilds = refRegistry.manager(GUILDS, storage, CachePolicy.always());
Ref<UUID, Guild> ref = refRegistry.ref(guildId, Guild.class); // bound refRef<K, V> (serializes as its key):
| Call | Blocks? | I/O? | Returns |
|---|---|---|---|
ref.peek() |
no | never |
Optional<V> — cache-only |
ref.resolve() |
no | on miss | CompletableFuture<Optional<V>> |
ref.join() |
yes | on cold miss |
V or null
|
Build: Ref.of(key, type, null) (unbound — store-only), Ref.of(key, type, registry) /
refRegistry.ref(key, type) (bound), Ref.empty(type). Derive: ref.withTtl(Duration),
ref.withPolicy(CachePolicy), ref.withRegistry(RefRegistry).
CachingManager<K, V>: resolve(key) · peek(key) · getAll(keys) (N+1 antidote) · preloadAll()
· saveAndCache(v) · saveAllAndCache(values) (batch write-through → BatchSaveReport) ·
seedIfAbsent(key, v) (cache, no I/O - keep-first) · flushDirty() (write-back, batch flush →
BatchSaveReport) · deleteAndEvict(key) · invalidate(key) · evict(key) · invalidateAll() ·
clearCache() · purgeExpired() · repository() · cachedSize().
Write-back (opt-in mutate-in-memory / flush-later): an entity opts in either by implementing
IDirtyable (boolean isDirty() · void markClean() · void markDirty()) or by annotating a
boolean field with @DirtyFlag (keep the flag transient + @JsonIgnore; pick one, not both).
Dirty wins - while dirty a cell is always served and never reloaded over (not by TTL, not by
invalidate). seedIfAbsent + mutate + flushDirty() is
the loop. BatchSaveReport<K> lists failures only: isEmpty() · hasFailures() · failures() ·
conflictedKeys() (cells evicted) · erroredKeys() (cells kept); each KeyOutcome<K> has key() ·
status() (SAVED/CONFLICT/ERROR) · error(). See Caching Managers.
Parent registries: new RefRegistry(parent) chains to a parent - parent(), resolver(type)
falls back up the chain (register/manager stay local), isRegistered(type) (local) vs
isRegisteredInChain(type) (walks the chain). Private-then-shared: keep the chain shallow (yours ->
shared).
Freshness vs capacity: CachePolicy.always() / ttl(Duration) / noCache() (per-read,
per-ref overridable) — CacheOptions.builder().policy(...).maxSize(n).build() (LRU, store-level).
@RefPolicy(ttlSeconds = …, noCache = …) per field.
⚠️ Gotcha — a bareRef.of(key, type, null)is unbound: fine to store (writes just the key), butresolve()/peek()fail fast until bound to a registry. See Caching & References.
Keep CachingManager caches fresh across instances — push where the backend supports it, poll where it
doesn't, behind one API.
CacheSync sync = CacheSync.attach(storage) // or CacheSync.auto() for managers on different backends
.pollEvery(Duration.ofSeconds(10)) // required only if `storage` can't push
.bind(guilds) // bind(manager) or bind(manager, str -> myKey(str))
.includeOwnOrigin() // optional: process this instance's own events too
.onError(t -> log.warn(t)) // optional: surface key-parse / poll errors
.start();
sync.close(); // idempotent; pollOnce() for a synchronous cycle (tests)
// pull primitive, used directly:
PollingCacheSync.every(Duration.ofSeconds(10)).bind(guilds).start();SAVE → invalidate, DELETE → evict. Built-in key parsers: String/UUID/Long/Integer (pass an
explicit parser for composite/record keys). Push backends: Mongo (Change Streams), PostgreSQL
(LISTEN/NOTIFY), InMemory; the rest poll via Repository.versions(...). Delivery is at-least-once
and (Postgres) lossy — keep a TTL as the safety net. See Cross-Process Cache Sync.
-
The Async API — the
CompletableFuturemodel every call shares. - CRUD Operations · Indexing & Queries · Optimistic Locking · Transactions · Schema Migrations.
- Codecs · Defining Entities · Choosing a Backend.
- Caching & References · Cross-Process Cache Sync — the manager add-on in full.
- Gotchas & Pitfalls · FAQ / Troubleshooting · Glossary · Dependency Versions & Overrides.
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