Skip to content

Repository files navigation

Bridge Logo

Bridge

Performance: Native FFIAsync: Tokio/AsyncioSecurity: SQL_Injection_ProofReliability: Circuit_BreakerObservability: OpenTelemetryPython 3.10+Rust 1.70+sqlx 0.7

Bridge is a cross-language ORM (Rust+Python). It is lightweight, secure by default.


Documentation

Full documentation is available in the docs/ directory:


Architecture

Bridge uses the Performance Bridge principle by splitting the ORM into two distinct parts to maximize both Speed and Developer Ergonomics:

  1. Expression Layer (Python): A thin, expressive API for intuitive queries and models. Handles high-level logic, task-local identity mapping, dirty tracking, hooks, and eager loading orchestration.
  2. Execution Engine (Rust): An ultra-fast core built on sqlx and tokio. Handles connection pooling, SQL construction, row hydration, circuit breaking, and cross-language telemetry.

Instead of slow HTTP or JSON-over-pipe communication, Bridge utilizes Native Memory Bindings (FFI via PyO3), allowing data to flow between Python and Rust with near-zero latency.


Quick Start

frombridgeimportBaseModel, HasMany, BelongsToMany, transaction, connectclassUser(BaseModel):
table="users"_fields= ["id", "username", "email"]
id: strusername: stremail: strasyncdefmain():
pool=awaitconnect("postgres://localhost/mydb")
asyncwithtransaction() astx:
user=awaitUser.create(tx, username="alice", email="alice@example.com")
found=awaitUser.find_one(tx, username="alice")
print(found.to_dict())

Key Features

FeatureDescription
Declarative ModelsDefine models with Python type hints; auto-registration with Rust metadata
Fluent Query Builder.filter(), .limit(), .select(), .prefetch_related(), .first()
CRUD OperationsSingle and bulk insert, update, delete with automatic type coercion
Unit of Work / SessionIdentity map, dirty tracking with snapshot-based diff, automatic flush on commit
Eager LoadingBatch SELECT IN for HasMany, BelongsToMany, and SelfReferential relations
Lazy LoadingPer-relation lazy proxies that resolve on first access
Lazy Streamingfetch_lazy() returns an async iterator for large result sets
Arrow IPCfetch_arrow() uses Apache Arrow for zero-copy data transfer (feature data-science)
Schema Migration EngineSnapshot-based diffing generates UP/DOWN SQL for evolving schemas
CLI Toolsbridge reflect, bridge makemigrations, bridge migrate
Schema IntrospectionReflect existing database tables into Python model classes
Admin PanelAuto-generated FastAPI admin with JWT auth, CSRF, rate limiting (optional)
REST API GeneratorAuto-generate FastAPI routers from model classes
Lifecycle Hooksbefore_create, after_create, before_delete, after_delete decorators
Optimistic ConcurrencyVersion-guarded updates via _bridge_row_version column
OpenTelemetryDistributed tracing with OTLP export, slow query logging
Pytest Integrationdb_session fixture with transactional rollback
factory_boyBridgeFactory base class for async test data creation

Supported SQL Databases

Bridge provides native and protocol-compatible support for a wide range of modern and enterprise databases:

DatabaseCompatibilitySpecific Optimizations
PostgreSQLNativeFull async support via sqlx.
SQLiteNativeHigh-performance local and embedded storage.
MySQLNativeStandard industry support with backtick quoting.
MariaDBNativeSpecialized MariaDB dialect optimizations.
OracleCustomCustom :1 placeholders & FETCH NEXT pagination.
MS SQL ServerNativeSupport for [] quoting and @p1 placeholders.
CockroachDBPostgres-ProtocolOptimized for distributed UUIDs and SERIAL8.
PlanetScaleMySQL-ProtocolOptimized for Vitess-based serverless pooling.
NeonPostgres-ProtocolNative support for serverless Postgres architecture.
YugabyteDBPostgres-ProtocolBuilt for distributed SQL workloads.
Cloudflare D1SQLite-ProtocolOptimized for serverless SQLite environments.
DoltMySQL-ProtocolNative support for versioned SQL databases.

Security Mandate

When I started designing Bridge, my absolute priority was Security. I've tried my best to build a secure wall around your data.

Here is how Bridge protection works around your data:

  1. Forbidden String Interpolation: String interpolation in queries is strictly forbidden. If it's not parameterized, it doesn't run. Period.
  2. Rust-Level Guardrails: Before any dynamic SQL identifier reaches the database, the Rust Engine forces it through a strict regular expression validator. No sneak attacks.
  3. Panic-Proof FFI: The language boundary is wrapped in catch_unwind blocks. If something goes wrong in the Rust core, your Python app won't crash; it gets a clean exception.
  4. Strict Type Coercion: We don't guess types. Every piece of data crossing the bridge is validated against your model's metadata. No silent data corruption.
  5. The Circuit Breaker: If your database starts failing or slowing down, our internal circuit breaker trips. This protects your application from cascading failures and keeps your threads alive.

Feature Flags

Bridge uses Cargo feature flags to keep the core lightweight:

FeatureDescription
defaultNo default features — build only what you need
allow-raw-sqlEnables execute_raw() and Raw SQL expressions
data-scienceEnables Arrow IPC via fetch_arrow()
java-interopEnables JNI bindings for Java interop

CLI Commands

bridge reflect --url <DATABASE_URL> --table <TABLE_NAME> # Introspect table → Python model
bridge makemigrations --dialect <sqlite|postgres> # Generate migration SQL from models
bridge migrate --url <DATABASE_URL> # Apply pending migrations

Rules

Collaborator Must Follow This Rules:

  1. Self-Documenting Code: Meaningful identifiers are a must. If something doesn't make sense to you, rename it so its logic inspires clarity.
  2. Single Responsibility Principle: Each method must have only one responsibility and be of equal simplicity.
  3. D.R.Y. Principle: Do not duplicate common functionality; instead, use a single reference point when using common functionality.
  4. Meaningful Identifier: Write your identifiers as if they were spoken words. Use common sense when naming them; avoid unnecessary jargon; choose names with clarity as the focus.
  5. Avoid Magic Numbers/Strings: Use named constants for hard-coded values so their meaning is clear.
  6. Explicit Handling of Errors: Fix the actual problem first (fix the code), then use typed return values or exception handling to guarantee errors are visible and cannot go unaddressed.
  7. Consistent Formatting: Use automated tools for visual consistency across the entire codebase.
  8. Provide Explanation to your Intent: Comment on your code to explain why you made those coding decisions, not just what the code is doing.
  9. FFI Boundary Safety: Any new feature crossing the Python/Rust boundary MUST be wrapped in the ffi_guard! macro to ensure the application remains crash-safe.
  10. Dialect Agnosticism: Never write SQL specific to one database in the core engine. Always use the Dialect trait to ensure changes work across all supported databases.
  11. Telemetry Integrity: Every new database operation must include tracing spans. If we can't measure it, we shouldn't merge it.

Current Limitations

  • Eager Loading: Relations support both high-speed Lazy Loading (per-relation) and batch prefetch_related via QueryBuilder.with_relation() / .prefetch_related().
  • SQL Complexity: Advanced operations like CTEs and Window Functions require the execute_raw() fallback (requires allow-raw-sql feature).
  • Identity Isolation: The Identity Map is strictly scoped per asyncio.Task to ensure memory safety.
  • ALTER COLUMN Nullability: Changing column nullability via migration requires dialect-specific SQL syntax (SET NOT NULL / DROP NOT NULL).
  • Composite Foreign Keys: Relations assume single-column foreign keys; composite FKs are not yet supported.

Releases

Packages

Contributors

Languages