Skip to main content

Add your description here

Project description

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 🐍

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fiabledb-0.1.0.tar.gz (21.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fiabledb-0.1.0-py3-none-any.whl (22.5 kB view details)

Uploaded Python 3

File details

Details for the file fiabledb-0.1.0.tar.gz.

File metadata

  • Download URL: fiabledb-0.1.0.tar.gz
  • Upload date:
  • Size: 21.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for fiabledb-0.1.0.tar.gz
Algorithm Hash digest
SHA256 94b9e041bc17354641845d6541a268ac43f84c5297cafa7c265f1dc4cbfcfd39
MD5 4e5b6bea6f5f2ae50ca6242add8de03f
BLAKE2b-256 fc07daebf1a3cd3300e8d9a09c9b57325c34aace857fd7ca338115f2beecb78b

See more details on using hashes here.

File details

Details for the file fiabledb-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: fiabledb-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for fiabledb-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dbab1eb99bf6c8bc231dfbc111612cd3f06b7f2e26324cbed60b87077e6411bd
MD5 fc593edcd3dcba1d3fee5f7d2ccf7eba
BLAKE2b-256 d72d4f0b95dd589b794ad0633a978dc9a105d7c87320546979235c4d920fabe3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page