thejunglejane/datums

View on GitHub
datums/models/base.py

Summary

Maintainability
B
4 hrs
Test Coverage
# -*- coding: utf-8 -*-

import os
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session


# Initialize Base class
Base = declarative_base()
metadata = Base.metadata

session_maker = sessionmaker()
session = scoped_session(session_maker)

engine = create_engine(os.environ['DATABASE_URI'])
session.configure(bind=engine)


def database_setup(engine):
    '''Set up the database.
    '''
    metadata.create_all(engine)


def database_teardown(engine):
    '''BURN IT ALL DOWN (╯°□°)╯︵ ┻━┻
    '''
    metadata.drop_all(engine)


def _action_and_commit(obj, action):
    '''Adds/deletes the instance obj to/from the session based on the action.
    '''
    action(obj)
    session.commit()


class GhostBase(Base):

    '''The GhostBase class extends the declarative Base class.'''

    __abstract__ = True

    def __str__(self, attrs):
        return '''<{0}({1})>'''.format(self.__class__.__name__, ', '.join([
            '='.join([attr, str(getattr(self, attr, ''))]) for attr in attrs]))

    @classmethod
    def _get_instance(cls, **kwargs):
        '''Returns the first instance of cls with attributes matching **kwargs.
        '''
        return session.query(cls).filter_by(**kwargs).first()

    @classmethod
    def get_or_create(cls, **kwargs):
        '''
        If a record matching the instance already exists in the database, then
        return it, otherwise create a new record.
        '''
        q = cls._get_instance(**kwargs)
        if q:
            return q
        q = cls(**kwargs)
        _action_and_commit(q, session.add)
        return q

    # TODO (jsa): _traverse_report only needs to return the ID for an update
    @classmethod
    def update(cls, **kwargs):
        '''
        If a record matching the instance id already exists in the database, 
        update it. If a record matching the instance id does not already exist,
        create a new record.
        '''
        q = cls._get_instance(**{'id': kwargs['id']})
        if q:
            for k, v in kwargs.items():
                setattr(q, k, v)
            _action_and_commit(q, session.add)
        else:
            cls.get_or_create(**kwargs)

    @classmethod
    def delete(cls, **kwargs):
        '''
        If a record matching the instance id exists in the database, delete it.
        '''
        q = cls._get_instance(**kwargs)
        if q:
            _action_and_commit(q, session.delete)


class ResponseClassLegacyAccessor(object):

    def __init__(self, response_class, column, accessor):
        self.response_class = response_class
        self.column = column
        self.accessor = accessor

    def _get_instance(self, **kwargs):
        '''Return the first existing instance of the response record.
        '''
        return session.query(self.response_class).filter_by(**kwargs).first()

    def get_or_create_from_legacy_response(self, response, **kwargs):
        '''
        If a record matching the instance already does not already exist in the
        database, then create a new record.
        '''
        response_cls = self.response_class(**kwargs).get_or_create(**kwargs)
        if not getattr(response_cls, self.column):
            setattr(response_cls, self.column, self.accessor(response))
            _action_and_commit(response_cls, session.add)

    def update(self, response, **kwargs):
        '''
        If a record matching the instance already exists in the database, update
        it, else create a new record.
        '''
        response_cls = self._get_instance(**kwargs)
        if response_cls:
            setattr(response_cls, self.column, self.accessor(response))
            _action_and_commit(response_cls, session.add)
        else:
            self.get_or_create_from_legacy_response(response, **kwargs)

    def delete(self, response, **kwargs):
        '''
        If a record matching the instance id exists in the database, delete it.
        '''
        response_cls = self._get_instance(**kwargs)
        if response_cls:
            _action_and_commit(response_cls, session.delete)


class LocationResponseClassLegacyAccessor(ResponseClassLegacyAccessor):

    def __init__(
            self, response_class, column,
            accessor, venue_column, venue_accessor):
        super(LocationResponseClassLegacyAccessor, self).__init__(
            response_class, column, accessor)
        self.venue_column = venue_column
        self.venue_accessor = venue_accessor

    def get_or_create_from_legacy_response(self, response, **kwargs):
        '''
        If a record matching the instance already does not already exist in the
        database, then create a new record.
        '''
        response_cls = self.response_class(**kwargs).get_or_create(**kwargs)
        if not getattr(response_cls, self.column):
            setattr(response_cls, self.column, self.accessor(response))
            _action_and_commit(response_cls, session.add)
        if not getattr(response_cls, self.venue_column):
            setattr(
                response_cls, self.venue_column, self.venue_accessor(response))
            _action_and_commit(response_cls, session.add)

    def update(self, response, **kwargs):
        '''
        If a record matching the instance already exists in the database, update
        both the column and venue column attributes, else create a new record.
        '''
        response_cls = super(
            LocationResponseClassLegacyAccessor, self)._get_instance(**kwargs)
        if response_cls:
            setattr(response_cls, self.column, self.accessor(response))
            setattr(
                response_cls, self.venue_column, self.venue_accessor(response))
            _action_and_commit(response_cls, session.add)