This release is a pre-release and may not be stable for production use.
datasette-transactions
A Datasette plugin providing an API for executing multiple SQL commands within a single transaction, with support for SQLite authorization callbacks to control table-level read/write access.
Installation
Install this plugin in the same environment as Datasette.
datasette install datasette-transactions
Usage
Begin a Transaction
POST /-/transactions/begin/<database>
Content-Type: application/json
{
"read": ["table1", "table2"],
"write": ["table1"],
"timeout_ms": 5000
}
Parameters:
read: List of tables the transaction can read fromwrite: List of tables the transaction can write totimeout_ms: Optional timeout in milliseconds (transaction auto-rolls back after this time)
Response:
{
"ok": true,
"transaction_id": "550e8400-e29b-41d4-a716-446655440000"
}
Required Permissions:
execute-sqlon the databaseview-tableon each table in thereadlistinsert-rowandupdate-rowon each table in thewritelist
Execute SQL
POST /-/transactions/<transaction_id>
Content-Type: application/json
{
"sql": "INSERT INTO table1 (name) VALUES (:name)",
"params": {"name": "Alice"}
}
Response:
{
"ok": true,
"rows": [],
"columns": [],
"truncated": false
}
For SELECT queries, rows contains the results as a list of objects.
Create a Savepoint
POST /-/transactions/<transaction_id>/savepoint
Content-Type: application/json
{
"name": "before_batch"
}
Response:
{
"ok": true,
"savepoint": "before_batch"
}
Release a Savepoint
POST /-/transactions/<transaction_id>/release
Content-Type: application/json
{
"name": "before_batch"
}
Rollback to a Savepoint
POST /-/transactions/<transaction_id>/rollback-to
Content-Type: application/json
{
"name": "before_batch"
}
Commit a Transaction
POST /-/transactions/commit/<transaction_id>
Response:
{
"ok": true
}
Rollback a Transaction
POST /-/transactions/rollback/<transaction_id>
Response:
{
"ok": true
}
Error Codes
| Status | Meaning |
|---|---|
| 400 | Bad request (invalid JSON, missing parameters, SQL error) |
| 403 | Permission denied (missing required permissions, table access denied) |
| 404 | Transaction or savepoint not found |
| 405 | Method not allowed (use POST) |
| 410 | Transaction expired (timed out) |
| 429 | Too many concurrent transactions (max 5 per database) |
Authorization
The plugin uses SQLite's set_authorizer() callback to enforce table-level permissions:
- Reading from tables not in
readlist is blocked - Writing to tables not in
writelist is blocked ATTACH DATABASEis always blocked
Concurrency
- Maximum 5 concurrent transactions per database
- Read-only transactions use
BEGIN DEFERRED(allows concurrent reads) - Write transactions use
BEGIN IMMEDIATE(exclusive lock)
Example: Batch Insert with Rollback on Error
import httpx
# Begin transaction
response = httpx.post(
"http://localhost:8001/-/transactions/begin/mydb",
json={"read": ["users"], "write": ["users"]}
)
tx_id = response.json()["transaction_id"]
try:
# Insert multiple rows
for user in users:
httpx.post(
f"http://localhost:8001/-/transactions/{tx_id}",
json={
"sql": "INSERT INTO users (name, email) VALUES (:name, :email)",
"params": user
}
)
# Commit if all succeeded
httpx.post(f"http://localhost:8001/-/transactions/commit/{tx_id}")
except Exception:
# Rollback on error
httpx.post(f"http://localhost:8001/-/transactions/rollback/{tx_id}")
raise
Development
To set up this plugin locally, first checkout the code:
cd datasette-transactions
uv run pytest # Run tests
This project follows TDD (Test-Driven Development). See CLAUDE.md for development guidelines.
Metadata
Release files for datasette-transactions 0.1a0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| datasette_transactions-0.1a0.tar.gz | 19.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| datasette_transactions-0.1a0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.4 kB
Release files / datasette_transactions-0.1a0.tar.gz
| Download URL | datasette_transactions-0.1a0.tar.gz |
|---|---|
| Size | 19.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b94f948cf16139595ca9fd484846829273c186e80e875d5d8e06e3d1aa1709b9
|
|
BLAKE2b-256 checksum How to use checksums |
e504114faa37c67a497d76fce140f97cb91928da9dc98f5010cebc22897bd564
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 10, 2026.
Transparency logRelease files / datasette_transactions-0.1a0-py3-none-any.whl
| Download URL | datasette_transactions-0.1a0-py3-none-any.whl |
|---|---|
| Size | 13.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
87581716bebd87e76c47072ea407f02acc41047eeef1805e6c5f3881bd356650
|
|
BLAKE2b-256 checksum How to use checksums |
428f17e3c95c5cd808fd237ff41ba428a2647e0aabc8f221bf2e5b14f29c0878
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 10, 2026.
Transparency log