mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-11 14:27:48 +00:00
Introduce the Python<->Postgres value-mapping layer that the forthcoming Rust DBAPI2 backend will build on, plus the module scaffolding to hang it off (`synapse_rust.database.postgres`). `PgValue` is an owned representation of a bound parameter that implements `tokio_postgres::types::ToSql`, encoding into Postgres' binary wire format according to the column type from the prepared statement (so a single Python `int` becomes INT2/INT4/INT8 as appropriate, with range checks). `PythonPgFromSql` is the decode counterpart, turning a column's wire bytes back into the natural Python object (and SQL NULL into `None`). The two `accepts` lists are kept in sync via tests. The `value` submodule is exposed as `pub` for now so its not-yet-consumed public items don't trip clippy's `dead_code` lint; later changes that wire it into the cursor/connection code tighten that back up. Covers int / float / bool / str / bytes / None; lists and richer types (json, decimal, timestamps) are left to a follow-up. The unit tests exercise the whole mapping without a live Postgres server, including the float4 lossy narrowing, integer width boundaries, the WrongType and out-of-range paths, and the unsupported/non-UTF-8 decode errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 lines
1.6 KiB
Rust
38 lines
1.6 KiB
Rust
//! [`tokio_postgres`]-backed Postgres backend for the Rust `database` module.
|
|
//!
|
|
//! This module will grow the Python-facing `Connection` / `Cursor` classes and
|
|
//! the `connect` factory; for now it hosts the value-mapping layer ([`value`])
|
|
//! that converts between Python objects and Postgres' binary wire format.
|
|
//!
|
|
//! The driver itself is async; the eventual `Connection` / `Cursor` types will
|
|
//! drive it from sync Python methods via a shared multi-thread tokio runtime.
|
|
|
|
use pyo3::prelude::*;
|
|
use pyo3::types::PyModule;
|
|
|
|
// `pub` (rather than private) so the value-mapping types are reachable from the
|
|
// crate root as public API while nothing inside the crate consumes them yet.
|
|
// This is what stops clippy's `dead_code` lint from firing on them before the
|
|
// cursor/connection code (added in later changes) wires them up; the visibility
|
|
// is tightened back to private once that happens.
|
|
pub mod value;
|
|
|
|
/// Register the `postgres` submodule under the parent `database` module.
|
|
///
|
|
/// The `Connection` / `Cursor` classes and the `connect` factory are added in
|
|
/// later changes; for now this just creates the (otherwise empty) submodule so
|
|
/// the module tree — and the `value` mapping layer hanging off it — exists.
|
|
pub fn register_module(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
let child = PyModule::new(py, "postgres")?;
|
|
|
|
m.add_submodule(&child)?;
|
|
|
|
// We need to manually add the module to sys.modules to make `from
|
|
// synapse.synapse_rust.database import postgres` work.
|
|
py.import("sys")?
|
|
.getattr("modules")?
|
|
.set_item("synapse.synapse_rust.database.postgres", child)?;
|
|
|
|
Ok(())
|
|
}
|