revamped the website and the readme.md for clearer documentation

Commit 8de2505 · patx · 2025-02-09T21:06:42-05:00

Changeset
8de2505270dd0bfd3df4f607326fcea8a0e80ecc
Parents
94f1df93adc1bc480ea6f2342df0f23c784d0b7e

View source at this commit

Comments

No comments yet.

Log in to comment

Diff

diff --git a/README.md b/README.md
index 0d183d7..ebd9547 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,7 @@
 
 # **pickleDB: Your Lightweight, High-Speed Key-Value Store**
 
-## **Fast. Simple. Reliable.**
-Unlock the power of effortless data storage with **pickleDB**—the no-fuss, blazing-fast key-value store designed for Python developers. Whether you're building a small script or a performant microservice, pickleDB delivers simplicity and speed with the reliability you can count on.
+**Fast. Simple. Reliable.** Unlock the power of effortless data storage with **pickleDB**—the no-fuss, blazing-fast key-value store designed for Python developers. Whether you're building a small script or a performant microservice, pickleDB delivers simplicity and speed with the reliability you can count on.
 
 ## **Why Choose pickleDB?**
 
@@ -25,30 +24,8 @@ Store strings, lists, dictionaries, and more—all with native Python operations
 Use pickleDB's `AsyncPickleDB` class for async operations and saves made possible with aiofiles. Ready to go for use with web frameworks like Starlette, FastAPI, and [MicroPie](https://patx.github.io/micropie).
 
 ## **Getting Started**
+### Check out pickleDB's [website](https://patx.github.io/pickledb) for a [user guide](https://patx.github.io/pickledb/guide) complete with advanced examples and the complete [API documentation](https://patx.github.io/pickledb/commands).
 
-### **Install in Seconds**
-pickleDB is available on PyPI. Get started with just one command:
-```bash
-pip install pickledb
-```
-
-### **Your First pickleDB**
-```python
-from pickledb import PickleDB
-
-# Initialize the database
-db = PickleDB('my_database.db')
-
-# Add a key-value pair
-db.set('greeting', 'Hello, world!')
-
-# Retrieve the value
-db.get('greeting')  # Output: Hello, world!
-
-# Save the data to disk
-db.save()
-```
-It’s that simple! In just a few lines, you have a fully functioning key-value store.
 
 ## **Performance Highlights**
 
@@ -62,450 +39,6 @@ pickleDB demonstrates strong performance for handling large-sized datasets:
 
 Tests were performed on a StarLabs StarLite Mk IV (Quad-Core Intel® Pentium® Silver N5030 CPU @ 1.10GHz w/ 8GB memory) running elementary OS 7.1 Horus.
 
-## **Minimal, Powerful API**
-
-pickleDB offers a clean and Pythonic API for managing data efficiently:
-
-### **`set(key, value)`**
-Add or update a key-value pair:
-```python
-# Add a new key-value pair
-db.set('username', 'admin')
-
-# Or shorthand
-db['username'] = 'admin'
-
-# Update an existing key-value pair
-db.set('username', 'superadmin')
-print(db.get('username'))  # Output: 'superadmin'
-```
-
-### **`get(key)`**
-Retrieve the value associated with a key:
-```python
-# Get the value for a key
-print(db.get('username'))  # Output: 'superadmin'
-
-# Like the set() method, you can use Python syntax sugar here as well
-print(db['username']) # Output: 'superadmin'
-
-# Attempt to retrieve a non-existent key
-print(db.get('nonexistent_key'))  # Output: None
-```
-
-### **`all()`**
-Get a list of all keys:
-```python
-# Add multiple keys
-db.set('item1', 'value1')
-db.set('item2', 'value2')
-
-# Retrieve all keys
-print(db.all())  # Output: ['username', 'item1', 'item2']
-```
-
-### **`remove(key)`**
-Delete a key and its value:
-```python
-# Remove a key-value pair
-db.remove('item1')
-print(db.all())  # Output: ['username', 'item2']
-```
-
-### **`purge()`**
-Clear all data in the database:
-```python
-# Clear the database
-db.purge()
-print(db.all())  # Output: []
-```
-
-### **`save()`**
-Persist the database to disk:
-```python
-# Save the current state of the database
-db.save()
-print("Database saved successfully!")
-```
-
-### **Asynchronous API (AsyncPickleDB)**
-
-- `aset(key, value)`: Async version of `set()`.
-- `aget(key)`: Async version of `get()`.
-- `aall()`: Async version of `all()`.
-- `aremove(key)`: Async version of `remove()`.
-- `apurge()`: Async version of `purge()`.
-- `asave()`: Async version of `save()`.
-
-
-See full API documentation at [patx.github.io/pickledb/commands](https://patx.github.io/pickledb/commands).
-## **Key Improvements in Version 1.0**
-
-pickleDB 1.0 is a reimagined version designed for speed, simplicity, and reliability. Key changes include:
-
-- **Atomic Saves**: Ensures data integrity during writes, eliminating potential corruption issues.
-- **Faster Serialization**: Switched to `orjson` for significantly improved speed.
-- **Streamlined API**: Removed legacy methods (e.g., `ladd`, `dmerge`) in favor of native Python operations.
-- **Unified Handling of Data Types**: Treats all Python-native types (lists, dicts, etc.) as first-class citizens.
-- **Explicit Saves**: The `auto_save` feature was removed to provide users greater control and optimize performance.
-- **`AsyncPickleDB`**: Added built in async class for use with event based applications.
-
-If backward compatibility is essential, version 0.9 is still available:
-- View the legacy code [here](https://gist.github.com/patx/3ad47fc3814d7293feb902f6ab49c48f).
-- Install it by:
-  ```bash
-  pip uninstall pickledb
-  ```
-  Then download the legacy file and include it in your project.
-
-
-## **With pickleDB you have the full power of Python behind you! Check out some examples of advanced use cases**
-
-### **Store and Retrieve Complex Data**
-PickleDB works seamlessly with Python data structures. Example:
-```python
-# Store a dictionary
-db.set('user', {'name': 'Alice', 'age': 30, 'city': 'Wonderland'})
-
-# Retrieve and update it
-user = db.get('user')
-user['age'] += 1
-
-# Save the updated data
-db.set('user', user)
-print(db.get('user'))  # Output: {'name': 'Alice', 'age': 31, 'city': 'Wonderland'}
-```
-
-### **Use Lists for Dynamic Data**
-Handle lists with ease:
-```python
-# Add a list of items
-db.set('tasks', ['Write code', 'Test app', 'Deploy'])
-
-# Retrieve and modify
-tasks = db.get('tasks')
-tasks.append('Celebrate')
-db.set('tasks', tasks)
-
-print(db.get('tasks'))  # Output: ['Write code', 'Test app', 'Deploy', 'Celebrate']
-```
-
-### **Store Configurations**
-Create a simple, persistent configuration store:
-```python
-# Set configuration options
-db.set('config', {'theme': 'dark', 'notifications': True})
-
-# Access and update settings
-config = db.get('config')
-config['notifications'] = False
-db.set('config', config)
-print(db.get('config'))  # Output: {'theme': 'dark', 'notifications': False}
-```
-
-### **Session Management**
-Track user sessions effortlessly:
-```python
-# Add session data
-db.set('session_12345', {'user_id': 1, 'status': 'active'})
-
-# End a session
-session = db.get('session_12345')
-session['status'] = 'inactive'
-db.set('session_12345', session)
-
-print(db.get('session_12345'))  # Output: {'user_id': 1, 'status': 'inactive'}
-```
-
-### **Advanced Key Search**
-Search the database with the full power of Python:
-```python
-# Create simple helper methods based on what YOU need
-def get_keys_with_match_list(db_instance, match):
-    return [key for key in db_instance.all() if match in key]
-
-def get_keys_with_match_dict(db_instance, match):
-    return dict(filter(lambda item: match in item[0], db_instance.db.items()))
-
-# Create an instance of PickleDB
-db = PickleDB("example.json")
-
-# Add key-value pairs
-db.set('apple', 1)
-db.set('apricot', 2)
-db.set('banana', 3)
-
-# Use glob search to return a list
-matching_keys = get_keys_with_match_list(db, 'ap')
-print(matching_keys)  # Output: ['apple', 'apricot']
-
-# Use glob search to return a dict
-matching_dict = get_keys_with_match_dict(db, 'ap')
-print(matching_dict)  # Output: {"apple": 1, "apricot": 3}
-```
-
-### Namespace Support
-If you use prefixes to simulate namespaces, you can manage groups of keys more efficiently:
-```python
-# Set multiple keys with a namespace
-db.set('user:1', {'name': 'Alice', 'age': 30})
-db.set('user:2', {'name': 'Bob', 'age': 25})
-
-# Get all keys in a namespace
-def get_namespace_keys(db_instance, namespace):
-    return [key for key in db_instance.all() if key.startswith(f"{namespace}:")]
-
-user_keys = get_namespace_keys(db, 'user')
-print(user_keys)  # Output: ['user:1', 'user:2']
-```
-
-### Expire Keys
-Manually simulate a basic TTL (time-to-live) mechanism for expiring keys:
-```python
-import time
-
-# Set a key with an expiration time
-def set_with_expiry(db_instance, key, value, ttl):
-    db_instance.set(key, {'value': value, 'expires_at': time.time() + ttl})
-
-# Get a key only if it hasn't expired
-def get_if_not_expired(db_instance, key):
-    data = db_instance.get(key)
-    if data and time.time() < data['expires_at']:
-        return data['value']
-    db_instance.remove(key)  # Remove expired key
-    return None
-
-# Example usage
-set_with_expiry(db, 'session_123', 'active', ttl=10)
-time.sleep(5)
-print(get_if_not_expired(db, 'session_123'))  # Output: 'active'
-time.sleep(6)
-print(get_if_not_expired(db, 'session_123'))  # Output: None
-```
-
-### Encrypted Storage
-Use encryption for secure storage of sensitive data:
-```python
-from cryptography.fernet import Fernet
-
-# Initialize encryption
-key = Fernet.generate_key()
-cipher = Fernet(key)
-
-# Encrypt and save data
-encrypted_value = cipher.encrypt(b"My secret data")
-db.set('secure_key', encrypted_value)
-
-# Retrieve and decrypt data
-encrypted_value = db.get('secure_key')
-decrypted_value = cipher.decrypt(encrypted_value)
-print(decrypted_value.decode())  # Output: My secret data
-
-```
-
-### Batch Operations
-Add multiple key-value pairs in a single operation:
-```python
-def batch_set(db_instance, items):
-    for key, value in items.items():
-        db_instance.set(key, value)
-
-# Add multiple keys
-batch_set(db, {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'})
-print(db.all())  # Output: ['key1', 'key2', 'key3']
-```
-
-Delete multiple key-value pairs in a single operation:
-```python
-def batch_delete(db_instance, keys):
-    for key in keys:
-        db_instance.remove(key)
-
-# Example usage
-db.set('temp1', 'value1')
-db.set('temp2', 'value2')
-batch_delete(db, ['temp1', 'temp2'])
-print(db.all())  # Output: []
-```
-
-### Manipulate Database Stats
-Display database statistics, such as the total number of keys, data size, or memory usage:
-```python
-def db_stats(db_instance):
-    total_keys = len(db_instance.all())
-    data_size = sum(len(str(value)) for value in db_instance.db.values())
-    return {"total_keys": total_keys, "data_size": data_size}
-
-# Example usage
-stats = db_stats(db)
-print(stats)  # Output: {'total_keys': 10, 'data_size': 12345}
-```
-
-### Data Migration
-Export and import database content between files:
-```python
-# Export database content
-def export_db(db_instance, export_path):
-    with open(export_path, 'w') as f:
-        f.write(orjson.dumps(db_instance.db).decode())
-
-# Import database content
-def import_db(db_instance, import_path):
-    with open(import_path, 'r') as f:
-        db_instance.db = orjson.loads(f.read())
-    db_instance.save()
-
-# Example usage
-export_db(db, 'exported_data.json')
-db.purge()
-import_db(db, 'exported_data.json')
-print(db.all())  # Restores all keys
-```
-
-### Backup to AWS
-Demonstrate a method for backing up the database to a remote location, such as an AWS S3 bucket:
-```python
-import boto3
-
-def backup_to_s3(db_instance, bucket_name, s3_key):
-    s3 = boto3.client('s3')
-    with open(db_instance.location, 'rb') as f:
-        s3.upload_fileobj(f, bucket_name, s3_key)
-
-# Example usage
-backup_to_s3(db, 'my-s3-bucket', 'backup/my_database.db')
-```
-
-### Use pickleDB over HTTP
-Access pickleDB database with any language that can handle REST requests:
-```python
-from pickledb import AsyncPickleDB
-from MicroPie import App
-import orjson
-import uvicorn
-
-DB_NAME = input('Enter database name: ')
-db = AsyncPickleDB(DB_NAME)
-
-
-class Root(App):
-
-    async def set(self, key, value):
-        await db.aset(key, value)
-        return orjson.dumps({key: value})
-
-    async def get(self, key):
-        value = await db.aget(key)
-        return orjson.dumps({key: value})
-
-    async def remove(self, key):
-        await db.aremove(key)
-        return orjson.dumps({'action': 'removed'})
-
-    async def purge(self):
-        await db.apurge()
-        return orjson.dumps({'action': 'purge'})
-
-    async def all(self):
-        return orjson.dumps(await db.aall())
-
-    async def save(self):
-        await db.asave()
-        return orjson.dumps({'action': 'save'})
-
-
-app = Root()
-
-if __name__ == "__main__":
-    uvicorn.run(app, host="127.0.0.1", port=5272)
-```
-
-### Key Pattern Matching
-Support complex matching patterns using regular expressions:
-```python
-import re
-
-# Get keys that match a regex pattern
-def get_keys_by_pattern(db_instance, pattern):
-    regex = re.compile(pattern)
-    return [key for key in db_instance.all() if regex.search(key)]
-
-# Example usage
-db.set('user:1', {'name': 'Alice'})
-db.set('user:2', {'name': 'Bob'})
-db.set('admin:1', {'name': 'Charlie'})
-matching_keys = get_keys_by_pattern(db, r'user:\d')
-print(matching_keys)  # Output: ['user:1', 'user:2']
-```
-
-### Adding Custom Signal Handling
-You can easily implement custom signal handling in your application to ensure graceful shutdowns and data persistence during unexpected terminations. Below is an example of how to integrate custom signal handling with pickleDB:
-
-```python
-import signal
-import sys
-from pickledb import PickleDB
-
-# Initialize the PickleDB instance
-db = PickleDB('my_database.db')
-
-# Register signal handlers for SIGINT (Ctrl+C) and SIGTERM (system termination)
-signal.signal(signal.SIGINT, lambda signum, frame: (db.save(), sys.exit(0)))
-signal.signal(signal.SIGTERM, lambda signum, frame: (db.save(), sys.exit(0)))
-
-# Example usage
-db.set('key1', 'value1')
-db.set('key2', 'value2')
-
-print("Database is running. Press Ctrl+C to save and exit.")
-
-# Keep the program running to allow signal handling
-try:
-    while True:
-        pass
-except KeyboardInterrupt:
-    pass
-```
-
-### **Async For Web Frameworks**
-For frameworks like FastAPI, Starlette, or MicroPie, use `AsyncPickleDB` to handle requests without blocking the server:
-
-```python
-from uuid import uuid4
-import asyncio
-from MicroPie import App
-from markupsafe import escape
-from pickledb import AsyncPickleDB
-
-db = AsyncPickleDB('pastes.db')
-
-class Root(App):
-
-    async def index(self):
-        if self.request.method == "POST":
-            paste_content = self.request.body_params.get('paste_content', [''])[0]
-            pid = str(uuid4())
-            await db.aset(pid, escape(paste_content))
-            await db.asave()
-            return self._redirect(f'/paste/{pid}')
-        return await self._render_template('index.html')
-
-    async def paste(self, paste_id, delete=None):
-        if delete == 'delete':
-            await db.aremove(paste_id)
-            await db.asave()
-            return self._redirect('/')
-        paste_content = await db.aget(paste_id)
-        return await self._render_template(
-            'paste.html',
-            paste_id=paste_id,
-            paste_content=paste_content
-        )
-
-app = Root()
-```
-
 ## **Limitations**
 
 While pickleDB is powerful, it’s important to understand its limitations:
diff --git a/docs/commands.html b/docs/commands.html
index 599e473..4753d97 100644
--- a/docs/commands.html
+++ b/docs/commands.html
@@ -1,30 +1,135 @@
 <!DOCTYPE html>
 <html lang="en">
 <head>
-    <meta charset="utf-8">
+    <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <link rel="shortcut icon" href="https://packages.python.org/pickleDB/favicon.ico" type="image/x-icon">
-    <link rel="icon" href="https://packages.python.org/pickleDB/favicon.ico" type="image/x-icon">
-    <title>pickleDB API Documentation</title>
+    <link rel="shortcut icon" href="https://pythonhosted.org/pickleDB/favicon.ico" type="image/x-icon">
+    <link rel="icon" href="https://pythonhosted.org/pickleDB/favicon.ico" type="image/x-icon">
+    <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
+    <title>pickleDB - Simple Key-Value Database</title>
     <style>
-        .logo { width: 800px; margin: 40px auto; }
-        .body { font-family: "Helvetica", sans-serif; width: 540px; margin: 40px auto; }
-        img.c1 { position: absolute; top: 0; right: 0; border: 0; }
-        span.c2 { color: #8F5902; }
-        span.c9 { color: #4E9A06; }
-        a { color: #008000; border-bottom: 0px dotted white; text-decoration: none; }
-        a:hover { color: #008000; border-bottom: 0px solid white; }
+        body {
+            font-family: 'Poppins', sans-serif;
+            margin: 0;
+            padding: 0;
+
+            color: #333;
+        }
+        .container {
+            max-width: 800px;
+            margin: auto;
+            margin-top: auto;
+            margin-bottom: auto;
+            background: #fff;
+            padding: 40px;
+            border-radius: 15px;
+            text-align: center;
+        }
+        h1, h2 {
+            font-weight: 600;
+        }
+        h2 {
+            color: #008000;
+            text-align: left;
+        }
+        p {
+            font-size: 18px;
+            line-height: 1.6;
+            color: #555;
+            text-align: left;
+        }
+        ul {
+            text-align: left;
+        }
+        a {
+            color: #008000;
+            text-decoration: none;
+            font-weight: 600;
+            transition: color 0.3s ease;
+        }
+        a:hover {
+            color: #008000;
+        }
+        pre {
+            background: #f5f2f0;
+            padding: 20px;
+            border-radius: 10px;
+            text-align: left;
+            overflow-x: auto;
+            font-size: 1.1em;
+        }
+        .logo img {
+            max-width: 600px;
+        }
+        span.c2 {
+            color: #8F5902;
+        }
+        span.c9 {
+            color: #008000;
+        }
+        .github-banner img {
+            position: fixed;
+            top: 0;
+            right: 0;
+            border: 0;
+        }
+        .button-container {
+            display: flex;
+            justify-content: space-between;
+            gap: 10px;
+            align-items: center;
+        }
+        .button {
+            display: flex; /* Use flexbox for proper vertical centering */
+            align-items: center; /* Vertically center the text */
+            justify-content: center; /* Horizontally center the text */
+            background: #008000;
+            color: #fff;
+            padding: 0 30px; /* Only horizontal padding */
+            height: 100px; /* Set a fixed height for both buttons */
+            border-radius: 30px;
+            font-size: 18px;
+            font-weight: 600;
+            text-align: center;
+            width: 48%; /* Ensure both buttons take up equal width */
+            transition: background 0.3s ease;
+        }
+        .button:hover {
+            background: white;
+            border: 2px solid #008000;
+            color: #008000;
+        }
+        .left-button {
+            margin-right: 10px;
+        }
+        .right-button {
+            margin-left: 10px;
+        }
+        @media (max-width: 768px) {
+            .container {
+                width: 100%;
+                padding: 20px;
+            }
+            .logo img {
+                max-width: 100%;
+            }
+            .button {
+                max-width: 100%;
+                text-align: center;
+                align-items: center
+            }
+            .github-banner {
+                display: none;
+            }
+        }
     </style>
 </head>
 <body>
-    <div class="logo">
-        <a href="index.html">
-            <img src="logo.png" alt="pickleDB logo">
-        </a>
-    </div>
-    <div class="body">
+    <div class="container">
+        <div class="logo">
+            <a href="index.html"><img src="logo.png" alt="pickleDB logo"></a>
+        </div>
         <h1>API Documentation</h1>
-        <p>For installation, more documentation, and examples see the <a href="https://github.com/patx/pickledb/?tab=readme-ov-file#readme">README on GitHub.</a></p>
 
         <p>
             <h2>PickleDB</h2>
diff --git a/docs/guide.html b/docs/guide.html
new file mode 100644
index 0000000..db63168
--- /dev/null
+++ b/docs/guide.html
@@ -0,0 +1,498 @@
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link rel="shortcut icon" href="https://pythonhosted.org/pickleDB/favicon.ico" type="image/x-icon">
+    <link rel="icon" href="https://pythonhosted.org/pickleDB/favicon.ico" type="image/x-icon">
+    <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
+    <title>pickleDB - Simple Key-Value Database</title>
+    <style>
+        body {
+            font-family: 'Poppins', sans-serif;
+            margin: 0;
+            padding: 0;
+
+            color: #333;
+        }
+        .container {
+            max-width: 800px;
+            margin: auto;
+            margin-top: auto;
+            margin-bottom: auto;
+            background: #fff;
+            padding: 40px;
+            border-radius: 15px;
+            text-align: center;
+        }
+        h1, h2 {
+            font-weight: 600;
+        }
+        h2 {
+            color: #008000;
+            text-align: left;
+        }
+        p {
+            font-size: 18px;
+            line-height: 1.6;
+            color: #555;
+            text-align: left;
+        }
+        a {
+            color: #008000;
+            text-decoration: none;
+            font-weight: 600;
+            transition: color 0.3s ease;
+        }
+        a:hover {
+            color: #008000;
+        }
+        pre {
+            background: #f5f2f0;
+            padding: 20px;
+            border-radius: 10px;
+            text-align: left;
+            overflow-x: auto;
+            font-size: 1.1em;
+        }
+        .logo img {
+            max-width: 600px;
+        }
+        span.c2 {
+            color: #8F5902;
+        }
+        span.c9 {
+            color: #008000;
+        }
+        .github-banner img {
+            position: fixed;
+            top: 0;
+            right: 0;
+            border: 0;
+        }
+        .button-container {
+            display: flex;
+            justify-content: space-between;
+            gap: 10px;
+            align-items: center;
+        }
+        .button {
+            display: flex; /* Use flexbox for proper vertical centering */
+            align-items: center; /* Vertically center the text */
+            justify-content: center; /* Horizontally center the text */
+            background: #008000;
+            color: #fff;
+            padding: 0 30px; /* Only horizontal padding */
+            height: 100px; /* Set a fixed height for both buttons */
+            border-radius: 30px;
+            font-size: 18px;
+            font-weight: 600;
+            text-align: center;
+            width: 48%; /* Ensure both buttons take up equal width */
+            transition: background 0.3s ease;
+        }
+        .button:hover {
+            background: white;
+            border: 2px solid #008000;
+            color: #008000;
+        }
+        .left-button {
+            margin-right: 10px;
+        }
+        .right-button {
+            margin-left: 10px;
+        }
+        @media (max-width: 768px) {
+            .container {
+                width: 100%;
+                padding: 20px;
+            }
+            .logo img {
+                max-width: 100%;
+            }
+            .button {
+                max-width: 100%;
+                text-align: center;
+                align-items: center
+            }
+            .github-banner {
+                display: none;
+            }
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div class="logo">
+            <a href='index.html'><img src="logo.png" alt="pickleDB logo"></a>
+        </div>
+<h2>Installation</h2>
+<p>pickleDB is available on PyPI. Install it with pip in just one command:
+<pre>
+pip install pickledb
+</pre>
+
+<h2>Your first pickleDB</h2>
+<p>Open up your favorite terminal and start a Python shell. Enter the following commands and watch pickleDB go to work!</p>
+<pre>
+from pickledb import PickleDB
+
+
+db = PickleDB('my_database.db')  <small># Initialize the database</small>
+
+
+db.set('greeting', 'Hello, world!')  <small># Add a key-value pair</small>
+
+
+db.get('greeting')  <small># Retrieve the value. Output: `Hello, world!`</small>
+
+
+db.save()  <small># Save the data to disk</small>
+</pre>
+<p>You should now have a file called <code>my_database.py</code> in your working directory. In it you should see your key-value pair you just added.
+It’s that simple! In just a few lines, you have a fully functioning key-value store.</p>
+
+<h2>Add or update a key-value pair</h2>
+<p>We can add key-value pairs to our database with the <code>set(key, value)</code> method provided in the <code>PickleDB</code> class for synchronous operations:
+<pre>
+# Add a new key-value pair
+db.set('username', 'admin')
+
+# Or shorthand
+db['username'] = 'admin'
+
+# Update an existing key-value pair
+db.set('username', 'superadmin')
+db.get('username')  # Output: 'superadmin'
+</pre>
+<p>Your <code>key</code> must be a string. If it is not, pickleDB will convert it into one for you using <code>str()</code>. Your <code>value</code> can be any JSON serializable object.</p>
+
+<h2>Retrieve the value associated with a key</h2>
+<p>In order to get the <code>value</code> of a <code>key</code> we can use <code>PickleDB</code>'s <code>get(key)</code> method. Remember your <code>key</code> must be a string.
+<pre>
+# Get the value for a key
+print(db.get('username'))  # Output: 'superadmin'
+
+# Like the set() method, you can use Python syntax sugar here as well
+db['username'] # Output: 'superadmin'
+
+# Attempt to retrieve a non-existent key
+db.get('nonexistent_key')  # Output: None
+</pre>
+
+<h2>Get a list of all keys</h2>
+<p>It is useful to get a list of all the keys in your database for many reasons. To do this we can use the <code>all()</code> method for this:</p>
+<pre>
+# Add multiple keys
+db.set('item1', 'value1')
+db.set('item2', 'value2')
+
+# Retrieve all keys
+db.all()  # Output: ['username', 'item1', 'item2']
+</pre>
+
+<h2>Delete a key and its value</h2>
+<p>To delete a key from the database you can use the <code>remove(key)</code> method. This will delete the key and its associated value.</p>
+<pre>
+# Remove a key-value pair
+db.remove('item1')
+db.all()  # Output: ['username', 'item2']
+</pre>
+<p>As you can see, when we call the <code>all()</code> method now, it no longer shows the key we removed.</p>
+
+<h2>Delete all keys</h2>
+<p>You can delete all data in the database using the <code>purge()</code> method in the <code>PickleDB</code> class.</p>
+<pre>
+db.purge()
+
+db.all()  # Output: []
+</pre>
+
+<h2>Persist the database to disk</h2>
+<p>In order for <strong>any</strong> of these other methods to be permanent you <strong>must</strong> call the <code>save()</code> method. Saving to disk only happens when this method is called. If you add a bunch of
+key-value pairs to your database and the program exits without this command being called all data will be lost! The explicit nature lets you tune the performance of pickleDB to your needs.</p>
+<pre>
+db.save()  # Output: True
+</pre>
+<p>You can also also save the database using a context manager:</p>
+<pre>
+with db:
+    db.set('foo', 'bar')
+    db.set('hello', 'world')
+    db.set('candy': 'bad')
+
+# Database saved when the `with` statement exits.
+</pre>
+
+<h2>The <code>AsyncPickleDB</code> Class</h2>
+<p>While the <code>PickleDB</code> is great for simple and fast data storage, it is not thread safe or asynchronous. So when you are working with things like ASGI frameworks the standard <code>PickleDB</code class is ill-suited.
+When you need async you need to use the <code>AsyncPickleDB</code class. This class operates close to the same as we are used to. Lets take a look:</p>
+<pre>
+import asyncio
+from pickledb import AsyncPickleDB
+
+async def main():
+    # Initialize the AsyncPickleDB object
+    db = AsyncPickleDB('my_database.db')
+
+    # Add a key-value pair
+    await db.aset('greeting', 'Hello, world!')
+
+    # Retrieve the value
+    greeting = await db.aget('greeting')
+    print(greeting)  # Output: 'Hello, world!'
+
+    # Save the data to disk
+    await db.asave()
+
+asyncio.run(main())
+</pre>
+<p>To use <code>AsyncPickleDB</code> you can simply add the <code>await</code> keyword and an "<code>a</code>" to the beginning of the sync commands your used to:</p>
+<pre>
+await db.aset('foo', 'bar')
+
+await db.aget('foo')
+
+await db.aremove('foo')
+
+await db.aall()
+
+await db.apurge()
+
+await db.asave()
+</pre>
+
+<h2>Store and Retrieve Complex Data</h2>
+<p>PickleDB works seamlessly with Python data structures. Example:</p>
+<pre>
+# Store a dictionary
+db.set('user', {'name': 'Alice', 'age': 30, 'city': 'Wonderland'})
+
+# Retrieve and update it
+user = db.get('user')
+user['age'] += 1
+
+# Save the updated data
+db.set('user', user)
+print(db.get('user'))  # Output: {'name': 'Alice', 'age': 31, 'city': 'Wonderland'}
+</pre>
+
+<h2>Use Lists for Dynamic Data</h2>
+<p>Handle lists with ease:</p>
+<pre>
+# Add a list of items
+db.set('tasks', ['Write code', 'Test app', 'Deploy'])
+
+# Retrieve and modify
+tasks = db.get('tasks')
+tasks.append('Celebrate')
+db.set('tasks', tasks)
+
+print(db.get('tasks'))  # Output: ['Write code', 'Test app', 'Deploy', 'Celebrate']
+</pre>
+
+<h2>Advanced Key Search</h2>
+<p>Search the database with the full power of Python:</p>
+<pre>
+# Create simple helper methods based on what YOU need
+def get_keys_with_match_list(db_instance, match):
+    return [key for key in db_instance.all() if match in key]
+
+def get_keys_with_match_dict(db_instance, match):
+    return dict(filter(lambda item: match in item[0], db_instance.db.items()))
+
+# Create an instance of PickleDB
+db = PickleDB("example.json")
+
+# Add key-value pairs
+db.set('apple', 1)
+db.set('apricot', 2)
+db.set('banana', 3)
+
+# Use glob search to return a list
+matching_keys = get_keys_with_match_list(db, 'ap')
+print(matching_keys)  # Output: ['apple', 'apricot']
+
+# Use glob search to return a dict
+matching_dict = get_keys_with_match_dict(db, 'ap')
+print(matching_dict)  # Output: {"apple": 1, "apricot": 3}
+</pre>
+
+<h2>Namespace Support</h2>
+<p>If you use prefixes to simulate namespaces, you can manage groups of keys more efficiently:</p>
+<pre>
+# Set multiple keys with a namespace
+db.set('user:1', {'name': 'Alice', 'age': 30})
+db.set('user:2', {'name': 'Bob', 'age': 25})
+
+# Get all keys in a namespace
+def get_namespace_keys(db_instance, namespace):
+    return [key for key in db_instance.all() if key.startswith(f"{namespace}:")]
+
+user_keys = get_namespace_keys(db, 'user')
+print(user_keys)  # Output: ['user:1', 'user:2']
+</pre>
+
+<h2>Expire Keys</h2>
+<p>Manually simulate a basic TTL (time-to-live) mechanism for expiring keys:</p>
+<pre>
+import time
+
+# Set a key with an expiration time
+def set_with_expiry(db_instance, key, value, ttl):
+    db_instance.set(key, {'value': value, 'expires_at': time.time() + ttl})
+
+# Get a key only if it hasn't expired
+def get_if_not_expired(db_instance, key):
+    data = db_instance.get(key)
+    if data and time.time() < data['expires_at']:
+        return data['value']
+    db_instance.remove(key)  # Remove expired key
+    return None
+
+# Example usage
+set_with_expiry(db, 'session_123', 'active', ttl=10)
+time.sleep(5)
+print(get_if_not_expired(db, 'session_123'))  # Output: 'active'
+time.sleep(6)
+print(get_if_not_expired(db, 'session_123'))  # Output: None
+</pre>
+
+<h2>Encrypted Storage</h2>
+<p>Use encryption for secure storage of sensitive data:</p>
+<pre>
+from cryptography.fernet import Fernet
+
+# Initialize encryption
+key = Fernet.generate_key()
+cipher = Fernet(key)
+
+# Encrypt and save data
+encrypted_value = cipher.encrypt(b"My secret data")
+db.set('secure_key', encrypted_value)
+
+# Retrieve and decrypt data
+encrypted_value = db.get('secure_key')
+decrypted_value = cipher.decrypt(encrypted_value)
+print(decrypted_value.decode())  # Output: My secret data
+</pre>
+
+
+<h2>Batch Operations</h2>
+<p>Add multiple key-value pairs in a single operation:</p>
+<pre>
+def batch_set(db_instance, items):
+    for key, value in items.items():
+        db_instance.set(key, value)
+
+# Add multiple keys
+batch_set(db, {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'})
+print(db.all())  # Output: ['key1', 'key2', 'key3']
+
+# Delete multiple key-value pairs in a single operation:
+
+def batch_delete(db_instance, keys):
+    for key in keys:
+        db_instance.remove(key)
+
+# Example usage
+db.set('temp1', 'value1')
+db.set('temp2', 'value2')
+batch_delete(db, ['temp1', 'temp2'])
+print(db.all())  # Output: []
+</pre>
+
+<h2>Key Pattern Matching</h2>
+<p>Support complex matching patterns using regular expressions:</p>
+<pre>
+import re
+
+# Get keys that match a regex pattern
+def get_keys_by_pattern(db_instance, pattern):
+    regex = re.compile(pattern)
+    return [key for key in db_instance.all() if regex.search(key)]
+
+# Example usage
+db.set('user:1', {'name': 'Alice'})
+db.set('user:2', {'name': 'Bob'})
+db.set('admin:1', {'name': 'Charlie'})
+matching_keys = get_keys_by_pattern(db, r'user:\d')
+print(matching_keys)  # Output: ['user:1', 'user:2']
+</pre>
+
+<h2>Adding Custom Signal Handling</h2>
+<p>You can easily implement custom signal handling in your application to ensure graceful shutdowns and data persistence during unexpected terminations.
+Below is an example of how to integrate custom signal handling with pickleDB:</p>
+<pre>
+import signal
+import sys
+from pickledb import PickleDB
+
+# Initialize the PickleDB instance
+db = PickleDB('my_database.db')
+
+# Register signal handlers for SIGINT (Ctrl+C) and SIGTERM (system termination)
+signal.signal(signal.SIGINT, lambda signum, frame: (db.save(), sys.exit(0)))
+signal.signal(signal.SIGTERM, lambda signum, frame: (db.save(), sys.exit(0)))
+
+# Example usage
+db.set('key1', 'value1')
+db.set('key2', 'value2')
+
+print("Database is running. Press Ctrl+C to save and exit.")
+
+# Keep the program running to allow signal handling
+try:
+    while True:
+        pass
+except KeyboardInterrupt:
+    pass
+</pre>
+
+<h2>Async For Web Frameworks</h2>
+<p>For frameworks like FastAPI, Starlette, or MicroPie, use AsyncPickleDB to handle requests without blocking the server:</p>
+<pre>
+from uuid import uuid4
+import asyncio
+from MicroPie import App
+from markupsafe import escape
+from pickledb import AsyncPickleDB
+
+db = AsyncPickleDB('pastes.db')
+
+class Root(App):
+
+    async def index(self):
+        if self.request.method == "POST":
+            paste_content = self.request.body_params.get('paste_content', [''])[0]
+            pid = str(uuid4())
+            await db.aset(pid, escape(paste_content))
+            await db.asave()
+            return self._redirect(f'/paste/{pid}')
+        return await self._render_template('index.html')
+
+    async def paste(self, paste_id, delete=None):
+        if delete == 'delete':
+            await db.aremove(paste_id)
+            await db.asave()
+            return self._redirect('/')
+        paste_content = await db.aget(paste_id)
+        return await self._render_template(
+            'paste.html',
+            paste_id=paste_id,
+            paste_content=paste_content
+        )
+
+app = Root()
+</pre>
+    </div>
+    <div class="github-banner">
+        <a href="https://github.com/patx/pickledb">
+            <img style="position: fixed; top: 0; right: 0; border: 0;" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_green_007200.png" alt="Fork me on GitHub">
+        </a>
+    </div>
+</body>
+</html>
+
+
diff --git a/docs/index.html b/docs/index.html
index 430e2d2..54bc300 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -83,12 +83,12 @@
             background: #008000;
             color: #fff;
             padding: 0 30px; /* Only horizontal padding */
-            height: 100px; /* Set a fixed height for both buttons */
+            height: 60px; /* Set a fixed height for both buttons */
             border-radius: 30px;
             font-size: 18px;
             font-weight: 600;
             text-align: center;
-            width: 48%; /* Ensure both buttons take up equal width */
+            width: 32%; /* Ensure both buttons take up equal width */
             transition: background 0.3s ease;
         }
         .button:hover {
@@ -102,6 +102,9 @@
         .right-button {
             margin-left: 10px;
         }
+        .middle-button {
+            margin: 0 10px;
+        }
         @media (max-width: 768px) {
             .container {
                 width: 100%;
@@ -147,8 +150,9 @@ True
 
         <p><br><br>
             <div class="button-container">
-                <a href="https://github.com/patx/pickledb" class="button left-button">View the source code and examples on GitHub</a>
-                <a href="commands.html" class="button right-button">View the API reference</a>
+                <a href="guide.html" class="button left-button">User Guide</a>
+                <a href="commands.html" class="button middle-button">API Reference</a>
+                <a href="https://github.com/patx/pickledb" class="button right-button">GitHub Repo</a>
             </div>
         </p>
     </div>