import datetime import logging import uuid from typing import Optional import peewee import peewee_plus from section7 import configuration from section7 import constants INTERFACE = peewee.DatabaseProxy() def initialize(config: Optional[configuration.Section7Config] = None): """Initialize the database interface Defining the database as an `unconfigured proxy object `_ allows it to be configured at runtime based on the config values. :param config: Populated configuration container object """ logger = logging.getLogger(__name__) config = config or configuration.load() if config.database.backend == constants.DatabaseBackend.SQLITE: logger.debug("Using SQLite database backend") logger.debug(f"Applying SQLite pragmas: {peewee_plus.SQLITE_DEFAULT_PRAGMAS}") database = peewee.SqliteDatabase( config.database.sqlite.path, pragmas=peewee_plus.SQLITE_DEFAULT_PRAGMAS ) elif config.database.backend == constants.DatabaseBackend.MARIADB: logger.debug("Using MariaDB database backend") logger.debug( "Configuring MariaDB:" f" {config.database.mariadb.username}@{config.database.mariadb.hostname}:{config.database.mariadb.port}," f" with database '{config.database.mariadb.schema}'" ) database = peewee.MySQLDatabase( config.database.mariadb.schema, host=config.database.mariadb.hostname, port=config.database.mariadb.port, user=config.database.mariadb.username, password=config.database.mariadb.password, charset="utf8mb4", ) else: raise RuntimeError( f"Invalid storage backend in configuration: {config.database.backend.name}" ) INTERFACE.initialize(database) with INTERFACE.atomic(): INTERFACE.create_tables([DisclosureRecord]) class Section7Model(peewee.Model): """Base model for defining common fields and attaching database""" class Meta: # pylint: disable=too-few-public-methods,missing-class-docstring database = INTERFACE uuid = peewee.UUIDField(null=False, unique=True, default=uuid.uuid4) created = peewee.DateTimeField(null=False, default=datetime.datetime.utcnow) class DisclosureRecord(Section7Model): """Record of a user submitted payment disclosure :param value: The monetary value of the compensation :param currency: The currency the value is represented in :param rate: The rate that the compensation is assigned :param additionals: Mapping of additional, user defined, compensation details :param recipients: List of email addresses that should receive the compensation disclosure :param publish: Whether the record should be published in the publicly available dataset :param age: Optional age of the user :param gender: Optional gender of the user :param race: Optional race of the user :param country: Optional country where the user's job is located :param city: Optional city where the user's job is located :param industry: Optional industry that the user works in :param title: Optional job title of the user's job :param company: Optional company the user works at :param years_experience: Optional number of years the user has worked in the inudstry :param years_at_company: Optional number of years the user has worked at the company """ value = peewee.DecimalField(max_digits=20, decimal_places=3) currency = peewee_plus.EnumField(constants.Currency) rate = peewee_plus.EnumField(constants.PayRate) additionals = peewee_plus.JSONField(default={}) recipients = peewee_plus.JSONField(default=[]) publish = peewee.BooleanField() age = peewee.IntegerField(null=True) gender = peewee.CharField(null=True) race = peewee.CharField(null=True) country = peewee_plus.EnumField(constants.Country, null=True) city = peewee.CharField(null=True) industry = peewee_plus.EnumField(constants.Industry, null=True) title = peewee.CharField(null=True) years_experience = peewee.IntegerField(null=True) years_at_company = peewee.IntegerField(null=True)