data
ClickHouse access for the kernel and modules
(Architecture › Database).
Everything a module needs to persist goes through Database; nothing else in
the tree opens a socket to the database. Source in libs/data/.
Types
| Type | Role |
|---|---|
DatabaseConfig | URL, database name and credentials from SHATTERVEIL_DB_URL / _NAME / _USER / _PASSWORD, falling back to CLICKHOUSE_USER / CLICKHOUSE_PASSWORD (the names in deploy/clickhouse/.env). Only loopback URLs are accepted; the password never appears in toString() |
Database | The entry point: open(config), migrate(migrations), query(sql, params) → List<Row>, insert(table, rows) via AsyncWriter, ping(), close(). All calls are asynchronous (CompletableFuture) and never block the tick thread |
Row | One JSONEachRow result: typed getters (requireUuid, requireLong, requireInstant, stringMap, …) with clear errors |
Migration | V<n>__<name>.sql files listed in a module's db/migrations/<module>/migrations.list; applied once, in order, recorded in schema_migrations |
AsyncWriter | Batches inserts per table on a virtual thread; bounded queue, drops with a counter instead of blocking |
DatabaseException | isUnavailable() separates "ClickHouse is down" (retry later) from "the query is wrong" (a bug) |
modules.ModuleStateRepository | The kernel's module_state table (enabled/disabled flags that survive restarts) |
player.PlayerRecord, player.PlayerRecordStore | The players table: immutable, versioned records; inMemory() store for tests and for running without a database |
Safety
- Identifiers are validated (
Database.requireIdentifier) and parameters are bound through ClickHouse's{name:Type}syntax; nothing from a player is ever concatenated into SQL. - Only
http://127.0.0.1/http://localhostURLs are accepted — the database is never exposed. - No database configured →
DatabaseConfig.fromEnv()is empty and every consumer falls back to memory, saying so once in the log.
Adding a table
A module owns its tables and ships their schema:
- Put
V<n>__<name>.sqlfiles undersrc/main/resources/db/migrations/<module>/. - List them in
migrations.listin that directory. - Apply them from
onEnablethroughDatabase.migrate(...).
Applied migrations are recorded in shatterveil.schema_migrations, which the
ClickHouse container creates on first start.
Tests
DataLibraryTest covers configuration, identifier validation, row parsing,
migration loading and PlayerRecord without a live ClickHouse. Integration
against the real container (deploy/clickhouse/) is manual for now.