Metadata-Version: 2.4
Name: cavedb
Version: 1.0.2
Summary: Async JSONL-based database with ORM bindings to Python dataclasses
Author-email: Nikita Belomestnykh <medbeebs@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/medbeebs/cavedb
Project-URL: Repository, https://github.com/medbeebs/cavedb
Project-URL: Issues, https://github.com/medbeebs/cavedb/issues
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development
Classifier: Typing :: Typed
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Framework :: AsyncIO
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Database :: Front-Ends
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: aiofiles>=25.1.0
Requires-Dist: orjson>=3.11.3
Dynamic: license-file

# cavedb

![PyPI - License](https://img.shields.io/pypi/l/cavedb?style=for-the-badge)
![PyPI - Types](https://img.shields.io/pypi/types/cavedb?style=for-the-badge)
![PyPI - Version](https://img.shields.io/pypi/v/cavedb?style=for-the-badge)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/cavedb?style=for-the-badge)

An async JSONL-based **database** with ORM bindings to Python dataclasses.

Name is stylised all-lowercase.

## Features

Define table models as dataclasses-subclasses of Entity to begin using ORM features.

```python
from cavedb import Entity

# A user.jsonl table, will create user.jsonl file
@dataclass
class User(Entity):
    usename: str                           # Required field
    age: int | None = field(default=None)  # Nullable field
```

Start using **threadsafe** and **fully async** database Sessions to query and write data to storage.

```python
from cavedb import Session

# Zero configuration required
async with Session() as session:
    user = await session.select(User).first()
    # -> User(_id=UUID(bf911f00-117e-4a66-8f62-e0429492d5b0), username='john', age=25)
```

Full typing support through Generics. You will never have to guess what is returned.

```python
session.select(User)          # -> <SelectQuery>
session.select(User).first()  # -> <User | None>
session.select(User).stream() # -> <AsyncGenerator[User, None]>
session.select(User).all()    # -> <list[User]>
User.id                       # -> <EntityField>
User.id != None               # -> <FieldClause>
```

Stored data is in **JSONL** format files one-per-table and _easily human-readable_!

```json
{"_id":"bf911f00-117e-4a66-8f62-e0429492d5b0","username":"john","age":25}
{"_id":"fc4d0ada-6ea0-423e-a096-973a3a2779ee","username":"julia","age":27}
{"_id":"b3f647bf-d15e-4891-b383-2951f099a9a3","username":"jacob","age":null}
```

Create queries with ease:

```python
users = await session.select(User).where(
    User.name != "john",
    User.age != None,
).all()
# -> [User(_id=UUID(fc4d0ada-6ea0-423e-a096-973a3a2779ee), username='julia', age=27)]
```

Upsert objects through session:

```python
async with Session() as session:
    user = User(name="jack", age=50)
    user.id # -> UUID(...) - Readonly, already managed for you

    # Use just as any other dataclass
    user.age -= 23

    # Register in session for upserting
    session.add(user)

    # Commit changes (autocommit is set on session close - if no exceptions occur)
    await session.commit()

    # Choose your own paradigm: Commit As You Go / Unit Of Work
```

Threadsafe and true async when working with persistant storage in files.

## Limitations

1. Required PK field `id` as `UUID`.
2. Missing FK relations and JOIN/select in load operations
