# BStore-j Explicit-first successor line for the Java BStore data access layer. `bstore-j` starts as a clean copy of `bstore-java`, but evolves independently: - build and publication identity are separate - the package surface remains familiar - explicit model definition becomes first-class - reflection remains available only as optional sugar - GraalVM-friendlier operation is a design goal ## What It Is `bstore-j` has two main pieces: - `com.reliancy.rec` - lightweight structured data types - JSON-like records, headers, slots, arrays/objects - `com.reliancy.dbo` - storage-oriented entity/field/record model - SQL-inspired actions and filters - SQL backend via `com.reliancy.dbo.sql` The API is inspired by SQL, but the design goal is not to reproduce SQLAlchemy or raw SQL access. The goal is a small, consistent data layer that can later be ported across languages and backed by other systems. ## Current Direction The Java codebase is the reference implementation for: - CRUD over entities and fields - backend-neutral `dbo` contracts - SQL as the first reference backend - metadata/migration support through `dbo.meta` The current meta model is intentionally lean: - `ChangeEvent` is the canonical persisted history - `DataOriginator` is a module/plugin registry snapshot - `EntityDefinition` and `FieldDefinition` are utility/transient planning models ## Core Features - explicit and reflective entity definition paths - CRUD with `Terminal`, `Action`, `Check`, and `Ordering` - joined inheritance support - SQL backends for PostgreSQL/MySQL/SQL Server/Oracle/H2 - streaming loads and batched writes - migration/change discovery through `MetaTerminal` - replay-safe structural change application - startup-oriented migration flow ## Status The library is being revised so that: - explicit metadata becomes the canonical runtime path - `DBO` remains the runtime record type - typed non-`DBO` models can use adapters - reflection and annotation-driven publication remain optional convenience The active implementation plan lives in: - [`../docs/BSTORE_JAVA_BACKPORT_PLAN.md`](../docs/BSTORE_JAVA_BACKPORT_PLAN.md) ## Explicit-First Example ```java import com.reliancy.dbo.DBO; import com.reliancy.dbo.Entity; import com.reliancy.dbo.Field; import com.reliancy.dbo.sql.SQLTerminal; Entity person = Entity.define("public.person") .setId("person") .field( Field.Int("id").setPk(true).setAutoIncrement(true).nullable(false), Field.Str("name").nullable(false), Field.Int("age") ) .publish(); SQLTerminal db = new SQLTerminal("postgres://user:pass@localhost:5432/appdb"); db.meta().migrate("core", "person-v1", person); DBO alice = DBO.of(person); alice.set(person.getField("name"), "Alice"); alice.set(person.getField("age"), 30); db.save(alice); DBO loaded = db.load(person, alice.get(person.getField("id"))); ``` ## Optional Sugar Example ```java import com.reliancy.dbo.DBO; import com.reliancy.dbo.Entity; import com.reliancy.dbo.Field; import com.reliancy.dbo.sugar.BStoreRegistry; import com.reliancy.dbo.sql.SQLTerminal; @Entity.Info(name="public.person") public class Person extends DBO { public static final Field ID = Field.Int("id").setPk(true).setAutoIncrement(true); public static final Field NAME = Field.Str("name"); } SQLTerminal db = new SQLTerminal("postgres://user:pass@localhost:5432/appdb"); BStoreRegistry registry = BStoreRegistry.builder().register(Person.class).build(); registry.publishAll(); db.meta().migrate("core", "person-v1", registry.entity(Person.class)); Person loaded = db.load(registry.adapter(Person.class), 1); ``` ## Quick Start ```java import com.reliancy.dbo.DBO; import com.reliancy.dbo.Entity; import com.reliancy.dbo.Field; import com.reliancy.dbo.sql.SQLTerminal; @Entity.Info(name="public.person") public class Person extends DBO { public static final Field ID = Field.Int("id").setPk(true).setAutoIncrement(true); public static final Field NAME = Field.Str("name").setTypeParams("255"); public static final Field AGE = Field.Int("age"); } SQLTerminal db = new SQLTerminal("postgres://user:pass@localhost:5432/appdb"); Person person = new Person(); person.set(Person.NAME, "Alice"); person.set(Person.AGE, 30); db.save(person); Person loaded = db.load(Person.class, person.get(Person.ID)); ``` ## Query Example ```java import com.reliancy.dbo.Action; import com.reliancy.dbo.DBO; try (Action action = db.begin() .load(Person.class) .filterBy(Person.AGE.gte(18)) .orderBy(Person.NAME.asc()) .limit(100) .execute()) { for (DBO row : action) { System.out.println(row.get(Person.NAME)); } } ``` ## Startup Migration Example ```java import com.reliancy.dbo.Entity; import com.reliancy.dbo.meta.MetaTerminal; MetaTerminal meta = db.meta(Entity.recall(Person.class)); meta.migrate( "core-module", "release-2026-03-17", Entity.recall(Person.class) ); ``` Current behavior: - ensures the required `bstore.change_event` history table exists - discovers expected entity structure from code - discovers actual structure from the backend - computes ordered structural changes - applies unapplied changes - records applied changes in the change log ## Module Registry Example ```java import com.reliancy.dbo.meta.DataOriginator; DataOriginator module = new DataOriginator(); module.set(DataOriginator.ID, "core-module"); module.set(DataOriginator.ORIGINATOR_ID, "core-module"); module.set(DataOriginator.ORIGINATOR_VERSION, "1.0.0"); module.set(DataOriginator.INSTALLED_VERSION, "1.0.0"); module.set(DataOriginator.DESCRIPTION, "Core application module"); db.save(module); ``` `DataOriginator` is meant for module/plugin registry data, not arbitrary module state and not detailed migration history. ## What Is Supported Today - install-style schema creation - additive schema upgrades - safe table rename within the same schema - replay-safe change application - schema downgrade by replaying a contraction plan ## What Is Intentionally Not Broad Yet - rich relationship/foreign-key navigation - generic rollback synthesis - plugin settings/state storage in meta records - non-SQL backends in Java ## Testing The curated test suite uses a Postgres database via `DB_URL`. ```bash export DB_URL="postgres://user:pass@localhost:5432/testdb" ./gradlew test ``` There are focused integration tests for: - CRUD and SQL backend behavior - change discovery ordering - change replay/idempotency - startup migration flow - install/upgrade/downgrade lifecycle at the schema level ## Docs - [`../docs/BSTORE_DBO_CONTRACT.md`](../docs/BSTORE_DBO_CONTRACT.md) - [`../docs/BSTORE_META_CONTRACT.md`](../docs/BSTORE_META_CONTRACT.md) - [`../docs/BSTORE_JAVA_PLAN.md`](../docs/BSTORE_JAVA_PLAN.md) ## License GNU Lesser General Public License, Version 3.0