You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

fiabledb

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fiabledb

Immutable NoSQL database in a plain file

1.0.0
pipPyPI
Maintainers
1

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

  • Clojure
  • Haskell

Thanks to the power of 🐍 Python 🐍

FAQs

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts