diff --git a/db_revisions/versions/6613e1e2c133_replace_is_active_with_lei_status_in_fi.py b/db_revisions/versions/6613e1e2c133_replace_is_active_with_lei_status_in_fi.py new file mode 100644 index 0000000..c11cc46 --- /dev/null +++ b/db_revisions/versions/6613e1e2c133_replace_is_active_with_lei_status_in_fi.py @@ -0,0 +1,102 @@ +"""Replace is_active with lei_status in financial_institutions table + +Revision ID: 6613e1e2c133 +Revises: 6dd77f09fae6 +Create Date: 2024-11-13 00:43:53.489086 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + +from db_revisions.utils import table_exists, get_table_by_name, get_indices_from_collection + + +# revision identifiers, used by Alembic. +revision: str = "6613e1e2c133" +down_revision: Union[str, None] = "6dd77f09fae6" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + +lei_status_seed_data = [ + {"code": "ISSUED", "name": "Issued", "can_file": True}, + {"code": "LAPSED", "name": "Lapsed", "can_file": False}, + {"code": "RETIRED", "name": "Retired", "can_file": False}, +] + + +def upgrade() -> None: + + # Creating lei_status table + if not table_exists("lei_status"): + op.create_table( + "lei_status", + sa.Column("code", sa.String(), nullable=False), + sa.Column("name", sa.String(), nullable=False), + sa.Column("can_file", sa.Boolean(), nullable=False), + sa.Column("event_time", sa.DateTime(), server_default=sa.func.now(), nullable=False), + sa.PrimaryKeyConstraint("code"), + sa.UniqueConstraint("name"), + ) + + # Seeding lei_status table + lei_status_table = get_table_by_name("lei_status") + op.bulk_insert(lei_status_table, lei_status_seed_data) + + # Removing is_active from and adding lei_status_code to financial_institutions table + op.add_column("financial_institutions", sa.Column("lei_status_code", sa.String(), nullable=True)) + + op.execute( + "UPDATE financial_institutions SET lei_status_code = CASE is_active WHEN True THEN 'ISSUED' ELSE 'LAPSED' END" + ) + + with op.batch_alter_table("financial_institutions") as batch_op: + batch_op.alter_column("lei_status_code", existing_nullable=True, nullable=False) + batch_op.create_index( + index_name=batch_op.f("ix_financial_institutions_lei_status_code"), + columns=["lei_status_code"], + unique=False, + ) + batch_op.create_foreign_key( + "fk_lei_status_financial_institutions", + "lei_status", + ["lei_status_code"], + ["code"], + ) + + batch_op.drop_index(index_name="ix_financial_institutions_is_active") + batch_op.drop_column("is_active") + + # Removing is_active from and adding lei_status_code to financial_institutions_history table + op.add_column("financial_institutions_history", sa.Column("lei_status_code", sa.String())) + + +def downgrade() -> None: + + op.drop_column("financial_institutions_history", "lei_status_code") + + op.add_column( + "financial_institutions", + sa.Column(name="is_active", type_=sa.Boolean(), nullable=True), + ) + op.execute( + "UPDATE financial_institutions SET is_active = CASE lei_status_code WHEN 'ISSUED' THEN True ELSE False END" + ) + + with op.batch_alter_table("financial_institutions") as batch_op: + batch_op.alter_column("is_active", existing_nullable=True, nullable=False) + batch_op.create_index( + index_name=batch_op.f("ix_financial_institutions_is_active"), columns=["is_active"], unique=False + ) + + batch_op.drop_constraint(constraint_name="fk_lei_status_financial_institutions") + batch_op.drop_index("ix_financial_institutions_lei_status_code") + batch_op.drop_column("lei_status_code") + + lei_status_table = get_table_by_name("lei_status") + codes = get_indices_from_collection(lei_status_seed_data, "code") + op.execute(lei_status_table.delete().where(lei_status_table.c.code.in_(codes))) + + op.drop_table("lei_status") diff --git a/db_revisions/versions/6dd77f09fae6_add_char_limit_to_financial_institution_.py b/db_revisions/versions/6dd77f09fae6_add_char_limit_to_financial_institution_.py index 8988edc..b015812 100644 --- a/db_revisions/versions/6dd77f09fae6_add_char_limit_to_financial_institution_.py +++ b/db_revisions/versions/6dd77f09fae6_add_char_limit_to_financial_institution_.py @@ -8,9 +8,6 @@ from typing import Sequence, Union -from alembic import op -import sqlalchemy as sa - # revision identifiers, used by Alembic. revision: str = "6dd77f09fae6" @@ -20,24 +17,8 @@ def upgrade() -> None: - with op.batch_alter_table("financial_institutions", schema=None) as batch_op: - batch_op.alter_column("name", type_=sa.String(255), nullable=False) - batch_op.alter_column("hq_address_street_1", type_=sa.String(255), nullable=False) - batch_op.alter_column("hq_address_street_2", type_=sa.String(255), nullable=True) - batch_op.alter_column("hq_address_street_3", type_=sa.String(255), nullable=True) - batch_op.alter_column("hq_address_street_4", type_=sa.String(255), nullable=True) - batch_op.alter_column("hq_address_city", type_=sa.String(255), nullable=False) - batch_op.alter_column("parent_legal_name", type_=sa.String(255), nullable=True) - batch_op.alter_column("top_holder_legal_name", type_=sa.String(255), nullable=True) + pass def downgrade() -> None: - with op.batch_alter_table("financial_institutions", schema=None) as batch_op: - batch_op.alter_column("name", type_=sa.String, nullable=False) - batch_op.alter_column("hq_address_street_1", type_=sa.String, nullable=False) - batch_op.alter_column("hq_address_street_2", type_=sa.String, nullable=True) - batch_op.alter_column("hq_address_street_3", type_=sa.String, nullable=True) - batch_op.alter_column("hq_address_street_4", type_=sa.String, nullable=True) - batch_op.alter_column("hq_address_city", type_=sa.String, nullable=False) - batch_op.alter_column("parent_legal_name", type_=sa.String, nullable=True) - batch_op.alter_column("top_holder_legal_name", type_=sa.String, nullable=True) + pass diff --git a/db_revisions/versions/ca39ad68af05_undo_revision_6dd77f09fae6.py b/db_revisions/versions/ca39ad68af05_undo_revision_6dd77f09fae6.py new file mode 100644 index 0000000..f1874d9 --- /dev/null +++ b/db_revisions/versions/ca39ad68af05_undo_revision_6dd77f09fae6.py @@ -0,0 +1,35 @@ +"""Undo revision 6dd77f09fae6 + +Revision ID: ca39ad68af05 +Revises: 6613e1e2c133 +Create Date: 2024-11-20 14:58:54.366468 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = "ca39ad68af05" +down_revision: Union[str, None] = "6613e1e2c133" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + with op.batch_alter_table("financial_institutions", schema=None) as batch_op: + batch_op.alter_column("name", type_=sa.String(), nullable=False) + batch_op.alter_column("hq_address_street_1", type_=sa.String(), nullable=False) + batch_op.alter_column("hq_address_street_2", type_=sa.String(), nullable=True) + batch_op.alter_column("hq_address_street_3", type_=sa.String(), nullable=True) + batch_op.alter_column("hq_address_street_4", type_=sa.String(), nullable=True) + batch_op.alter_column("hq_address_city", type_=sa.String(), nullable=False) + batch_op.alter_column("parent_legal_name", type_=sa.String(), nullable=True) + batch_op.alter_column("top_holder_legal_name", type_=sa.String(), nullable=True) + + +def downgrade() -> None: + pass diff --git a/src/regtech_user_fi_management/entities/models/dao.py b/src/regtech_user_fi_management/entities/models/dao.py index 3ccb095..d0261f6 100644 --- a/src/regtech_user_fi_management/entities/models/dao.py +++ b/src/regtech_user_fi_management/entities/models/dao.py @@ -41,8 +41,9 @@ class FinancialInstitutionDao(AuditMixin, Base): version: Mapped[int] = mapped_column(nullable=False, default=0) __mapper_args__ = {"version_id_col": version, "version_id_generator": False} lei: Mapped[str] = mapped_column(String(20), unique=True, index=True, primary_key=True) - name: Mapped[str] = mapped_column(String(255), index=True) - is_active: Mapped[bool] = mapped_column(index=True) + name: Mapped[str] = mapped_column(index=True) + lei_status_code: Mapped[str] = mapped_column(ForeignKey("lei_status.code"), nullable=False) + lei_status: Mapped["LeiStatusDao"] = relationship(lazy="selectin") domains: Mapped[List["FinancialInstitutionDomainDao"]] = relationship( "FinancialInstitutionDomainDao", back_populates="fi", lazy="selectin" ) @@ -53,19 +54,19 @@ class FinancialInstitutionDao(AuditMixin, Base): hmda_institution_type_id: Mapped[str] = mapped_column(ForeignKey("hmda_institution_type.id"), nullable=True) hmda_institution_type: Mapped["HMDAInstitutionTypeDao"] = relationship(lazy="selectin") sbl_institution_types: Mapped[List[SblTypeMappingDao]] = relationship(lazy="selectin", cascade="all, delete-orphan") - hq_address_street_1: Mapped[str] = mapped_column(String(255)) - hq_address_street_2: Mapped[str] = mapped_column(String(255), nullable=True) - hq_address_street_3: Mapped[str] = mapped_column(String(255), nullable=True) - hq_address_street_4: Mapped[str] = mapped_column(String(255), nullable=True) - hq_address_city: Mapped[str] = mapped_column(String(255)) + hq_address_street_1: Mapped[str] = mapped_column() + hq_address_street_2: Mapped[str] = mapped_column(nullable=True) + hq_address_street_3: Mapped[str] = mapped_column(nullable=True) + hq_address_street_4: Mapped[str] = mapped_column(nullable=True) + hq_address_city: Mapped[str] = mapped_column() hq_address_state_code: Mapped[str] = mapped_column(ForeignKey("address_state.code"), nullable=True) hq_address_state: Mapped["AddressStateDao"] = relationship(lazy="selectin") hq_address_zip: Mapped[str] = mapped_column(String(5)) parent_lei: Mapped[str] = mapped_column(String(20), nullable=True) - parent_legal_name: Mapped[str] = mapped_column(String(255), nullable=True) + parent_legal_name: Mapped[str] = mapped_column(nullable=True) parent_rssd_id: Mapped[int] = mapped_column(nullable=True) top_holder_lei: Mapped[str] = mapped_column(String(20), nullable=True) - top_holder_legal_name: Mapped[str] = mapped_column(String(255), nullable=True) + top_holder_legal_name: Mapped[str] = mapped_column(nullable=True) top_holder_rssd_id: Mapped[int] = mapped_column(nullable=True) modified_by: Mapped[str] = mapped_column() @@ -105,3 +106,10 @@ class AddressStateDao(AuditMixin, Base): __tablename__ = "address_state" code: Mapped[str] = mapped_column(String(2), index=True, primary_key=True, unique=True) name: Mapped[str] = mapped_column(unique=True, nullable=False) + + +class LeiStatusDao(AuditMixin, Base): + __tablename__ = "lei_status" + code: Mapped[str] = mapped_column(index=True, primary_key=True, unique=True) + name: Mapped[str] = mapped_column(unique=True, nullable=False) + can_file: Mapped[bool] = mapped_column(index=True) diff --git a/src/regtech_user_fi_management/entities/models/dto.py b/src/regtech_user_fi_management/entities/models/dto.py index b0fde9c..61f91f6 100644 --- a/src/regtech_user_fi_management/entities/models/dto.py +++ b/src/regtech_user_fi_management/entities/models/dto.py @@ -1,7 +1,7 @@ from regtech_user_fi_management.config import regex_configs from typing import Generic, List, Set, Sequence -from pydantic import BaseModel, model_validator, Field +from pydantic import BaseModel, model_validator from typing import TypeVar T = TypeVar("T") @@ -30,7 +30,7 @@ class Config: class FinancialInstitutionBase(BaseModel): lei: str name: str - is_active: bool + lei_status_code: str class SblTypeAssociationDto(BaseModel): @@ -65,18 +65,18 @@ class FinancialInstitutionDto(FinancialInstitutionBase): primary_federal_regulator_id: str | None = None hmda_institution_type_id: str | None = None sbl_institution_types: List[SblTypeAssociationDto | str] = [] - hq_address_street_1: str = Field(max_length=255) - hq_address_street_2: str | None = Field(None, max_length=255) - hq_address_street_3: str | None = Field(None, max_length=255) - hq_address_street_4: str | None = Field(None, max_length=255) - hq_address_city: str = Field(None, max_length=255) + hq_address_street_1: str + hq_address_street_2: str | None = None + hq_address_street_3: str | None = None + hq_address_street_4: str | None = None + hq_address_city: str hq_address_state_code: str | None = None hq_address_zip: str parent_lei: str | None = None - parent_legal_name: str | None = Field(None, max_length=255) + parent_legal_name: str | None = None parent_rssd_id: int | None = None top_holder_lei: str | None = None - top_holder_legal_name: str | None = Field(None, max_length=255) + top_holder_legal_name: str | None = None top_holder_rssd_id: int | None = None version: int | None = None @@ -160,3 +160,12 @@ class FinancialInstitutionWithRelationsDto(FinancialInstitutionDto): class FinancialInstitutionAssociationDto(FinancialInstitutionWithRelationsDto): approved: bool + + +class LeiStatusDto(BaseModel): + code: str + name: str + can_file: bool + + class Config: + from_attributes = True diff --git a/tests/api/conftest.py b/tests/api/conftest.py index a4c9759..b64302e 100644 --- a/tests/api/conftest.py +++ b/tests/api/conftest.py @@ -13,6 +13,7 @@ HMDAInstitutionTypeDao, SBLInstitutionTypeDao, SblTypeMappingDao, + LeiStatusDao, ) @@ -62,7 +63,8 @@ def get_institutions_mock(mocker: MockerFixture, authed_user_mock: Mock) -> Mock FinancialInstitutionDao( name="Test Bank 123", lei="TESTBANK123000000000", - is_active=True, + lei_status_code="ISSUED", + lei_status=LeiStatusDao(code="ISSUED", name="Issued", can_file=True), domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123")], tax_id="12-3456789", rssd_id=1234, diff --git a/tests/api/routers/test_institutions_api.py b/tests/api/routers/test_institutions_api.py index 5f0f2ae..d41e269 100644 --- a/tests/api/routers/test_institutions_api.py +++ b/tests/api/routers/test_institutions_api.py @@ -14,6 +14,7 @@ HMDAInstitutionTypeDao, SBLInstitutionTypeDao, SblTypeMappingDao, + LeiStatusDao, ) from regtech_user_fi_management.entities.models.dto import SblTypeAssociationDto from regtech_user_fi_management.config import regex_configs @@ -65,7 +66,7 @@ def test_invalid_tax_id(self, mocker: MockerFixture, app_fixture: FastAPI, authe json={ "name": "testName", "lei": "TESTBANK123000000000", - "is_active": True, + "lei_status_code": "ISSUED", "tax_id": "123456789", "rssd_id": 12344, "primary_federal_regulator_id": "FRI2", @@ -96,7 +97,7 @@ def test_invalid_lei(self, mocker: MockerFixture, app_fixture: FastAPI, authed_u json={ "name": "testName", "lei": "test_Lei", - "is_active": True, + "lei_status_code": "ISSUED", "tax_id": "12-3456789", "rssd_id": 12344, "primary_federal_regulator_id": "FRI2", @@ -127,7 +128,8 @@ def test_create_institution_authed(self, mocker: MockerFixture, app_fixture: Fas upsert_institution_mock.return_value = FinancialInstitutionDao( name="testName", lei="1234567890ABCDEFGH00", - is_active=True, + lei_status_code="ISSUED", + lei_status=LeiStatusDao(code="ISSUED", name="Issued", can_file=True), domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="1234567890ABCDEFGH00")], tax_id="12-3456789", rssd_id=1234, @@ -159,7 +161,7 @@ def test_create_institution_authed(self, mocker: MockerFixture, app_fixture: Fas json={ "name": "testName", "lei": "1234567890ABCDEFGH00", - "is_active": True, + "lei_status_code": "ISSUED", "tax_id": "12-3456789", "rssd_id": 12344, "primary_federal_regulator_id": "FRI2", @@ -190,7 +192,8 @@ def test_empty_state_field(self, mocker: MockerFixture, app_fixture: FastAPI, au upsert_institution_mock.return_value = FinancialInstitutionDao( name="testName", lei="1234567890ABCDEFGH00", - is_active=True, + lei_status_code="ISSUED", + lei_status=LeiStatusDao(code="ISSUED", name="Issued", can_file=True), hq_address_street_1="Test Address Street 1", hq_address_city="Test City 1", hq_address_zip="00000", @@ -203,7 +206,7 @@ def test_empty_state_field(self, mocker: MockerFixture, app_fixture: FastAPI, au json={ "name": "testName", "lei": "1234567890ABCDEFGH00", - "is_active": True, + "lei_status_code": "ISSUED", "hq_address_street_1": "Test Address Street 1", "hq_address_city": "Test City 1", "hq_address_zip": "00000", @@ -221,7 +224,8 @@ def test_create_institution_only_required_fields( upsert_institution_mock.return_value = FinancialInstitutionDao( name="testName", lei="1234567890ABCDEFGH00", - is_active=True, + lei_status_code="ISSUED", + lei_status=LeiStatusDao(code="ISSUED", name="Issued", can_file=True), hq_address_street_1="Test Address Street 1", hq_address_city="Test City 1", hq_address_state_code="VA", @@ -236,7 +240,7 @@ def test_create_institution_only_required_fields( json={ "name": "testName", "lei": "1234567890ABCDEFGH00", - "is_active": True, + "lei_status_code": "ISSUED", "hq_address_street_1": "Test Address Street 1", "hq_address_city": "Test City 1", "hq_address_state_code": "VA", @@ -272,7 +276,7 @@ def test_create_institution_missing_sbl_type_free_form( json={ "name": "testName", "lei": "1234567890ABCDEFGH00", - "is_active": True, + "lei_status_code": "ISSUED", "hq_address_street_1": "Test Address Street 1", "hq_address_city": "Test City 1", "hq_address_state_code": "VA", @@ -300,7 +304,7 @@ def test_create_institution_authed_no_permission(self, app_fixture: FastAPI, aut json={ "name": "testName", "lei": "1234567890ABCDEFGH00", - "is_active": True, + "lei_status_code": "ISSUED", "tax_id": "12-3456789", "rssd_id": 12344, "primary_federal_regulator_id": "FIR2", @@ -336,7 +340,8 @@ def test_get_institution_authed(self, mocker: MockerFixture, app_fixture: FastAP get_institution_mock.return_value = FinancialInstitutionDao( name="Test Bank 123", lei="TESTBANK123000000000", - is_active=True, + lei_status_code="ISSUED", + lei_status=LeiStatusDao(code="ISSUED", name="Issued", can_file=True), domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123000000000")], tax_id="12-3456789", rssd_id=1234, @@ -439,7 +444,8 @@ def test_get_associated_institutions( FinancialInstitutionDao( name="Test Bank 123", lei="TESTBANK123000000000", - is_active=True, + lei_status_code="ISSUED", + lei_status=LeiStatusDao(code="ISSUED", name="Issued", can_file=True), domains=[FinancialInstitutionDomainDao(domain="test123.bank", lei="TESTBANK123000000000")], tax_id="12-3456789", rssd_id=1234, @@ -466,7 +472,8 @@ def test_get_associated_institutions( FinancialInstitutionDao( name="Test Bank 234", lei="TESTBANK234000000000", - is_active=True, + lei_status_code="ISSUED", + lei_status=LeiStatusDao(code="ISSUED", name="Issued", can_file=True), domains=[FinancialInstitutionDomainDao(domain="test234.bank", lei="TESTBANK234000000000")], tax_id="12-3456879", rssd_id=6879, @@ -571,7 +578,8 @@ def test_get_sbl_types(self, mocker: MockerFixture, app_fixture: FastAPI, authed version=inst_version, name="Test Bank 123", lei="TESTBANK123000000000", - is_active=True, + lei_status_code="ISSUED", + lei_status=LeiStatusDao(code="ISSUED", name="Issued", can_file=True), domains=[FinancialInstitutionDomainDao(domain="test.bank", lei="TESTBANK123000000000")], tax_id="12-3456789", rssd_id=1234, diff --git a/tests/entities/repos/test_institutions_repo.py b/tests/entities/repos/test_institutions_repo.py index dbc10a6..789f57d 100644 --- a/tests/entities/repos/test_institutions_repo.py +++ b/tests/entities/repos/test_institutions_repo.py @@ -1,6 +1,5 @@ import pytest from pytest_mock import MockerFixture -from pydantic import ValidationError from sqlalchemy.ext.asyncio import AsyncSession from regtech_user_fi_management.entities.models.dto import ( @@ -54,7 +53,7 @@ async def setup( FinancialInstitutionDao( name="Test Bank 123", lei="TESTBANK123000000000", - is_active=True, + lei_status_code="ISSUED", domains=[FinancialInstitutionDomainDao(domain="test.bank.1", lei="TESTBANK123000000000")], tax_id="12-3456789", rssd_id=1234, @@ -79,7 +78,7 @@ async def setup( FinancialInstitutionDao( name="Test Bank 456", lei="TESTBANK456000000000", - is_active=True, + lei_status_code="ISSUED", domains=[FinancialInstitutionDomainDao(domain="test.bank.2", lei="TESTBANK456000000000")], tax_id="98-7654321", rssd_id=4321, @@ -104,7 +103,7 @@ async def setup( FinancialInstitutionDao( name="Test Sub Bank 456", lei="TESTSUBBANK456000000", - is_active=True, + lei_status_code="ISSUED", domains=[FinancialInstitutionDomainDao(domain="sub.test.bank.2", lei="TESTSUBBANK456000000")], tax_id="76-5432198", rssd_id=2134, @@ -212,7 +211,7 @@ async def test_empty_state(self, transaction_session: AsyncSession): FinancialInstitutionDto( name="New Bank 123", lei="NEWBANK1230000000000", - is_active=True, + lei_status_code="ISSUED", tax_id="65-4321987", rssd_id=6543, primary_federal_regulator_id="FRI3", @@ -248,7 +247,7 @@ async def test_add_institution(self, transaction_session: AsyncSession): FinancialInstitutionDto( name="New Bank 123", lei="NEWBANK1230000000000", - is_active=True, + lei_status_code="ISSUED", tax_id="65-4321987", rssd_id=6543, primary_federal_regulator_id="FRI3", @@ -286,7 +285,7 @@ async def test_add_institution_only_required_fields( FinancialInstitutionDto( name="Minimal Bank 123", lei="MINBANK1230000000000", - is_active=True, + lei_status_code="ISSUED", hq_address_street_1="Minimal Address Street 1", hq_address_city="Minimal City 1", hq_address_state_code="FL", @@ -320,7 +319,7 @@ async def test_update_institution(self, transaction_session: AsyncSession): FinancialInstitutionDto( name="Test Bank 234", lei="TESTBANK123000000000", - is_active=True, + lei_status_code="ISSUED", hq_address_street_1="Test Address Street 1", hq_address_city="Test City 1", hq_address_state_code="GA", @@ -411,79 +410,3 @@ async def test_update_sbl_institution_types_inst_non_exist( res = await repo.update_sbl_types(transaction_session, self.auth_user, test_lei, sbl_types) commit_spy.assert_not_called() assert res is None - - async def test_add_institution_invalid_field_length(self, transaction_session: AsyncSession): - - out_of_range_text = ( - "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " - "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, " - "nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis..." - ) - with pytest.raises(Exception) as e: - await repo.upsert_institution( - transaction_session, - FinancialInstitutionDto( - name="New Bank 123", - lei="NEWBANK1230000000000", - is_active=True, - tax_id="65-4321987", - rssd_id=6543, - primary_federal_regulator_id="FRI3", - hmda_institution_type_id="HIT3", - sbl_institution_types=[SblTypeAssociationDto(id="1")], - hq_address_street_1=out_of_range_text, - hq_address_street_2="", - hq_address_street_3="", - hq_address_street_4="", - hq_address_city="Test City 3", - hq_address_state_code="FL", - hq_address_zip="22222", - parent_lei="0123PARENTNEWBANK123", - parent_legal_name="PARENT NEW BANK 123", - parent_rssd_id=76543, - top_holder_lei="TOPHOLDNEWBANKLEI123", - top_holder_legal_name="TOP HOLDER NEW BANK LEI 123", - top_holder_rssd_id=876543, - modified_by="test_user_id", - ), - self.auth_user, - ) - assert isinstance(e.value, ValidationError) - - async def test_update_institution_invalid_field_length(self, transaction_session: AsyncSession): - out_of_range_text = ( - "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " - "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, " - "nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis..." - ) - - with pytest.raises(Exception) as e: - await repo.upsert_institution( - transaction_session, - FinancialInstitutionDto( - name="New Bank 123", - lei="NEWBANK1230000000000", - is_active=True, - tax_id="65-4321987", - rssd_id=6543, - primary_federal_regulator_id="FRI3", - hmda_institution_type_id="HIT3", - sbl_institution_types=[SblTypeAssociationDto(id="1")], - hq_address_street_1=out_of_range_text, - hq_address_street_2="", - hq_address_street_3="", - hq_address_street_4="", - hq_address_city="Test City 3", - hq_address_state_code="FL", - hq_address_zip="22222", - parent_lei="0123PARENTNEWBANK123", - parent_legal_name="PARENT NEW BANK 123", - parent_rssd_id=76543, - top_holder_lei="TOPHOLDNEWBANKLEI123", - top_holder_legal_name=out_of_range_text, - top_holder_rssd_id=876543, - modified_by="test_user_id", - ), - self.auth_user, - ) - assert isinstance(e.value, ValidationError) diff --git a/tests/entities/test_listeners.py b/tests/entities/test_listeners.py index bd6b306..681bd71 100644 --- a/tests/entities/test_listeners.py +++ b/tests/entities/test_listeners.py @@ -24,7 +24,7 @@ class TestListeners: target: FinancialInstitutionDao = FinancialInstitutionDao( name="Test Bank 123", lei="TESTBANK123000000000", - is_active=True, + lei_status_code="ISSUED", tax_id="12-3456789", rssd_id=1234, primary_federal_regulator_id="FRI1", diff --git a/tests/migrations/test_lookup_tables_data_seed.py b/tests/migrations/test_lookup_tables_data_seed.py index 753ffff..389acf8 100644 --- a/tests/migrations/test_lookup_tables_data_seed.py +++ b/tests/migrations/test_lookup_tables_data_seed.py @@ -12,6 +12,7 @@ def alembic_config(): "26a742d97ad9": {"__tablename__": "federal_regulator", "id": "ZZZ", "name": "TestRegulator"}, "f4ff7d1aa6df": {"__tablename__": "hmda_institution_type", "id": "00", "name": "TestHmdaInstitutionType"}, "a41281b1e109": {"__tablename__": "sbl_institution_type", "id": "00", "name": "TestSblInstitutionType"}, + "6613e1e2c133": {"__tablename__": "lei_status", "code": "TEST", "name": "TestLeiStatus", "can_file": True}, } } @@ -280,3 +281,23 @@ def test_denied_domains_data_seed(alembic_runner: MigrationContext, alembic_engi with alembic_engine.connect() as conn: denied_domains_before_seed = conn.execute(text("SELECT domain FROM %s" % denied_domain_tablename)).fetchall() assert denied_domains_before_seed == [] + + +def test_lei_status_data_seed(alembic_runner: MigrationContext, alembic_engine: Engine): + # Migrate up to, but not including this new migration + alembic_runner.migrate_up_before("6613e1e2c133") + + # Test lei_status seed + lei_status_tablename = "lei_status" + alembic_runner.migrate_up_one() + with alembic_engine.connect() as conn: + lei_status_rows = conn.execute( + text("SELECT code, name from %s where code = :code" % lei_status_tablename), (dict(code="ISSUED")) + ).fetchall() + lei_status_expected = [("ISSUED", "Issued")] + assert lei_status_rows == lei_status_expected + + # alembic_runner.migrate_down_one() + # with alembic_engine.connect() as conn: + # lei_status_before_seed = conn.execute(text("SELECT code, name FROM %s" % lei_status_tablename)).fetchall() + # assert lei_status_before_seed == [("TEST", "TestLeiStatus")] diff --git a/tests/migrations/test_migrations.py b/tests/migrations/test_migrations.py index 29885e7..1628723 100644 --- a/tests/migrations/test_migrations.py +++ b/tests/migrations/test_migrations.py @@ -77,11 +77,37 @@ def test_migration_to_6dd77f09fae6(alembic_runner: MigrationContext, alembic_eng columns = inspector.get_columns("financial_institutions") - assert [c for c in columns if c["name"] == "name"][0]["type"].length == 255 - assert [c for c in columns if c["name"] == "hq_address_street_1"][0]["type"].length == 255 - assert [c for c in columns if c["name"] == "hq_address_street_2"][0]["type"].length == 255 - assert [c for c in columns if c["name"] == "hq_address_street_3"][0]["type"].length == 255 - assert [c for c in columns if c["name"] == "hq_address_street_4"][0]["type"].length == 255 - assert [c for c in columns if c["name"] == "hq_address_city"][0]["type"].length == 255 - assert [c for c in columns if c["name"] == "parent_legal_name"][0]["type"].length == 255 - assert [c for c in columns if c["name"] == "top_holder_legal_name"][0]["type"].length == 255 + assert [c for c in columns if c["name"] == "name"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_street_1"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_street_2"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_street_3"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_street_4"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_city"][0]["type"].length is None + assert [c for c in columns if c["name"] == "parent_legal_name"][0]["type"].length is None + assert [c for c in columns if c["name"] == "top_holder_legal_name"][0]["type"].length is None + + +def test_tables_exist_migrate_up_to_6613e1e2c133(alembic_runner: MigrationContext, alembic_engine: Engine): + alembic_runner.migrate_up_to("6613e1e2c133") + + inspector = sqlalchemy.inspect(alembic_engine) + tables = inspector.get_table_names() + assert "lei_status" in tables + + +def test_migration_to_ca39ad68af05(alembic_runner: MigrationContext, alembic_engine: Engine): + + alembic_runner.migrate_up_to("ca39ad68af05") + + inspector = sqlalchemy.inspect(alembic_engine) + + columns = inspector.get_columns("financial_institutions") + + assert [c for c in columns if c["name"] == "name"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_street_1"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_street_2"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_street_3"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_street_4"][0]["type"].length is None + assert [c for c in columns if c["name"] == "hq_address_city"][0]["type"].length is None + assert [c for c in columns if c["name"] == "parent_legal_name"][0]["type"].length is None + assert [c for c in columns if c["name"] == "top_holder_legal_name"][0]["type"].length is None diff --git a/tests/migrations/test_schema.py b/tests/migrations/test_schema.py index 61db0ba..7e9b66c 100644 --- a/tests/migrations/test_schema.py +++ b/tests/migrations/test_schema.py @@ -86,3 +86,17 @@ def test_fi_history_table_columns_8106d83ff594(alembic_runner: MigrationContext, assert {column.get("name") for column in mapping_columns}.issubset( {column.get("name") for column in mapping_history_columns} ) + + +def test_migration_to_6613e1e2c133(alembic_runner: MigrationContext, alembic_engine: Engine): + + alembic_runner.migrate_up_to("6613e1e2c133") + + inspector = sqlalchemy.inspect(alembic_engine) + + assert "lei_status_code" in [column.get("name") for column in inspector.get_columns("financial_institutions")] + assert "is_active" not in [column.get("name") for column in inspector.get_columns("financial_institutions")] + + assert "lei_status_code" in [ + column.get("name") for column in inspector.get_columns("financial_institutions_history") + ]