webservices/common/models/candidates.py

Summary

Maintainability
A
1 hr
Test Coverage
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ARRAY, TSVECTOR
from sqlalchemy.ext.declarative import declared_attr

from webservices import docs

from .base import db, BaseModel


class CandidateSearch(BaseModel):
    __tablename__ = 'ofec_candidate_fulltext_mv'

    id = db.Column(db.String)
    name = db.Column(db.String, doc=docs.CANDIDATE_NAME)
    office_sought = db.Column(db.String, doc=docs.OFFICE)
    fulltxt = db.Column(TSVECTOR)
    receipts = db.Column(db.Numeric(30, 2))


class CandidateFlags(db.Model):
    __tablename__ = 'ofec_candidate_flag_mv'

    candidate_id = db.Column(db.String, index=True, primary_key=True, doc=docs.CANDIDATE_ID)
    federal_funds_flag = db.Column(db.Boolean, index=True, doc=docs.FEDERAL_FUNDS_FLAG)
    has_raised_funds = db.Column(db.Boolean, index=True, doc=docs.HAS_RAISED_FUNDS)


class BaseCandidate(BaseModel):
    __abstract__ = True

    name = db.Column(db.String(100), index=True, doc=docs.CANDIDATE_NAME)
    office = db.Column(db.String(1), index=True, doc=docs.OFFICE)
    office_full = db.Column(db.String(9), doc=docs.OFFICE_FULL)
    party = db.Column(db.String(3), index=True, doc=docs.PARTY)
    party_full = db.Column(db.String(255), doc=docs.PARTY_FULL)
    state = db.Column(db.String(2), index=True, doc=docs.STATE)
    district = db.Column(db.String(2), index=True, doc=docs.DISTRICT)
    # ? difference between district and district_number
    district_number = db.Column(db.Integer, index=True, doc=docs.CANDIDATE_STATUS)
    election_districts = db.Column(ARRAY(db.String), index=True, doc=docs.DISTRICT)
    election_years = db.Column(ARRAY(db.Integer), index=True, doc='Years in which a candidate ran for office.')
    cycles = db.Column(ARRAY(db.Integer), index=True, doc=docs.CANDIDATE_CYCLE)
    candidate_status = db.Column(db.String(1), index=True, doc=docs.CANDIDATE_STATUS)
    incumbent_challenge = db.Column(db.String(1), index=True, doc=docs.INCUMBENT_CHALLENGE)
    incumbent_challenge_full = db.Column(db.String(10), doc=docs.INCUMBENT_CHALLENGE_FULL)
    load_date = db.Column(db.Date, index=True, doc=docs.LOAD_DATE)

    first_file_date = db.Column(db.Date, index=True, doc=docs.FIRST_CANDIDATE_FILE_DATE)
    last_file_date = db.Column(db.Date, doc=docs.LAST_CANDIDATE_FILE_DATE)
    last_f2_date = db.Column(db.Date, doc=docs.LAST_F2_DATE)

    @declared_attr
    def flags(self):
        return sa.orm.relationship(
            CandidateFlags,
            primaryjoin=sa.orm.foreign(CandidateFlags.candidate_id) == self.candidate_id,
            uselist=False,
        )


class BaseConcreteCandidate(BaseCandidate):
    __tablename__ = 'ofec_candidate_detail_mv'

    candidate_id = db.Column(db.String, unique=True, doc=docs.CANDIDATE_ID)


class Candidate(BaseConcreteCandidate):
    __table_args__ = {'extend_existing': True}
    __tablename__ = 'ofec_candidate_detail_mv'

    active_through = db.Column(db.Integer, doc=docs.ACTIVE_THROUGH)

    # Customize join to restrict to principal committees
    principal_committees = db.relationship(
        'Committee',
        secondary='ofec_cand_cmte_linkage_mv',
        secondaryjoin='''and_(
            Committee.committee_id == ofec_cand_cmte_linkage_mv.c.cmte_id,
            ofec_cand_cmte_linkage_mv.c.cmte_dsgn == 'P',
        )''',
        order_by=(
            'desc(ofec_cand_cmte_linkage_mv.c.cand_election_yr),'
            'desc(Committee.last_file_date),'
        )
    )


class CandidateDetail(BaseConcreteCandidate):
    __table_args__ = {'extend_existing': True}
    __tablename__ = 'ofec_candidate_detail_mv'

    address_city = db.Column(db.String(100), doc='City of candidate\'s address, as reported on their Form 2.')
    address_state = db.Column(db.String(2), doc='State of candidate\'s address, as reported on their Form 2.')
    address_street_1 = db.Column(db.String(200), doc='Street of candidate\'s address, as reported on their Form 2.')
    address_street_2 = db.Column(db.String(200), doc='Additional street information of candidate\'s address, as reported on their Form 2.')
    address_zip = db.Column(db.String(10), doc='Zip code of candidate\'s address, as reported on their Form 2.')
    candidate_inactive = db.Column(db.Boolean, doc='True indicates that a candidate is inactive.')
    active_through = db.Column(db.Integer, doc=docs.ACTIVE_THROUGH)


class CandidateHistory(BaseCandidate):
    __tablename__ = 'ofec_candidate_history_mv'

    candidate_id = db.Column(db.String, primary_key=True, index=True, doc=docs.CANDIDATE_ID)
    two_year_period = db.Column(db.Integer, primary_key=True, index=True, doc=docs.CANDIDATE_CYCLE)
    candidate_election_year = db.Column(db.Integer, doc="The last year of the cycle for this election.")
    address_city = db.Column(db.String(100), doc='City of candidate\'s address, as reported on their Form 2.')
    address_state = db.Column(db.String(2), doc='State of candidate\'s address, as reported on their Form 2.')
    address_street_1 = db.Column(db.String(200), doc='Street of candidate\'s address, as reported on their Form 2.')
    address_street_2 = db.Column(db.String(200), doc='Additional street information of candidate\'s address, as reported on their Form 2.')
    address_zip = db.Column(db.String(10), doc='Zip code of candidate\'s address, as reported on their Form 2.')
    candidate_inactive = db.Column(db.Boolean, doc='True indicates that a candidate is inactive.')
    active_through = db.Column(db.Integer, doc=docs.ACTIVE_THROUGH)


class CandidateHistoryLatest(BaseCandidate):
    __tablename__ = 'ofec_candidate_history_latest_mv'
    #Is there any good reason to have this as a separate model?
    candidate_id = db.Column(db.String, primary_key=True, index=True)
    two_year_period = db.Column(db.Integer, primary_key=True, index=True)
    candidate_election_year = db.Column(db.Integer, doc="The last year of the cycle for this election.")
    address_city = db.Column(db.String(100))
    address_state = db.Column(db.String(2))
    address_street_1 = db.Column(db.String(200))
    address_street_2 = db.Column(db.String(200))
    address_zip = db.Column(db.String(10))
    candidate_inactive = db.Column(db.Boolean)


class CandidateTotal(db.Model):
    __tablename__ = 'ofec_candidate_totals_mv'
    candidate_id = db.Column(db.String, index=True, primary_key=True)
    election_year = db.Column(db.Integer, index=True, primary_key=True)
    cycle = db.Column(db.Integer, index=True, primary_key=True)
    is_election = db.Column(db.Boolean, index=True, primary_key=True)
    receipts = db.Column(db.Numeric(30, 2), index=True)
    disbursements = db.Column(db.Numeric(30, 2), index=True)
    cash_on_hand_end_period = db.Column(db.Numeric(30, 2))
    debts_owed_by_committee = db.Column(db.Numeric(30, 2))
    coverage_start_date = db.Column(db.Date, doc=docs.COVERAGE_START_DATE)
    coverage_end_date = db.Column(db.Date, doc=docs.COVERAGE_END_DATE)


class CandidateElection(db.Model):
    __tablename__ = 'ofec_candidate_election_mv'

    candidate_id = db.Column(db.String, primary_key=True, index=True, doc=docs.CANDIDATE_ID)
    cand_election_year = db.Column(db.Integer, primary_key=True, index=True, doc='Year a candidate runs for federal office.')
    prev_election_year = db.Column(db.Integer, index=True)