jarvis.Database
View Source
# # Copyright (c) 2020 by Philipp Scheer. All Rights Reserved. # import types import couchdb2 import requests import traceback class Database: """ A Database class which handles DB connections and exceptions """ Exception = requests.ConnectionError """ An exception or a list of exception which might occur while making operations with the Database """ def __init__(self, username: str = "jarvis", password: str = "jarvis", name: str = "jarvis", hostname: str = "127.0.0.1", port: int = 5984) -> None: """ Creates a Database connection with the following arguments: * `username` specifies the database username * `password` specifies the database password * `name` specifies the database name * `hostname` specifies the hostname the database is running on * `port` specifies the port the database is running on """ self.host = hostname self.port = port self.user = username self.name = name try: self.server = couchdb2.Server( f"http://{self.host}:{self.port}/", username=self.user, password=password) except Database.Exception: from jarvis import Logger Logger.e1("database", "refused", "connection refused, database not running", traceback.format_exc(), database_entry=False) exit(1) def table(self, table_name: str, pure: bool = False): """ Get a table in the database Because CouchDB does not support tables, all tables are prefixed with the database name `self.name` The final table name therefore is `self.name`-`table_name` If `pure` is True, the final table name is `table_name` """ return Table(self.server, table_name if pure else f"{self.name}-{table_name}") def delete(self): """ Delete the current Database """ for db in self.server: if str(db).startswith(f"{self.name}-"): db.destroy() def drop(self): """ Delete the current Database """ return self.delete() @property def stats(self): """ Contains Database stats """ return self.server.get_node_stats(nodename='_local') @property def up(self): """ Check if Database is up and running """ return self.server.up() def __str__(self) -> str: """ Return string representation of the Database """ return f"jarvis.Database.Database({self.name})" class Table: """ Represents a Table in a Database This class should never be called by the user, only by the `Database` class """ def __init__(self, server: couchdb2.Server, table_name: str) -> None: """ Initialize the table * `server` is a CouchDB instance * `table_name` specifies the table name """ self.server = server self.name = table_name if self.name in self.server: self.table = self.server.get(self.name) else: self.table = self.server.create(self.name) def get(self, id: str) -> dict: """ Get a document from the current table by `id` """ return self.table.get(id) def all(self) -> list: """ Return all documents from the current table """ all_list = DocumentList(self) for doc in self.table: all_list.add(dict(doc)) return all_list def insert(self, document: dict) -> any: """ Insert a document in the current table """ return self.table.put(document) def filter(self, filter: any = {}) -> list: """ Filters a table `filter` can be either a lamba or object Returns a list of all documents that match """ doc_list = DocumentList(self) if (isinstance(filter, types.LambdaType)): for document in self.all(): if filter.__call__(document): doc_list.add(document) if (isinstance(filter, dict)): if len(filter) == 0: return self.all() for document in self.all(): for key in filter: if key in document and document[key] == filter[key]: doc_list.add(document) return doc_list def find(self, filter: dict = {}) -> list: """ Find documents by a <a href="https://pouchdb.com/guides/mango-queries.html">Mango query</a> """ doc_list = DocumentList(self) doc_list.document_list = self.table.find(filter)["docs"] return doc_list def delete(self, document): """ Delete a document from the table """ self.table.purge([document]) def drop(self): """ Drop the current table """ return self.table.destroy() @property def size(self): """ Return the size of the current table in bytes """ return dict(self.table.get_info())["sizes"]["active"] def __str__(self) -> str: """ Returns string representation of the current table """ return f"jarvis.Database.Table({self.name})" class DocumentList: """ A list of object with various additional features This class should never be called by the user, only by the `Table` class """ def __init__(self, table: Table) -> None: """ Initialize an empty DocumentList * `table` is a `Table` object which got called by `Database` """ self.table = table self.document_list = [] def add(self, item: dict) -> None: """ Add a document to the DocumentList """ self.document_list.append(item) def set(self, new_document: dict) -> None: """ Update a document, the document needs to contain an _id and _rev (CouchDB internals) """ for document in self.document_list: if "_id" not in new_document: new_document["_id"] = document["_id"] new_document["_rev"] = document["_rev"] self.table.insert(new_document) def update(self, modify_function_or_new_object: any) -> None: """ Update all documents using a function or a dictionary with updated keys The if a function is passed, the object the function returns is used, else the merged dictionaries """ if isinstance(modify_function_or_new_object, dict): for document in self.document_list: def merge_dicts(x, y): z = x.copy() z.update(y) return z self.table.insert(merge_dicts(document, modify_function_or_new_object)) else: for old_document in self.document_list: new_document = modify_function_or_new_object(dict(old_document)) self.table.insert(new_document) def delete(self) -> None: """ Delete all documents in the current DocumentList """ for document in self.document_list: self.table.delete(document) def sort(self, keyname: str) -> None: """ Sort all documents in the current DocumentList by a given `keyname` """ self.document_list = sorted( self.document_list, key=lambda k: k[keyname] if keyname in k else 0) return self def reverse(self): """ Reverse the current DocumentList """ self.document_list.reverse() return self @property def found(self): """ Check if the Table query returned any results (length of the current DocumentList is not 0) """ return len(self.document_list) != 0 def __getitem__(self, key: int): """ Get element from DocumentList """ return self.document_list[key] def __list__(self): """ Return the full DocumentList as a list object """ return self.document_list def __str__(self) -> str: """ String representation of the current DocumentList """ return f"jarvis.Database.DocumentList(table={str(self.table)}, list={str(self.document_list)})"
View Source
class Database: """ A Database class which handles DB connections and exceptions """ Exception = requests.ConnectionError """ An exception or a list of exception which might occur while making operations with the Database """ def __init__(self, username: str = "jarvis", password: str = "jarvis", name: str = "jarvis", hostname: str = "127.0.0.1", port: int = 5984) -> None: """ Creates a Database connection with the following arguments: * `username` specifies the database username * `password` specifies the database password * `name` specifies the database name * `hostname` specifies the hostname the database is running on * `port` specifies the port the database is running on """ self.host = hostname self.port = port self.user = username self.name = name try: self.server = couchdb2.Server( f"http://{self.host}:{self.port}/", username=self.user, password=password) except Database.Exception: from jarvis import Logger Logger.e1("database", "refused", "connection refused, database not running", traceback.format_exc(), database_entry=False) exit(1) def table(self, table_name: str, pure: bool = False): """ Get a table in the database Because CouchDB does not support tables, all tables are prefixed with the database name `self.name` The final table name therefore is `self.name`-`table_name` If `pure` is True, the final table name is `table_name` """ return Table(self.server, table_name if pure else f"{self.name}-{table_name}") def delete(self): """ Delete the current Database """ for db in self.server: if str(db).startswith(f"{self.name}-"): db.destroy() def drop(self): """ Delete the current Database """ return self.delete() @property def stats(self): """ Contains Database stats """ return self.server.get_node_stats(nodename='_local') @property def up(self): """ Check if Database is up and running """ return self.server.up() def __str__(self) -> str: """ Return string representation of the Database """ return f"jarvis.Database.Database({self.name})"
A Database class which handles DB connections and exceptions
View Source
def __init__(self, username: str = "jarvis", password: str = "jarvis", name: str = "jarvis", hostname: str = "127.0.0.1", port: int = 5984) -> None: """ Creates a Database connection with the following arguments: * `username` specifies the database username * `password` specifies the database password * `name` specifies the database name * `hostname` specifies the hostname the database is running on * `port` specifies the port the database is running on """ self.host = hostname self.port = port self.user = username self.name = name try: self.server = couchdb2.Server( f"http://{self.host}:{self.port}/", username=self.user, password=password) except Database.Exception: from jarvis import Logger Logger.e1("database", "refused", "connection refused, database not running", traceback.format_exc(), database_entry=False) exit(1)
Creates a Database connection with the following arguments:
usernamespecifies the database usernamepasswordspecifies the database passwordnamespecifies the database namehostnamespecifies the hostname the database is running onportspecifies the port the database is running on
View Source
def table(self, table_name: str, pure: bool = False): """ Get a table in the database Because CouchDB does not support tables, all tables are prefixed with the database name `self.name` The final table name therefore is `self.name`-`table_name` If `pure` is True, the final table name is `table_name` """ return Table(self.server, table_name if pure else f"{self.name}-{table_name}")
Get a table in the database
Because CouchDB does not support tables, all tables are prefixed with the database name self.name
The final table name therefore is self.name-table_name
If pure is True, the final table name is table_name
View Source
def delete(self): """ Delete the current Database """ for db in self.server: if str(db).startswith(f"{self.name}-"): db.destroy()
Delete the current Database
View Source
def drop(self): """ Delete the current Database """ return self.delete()
Delete the current Database
Contains Database stats
Check if Database is up and running
View Source
class ConnectionError(RequestException): """A Connection error occurred."""
A Connection error occurred.
Inherited Members
- requests.exceptions.RequestException
- RequestException
- builtins.OSError
- errno
- strerror
- filename
- filename2
- winerror
- characters_written
- builtins.BaseException
- with_traceback
- args
View Source
class Table: """ Represents a Table in a Database This class should never be called by the user, only by the `Database` class """ def __init__(self, server: couchdb2.Server, table_name: str) -> None: """ Initialize the table * `server` is a CouchDB instance * `table_name` specifies the table name """ self.server = server self.name = table_name if self.name in self.server: self.table = self.server.get(self.name) else: self.table = self.server.create(self.name) def get(self, id: str) -> dict: """ Get a document from the current table by `id` """ return self.table.get(id) def all(self) -> list: """ Return all documents from the current table """ all_list = DocumentList(self) for doc in self.table: all_list.add(dict(doc)) return all_list def insert(self, document: dict) -> any: """ Insert a document in the current table """ return self.table.put(document) def filter(self, filter: any = {}) -> list: """ Filters a table `filter` can be either a lamba or object Returns a list of all documents that match """ doc_list = DocumentList(self) if (isinstance(filter, types.LambdaType)): for document in self.all(): if filter.__call__(document): doc_list.add(document) if (isinstance(filter, dict)): if len(filter) == 0: return self.all() for document in self.all(): for key in filter: if key in document and document[key] == filter[key]: doc_list.add(document) return doc_list def find(self, filter: dict = {}) -> list: """ Find documents by a <a href="https://pouchdb.com/guides/mango-queries.html">Mango query</a> """ doc_list = DocumentList(self) doc_list.document_list = self.table.find(filter)["docs"] return doc_list def delete(self, document): """ Delete a document from the table """ self.table.purge([document]) def drop(self): """ Drop the current table """ return self.table.destroy() @property def size(self): """ Return the size of the current table in bytes """ return dict(self.table.get_info())["sizes"]["active"] def __str__(self) -> str: """ Returns string representation of the current table """ return f"jarvis.Database.Table({self.name})"
Represents a Table in a Database
This class should never be called by the user, only by the Database class
View Source
def __init__(self, server: couchdb2.Server, table_name: str) -> None: """ Initialize the table * `server` is a CouchDB instance * `table_name` specifies the table name """ self.server = server self.name = table_name if self.name in self.server: self.table = self.server.get(self.name) else: self.table = self.server.create(self.name)
Initialize the table
serveris a CouchDB instancetable_namespecifies the table name
View Source
def get(self, id: str) -> dict: """ Get a document from the current table by `id` """ return self.table.get(id)
Get a document from the current table by id
View Source
def all(self) -> list: """ Return all documents from the current table """ all_list = DocumentList(self) for doc in self.table: all_list.add(dict(doc)) return all_list
Return all documents from the current table
View Source
def insert(self, document: dict) -> any: """ Insert a document in the current table """ return self.table.put(document)
Insert a document in the current table
View Source
def filter(self, filter: any = {}) -> list: """ Filters a table `filter` can be either a lamba or object Returns a list of all documents that match """ doc_list = DocumentList(self) if (isinstance(filter, types.LambdaType)): for document in self.all(): if filter.__call__(document): doc_list.add(document) if (isinstance(filter, dict)): if len(filter) == 0: return self.all() for document in self.all(): for key in filter: if key in document and document[key] == filter[key]: doc_list.add(document) return doc_list
Filters a table
filter can be either a lamba or object
Returns a list of all documents that match
View Source
def find(self, filter: dict = {}) -> list: """ Find documents by a <a href="https://pouchdb.com/guides/mango-queries.html">Mango query</a> """ doc_list = DocumentList(self) doc_list.document_list = self.table.find(filter)["docs"] return doc_list
Find documents by a Mango query
View Source
def delete(self, document): """ Delete a document from the table """ self.table.purge([document])
Delete a document from the table
View Source
def drop(self): """ Drop the current table """ return self.table.destroy()
Drop the current table
Return the size of the current table in bytes
View Source
class DocumentList: """ A list of object with various additional features This class should never be called by the user, only by the `Table` class """ def __init__(self, table: Table) -> None: """ Initialize an empty DocumentList * `table` is a `Table` object which got called by `Database` """ self.table = table self.document_list = [] def add(self, item: dict) -> None: """ Add a document to the DocumentList """ self.document_list.append(item) def set(self, new_document: dict) -> None: """ Update a document, the document needs to contain an _id and _rev (CouchDB internals) """ for document in self.document_list: if "_id" not in new_document: new_document["_id"] = document["_id"] new_document["_rev"] = document["_rev"] self.table.insert(new_document) def update(self, modify_function_or_new_object: any) -> None: """ Update all documents using a function or a dictionary with updated keys The if a function is passed, the object the function returns is used, else the merged dictionaries """ if isinstance(modify_function_or_new_object, dict): for document in self.document_list: def merge_dicts(x, y): z = x.copy() z.update(y) return z self.table.insert(merge_dicts(document, modify_function_or_new_object)) else: for old_document in self.document_list: new_document = modify_function_or_new_object(dict(old_document)) self.table.insert(new_document) def delete(self) -> None: """ Delete all documents in the current DocumentList """ for document in self.document_list: self.table.delete(document) def sort(self, keyname: str) -> None: """ Sort all documents in the current DocumentList by a given `keyname` """ self.document_list = sorted( self.document_list, key=lambda k: k[keyname] if keyname in k else 0) return self def reverse(self): """ Reverse the current DocumentList """ self.document_list.reverse() return self @property def found(self): """ Check if the Table query returned any results (length of the current DocumentList is not 0) """ return len(self.document_list) != 0 def __getitem__(self, key: int): """ Get element from DocumentList """ return self.document_list[key] def __list__(self): """ Return the full DocumentList as a list object """ return self.document_list def __str__(self) -> str: """ String representation of the current DocumentList """ return f"jarvis.Database.DocumentList(table={str(self.table)}, list={str(self.document_list)})"
A list of object with various additional features
This class should never be called by the user, only by the Table class
View Source
def __init__(self, table: Table) -> None: """ Initialize an empty DocumentList * `table` is a `Table` object which got called by `Database` """ self.table = table self.document_list = []
View Source
def add(self, item: dict) -> None: """ Add a document to the DocumentList """ self.document_list.append(item)
Add a document to the DocumentList
View Source
def set(self, new_document: dict) -> None: """ Update a document, the document needs to contain an _id and _rev (CouchDB internals) """ for document in self.document_list: if "_id" not in new_document: new_document["_id"] = document["_id"] new_document["_rev"] = document["_rev"] self.table.insert(new_document)
Update a document, the document needs to contain an _id and _rev (CouchDB internals)
View Source
def update(self, modify_function_or_new_object: any) -> None: """ Update all documents using a function or a dictionary with updated keys The if a function is passed, the object the function returns is used, else the merged dictionaries """ if isinstance(modify_function_or_new_object, dict): for document in self.document_list: def merge_dicts(x, y): z = x.copy() z.update(y) return z self.table.insert(merge_dicts(document, modify_function_or_new_object)) else: for old_document in self.document_list: new_document = modify_function_or_new_object(dict(old_document)) self.table.insert(new_document)
Update all documents using a function or a dictionary with updated keys
The if a function is passed, the object the function returns is used,
else the merged dictionaries
View Source
def delete(self) -> None: """ Delete all documents in the current DocumentList """ for document in self.document_list: self.table.delete(document)
Delete all documents in the current DocumentList
View Source
def sort(self, keyname: str) -> None: """ Sort all documents in the current DocumentList by a given `keyname` """ self.document_list = sorted( self.document_list, key=lambda k: k[keyname] if keyname in k else 0) return self
Sort all documents in the current DocumentList by a given keyname
View Source
def reverse(self): """ Reverse the current DocumentList """ self.document_list.reverse() return self
Reverse the current DocumentList
Check if the Table query returned any results (length of the current DocumentList is not 0)