Skip to content

Commit bc589b5

Browse files
Add PostgreSQL data store implementation
This commit adds a new PostgreSQL-based key-value store using asyncpg for async operations. The implementation follows the pattern established by MongoDB and other distributed stores. Features: - Uses asyncpg (>=0.30.0) for native async/await operations - Stores data in a single table with JSONB column for values - Supports TTL via expires_at timestamps with lazy cleanup - Implements all base store operations (get, put, delete, ttl) - Includes optimized bulk operations using PostgreSQL's batch capabilities - Provides collection enumeration and deletion - Comprehensive test suite following existing patterns - Marked as "Unstable" initially The store supports initialization via: - Connection pool injection - Connection URL - Individual connection parameters (host, port, database, etc.) Files changed: - Added PostgreSQLStore implementation and tests - Updated pyproject.toml to include asyncpg dependency - Updated README.md to document the new store 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: William Easton <strawgate@users.noreply.github.com>
1 parent edc0d89 commit bc589b5

File tree

7 files changed

+723
-7
lines changed

7 files changed

+723
-7
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ This monorepo contains two libraries:
88

99
## Why use this library?
1010

11-
- **Multiple backends**: DynamoDB, Elasticsearch, Memcached, MongoDB, Redis,
12-
RocksDB, Valkey, and In-memory, Disk, etc
11+
- **Multiple backends**: DynamoDB, Elasticsearch, Memcached, MongoDB,
12+
PostgreSQL, Redis, RocksDB, Valkey, and In-memory, Disk, etc
1313
- **TTL support**: Automatic expiration handling across all store types
1414
- **Type-safe**: Full type hints with Protocol-based interfaces
1515
- **Adapters**: Pydantic model support, raise-on-missing behavior, etc
@@ -123,7 +123,7 @@ pip install py-key-value-aio[memory]
123123
pip install py-key-value-aio[disk]
124124
pip install py-key-value-aio[dynamodb]
125125
pip install py-key-value-aio[elasticsearch]
126-
# or: redis, mongodb, memcached, valkey, vault, registry, rocksdb, see below for all options
126+
# or: redis, mongodb, postgresql, memcached, valkey, vault, registry, rocksdb, see below for all options
127127
```
128128

129129
```python
@@ -231,6 +231,7 @@ system, for access across multiple application nodes.
231231
| Elasticsearch | Unstable ||| `ElasticsearchStore(url="https://localhost:9200", api_key="your-api-key", index="kv-store")` |
232232
| Memcached | Unstable || ✖️ | `MemcachedStore(host="127.0.0.1", port=11211")` |
233233
| MongoDB | Unstable ||| `MongoDBStore(url="mongodb://localhost:27017/test")` |
234+
| PostgreSQL | Unstable || ✖️ | `PostgreSQLStore(url="postgresql://localhost:5432/mydb")` |
234235
| Redis | Stable ||| `RedisStore(url="redis://localhost:6379/0")` |
235236
| Valkey | Stable ||| `ValkeyStore(host="localhost", port=6379)` |
236237

key-value/key-value-aio/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ memory = ["cachetools>=5.0.0"]
3636
disk = ["diskcache>=5.0.0", "pathvalidate>=3.3.1",]
3737
redis = ["redis>=4.3.0"]
3838
mongodb = ["pymongo>=4.0.0"]
39+
postgresql = ["asyncpg>=0.30.0"]
3940
valkey = ["valkey-glide>=2.1.0"]
4041
vault = ["hvac>=2.3.0", "types-hvac>=2.3.0"]
4142
memcached = ["aiomcache>=0.8.0"]
@@ -67,7 +68,7 @@ env_files = [".env"]
6768

6869
[dependency-groups]
6970
dev = [
70-
"py-key-value-aio[memory,disk,redis,elasticsearch,memcached,mongodb,vault,dynamodb,rocksdb]",
71+
"py-key-value-aio[memory,disk,redis,elasticsearch,memcached,mongodb,postgresql,vault,dynamodb,rocksdb]",
7172
"py-key-value-aio[valkey]; platform_system != 'Windows'",
7273
"py-key-value-aio[keyring]",
7374
"py-key-value-aio[pydantic]",
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""PostgreSQL store for py-key-value-aio."""
2+
3+
try:
4+
from key_value.aio.stores.postgresql.store import PostgreSQLStore
5+
except ImportError as e:
6+
msg = "PostgreSQLStore requires py-key-value-aio[postgresql]"
7+
raise ImportError(msg) from e
8+
9+
__all__ = ["PostgreSQLStore"]

0 commit comments

Comments
 (0)