Typed collections backed by NATS JetStream KV
Project description
Brainless DB
Typed collections backed by NATS JetStream KV. In-memory with background sync.
Quick Start
from typing import Annotated
from msgspec import Meta
from brainlessdb import BrainlessDB, BrainlessDBFeat, BrainlessStruct
class UserV1(BrainlessStruct):
id: Annotated[int, Meta(extra={"brainlessdb_flags": BrainlessDBFeat.INDEX})]
name: Annotated[str, Meta()] = ""
db = BrainlessDB(nats, namespace="app")
await db.start()
users = db.collection(UserV1)
await users.watch() # start watching for remote changes
# Create
user = users.add(UserV1(id=1, name="Alice"))
# Update
user.name = "Bob"
user.save() # marks dirty, schedules flush
# Query (async, auto-loads from NATS)
user = await users.find(id=1) # uses index
all_users = await users.filter(lambda u: u.id > 0)
await db.stop()
When to Use What
| Class | Use for | Has UUID | Stored in |
|---|---|---|---|
BrainlessStruct |
Main entities (User, Order, etc.) | Yes | Own bucket(s) |
Struct (msgspec) |
Nested data, app-local data | No | Inside parent entity |
from msgspec import Struct
from brainlessdb import BrainlessStruct
# App-local data - plain Struct (no UUID, not an entity)
class UcsLocal(Struct):
sid: int = 0
pointer: int = 0
# Nested data - plain Struct
class Address(Struct):
street: str = ""
city: str = ""
# Main entity - BrainlessStruct (has UUID, stored in NATS)
class UserV1(BrainlessStruct):
id: Annotated[int, Meta()]
address: Optional[Address] = None # nested struct
_: Optional[UcsLocal] = None # app-local struct
Global API
import brainlessdb
await brainlessdb.setup(nats, namespace="app")
users = brainlessdb.collection(UserV1)
await brainlessdb.flush() # manual flush
await brainlessdb.stop()
Field Types
Config Fields (default)
Persistent data synced across all instances:
class UserV1(BrainlessStruct):
id: Annotated[int, Meta()]
name: Annotated[str, Meta()] = ""
State Fields
Ephemeral data (separate bucket, faster sync):
class UserV1(BrainlessStruct):
id: Annotated[int, Meta()]
status: Annotated[int, Meta(extra={"brainlessdb_flags": BrainlessDBFeat.STATE})] = 0
Indexed Fields
Fast O(1) lookups:
class UserV1(BrainlessStruct):
id: Annotated[int, Meta(extra={"brainlessdb_flags": BrainlessDBFeat.INDEX})]
Combine flags with |:
counter: Annotated[int, Meta(extra={"brainlessdb_flags": BrainlessDBFeat.INDEX | BrainlessDBFeat.STATE})] = 0
App-Local Fields
Data private to each namespace. Use plain Struct (not BrainlessStruct):
from msgspec import Struct
# Plain Struct - just data, no UUID
class UcsLocal(Struct):
sid: int = 0
class AriLocal(Struct):
channel_id: str = ""
# Entity with app-local field
class UserV1(BrainlessStruct):
id: Annotated[int, Meta()]
_: Union[UcsLocal, AriLocal, None] = None
Each namespace only sees its own local data:
# In UCS app (namespace="ucs")
user = UserV1(id=1, _=UcsLocal(sid=123))
users.add(user)
user._.sid # 123
# In ARI app (namespace="ari")
user = await users.find(id=1)
user._ # None - no ARI local data yet
CRUD Operations
# Add/update
item = coll.add(MyStruct(...))
# Update via save()
item.field = value
item.save()
# Get by UUID
item = coll.get(uuid_str)
# Delete
coll.delete(item)
coll.delete(uuid_str)
# Clear all
coll.clear()
# Dict-style access
item = coll[uuid_str]
del coll[item]
len(coll)
for item in coll: ...
item in coll
Filtering
# By predicate
items = await coll.filter(lambda i: i.priority > 5)
# By field (uses index if available)
items = await coll.filter(status=1)
# Nested fields
items = await coll.filter(address__city="Prague")
# Combined
items = await coll.filter(lambda i: i.active, status=1, limit=10)
# Find single
item = await coll.find(id=123)
# Sort
items = await coll.order_by("priority", reverse=True)
Events
Callbacks fire on remote changes by default. Set trigger_local=True to also fire on local changes.
# Any change
coll.on_change(lambda old, new: print(f"{old} -> {new}"))
# Deletion
coll.on_delete(lambda item: print(f"deleted: {item}"))
# Specific property
coll.on_property_change(
status=lambda item, field, old, new: print(f"{field}: {old} -> {new}")
)
# Also trigger on local changes
coll.on_change(my_callback, trigger_local=True)
Watching
# Watch single collection
await coll.watch()
await coll.unwatch()
# Watch all collections
await db.watch()
await db.unwatch()
Watch updates in-memory entities automatically when remote changes arrive.
Flush Scheduling
- Changes schedule flush after
flush_interval(default 100ms) - Multiple changes batch into single flush
flush_interval=0flushes immediatelyawait db.flush()forces immediate flush
Multi-Bucket Architecture
Each struct uses up to 3 NATS KV buckets:
{StructName}- config fields (persistent){StructName}-State- state fields (ephemeral){StructName}-{LocalClass}- app-local fields (per namespace)
Example: UserV1 with UCS namespace creates:
UserV1(config)UserV1-State(if state fields exist)UserV1-UcsLocal(local data for UCS app)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file brainlessdb-0.2.0.tar.gz.
File metadata
- Download URL: brainlessdb-0.2.0.tar.gz
- Upload date:
- Size: 40.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
914f835cce04914d3f39fe2a97e4accf67654d24d5e768ca4784301f9073d91f
|
|
| MD5 |
4c1dcea8aac62f97f6989a0965c6256f
|
|
| BLAKE2b-256 |
5ceaacadfa87f10de2b672729be4563bedc6b37d017980b1d88d5023b3c677a1
|
File details
Details for the file brainlessdb-0.2.0-py3-none-any.whl.
File metadata
- Download URL: brainlessdb-0.2.0-py3-none-any.whl
- Upload date:
- Size: 11.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4fbf645015ca4c23ba7999fda2131348bb6e2d0fa141b0899d494fbf0842bda9
|
|
| MD5 |
efafc36db0c0b0e93abbc2e8bb1f292a
|
|
| BLAKE2b-256 |
07bb37fcbdb92bf87a9bcd67383585b6d00dbf6e9959f0fc1b578d8cadd18405
|