systemprompt_database/lib.rs
1//! # systemprompt-database
2//!
3//! `PostgreSQL` infrastructure for systemprompt.io: a thin `SQLx`-backed pool,
4//! generic repository traits, dynamic-query primitives for admin tooling, and
5//! lifecycle helpers (schema installation, extension migrations, validation).
6//!
7//! ## Public API surface
8//!
9//! - [`Database`] / [`DbPool`] — owned pool wrapper with optional split
10//! read/write providers.
11//! - [`DatabaseProvider`] — dyn-safe trait abstracting
12//! query/execute/transaction primitives across providers (currently only
13//! `PostgreSQL`).
14//! - [`PostgresProvider`] — the `PostgreSQL` implementation.
15//! - [`DatabaseResult`] — result alias over the workspace's single
16//! [`systemprompt_traits::RepositoryError`].
17//! - [`MigrationService`], [`install_extension_schemas_full`] — lifecycle
18//! helpers driving extension-supplied DDL.
19//! - [`DatabaseAdminService`], [`QueryExecutor`], [`AdminSql`],
20//! [`SafeIdentifier`] — admin/introspection layer used by the CLI.
21//! - [`resilience`] — domain-agnostic resilience primitives
22//! ([`resilience::ResilienceGuard`], [`resilience::CircuitBreaker`],
23//! [`resilience::Bulkhead`], [`resilience::retry_async`]) wrapping outbound
24//! calls; the crate's own connection and transaction retries run on them.
25//!
26//! ## Feature flags
27//!
28//! This crate currently has no Cargo features; everything compiles
29//! unconditionally. The `[package.metadata.docs.rs]` block is in place so
30//! `--all-features` documentation builds remain stable as features are added.
31//!
32//! ## sqlx allowlist
33//!
34//! Static SQL goes through the compile-time-verified `sqlx::query!` /
35//! `query_as!` / `query_scalar!` macros. Runtime/dynamic SQL is contained to
36//! two paths whose contract is dynamic SQL by design; the `lint-sqlx` gate
37//! allows runtime `sqlx::query` only there:
38//!
39//! - `src/admin/` — admin CLI surfaces (introspection, restricted query
40//! executor) where the SQL is the user input.
41//! - `src/services/postgres/` — the dyn-safe `DatabaseProvider` implementation,
42//! transaction wrapper, type-erased helpers and `PostgreSQL` schema
43//! introspection.
44//! - `src/projection/` — `drain_with_sql` calls the projector function the
45//! caller names (validated as a bare identifier); the name is the only
46//! dynamic part and no value is interpolated.
47//!
48//! Every other call site uses verified macros.
49//!
50//! ## Data paradigm
51//!
52//! [`projection`] documents the rule every analytics-shaped read follows:
53//! store the answer when the row is written, read the stored answer. Raw
54//! ledger tables are read by projectors and single-entity detail queries
55//! only; the queue, drainer and backfill detector that make that hold live
56//! there and in [`backfill_statements`].
57//!
58//! Copyright (c) systemprompt.io — Business Source License 1.1.
59//! See <https://systemprompt.io> for licensing details.
60
61pub mod admin;
62pub mod error;
63pub mod extension;
64pub mod lifecycle;
65pub mod models;
66pub mod projection;
67#[macro_use]
68pub mod repository;
69pub mod resilience;
70pub mod services;
71
72pub use extension::DatabaseExtension;
73
74pub use models::{
75 ColumnInfo, DatabaseInfo, DatabaseQuery, DatabaseTransaction, DbValue, FromDbValue, IndexInfo,
76 JsonRow, QueryResult, QueryRow, QuerySelector, TableInfo, ToDbValue, parse_database_datetime,
77};
78
79pub use services::{
80 BoxFuture, Database, DatabaseCliDisplay, DatabaseExt, DatabaseProvider, DbPool, PoolConfig,
81 PostgresProvider, SqlExecutor, mark_schema_changed, with_transaction_retry,
82};
83
84pub use error::DatabaseResult;
85pub use lifecycle::{
86 AppliedMigration, BOOTSTRAP_ADVISORY_LOCK_KEY, BackfillStatement, BaselineStamp,
87 BootstrapLockGuard, ChecksumDrift, DeferredForeignKey, ExpensiveStatement,
88 ExtensionMigrationStatus, FkDeferralError, ForeignKeyDrift, FreshnessCheck, HOT_TABLES,
89 MarkAppliedOutcome, MigrationConfig, MigrationCost, MigrationResult, MigrationService,
90 MigrationStatus, OrphanMigrationLedger, OrphanedMigration, PROJECTION_BACKLOG,
91 PendingMigration, RepairResult, ReplicaStatus, SchemaCurrency, SchemaInstallReport,
92 SchemaResidue, SlotCollision, SplitCreateTable, TombstonedSlot, UndeclaredTable,
93 audit_migration_cost, audit_one, audit_schema_residue, backfill_statements,
94 check_migration_references, check_trigger_routines, install_extension_schemas_full,
95 is_retirement, replica_status, schema_currency, split_create_table_foreign_keys,
96 validate_column_exists, validate_database_connection, validate_table_exists,
97 validate_write_pool_is_primary,
98};
99pub use repository::{
100 CreateServiceInput, INSTANCE_CLAIM_CLASS, InstanceClaim, InstanceClaimError, PgDbPool,
101 ServiceConfig, ServiceModule, ServiceRepository, ServiceStatus, UpsertServiceProcessInput,
102};
103
104pub use admin::{
105 AdminSql, AdminSqlError, DEFAULT_READONLY_ROW_LIMIT, DatabaseAdminService, IdentifierError,
106 QueryExecutor, QueryExecutorError, SafeIdentifier,
107};
108
109use systemprompt_traits::DatabaseHandle;
110
111impl DatabaseHandle for Database {
112 fn is_connected(&self) -> bool {
113 !self.pool().is_closed() && !self.write_pool().is_closed()
114 }
115
116 fn as_any(&self) -> &dyn std::any::Any {
117 self
118 }
119}