Skip to main content
BinaryDB provides a simple and intuitive API for performing Create, Read, Update, and Delete (CRUD) operations on your key-value store.

Overview

All database operations work with an in-memory data structure (dict[str, Any]) that can be persisted to disk. The database tracks changes using an internal _dirty flag to know when data needs to be committed.

Key Validation

All operations validate keys before execution:
Key Requirements:
  • Keys must be strings (not integers, bytes, or other types)
  • Keys cannot be empty strings
  • Violating these rules raises KeyValidationError
database.py:65-70
def _validate_key(self, key: str) -> None:
    if not isinstance(key, str):
        raise KeyValidationError("Database keys must be strings")

    if not key:
        raise KeyValidationError("Database keys cannot be empty")

Creating Records

set()

Insert or overwrite a record in the database.
from binarydb.database import Database

db = Database("mydata.pkl")

# Store different types of values
db.set("username", "alice")
db.set("score", 100)
db.set("config", {"theme": "dark", "notifications": True})
db.set("tags", ["python", "database", "embedded"])

# Overwrite existing key
db.set("username", "bob")  # Replaces "alice"
Method Signature:
database.py:80-92
def set(self, key: str, value: Any) -> None:
    """
    Insert or overwrite a record.

    Args:
        key: Record identifier.
        value: Pickle-serializable object.
    """
    self._ensure_open()
    self._validate_key(key)

    self._data[key] = value
    self._mark_dirty()
The value can be any pickle-serializable Python object: strings, numbers, lists, dicts, custom classes, etc.

Reading Records

get()

Retrieve a record by its key.
db = Database("mydata.pkl")
db.load()

# Get existing value
username = db.get("username")  # Returns "alice"

# Get with default value
age = db.get("age", 25)  # Returns 25 if "age" doesn't exist

# Returns None if key doesn't exist and no default provided
missing = db.get("nonexistent")  # Returns None
Method Signature:
database.py:94-101
def get(self, key: str, default: Any = None) -> Any:
    """
    Retrieve a record by key.
    """
    self._ensure_open()
    self._validate_key(key)

    return self._data.get(key, default)

exists()

Check if a key exists in the database.
if db.exists("username"):
    print(f"User: {db.get('username')}")
else:
    print("No user found")
Method Signature:
database.py:134-139
def exists(self, key: str) -> bool:
    """Return True if the key exists."""
    self._ensure_open()
    self._validate_key(key)

    return key in self._data

all()

Retrieve all records as a dictionary.
db = Database("mydata.pkl")
db.set("user1", {"name": "Alice"})
db.set("user2", {"name": "Bob"})

all_records = db.all()
print(all_records)
# {"user1": {"name": "Alice"}, "user2": {"name": "Bob"}}
Method Signature:
database.py:141-144
def all(self) -> dict[str, Any]:
    """Return a shallow copy of all records."""
    self._ensure_open()
    return self._data.copy()
all() returns a shallow copy of the data. Modifying the returned dictionary won’t affect the database, but modifying nested objects will.

Updating Records

update()

Update specific fields of a dictionary record without replacing the entire value.
db = Database("mydata.pkl")

# Store a dictionary
db.set("user", {
    "name": "Alice",
    "email": "[email protected]",
    "age": 30
})

# Update only specific fields
db.update("user", {"age": 31, "city": "New York"})

# Result: {"name": "Alice", "email": "[email protected]", "age": 31, "city": "New York"}
Method Signature:
database.py:114-132
def update(self, key: str, changes: dict[str, Any]) -> None:
    """
    Update fields of a dictionary record.

    Raises:
        RecordTypeError: If the stored value is not a dict.
    """
    self._ensure_open()
    self._validate_key(key)

    if key not in self._data:
        raise KeyError(f"Key '{key}' not found")

    record = self._data[key]
    if not isinstance(record, dict):
        raise RecordTypeError("Cannot update non-dictionary record")

    record.update(changes)
    self._mark_dirty()
update() only works with dictionary values. Attempting to update a non-dict value raises RecordTypeError.
Error Handling:
db.set("score", 100)  # Not a dictionary

try:
    db.update("score", {"points": 150})
except RecordTypeError as e:
    print(f"Error: {e}")  # "Cannot update non-dictionary record"

Deleting Records

delete()

Remove a record from the database.
db = Database("mydata.pkl")
db.set("temp_data", "value")

# Delete the key
db.delete("temp_data")

# Safe to delete non-existent keys (no error)
db.delete("nonexistent")  # Does nothing
Method Signature:
database.py:103-112
def delete(self, key: str) -> None:
    """
    Delete a record if it exists.
    """
    self._ensure_open()
    self._validate_key(key)

    if key in self._data:
        del self._data[key]
        self._mark_dirty()
Deleting a non-existent key is a no-op (does not raise an error).

The Dirty Flag

BinaryDB uses an internal _dirty flag to track when in-memory data has changed and needs to be persisted.

How It Works

database.py:72-74
def _mark_dirty(self) -> None:
    if not self._in_transaction:
        self._dirty = True
  • Operations that modify data (set, delete, update) call _mark_dirty()
  • The flag is set to True unless you’re in a transaction
  • commit() only writes to disk if _dirty is True
  • After a successful commit, _dirty is reset to False

Example

db = Database("mydata.pkl")
db.load()

print(db._dirty)  # False - no changes yet

db.set("key", "value")
print(db._dirty)  # True - data modified

db.commit()
print(db._dirty)  # False - changes persisted

# No-op commit (data hasn't changed)
db.commit()  # Does nothing because _dirty is False
The dirty flag optimization prevents unnecessary disk writes when data hasn’t changed.

Python Protocol Support

BinaryDB supports Python’s built-in protocols for a more intuitive interface:

len()

db = Database("mydata.pkl")
db.set("key1", "value1")
db.set("key2", "value2")

print(len(db))  # 2

in operator

if "username" in db:
    print("Username exists!")
Implementation:
database.py:261-265
def __len__(self) -> int:
    return len(self._data)

def __contains__(self, key: str) -> bool:
    return key in self._data

Complete Example

from binarydb.database import Database
from binarydb.errors import KeyValidationError, RecordTypeError

# Create and initialize database
db = Database("users.pkl")
db.load()

# Create records
db.set("user:1", {"name": "Alice", "role": "admin", "active": True})
db.set("user:2", {"name": "Bob", "role": "user", "active": True})
db.set("stats:logins", 42)

# Read records
user = db.get("user:1")
print(f"User: {user['name']}")

if db.exists("user:3"):
    print("User 3 found")
else:
    print("User 3 not found")

# Update records
db.update("user:1", {"last_login": "2026-03-04"})

# Delete records
db.delete("user:2")

# Get all records
print(f"Total records: {len(db)}")
for key, value in db.all().items():
    print(f"{key}: {value}")

# Persist to disk
db.commit()
db.close()

Next Steps

Transactions

Learn how to use transactions for atomic operations

Persistence

Understand how data is saved and loaded from disk

Build docs developers (and LLMs) love