Add bstore-j public sync helper and refresh public README
This commit is contained in:
@@ -1,71 +1,84 @@
|
|||||||
# BStore-j
|
# bstore-j
|
||||||
|
|
||||||
Explicit-first successor line for the Java BStore data access layer.
|
`bstore-j` is a small Java data-access library built around entities, fields,
|
||||||
|
records, and schema change logs.
|
||||||
|
|
||||||
`bstore-j` starts as a clean copy of `bstore-java`, but evolves independently:
|
It is designed for applications that want a compact storage layer without
|
||||||
|
committing to a large ORM. The API stays close to database work, but it models
|
||||||
|
that work in Java types such as `Entity`, `Field`, `DBO`, `Action`, and
|
||||||
|
`Terminal` rather than centering everything on handwritten SQL strings.
|
||||||
|
|
||||||
- build and publication identity are separate
|
## What It Provides
|
||||||
- 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
|
The library is organized around a few core areas:
|
||||||
|
|
||||||
`bstore-j` has two main pieces:
|
|
||||||
|
|
||||||
- `com.reliancy.rec`
|
- `com.reliancy.rec`
|
||||||
- lightweight structured data types
|
- lightweight structured record and value types
|
||||||
- JSON-like records, headers, slots, arrays/objects
|
|
||||||
- `com.reliancy.dbo`
|
- `com.reliancy.dbo`
|
||||||
- storage-oriented entity/field/record model
|
- entity and field definitions
|
||||||
- SQL-inspired actions and filters
|
- runtime record objects
|
||||||
- SQL backend via `com.reliancy.dbo.sql`
|
- CRUD operations and query composition
|
||||||
|
- `com.reliancy.dbo.sql`
|
||||||
|
- SQL-backed terminal implementations
|
||||||
|
- `com.reliancy.dbo.meta`
|
||||||
|
- schema discovery
|
||||||
|
- ordered structural changes
|
||||||
|
- change log tracking for startup migrations
|
||||||
|
|
||||||
The API is inspired by SQL, but the design goal is not to reproduce SQLAlchemy
|
In practice, that gives you:
|
||||||
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
|
- explicit entity and field definitions
|
||||||
|
- a backend-neutral CRUD surface
|
||||||
|
- filtering, ordering, paging, and action execution
|
||||||
|
- SQL database support for the current Java implementation
|
||||||
|
- startup-oriented schema migration support
|
||||||
|
- a change history model built around append-only events
|
||||||
|
|
||||||
The Java codebase is the reference implementation for:
|
## Design Goals
|
||||||
|
|
||||||
- CRUD over entities and fields
|
`bstore-j` aims to be:
|
||||||
- backend-neutral `dbo` contracts
|
|
||||||
- SQL as the first reference backend
|
|
||||||
- metadata/migration support through `dbo.meta`
|
|
||||||
|
|
||||||
The current meta model is intentionally lean:
|
- small enough to understand without a large framework investment
|
||||||
|
- explicit about structure and schema
|
||||||
|
- usable as a runtime data layer in ordinary Java applications
|
||||||
|
- suitable for code-first schema installation and upgrade flows
|
||||||
|
|
||||||
- `ChangeEvent` is the canonical persisted history
|
It does not try to be a full ORM, rich object graph mapper, or a replacement
|
||||||
- `DataOriginator` is a module/plugin registry snapshot
|
for every direct SQL use case.
|
||||||
- `EntityDefinition` and `FieldDefinition` are utility/transient planning models
|
|
||||||
|
|
||||||
## Core Features
|
## Installation
|
||||||
|
|
||||||
- explicit and reflective entity definition paths
|
The published artifact is:
|
||||||
- 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
|
```text
|
||||||
|
com.reliancy:bstore-j:1.0.0-SNAPSHOT
|
||||||
|
```
|
||||||
|
|
||||||
The library is being revised so that:
|
If you have access to the Reliancy Maven repository:
|
||||||
|
|
||||||
- explicit metadata becomes the canonical runtime path
|
```gradle
|
||||||
- `DBO` remains the runtime record type
|
repositories {
|
||||||
- typed non-`DBO` models can use adapters
|
mavenCentral()
|
||||||
- reflection and annotation-driven publication remain optional convenience
|
maven {
|
||||||
|
url "https://repo.reliancy.com/repository/maven-snapshots"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
The active implementation plan lives in:
|
dependencies {
|
||||||
|
implementation "com.reliancy:bstore-j:1.0.0-SNAPSHOT"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- [`../docs/BSTORE_JAVA_BACKPORT_PLAN.md`](../docs/BSTORE_JAVA_BACKPORT_PLAN.md)
|
If you do not use that repository, you can build from source:
|
||||||
|
|
||||||
## Explicit-First Example
|
```bash
|
||||||
|
./gradlew jar
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
This example defines an entity, migrates the schema, writes a record, and loads
|
||||||
|
it back.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import com.reliancy.dbo.DBO;
|
import com.reliancy.dbo.DBO;
|
||||||
@@ -93,55 +106,6 @@ db.save(alice);
|
|||||||
DBO loaded = db.load(person, alice.get(person.getField("id")));
|
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
|
## Query Example
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@@ -149,98 +113,76 @@ import com.reliancy.dbo.Action;
|
|||||||
import com.reliancy.dbo.DBO;
|
import com.reliancy.dbo.DBO;
|
||||||
|
|
||||||
try (Action action = db.begin()
|
try (Action action = db.begin()
|
||||||
.load(Person.class)
|
.load(person)
|
||||||
.filterBy(Person.AGE.gte(18))
|
.filterBy(person.getField("age").gte(18))
|
||||||
.orderBy(Person.NAME.asc())
|
.orderBy(person.getField("name").asc())
|
||||||
.limit(100)
|
.limit(100)
|
||||||
.execute()) {
|
.execute()) {
|
||||||
for (DBO row : action) {
|
for (DBO row : action) {
|
||||||
System.out.println(row.get(Person.NAME));
|
System.out.println(row.get(person.getField("name")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Startup Migration Example
|
## Schema Migration Model
|
||||||
|
|
||||||
```java
|
`bstore-j` includes a lean metadata layer intended for application startup
|
||||||
import com.reliancy.dbo.Entity;
|
migrations.
|
||||||
import com.reliancy.dbo.meta.MetaTerminal;
|
|
||||||
|
|
||||||
MetaTerminal meta = db.meta(Entity.recall(Person.class));
|
The migration flow:
|
||||||
|
|
||||||
meta.migrate(
|
- discovers the expected entity structure from code
|
||||||
"core-module",
|
- discovers the current backend structure
|
||||||
"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
|
- computes ordered structural changes
|
||||||
- applies unapplied changes
|
- applies unapplied changes
|
||||||
- records applied changes in the change log
|
- records applied changes in a change-event log
|
||||||
|
|
||||||
## Module Registry Example
|
The central types in this area are:
|
||||||
|
|
||||||
```java
|
- `ChangeEvent`
|
||||||
import com.reliancy.dbo.meta.DataOriginator;
|
- `DataOriginator`
|
||||||
|
- `EntityDefinition`
|
||||||
|
- `FieldDefinition`
|
||||||
|
|
||||||
DataOriginator module = new DataOriginator();
|
## Databases
|
||||||
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);
|
The Java implementation is SQL-oriented today. The project currently includes
|
||||||
|
dependencies and test coverage around:
|
||||||
|
|
||||||
|
- PostgreSQL
|
||||||
|
- H2
|
||||||
|
|
||||||
|
The broader API is designed so application code can stay closer to entities and
|
||||||
|
actions than to vendor-specific SQL strings.
|
||||||
|
|
||||||
|
## Build And Test
|
||||||
|
|
||||||
|
Build the library:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew build
|
||||||
```
|
```
|
||||||
|
|
||||||
`DataOriginator` is meant for module/plugin registry data, not arbitrary module
|
Run the test suite:
|
||||||
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
|
```bash
|
||||||
export DB_URL="postgres://user:pass@localhost:5432/testdb"
|
export DB_URL="postgres://user:pass@localhost:5432/testdb"
|
||||||
./gradlew test
|
./gradlew test
|
||||||
```
|
```
|
||||||
|
|
||||||
There are focused integration tests for:
|
The tests exercise CRUD behavior, SQL execution paths, schema change discovery,
|
||||||
|
and migration flows.
|
||||||
|
|
||||||
- CRUD and SQL backend behavior
|
## Repository Layout
|
||||||
- change discovery ordering
|
|
||||||
- change replay/idempotency
|
|
||||||
- startup migration flow
|
|
||||||
- install/upgrade/downgrade lifecycle at the schema level
|
|
||||||
|
|
||||||
## Docs
|
```text
|
||||||
|
bstore-j/
|
||||||
- [`../docs/BSTORE_DBO_CONTRACT.md`](../docs/BSTORE_DBO_CONTRACT.md)
|
├── src/
|
||||||
- [`../docs/BSTORE_META_CONTRACT.md`](../docs/BSTORE_META_CONTRACT.md)
|
├── build.gradle
|
||||||
- [`../docs/BSTORE_JAVA_PLAN.md`](../docs/BSTORE_JAVA_PLAN.md)
|
├── extra.gradle
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
GNU Lesser General Public License, Version 3.0
|
GNU Lesser General Public License, Version 3.0
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user