# Database Resource Handler The `DatabaseResourceHandler` manages database resources within the CleverAgents resource model. It supports four database types (`postgres`, `mysql`, `sqlite`, `duckdb`) and implements the full `ResourceHandler` protocol including CRUD operations and checkpoint/rollback methods. Introduced in v3.7.0 (issues #1241, #836) as part of the ResourceHandler Protocol Completion epic (#825). **Module**: `cleveragents.resource.handlers.database` --- ## Supported Resource Types | Type | Kind | Sandbox Strategy | Connection | |------|------|-----------------|------------| | `sqlite` | physical | `transaction_rollback` | File path | | `postgres` | physical | `transaction_rollback` | Host/port/dbname or connection string | | `mysql` | physical | `transaction_rollback` | Host/port/dbname or connection string | | `duckdb` | physical | `transaction_rollback` | File path or in-memory | All types are user-addable via `agents resource add`. ### CLI Arguments **SQLite / DuckDB:** | Argument | Type | Required | Description | |----------|------|----------|-------------| | `--path` | string | Yes | Path to the database file | **PostgreSQL / MySQL:** | Argument | Type | Required | Description | |----------|------|----------|-------------| | `--connection-string` | string | No | Full connection string (overrides individual args) | | `--host` | string | No | Database server hostname (default: `localhost`) | | `--port` | integer | No | Database server port | | `--dbname` | string | No | Database name | | `--user` | string | No | Database user | | `--password` | string | No | Database password (masked in logs) | --- ## Content CRUD Methods All methods raise `ValueError` if the resource has no location. ### `read(*, resource, path="") → Content` Returns the database schema or connection information. | Database type | Behaviour | |---------------|-----------| | SQLite | Queries `sqlite_master` for tables, views, and indexes; returns DDL as UTF-8 text | | Remote (postgres, mysql, duckdb) | Returns a connection-info summary with credentials masked | The `path` argument is ignored for database resources (schema is always read). ### `write(*, resource, path, data) → WriteResult` Executes SQL statements against the database. | Database type | Behaviour | |---------------|-----------| | SQLite | Executes the SQL in `data` (decoded as UTF-8) using `executescript()` | | Remote | Returns `WriteResult(success=False, message="not supported")` | ### `delete(*, resource, path="") → DeleteResult` Drops a table from the database. | Database type | Behaviour | |---------------|-----------| | SQLite | Executes `DROP TABLE IF EXISTS ` | | Remote | Returns `DeleteResult(success=False, message="not supported")` | If `path` is empty, returns a failure result (no-op rather than dropping all tables). ### `list_children(*, resource) → list[str]` Lists the tables and views in the database. | Database type | Behaviour | |---------------|-----------| | SQLite | Queries `sqlite_master` for tables and views; returns their names | | Remote | Returns `[]` | ### `diff(*, resource, other_location) → DiffResult` Compares the schema of this database against another location by content hash. Both sides are read via `read()`. If both sides are absent (empty content), the `EMPTY_CONTENT_HASH` sentinel is used and the result is `no_change=True`. --- ## Checkpoint Methods Checkpoints allow the plan execution engine to save and restore database state during the Apply phase. ### `create_checkpoint(*, resource) → CheckpointResult` Creates a savepoint in the database. | Database type | Behaviour | |---------------|-----------| | SQLite | Opens a connection, executes `SAVEPOINT `, and holds the connection open | | Remote | Returns a content-hash-based checkpoint (no actual savepoint) | The returned `CheckpointResult.checkpoint_id` is used to identify the savepoint for `rollback_to()`. ### `rollback_to(*, resource, checkpoint_id) → RollbackResult` Rolls back to a previously created savepoint. | Database type | Behaviour | |---------------|-----------| | SQLite | Executes `ROLLBACK TO SAVEPOINT ` and closes the held connection | | Remote | Returns `RollbackResult(success=False, message="not supported")` | If `checkpoint_id` is not found (e.g. the process restarted), returns a failure result rather than raising. --- ## Error Handling All methods handle errors gracefully: - SQLite errors are caught and returned as failure results with the error message in `metadata["error"]`. - Credentials in connection strings are masked using `cleveragents.shared.redaction.mask_database_url()` before appearing in logs or error messages. - No unhandled exceptions propagate from CRUD or checkpoint methods. --- ## CLI Usage ```bash # Add a SQLite database resource agents resource add sqlite local/my-db --path /path/to/db.sqlite # Add a PostgreSQL database resource agents resource add postgres local/pg-db \ --host localhost --port 5432 --dbname myapp --user admin # Add using a full connection string agents resource add postgres local/pg-db \ --connection-string "postgresql://admin:secret@localhost:5432/myapp" # List database resources agents resource list --type sqlite # Show database details agents resource show local/my-db ``` --- ## Architecture Notes `DatabaseResourceHandler` extends `BaseResourceHandler` and uses the `transaction_rollback` sandbox strategy. SQLite checkpoints hold an open `sqlite3.Connection` with an active `SAVEPOINT` in the `_sqlite_checkpoints` dict (keyed by checkpoint ID). The connection is closed when `rollback_to()` is called or when the handler is garbage collected. --- ## Related Documentation - [Resource Handlers](resource_handlers.md) — handler protocol overview - [Resource Types (Built-in)](resource_types_builtin.md) — all built-in types - [Checkpointing](checkpointing.md) — checkpoint and rollback system - [Sandbox](sandbox.md) — sandbox strategies