Skip to main content

fiableDB

fiableDB logo

A simple, reliable, immutable database that stores all data revisions in JSON format.

Features

  • Information is never lost. Even if you make updates or deletions, you will be able to recover any information at any time.
  • There are no restrictions on the data structure or columns, since dictionaries are used without limitations on nesting. Similar to MongoDB Documents.
  • All the information is stored in a JSON file.
  • Extremely fast since it has no queue or locking limitations.
  • Minimalistic to implement and use.

Why use fiableDB instead of other relational databases?

  • High level of consistency and accuracy of data, such as a hospital patient's chronology or banking data. It cannot be modified once it has been aggregated.
  • They simplify the process of backing up and restoring data, because you can always revert to the original version of the data if necessary.
  • Very secure, modifying existing data will be detected and rejected.

Install

Python version: >=3.8

pip3 install --user fiable_db

Documentation

All documentation can be read as a sequential tutorial.

Step 1: Start

To load the database you must import fiable_db and start it.

import fiable_db

fiable_db.start()

It will create a file named fiabledb.json in the current directory. If you want to change the name of the file, you can do it by passing the name as a parameter.

fiable_db.start("my_db.json")
# Returns: "my_db.json"

If the file already exists, it will be loaded. Nothing is deleted here!

Error handling:

try:
    fiable_db.start("my_db.json")
except Exception as e:
    print(f"Database initialization failed: {e}")
    # Creates empty database if file is corrupted

Step 2: Aggregation

Add a single record:

result = fiable_db.add({"name": "Miguel", "age": 41, "height": 189})
print(result)
# {"id": 1, "rev": 1, "table": "default", "data": {"name": "Miguel", "age": 41, "height": 189}}

Add multiple records:

result = fiable_db.add([
    {"name": "Noelia", "age": 34, "height": 165},
    {"name": "Juan", "age": 41, "height": 187},
    {"name": "Valentina", "age": 12, "height": 142},
])
print(result)
# [
#     {"id": 2, "rev": 1, "table": "default", "data": {"name": "Noelia", "age": 34, "height": 165}},
#     {"id": 3, "rev": 1, "table": "default", "data": {"name": "Juan", "age": 41, "height": 187}},
#     {"id": 4, "rev": 1, "table": "default", "data": {"name": "Valentina", "age": 12, "height": 142}},
# ]

Input validation:

# These will raise errors
try:
    fiable_db.add({})  # ValueError: Cannot add empty dictionary
    fiable_db.add([])  # ValueError: Cannot add empty list
    fiable_db.add("invalid")  # TypeError: new_data must be a dict or list
except (ValueError, TypeError) as e:
    print(f"Invalid input: {e}")

Step 3: Update

Update a field:

result = fiable_db.update(4, {"age": 21})
print(result)
# {"id": 4, "rev": 2, "table": "default", "data": {"name": "Valentina", "age": 21, "height": 142}}

Add new fields:

result = fiable_db.update(4, {"is_active": True})
print(result)
# {"id": 4, "rev": 3, "table": "default", "data": {"name": "Valentina", "age": 21, "height": 142, "is_active": True}}

Delete a field (set to None):

result = fiable_db.update(4, {"height": None})
print(result)
# {"id": 4, "rev": 4, "table": "default", "data": {"name": "Valentina", "age": 21, "is_active": True}}

Force overwrite (replace entire data):

result = fiable_db.update(4, {"name": "Javier", "email": "foo@example.com"}, force=True)
print(result)
# {"id": 4, "rev": 5, "table": "default", "data": {"name": "Javier", "email": "foo@example.com"}}

Handle non-existent records:

result = fiable_db.update(999, {"name": "Ghost"})
print(result)
# None

Input validation:

try:
    fiable_db.update(-1, {"name": "Invalid"})  # ValueError: id must be a positive integer
    fiable_db.update(1, "not_dict")  # TypeError: new_data must be a dictionary
except (ValueError, TypeError) as e:
    print(f"Invalid input: {e}")

Step 4: Delete

You can delete by using the id. This creates a new revision with empty data.

result = fiable_db.delete(id=4)
print(result)
# {"id": 4, "rev": 6, "table": "default", "data": {}}

Input validation:

try:
    fiable_db.delete(-1)  # ValueError: id must be a positive integer
    fiable_db.delete("invalid")  # TypeError: id must be an integer
except (ValueError, TypeError) as e:
    print(f"Invalid input: {e}")

Step 5: Find One

Search by ID (gets latest revision):

result = fiable_db.find_one(id=2)
print(result)
# {"id": 2, "rev": 1, "table": "default", "data": {"name": "Noelia", "age": 34, "height": 165}}

Search by data filter (first match):

result = fiable_db.find_one(data={"name": "Noelia"})
print(result)
# {"id": 2, "rev": 1, "table": "default", "data": {"name": "Noelia", "age": 34, "height": 165}}

Search by multiple criteria:

result = fiable_db.find_one(data={"name": "Noelia", "age": 34})
print(result)
# {"id": 2, "rev": 1, "table": "default", "data": {"name": "Noelia", "age": 34, "height": 165}}

No results return None:

result = fiable_db.find_one(data={"name": "NonExistent"})
print(result)
# None

Input validation:

try:
    fiable_db.find_one(id="invalid")  # TypeError: id must be an integer
    fiable_db.find_one(data="invalid")  # TypeError: data must be a dictionary
except TypeError as e:
    print(f"Invalid input: {e}")

Step 6: Find All

Find all records in default table:

result = fiable_db.find_all()
print(result)
# Returns all active records (latest revisions) sorted by table and id

Filter by data:

result = fiable_db.find_all(data={"age": 41})
print(result)
# [
#      {"id": 1, "rev": 1, "table": "default", "data": {"name": "Miguel", "age": 41, "height": 189}},
#      {"id": 3, "rev": 1, "table": "default", "data": {"name": "Juan", "age": 41, "height": 187}},
# ]

No results return empty list:

result = fiable_db.find_all(data={"age": 999})
print(result)
# []

Input validation:

try:
    fiable_db.find_all(data="invalid")  # TypeError: data must be a dictionary
except TypeError as e:
    print(f"Invalid input: {e}")

Step 7: View Previous Revisions

At any time you can view the previous information of any row using the rev parameter.

Get specific revision:

result = fiable_db.find_one(id=4, rev=3)
print(result)
# {"id": 4, "rev": 3, "table": "default", "data": {"name": "Valentina", "age": 21, "height": 142, "is_active": True}}

Use negative numbers for relative revisions:

-1 will be the previous state, -2 is 2 states back, etc.

# Get previous revision
result = fiable_db.find_one(id=4, rev=-1)
print(result)
# {"id": 4, "rev": 5, "table": "default", "data": {"name": "Javier", "email": "foo@example.com"}}

# Get 2 revisions back
result = fiable_db.find_one(id=4, rev=-2)
print(result)
# {"id": 4, "rev": 4, "table": "default", "data": {"name": "Valentina", "age": 21, "is_active": True}}

Non-existent revisions return None:

result = fiable_db.find_one(id=4, rev=999)
print(result)
# None

result = fiable_db.find_one(id=4, rev=-999)
print(result)
# None

Step 8: Working with Tables/Collections

You can create as many tables as you want. The default table is called default. Use the table parameter in any function to work with different tables.

Add to specific table:

result = fiable_db.add({"name": "Luciano", "age": 54, "height": 165}, table="users")
print(result)
# {"id": 1, "rev": 1, "table": "users", "data": {"name": "Luciano", "age": 54, "height": 165}}

Find in specific table:

# Find in "users" table
result = fiable_db.find_one(id=1, table="users")
print(result)
# {"id": 1, "rev": 1, "table": "users", "data": {"name": "Luciano", "age": 54, "height": 165}}

# Find in "default" table
result = fiable_db.find_one(id=1, table="default")
print(result)
# {"id": 1, "rev": 1, "table": "default", "data": {"name": "Miguel", "age": 41, "height": 189}}

Update in specific table:

result = fiable_db.update(1, {"age": 10}, table="users")
print(result)
# {"id": 1, "rev": 2, "table": "users", "data": {"name": "Luciano", "age": 10, "height": 165}}

Delete in specific table:

result = fiable_db.delete(1, table="users")
print(result)
# {"id": 1, "rev": 3, "table": "users", "data": {}}

Find all in specific table:

result = fiable_db.find_all(table="users")
print(result)
# Returns all records from "users" table

Cross-table search (leave table empty):

result = fiable_db.find_one(data={"name": "Luciano"}, table="")
print(result)
# Searches across all tables

Step 9: Save Changes

Save the database to the current file.

success = fiable_db.save()
print(success)  # True if saved successfully, False if error occurred

Save to specific file:

success = fiable_db.save("backup.json")
print(success)  # True if saved successfully

Other Helper Functions

Get All Data

Get the complete database (all revisions, all tables).

all_data = fiable_db.get_database()
print(len(all_data))  # Total number of records (including all revisions)

Load File

Load a file into the database.

try:
    success = fiable_db.load("backup.json")
    print(f"File loaded: {success}")
except FileNotFoundError as e:
    print(f"File not found: {e}")

Error Handling

fiableDB includes comprehensive error handling:

Common Exceptions

  • TypeError: Invalid data types passed to functions
  • ValueError: Invalid values (negative IDs, empty data)
  • FileNotFoundError: Database file not found or corrupted
  • json.JSONDecodeError: Corrupted JSON file

Best Practices

import fiable_db

try:
    # Initialize database
    fiable_db.start("myapp.json")
    
    # Add data with validation
    if user_data and isinstance(user_data, dict):
        result = fiable_db.add(user_data, table="users")
        
    # Always check for None results
    user = fiable_db.find_one(id=user_id, table="users")
    if user is not None:
        print(f"Found user: {user['data']['name']}")
    else:
        print("User not found")
        
    # Save changes
    if not fiable_db.save():
        print("Warning: Could not save database")
        
except (TypeError, ValueError) as e:
    print(f"Invalid input: {e}")
except FileNotFoundError as e:
    print(f"Database error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

Data Structure

Each record in fiableDB has the following structure:

{
    "id": 1,           # Unique identifier within table
    "rev": 3,          # Revision number (increments with each update)
    "table": "users",  # Table/collection name
    "data": {          # Your actual data
        "name": "John",
        "age": 30
    }
}

Performance Notes

  • IDs are auto-generated starting from 1 for each table
  • All operations are O(n) where n is the total number of records
  • Memory usage grows with each revision (immutable design)
  • File I/O is synchronous - consider frequency of save() calls
  • Best for small to medium datasets (< 100k records)

Implementations in Other Languages


Thanks to the power of 🐍 Python 🐍

Metadata

Release files for fiabledb 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fiabledb 1.0.0
File Size Uploaded
fiabledb-1.0.0.tar.gz 21.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fiabledb 1.0.0
File Interpreter ABI Platform
fiabledb-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 44.1 kB

Release files / fiabledb-1.0.0.tar.gz

Download URL fiabledb-1.0.0.tar.gz
Size 21.6 kB
Tags Source
SHA-256 checksum
How to use checksums
17179ed8f69652620f2c8c9e8522a2b8e3446b06ede9e36ef760a7ab688c96af
BLAKE2b-256 checksum
How to use checksums
8b531bf4f9b167c8b534b944499fd1bba6263aca7518bd3e5da19b5fff40fcb5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.3

Release files / fiabledb-1.0.0-py3-none-any.whl

Download URL fiabledb-1.0.0-py3-none-any.whl
Size 22.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
556d199dbbfed747d54213201c6b59cfa2771238bf691cef470ec0a1a61ad806
BLAKE2b-256 checksum
How to use checksums
5a4cbb4b7f74734b401bee0acddec6ca591df58c3fc7dc6811e3af713b04ab50
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.3

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page