DB

Interfaces with a tinyDB database for converting search results to dict.

Classes

DBTable

Bases: Table

Extends TinyDB table to cast Document type to dict

Functions

all
all(*args, **kwargs)
Source code in fedbiomed/common/db.py
@cast_
def all(self, *args, **kwargs):
    return super().all(*args, **kwargs)
delete
delete(*args, **kwargs)
Source code in fedbiomed/common/db.py
@cast_
def delete(self, *args, **kwargs):
    return super().remove(*args, **kwargs)
get
get(*args, **kwargs)
Source code in fedbiomed/common/db.py
@cast_
def get(self, *args, **kwargs):
    return super().get(*args, **kwargs)
insert
insert(*args, **kwargs)
Source code in fedbiomed/common/db.py
@cast_
def insert(self, *args, **kwargs):
    return super().insert(*args, **kwargs)
search
search(*args, **kwargs)
Source code in fedbiomed/common/db.py
@cast_
def search(self, *args, **kwargs):
    return super().search(*args, **kwargs)
update
update(*args, **kwargs)
Source code in fedbiomed/common/db.py
@cast_
def update(self, *args, **kwargs):
    return super().update(*args, **kwargs)

TinyDBConnector

Singleton TinyDB connector

Attributes

db property
db

Return the shared TinyDB instance

Functions

table
table(name)

Return a table with the given name, ensuring it is a DBTable instance.

Source code in fedbiomed/common/db.py
def table(self, name: str) -> DBTable:
    """Return a table with the given name, ensuring it is a DBTable instance."""
    # Get the table from the underlying DB instance, forcing cache_size=0
    table = self._db.table(name, cache_size=0)
    return DBTable(table.storage, table.name)

TinyTableConnector

TinyTableConnector(path)

Base class for tables in TinyDB with common operations

Source code in fedbiomed/common/db.py
def __init__(self, path: str):
    if type(self) is TinyTableConnector:
        raise TypeError("`TinyTableConnector` cannot be instantiated directly")

    self._query = Query()
    self._table = TinyDBConnector(db_path=path).table(self._table_name)

Functions

all
all()

Get all entries (or empty list if none found).

Returns:

Type Description
List[dict]

The list of entries as dicts, or empty list if none found.

Source code in fedbiomed/common/db.py
def all(self) -> List[dict]:
    """Get all entries (or empty list if none found).

    Returns:
        The list of entries as dicts, or empty list if none found.
    """
    return self._table.all()
delete_by_id
delete_by_id(id_value)

Delete a document by its ID.

Parameters:

Name Type Description Default
id_value Union[str, list[str]]

The ID value or list of ID values to delete.

required

Returns:

Type Description
List[int]

The list of removed doc IDs.

Source code in fedbiomed/common/db.py
def delete_by_id(self, id_value: Union[str, list[str]]) -> List[int]:
    """Delete a document by its ID.

    Args:
        id_value: The ID value or list of ID values to delete.

    Returns:
        The list of removed doc IDs.
    """
    id_value = [id_value] if isinstance(id_value, str) else id_value

    for value in id_value:
        if not isinstance(value, str):
            raise TypeError(f"Expected id to be string, got {type(value)} instead.")
        if not id_value:
            raise ValueError("Expected id not to be an empty str.")

    return self._table.delete(self._query[self._id_name].one_of(id_value))
get_all_by_condition
get_all_by_condition(by, cond)

Search entries by a test condition on a field.

Parameters:

Name Type Description Default
by str

field name to search by.

required
cond Callable

A function that takes the field value and returns a boolean.

required

Returns:

Type Description
List[dict]

The list of entries as dicts, or empty list if none found.

Source code in fedbiomed/common/db.py
def get_all_by_condition(self, by: str, cond: Callable) -> List[dict]:
    """Search entries by a test condition on a field.

    Args:
        by: field name to search by.
        cond: A function that takes the field value and returns a boolean.

    Returns:
        The list of entries as dicts, or empty list if none found.
    """
    return self._table.search(self._query[by].test(cond))
get_all_by_value
get_all_by_value(by, value)

Get all entries by a field value (or empty list if none found).

Parameters:

Name Type Description Default
by str

field name to search by.

required
value Any

field value to search for.

required

Returns:

Type Description
List[dict]

The list of entries as dicts, or empty list if none found.

Source code in fedbiomed/common/db.py
def get_all_by_value(self, by: str, value: Any) -> List[dict]:
    """Get all entries by a field value (or empty list if none found).

    Args:
        by: field name to search by.
        value: field value to search for.

    Returns:
        The list of entries as dicts, or empty list if none found.
    """
    return self._table.search(
        self._query[by].one_of(value)
        if isinstance(value, (list, tuple))
        else self._query[by] == value
    )
get_by_id
get_by_id(id_value)

Get a document by its ID.

Parameters:

Name Type Description Default
id_value str

The ID value to search for.

required

Returns:

Type Description
Optional[dict]

The document if found, otherwise None.

Source code in fedbiomed/common/db.py
def get_by_id(self, id_value: str) -> Optional[dict]:
    """Get a document by its ID.

    Args:
        id_value: The ID value to search for.

    Returns:
        The document if found, otherwise None.
    """
    response = self._table.search(self._query[self._id_name] == id_value)
    assert len(response) < 2, (
        f"Multiple entries found for {self._id_name}={id_value}, "
        "which should be unique."
    )
    return response[0] if response else None
insert
insert(entry)

Insert a new document.

Parameters:

Name Type Description Default
entry dict

The document to insert.

required

Returns:

Type Description
int

The document ID of the inserted entry.

Source code in fedbiomed/common/db.py
def insert(self, entry: dict) -> int:
    """Insert a new document.

    Args:
        entry: The document to insert.

    Returns:
        The document ID of the inserted entry.
    """
    if not isinstance(entry, dict):
        raise TypeError(f"Expected entry to be dict, got {type(entry)}.")
    if self._id_name not in entry:
        raise ValueError(f"Entry must contain '{self._id_name}' field.")
    if self.get_by_id(entry[self._id_name]) is not None:
        raise KeyError(
            f"Entry with {self._id_name}={entry[self._id_name]} already exists."
        )
    _ = self._table.insert(entry)
    return entry[self._id_name]
update_by_id
update_by_id(id_value, update)

Update a document by its ID.

Parameters:

Name Type Description Default
id_value str

The ID value to update.

required
update Dict[str, Any]

A dictionary of fields to update.

required

Returns:

Type Description
dict

Updated document.

Source code in fedbiomed/common/db.py
def update_by_id(self, id_value: str, update: Dict[str, Any]) -> dict:
    """Update a document by its ID.

    Args:
        id_value: The ID value to update.
        update: A dictionary of fields to update.

    Returns:
        Updated document.
    """
    if self.get_by_id(id_value) is None:
        raise KeyError(f"No entry found with {self._id_name}={id_value}")

    _ = self._table.update(update, self._query[self._id_name] == id_value)

    return self.get_by_id(id_value)

Functions

cast_

cast_(func)

Decorator function for typing casting

Source code in fedbiomed/common/db.py
def cast_(func):
    """Decorator function for typing casting"""

    # Wraps TinyDb get, all, search and upsert methods
    def wrapped(*args, **kwargs):
        add_docs = kwargs.get("add_docs")
        if add_docs is not None:
            kwargs.pop("add_docs")

        document = func(*args, **kwargs)
        if isinstance(document, list):
            if document and isinstance(document[0], Document):
                casted = [dict(r) for r in document]
            else:
                casted = document
        elif isinstance(document, Document):
            casted = dict(document)
        else:
            # Plain python type
            casted = document

        if add_docs:
            return casted, document
        else:
            return casted

    return wrapped