orm

module
v0.0.0-...-915e3f0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: MIT

README

orm — one grammar, three languages, one compiler

A schema-driven fluent query grammar for Go, PHP and Rust that compiles through a single Go engine into database plans and executes on each language's native driver. Version 0.0.1.

$battles = Battle::query()->using($db)->serviceSeq(7)->isClose(false)
    ->and(fn(BattleWhere $w) => $w->isDisplay(true)->or()->isAllday(true))
    ->relation(User::query())->orderBySeqDesc()->limit(0, 20)->gets();
battles, err := gen.Battle().Using(ctx, db).ServiceSeq(7).IsClose(false).
    And(func(w *gen.BattleWhere) { w.IsDisplay(true).Or().IsAllday(true) }).
    Relation(gen.User()).OrderBySeqDesc().Limit(0, 20).Gets()
let battles = battle::query().using(&db).service_seq(7).is_close(false)
    .and(|w| w.is_display(true).or().is_allday(true))
    .relation(user::query()).order_by_seq_desc().limit(0, 20).gets().await?;

The three chains produce the same SQL, the same binds and the same results — checked byte for byte by tests/conformance (58 vectors) and ormgen tokens.

For a direct finder, the same getsBy token is generated in all three clients:

$battles = Battle::query()->using($db)->getsByServiceSeq(7);
battles, err := gen.Battle().Using(ctx, db).GetsByServiceSeq(7)
let battles = battle::query().using(&db).gets_by_service_seq(7).await?;

getBy is the one-row form for a primary or unique key; getCountBy is the scalar count form. getsBy<Field> and getCountBy<Field> are root-table equality shortcuts; index declarations affect the database plan, not whether the shortcut exists. For multiple predicates, keep the same root query and chain the columns before gets or getCount.

gen.Battle() is Go's query factory and returns *gen.BattleQuery. PHP and Rust use Battle::query() and battle::query() for the same query head. Creation, ownership and asynchronous execution follow each language; the query operations and semantics are shared. get returns one row, gets returns a collection. one/all remain compatibility aliases. Select the executor with using before execution; terminals receive only values. The selected executor runs every join and relation step, and loaded rows inherit it. Calling using again selects another database or transaction without changing the query predicates. Go passes its context with the executor. Unbound queries and finished transactions return CONFIG.

How it works

  • Schema: one hand-written Mermaid erDiagram (schema/*.mmd) → ormgen buildschema.json (manifest with schema_hash).
  • Engine (engine/, Go, compiler only): JSON IR → Plan (SQL text + bind slots + positional assembly). Never executes. Plans are value-free and cached per statement shape in every client.
  • Executors: Go database/sql in-process; PHP PDO + ormd (compile daemon over a unix socket, plans cached in APCu); Rust sqlx + the engine as wasm (wasmtime on a dedicated thread). Row data never crosses a language boundary.
  • Databases: MySQL 8 / MariaDB first; PostgreSQL 12+ and SQLite 3.35+ through the same plans (docs/dialects.md) — the conformance vectors produce identical results on all three.
  • Generated code: ormgen gen --lang go|php|rust emits typed builders, rows and relation accessors per entity.

Quick start (MySQL 8.x, local socket)

mysql -uroot orm_bench < bench/sql/battle.sql                       # bench schema + 100k rows
go run ./cmd/ormgen build schema/bench.mmd --out schema/schema.json
for l in go php rust; do go run ./cmd/ormgen gen --schema schema/schema.json --lang $l --out clients/$l/gen; done
go build -o bin/ormd ./cmd/ormd
GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o bin/ormengine.wasm ./engine/wasm
go test ./...                                                       # engine + Go client
bin/ormd -socket /abs/ormd.sock -schema schema/schema.json &        # PHP compile daemon
php clients/php/tests/integration.php /abs/ormd.sock /abs/schema/schema.json
(cd clients/rust && cargo build --release) && clients/rust/target/release/integration bin/ormengine.wasm schema/schema.json
go run ./tests/conformance/check run                                # 3 languages, identical output

Documents

Online documentation — static guides, interface diagrams and implementation status, built from docs/ and deployed through GitHub Pages.

공통 인터페이스 · 구현 대조표 · 자동 검사 — 자료구조·수명·공개 API와 검증 상태.

docs/usage.md — start here: schema, generation, connecting, querying, writing, relations, the three databases, operations.

examples/thin-slice (same statement in three languages) · examples/complex (joins, groups, three relation levels, aggregates — identical JSON in three languages) · docs/dsl.md grammar · docs/schema.md Mermaid dialect, import, validate · docs/protocol.md IR/Plan · docs/codec.md column styles · docs/dialects.md MySQL/PostgreSQL/SQLite · docs/config.md orm.toml · docs/errors.yaml codes · docs/perf.md measurements and gates · docs/checklist.md work plan · docs/lanes/ parallel lane specs.

Tooling

ormgen build | gen | import --dsn | validate --dsn | ddl --dialect | errors --lang | tokens | check --lang php, tests/conformance/check run|compare|record, scripts/build-artifacts.sh, deploy/ service units.

License

MIT — see LICENSE.

Directories

Path Synopsis
bench
seedaes command
seedaes fills the aes_hex_* columns of the bench battle table on databases that cannot run AES_ENCRYPT themselves (PostgreSQL, SQLite), using the same host-side AES the executors use, so every database holds identical bytes.
seedaes fills the aes_hex_* columns of the bench battle table on databases that cannot run AES_ENCRYPT themselves (PostgreSQL, SQLite), using the same host-side AES the executors use, so every database holds identical bytes.
clients
go/gen
Code generated from contracts/interfaces.json; DO NOT EDIT.
Code generated from contracts/interfaces.json; DO NOT EDIT.
go/orm
Package orm is the Go executor: it turns a Req (IR + params) into rows using database/sql, caching compiled plans by IR shape and prepared statements by SQL text.
Package orm is the Go executor: it turns a Req (IR + params) into rows using database/sql, caching compiled plans by IR shape and prepared statements by SQL text.
go/orm/pg
Package pg registers the PostgreSQL driver with the executor.
Package pg registers the PostgreSQL driver with the executor.
go/orm/sqlite
Package sqlite registers the SQLite driver with the executor.
Package sqlite registers the SQLite driver with the executor.
cmd
ormd command
ormd serves the compiler over a Unix domain socket for hosts that cannot link it in-process (PHP).
ormd serves the compiler over a Unix domain socket for hosts that cannot link it in-process (PHP).
ormgen command
ormgen check --lang php <dir>: what a PHP codebase uses that the compatibility layer (docs/dsl.md §6) must translate.
ormgen check --lang php <dir>: what a PHP codebase uses that the compatibility layer (docs/dsl.md §6) must translate.
Package contracts generates native interface declarations from the common interface manifest.
Package contracts generates native interface declarations from the common interface manifest.
Package engine is the query compiler: JSON IR in, Plan JSON out.
Package engine is the query compiler: JSON IR in, Plan JSON out.
dialect
Package dialect renders the database-specific pieces of SQL.
Package dialect renders the database-specific pieces of SQL.
ffi command
Package main builds libormengine (c-shared).
Package main builds libormengine (c-shared).
ir
Package ir defines the wire form clients send (JSON, docs/protocol.md) and validates it against the manifest.
Package ir defines the wire form clients send (JSON, docs/protocol.md) and validates it against the manifest.
plan
Package plan is what executors run: SQL text with bind slots and an assembly spec.
Package plan is what executors run: SQL text with bind slots and an assembly spec.
planner
Package planner turns a validated IR request into a Plan.
Package planner turns a validated IR request into a Plan.
schema
Package schema turns the hand-written Mermaid erDiagram (docs/schema.md) into the manifest the engine and generators consume.
Package schema turns the hand-written Mermaid erDiagram (docs/schema.md) into the manifest the engine and generators consume.
wasm command
Package main builds ormengine.wasm (wasip1 reactor).
Package main builds ormengine.wasm (wasip1 reactor).
examples
complex/go command
A complex statement in three languages, one JSON document (docs/examples/complex-query.md shows the same product-domain shapes).
A complex statement in three languages, one JSON document (docs/examples/complex-query.md shows the same product-domain shapes).
thin-slice/go command
S1 demo (Go): one statement, three languages, one JSON.
S1 demo (Go): one statement, three languages, one JSON.
tests
conformance/check command
Conformance checker: runs the three runners (or reads their outputs) and compares each vector's statements and result against tests/conformance/vectors.json after canonicalizing the JSON (sorted keys, shortest numbers).
Conformance checker: runs the three runners (or reads their outputs) and compares each vector's statements and result against tests/conformance/vectors.json after canonicalizing the JSON (sorted keys, shortest numbers).
conformance/runner_go command
Conformance runner (Go).
Conformance runner (Go).
interfaces/check command
Interface checks compare native declarations to a reviewed symbol manifest and enforce common method contracts independently of the generated source.
Interface checks compare native declarations to a reviewed symbol manifest and enforce common method contracts independently of the generated source.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL