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:
username
specifies the database usernamepassword
specifies the database passwordname
specifies the database namehostname
specifies the hostname the database is running onport
specifies 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
server
is a CouchDB instancetable_name
specifies 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)