Metadata-Version: 2.4
Name: fuckreplitdb
Version: 2.1.0
Summary: A small, persistent, dictionary-like JSON store for Python.
License-Expression: MIT
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: orjson
Dynamic: license-file

# fuckreplitdb

A small, persistent, dictionary-like JSON store for Python. `FuckReplitDB` is intended for projects that outgrow Replit DB but still need a simple local key-value API rather than a database server.

Data is kept in memory and written to disk after every mutation. Nested dictionaries and lists remain live, so changing a value deep inside the structure is persisted automatically.

## Features

- Familiar `MutableMapping` interface
- Automatic persistence for top-level and nested mutations
- Atomic file replacement to avoid partially written JSON files
- Thread-safe access within one `FuckReplitDB` instance
- Auto-vivifying nested dictionaries, matching common Replit DB usage
- Batched writes for efficient multi-step updates
- Fast JSON encoding and decoding with `orjson`

## Installation

```bash
python -m pip install fuckreplitdb
```

Python 3.8 or newer is required.

## Quick start

```python
from fuckreplitdb import FuckReplitDB

db = FuckReplitDB("data.json")

db["name"] = "Alice"
db.set("visits", 1)

print(db["name"])
print(db.get("missing", "fallback"))
print("visits" in db)

del db["visits"]
```

Every successful mutation is persisted before the operation returns.

## Nested data

Dictionaries and lists are recursively wrapped when assigned or loaded. Their mutations are written automatically:

```python
db["users"] = {
    "alice": {
        "roles": ["admin"],
        "settings": {"theme": "dark"},
    }
}

db["users"]["alice"]["roles"].append("editor")
db["users"]["alice"]["settings"]["theme"] = "light"
```

Missing keys accessed with brackets are created as nested dictionaries. This makes incremental construction concise:

```python
db["users"]["bob"]["profile"]["display_name"] = "Bob"
```

Use `get()` when a read should not create a missing key:

```python
profile = db.get("profile")
```

Nested lists support normal mutable-sequence operations, including assignment, deletion, `append`, `extend`, `insert`, `pop`, `remove`, `clear`, `reverse`, and `sort`.

## Batch multiple updates

A normal mutation performs an atomic disk write immediately. When making several related changes, use `batch()` to serialize and write only once:

```python
with db.batch():
    db["users"]["alice"]["visits"] = 12
    db["users"]["alice"]["roles"].append("moderator")
    db["last_updated_by"] = "worker-1"
```

Nested batch contexts are supported. The outermost context writes pending changes when it exits, including when the body raises an exception.

## Mapping API

`FuckReplitDB` implements `collections.abc.MutableMapping`, including:

```python
db[key] = value
db[key]
del db[key]
key in db
len(db)
iter(db)

db.get(key, default)
db.set(key, value)
db.setdefault(key, default)
db.update(values)
db.pop(key, default)
db.popitem()
db.clear()
db.keys()
db.values()
db.items()
```

`set()` is a convenience method that stores and returns the assigned value.

## Storage behavior

- The default path is `database.json`.
- Parent directories are created when needed.
- Files are encoded as indented, key-sorted JSON.
- Writes go to a temporary file, are flushed to disk, and then atomically replace the destination.
- A missing file starts as an empty database.
- Invalid JSON raises `orjson.JSONDecodeError` instead of silently replacing existing data.
- The JSON root must be an object; another root type raises `ValueError`.

Values must be serializable by `orjson`. In practice, use JSON-compatible strings, numbers, booleans, `None`, dictionaries, and lists. Dictionary keys are stored as strings.

## Concurrency and limitations

Operations and nested mutations are protected by a reentrant lock. This prevents threads sharing the same database instance from interleaving writes.

The library does not coordinate separate `FuckReplitDB` instances or separate processes that point to the same file. For multi-process access, transactions, queries, very large datasets, or high write throughput, use SQLite or another database designed for those workloads.

The full in-memory store is serialized on each write outside a `batch()` block, so batching is recommended for bulk changes.

## License

MIT
