Skip to content

feat: expose StatementType enum via Rust API - #7

Merged
adsharma merged 1 commit into
LadybugDB:mainfrom
russellromney:statement-type-api
Mar 31, 2026
Merged

adsharma merged 1 commit into
LadybugDB:mainfrom
russellromney:statement-type-api

Conversation

@russellromney

Copy link
Copy Markdown
Contributor

Summary

Expose the existing core StatementType enum (common/enums/statement_type.h) through the Rust FFI so consumers can inspect whether a prepared statement is a read, write, DDL, etc.

4 files changed, no new files, no changes to core engine.

Changes

File Change
include/lbug_rs.h Include core statement_type.h, add inline prepared_statement_get_statement_type() wrapper
src/ffi.rs CXX bridge: StatementType enum mirroring core + extern function
src/connection.rs PreparedStatement::get_statement_type() public method
src/lib.rs Re-export StatementType

Motivation

HA wrappers around LadybugDB need to know whether a query is a mutation (forward to leader) or a read (execute locally). Currently requires string-parsing. This exposes what the core already knows.

Usage

let stmt = conn.prepare("CREATE NODE TABLE Person(id INT64, PRIMARY KEY(id))")?;
match stmt.get_statement_type() {
    StatementType::CREATE_TABLE => { /* mutation */ }
    StatementType::QUERY => { /* read */ }
    _ => {}
}

Add FFI bindings for the existing core StatementType enum
(common/enums/statement_type.h) and get_statement_type() on
PreparedStatement so Rust consumers can inspect query types.

- include/lbug_rs.h: include core statement_type.h, add inline wrapper
- src/ffi.rs: CXX bridge enum mirroring core + extern function
- src/connection.rs: pub get_statement_type() on PreparedStatement
- src/lib.rs: re-export StatementType
@russellromney

Copy link
Copy Markdown
Contributor Author

I'm working on some ideas around replication and availability. Replication wrappers need to be able to view the statement types that ladybug already knows internally. I've been using a local fork with this change but as I'm looking to publish to crates.io, I'd like to upstream them. Thanks for the improved project organization here, it's really coming along!

@adsharma

Copy link
Copy Markdown
Contributor

Thanks for your contribution.

In the future we could have these enums in typespec and then codegen both C++ and Rust declarations from the same source.

https://github.com/adsharma/tsc-py

@adsharma
adsharma merged commit 3ed3b30 into LadybugDB:main Mar 31, 2026
1 check passed
@russellromney

Copy link
Copy Markdown
Contributor Author

That's a great idea, and exactly what claude suggested when i berated it for apparently doing duplicative work and re-opening what i felt was a redundant PR. To be fair, the statement types don't change very often and new languages are created only rarely, so having claude write them once per language doesn't feel too bad.

@russellromney

Copy link
Copy Markdown
Contributor Author

Also - thanks for your exceptional response time here. Saved me a few days of waiting.

@adsharma

adsharma commented Mar 31, 2026 •

Copy link
Copy Markdown
Contributor

Looking to codegen much of the repetitive WAL code from typespec defs and make it more robust, so adding a field to the WAL record doesn't result in backward incompat behavior. The current WAL implementation is missing record size field, so we can't safely replay WAL from a previous version.

That's probably a good time to revisit this.

@russellromney

Copy link
Copy Markdown
Contributor Author

Got it. Agree..

@adsharma

adsharma commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

so consumers can inspect whether a prepared statement is a read, write, DDL

This came up in an internal discussion about whether this API is sustainable in the long run.

How do you intend to use this API?

@russellromney

russellromney commented Apr 29, 2026 •

Copy link
Copy Markdown
Contributor Author

The use case is something I'm tring out around "Litestream for LadybugDB" — a journal-based replication layer ( hakuzu on graphstream ) where followers replay Cypher from S3, with leader election via hadb.

Two things I need on every query:

  1. Read vs write classification. Reads run locally on followers; writes are forwarded to the leader and
    journaled. Today I keyword-scan (is_mutation), which forces me to conservatively treat CALL as a write
    — I can't tell CALL db.checkpoint() (mutates) from CALL current_setting(...) (read-only). Missing a
    write would be catastrophic; over-journaling is just wasteful.
  2. Deterministic rewrite before journaling. current_timestamp(), gen_random_uuid(), current_date() have be rewritten to concrete params before the query is journaled, or leader and followers diverge (rewriter.rs). That work only needs to happen for writes -accurate classification gates it.

StatementType is the oracle that mutation detection, the deterministic rewriter, and journal entry all hang off of.

On sustainability: I take the point. If a narrower is_read() / is_write() / is_ddl() view is a more boundary than the full enum, I'd happily switch — that's really all my code branches on. The enum was just the lowest-friction thing to expose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants