KeiSeiKit-1.0/_primitives/_rust/kei-memory-postgres/src/store.rs
Parfii-bot 0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

79 lines
2.5 KiB
Rust

// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 <author org>
//!
//! Connection wrapper. `tokio_postgres::connect` returns `(Client,
//! Connection)`; the Connection future must be polled by an executor
//! task, otherwise the Client deadlocks. We spawn it on the current
//! tokio runtime as part of [`PgStore::connect`].
use crate::error::Result;
use crate::schema::apply_schema;
use tokio_postgres::{Client, NoTls};
/// Owns the live `tokio_postgres::Client`. Cheap to wrap in `Arc` and
/// share across many [`crate::PostgresBackend`] instances.
pub struct PgStore {
client: Client,
}
impl PgStore {
/// Connect to PostgreSQL using a libpq-style connection string and
/// spawn the driver task on the current tokio runtime.
///
/// Errors propagate from `tokio_postgres::connect`. Connection-task
/// errors are logged to `stderr` (the Client surfaces them on the
/// next operation as well).
pub async fn connect(conn_string: &str) -> Result<Self> {
let (client, connection) =
tokio_postgres::connect(conn_string, NoTls).await?;
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("kei-memory-postgres: connection error: {e}");
}
});
Ok(Self { client })
}
/// Bootstrap the schema. Idempotent.
pub async fn init(&self) -> Result<()> {
apply_schema(&self.client).await
}
/// Borrow the underlying client. Used by `PostgresBackend`; not
/// exposed for direct SQL by external callers (use the trait
/// surface instead).
pub(crate) fn client(&self) -> &Client {
&self.client
}
}
/// Lightweight validation: a libpq URI must start with `postgres://` or
/// `postgresql://`, otherwise the driver rejects it. We don't fully
/// parse — just sniff for the obvious mistake before a network call.
pub fn looks_like_pg_url(s: &str) -> bool {
s.starts_with("postgres://")
|| s.starts_with("postgresql://")
|| s.contains("host=")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn url_sniff_accepts_uri_form() {
assert!(looks_like_pg_url("postgres://u:p@h/db"));
assert!(looks_like_pg_url("postgresql://u@h/db"));
}
#[test]
fn url_sniff_accepts_kv_form() {
assert!(looks_like_pg_url("host=localhost user=kei dbname=kei"));
}
#[test]
fn url_sniff_rejects_obvious_garbage() {
assert!(!looks_like_pg_url("sqlite:///tmp/x.db"));
assert!(!looks_like_pg_url(""));
}
}