Skip to content

Commit

Permalink
Add ER Diagram, remove unused db models (#657)
Browse files Browse the repository at this point in the history
* Add ER Diagram, remove unused db models
* Removed schema associated with removed data models
* Upgrade marshmallow-sqlalchemy from 0.3 to 1.0
* Expand sqlalchemy test cases to show how to serialize/deserialize
* Add eralchemy2 linux install instructions
* Add migration script to drop unused tables
  • Loading branch information
Joshua-Douglas committed Mar 24, 2024
1 parent 2c9943c commit fea47a5
Show file tree
Hide file tree
Showing 10 changed files with 745 additions and 699 deletions.
535 changes: 284 additions & 251 deletions api/alembic/versions/3ceec084158f_.py

Large diffs are not rendered by default.

299 changes: 299 additions & 0 deletions api/alembic/versions/ec8b1c17739a_drop_unused_tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
"""Drop unused tables
Revision ID: ec8b1c17739a
Revises: 3ceec084158f
Create Date: 2024-03-10 15:54:55.578328
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'ec8b1c17739a'
down_revision = '3ceec084158f'
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index('ix_housing_program_pariticipant_id', table_name='housing_program_pariticipant')
op.drop_table('housing_program_pariticipant')
op.drop_index('ix_applicant_status_id', table_name='applicant_status')
op.drop_table('applicant_status')
op.drop_index('ix_applicant_type_id', table_name='applicant_type')
op.drop_table('applicant_type')
op.drop_index('ix_match_failure_id', table_name='match_failure')
op.drop_table('match_failure')
op.drop_index('ix_program_case_log_id', table_name='program_case_log')
op.drop_table('program_case_log')
op.drop_index('ix_intake_response_value_id', table_name='intake_response_value')
op.drop_table('intake_response_value')
op.drop_index('ix_case_status_id', table_name='case_status')
op.drop_table('case_status')
op.drop_index('ix_image_tag_type_id', table_name='image_tag_type')
op.drop_table('image_tag_type')
op.drop_index('ix_applicant_uploaded_image_id', table_name='applicant_uploaded_image')
op.drop_table('applicant_uploaded_image')
op.drop_index('ix_match_fail_condition_id', table_name='match_fail_condition')
op.drop_table('match_fail_condition')
op.drop_index('ix_host_household_member_id', table_name='host_household_member')
op.drop_table('host_household_member')
op.drop_index('ix_applicant_id', table_name='applicant')
op.drop_table('applicant')
op.drop_index('ix_intake_question_id', table_name='intake_question')
op.drop_table('intake_question')
op.drop_index('ix_image_tag_id', table_name='image_tag')
op.drop_table('image_tag')
op.drop_index('ix_match_status_id', table_name='match_status')
op.drop_table('match_status')
op.drop_index('ix_guest_group_id', table_name='guest_group')
op.drop_table('guest_group')
op.drop_index('ix_applicant_status_log_id', table_name='applicant_status_log')
op.drop_table('applicant_status_log')
op.drop_index('ix_host_household_id', table_name='host_household')
op.drop_table('host_household')
op.drop_index('ix_match_result_id', table_name='match_result')
op.drop_table('match_result')
op.drop_index('ix_intake_question_set_id', table_name='intake_question_set')
op.drop_table('intake_question_set')
op.drop_index('ix_program_case_id', table_name='program_case')
op.drop_table('program_case')
op.drop_index('ix_intake_question_type_id', table_name='intake_question_type')
op.drop_table('intake_question_type')
op.drop_index('ix_guest_group_member_id', table_name='guest_group_member')
op.drop_table('guest_group_member')
op.drop_index('ix_group_match_result_id', table_name='group_match_result')
op.drop_table('group_match_result')
op.drop_index('ix_program_coordinator_id', table_name='program_coordinator')
op.drop_table('program_coordinator')
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('program_coordinator',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('user', sa.INTEGER(), nullable=False),
sa.Column('housing_program', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['housing_program'], ['housing_program.id'], ),
sa.ForeignKeyConstraint(['user'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_program_coordinator_id', 'program_coordinator', ['id'], unique=False)
op.create_table('group_match_result',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('guest_group', sa.INTEGER(), nullable=False),
sa.Column('host_household', sa.INTEGER(), nullable=False),
sa.Column('match_status', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['guest_group'], ['guest_group.id'], ),
sa.ForeignKeyConstraint(['host_household'], ['host_household.id'], ),
sa.ForeignKeyConstraint(['match_status'], ['match_status.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_group_match_result_id', 'group_match_result', ['id'], unique=False)
op.create_table('guest_group_member',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('guest_group', sa.INTEGER(), nullable=False),
sa.Column('applicant', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['applicant'], ['applicant.id'], ),
sa.ForeignKeyConstraint(['guest_group'], ['guest_group.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_guest_group_member_id', 'guest_group_member', ['id'], unique=False)
op.create_table('intake_question_type',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('type_description', sa.VARCHAR(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_intake_question_type_id', 'intake_question_type', ['id'], unique=False)
op.create_table('program_case',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('coordinator', sa.INTEGER(), nullable=False),
sa.Column('case_status', sa.INTEGER(), nullable=False),
sa.Column('host_household', sa.INTEGER(), nullable=False),
sa.Column('guest_group', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['case_status'], ['case_status.id'], ),
sa.ForeignKeyConstraint(['coordinator'], ['program_coordinator.id'], ),
sa.ForeignKeyConstraint(['guest_group'], ['guest_group.id'], ),
sa.ForeignKeyConstraint(['host_household'], ['host_household.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_program_case_id', 'program_case', ['id'], unique=False)
op.create_table('intake_question_set',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('question_set_name', sa.VARCHAR(), nullable=False),
sa.Column('housing_program', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['housing_program'], ['housing_program.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_intake_question_set_id', 'intake_question_set', ['id'], unique=False)
op.create_table('match_result',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('applicant_a', sa.INTEGER(), nullable=False),
sa.Column('applicant_b', sa.INTEGER(), nullable=False),
sa.Column('match_status', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['applicant_a'], ['applicant.id'], ),
sa.ForeignKeyConstraint(['applicant_b'], ['applicant.id'], ),
sa.ForeignKeyConstraint(['match_status'], ['match_status.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_match_result_id', 'match_result', ['id'], unique=False)
op.create_table('host_household',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('household_name', sa.VARCHAR(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_host_household_id', 'host_household', ['id'], unique=False)
op.create_table('applicant_status_log',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('log_description', sa.VARCHAR(), nullable=False),
sa.Column('logtime', sa.DATETIME(), nullable=False),
sa.Column('applicant', sa.INTEGER(), nullable=False),
sa.Column('src_status', sa.INTEGER(), nullable=False),
sa.Column('dest_status', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['applicant'], ['applicant.id'], ),
sa.ForeignKeyConstraint(['dest_status'], ['applicant_status.id'], ),
sa.ForeignKeyConstraint(['src_status'], ['applicant_status.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_applicant_status_log_id', 'applicant_status_log', ['id'], unique=False)
op.create_table('guest_group',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('group_name', sa.VARCHAR(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_guest_group_id', 'guest_group', ['id'], unique=False)
op.create_table('match_status',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('status_description', sa.VARCHAR(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_match_status_id', 'match_status', ['id'], unique=False)
op.create_table('image_tag',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('applicant', sa.INTEGER(), nullable=False),
sa.Column('image_tag_type', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['applicant'], ['applicant_uploaded_image.id'], ),
sa.ForeignKeyConstraint(['image_tag_type'], ['image_tag_type.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_image_tag_id', 'image_tag', ['id'], unique=False)
op.create_table('intake_question',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('applicant_type', sa.INTEGER(), nullable=False),
sa.Column('intake_question_type', sa.INTEGER(), nullable=False),
sa.Column('intake_question_set', sa.INTEGER(), nullable=False),
sa.Column('question_text', sa.VARCHAR(), nullable=False),
sa.ForeignKeyConstraint(['applicant_type'], ['applicant_type.id'], ),
sa.ForeignKeyConstraint(['intake_question_set'], ['intake_question_set.id'], ),
sa.ForeignKeyConstraint(['intake_question_type'], ['intake_question_type.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_intake_question_id', 'intake_question', ['id'], unique=False)
op.create_table('applicant',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('applicant_type', sa.INTEGER(), nullable=False),
sa.Column('applicant_status', sa.INTEGER(), nullable=False),
sa.Column('user', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['applicant_status'], ['applicant_status.id'], ),
sa.ForeignKeyConstraint(['applicant_type'], ['applicant_type.id'], ),
sa.ForeignKeyConstraint(['user'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_applicant_id', 'applicant', ['id'], unique=False)
op.create_table('host_household_member',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('host_household', sa.INTEGER(), nullable=False),
sa.Column('applicant', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['applicant'], ['applicant.id'], ),
sa.ForeignKeyConstraint(['host_household'], ['host_household.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_host_household_member_id', 'host_household_member', ['id'], unique=False)
op.create_table('match_fail_condition',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('response_value_a', sa.INTEGER(), nullable=False),
sa.Column('response_value_b', sa.INTEGER(), nullable=False),
sa.Column('reason_text', sa.VARCHAR(), nullable=False),
sa.ForeignKeyConstraint(['response_value_a'], ['intake_response_value.id'], ),
sa.ForeignKeyConstraint(['response_value_b'], ['intake_response_value.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_match_fail_condition_id', 'match_fail_condition', ['id'], unique=False)
op.create_table('applicant_uploaded_image',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('applicant', sa.INTEGER(), nullable=False),
sa.Column('image_data', sa.BLOB(), nullable=False),
sa.ForeignKeyConstraint(['applicant'], ['applicant.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_applicant_uploaded_image_id', 'applicant_uploaded_image', ['id'], unique=False)
op.create_table('image_tag_type',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('tag_text', sa.VARCHAR(), nullable=False),
sa.Column('tag_description', sa.VARCHAR(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_image_tag_type_id', 'image_tag_type', ['id'], unique=False)
op.create_table('case_status',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('status_description', sa.VARCHAR(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_case_status_id', 'case_status', ['id'], unique=False)
op.create_table('intake_response_value',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('intake_question', sa.INTEGER(), nullable=False),
sa.Column('response_text', sa.VARCHAR(), nullable=False),
sa.ForeignKeyConstraint(['intake_question'], ['intake_question.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_intake_response_value_id', 'intake_response_value', ['id'], unique=False)
op.create_table('program_case_log',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('log_description', sa.VARCHAR(), nullable=False),
sa.Column('logtime', sa.DATETIME(), nullable=False),
sa.Column('program_case', sa.INTEGER(), nullable=False),
sa.Column('src_status', sa.INTEGER(), nullable=False),
sa.Column('dest_status', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['dest_status'], ['case_status.id'], ),
sa.ForeignKeyConstraint(['program_case'], ['program_case.id'], ),
sa.ForeignKeyConstraint(['src_status'], ['case_status.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_program_case_log_id', 'program_case_log', ['id'], unique=False)
op.create_table('match_failure',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('match_result', sa.INTEGER(), nullable=False),
sa.Column('failed_condition', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['failed_condition'], ['match_fail_condition.id'], ),
sa.ForeignKeyConstraint(['match_result'], ['match_result.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_match_failure_id', 'match_failure', ['id'], unique=False)
op.create_table('applicant_type',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('applicant_type_description', sa.VARCHAR(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_applicant_type_id', 'applicant_type', ['id'], unique=False)
op.create_table('applicant_status',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('applicant_type', sa.INTEGER(), nullable=False),
sa.Column('status_description', sa.VARCHAR(), nullable=False),
sa.ForeignKeyConstraint(['applicant_type'], ['applicant_type.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_applicant_status_id', 'applicant_status', ['id'], unique=False)
op.create_table('housing_program_pariticipant',
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('applicant', sa.INTEGER(), nullable=False),
sa.Column('housing_program', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['applicant'], ['applicant.id'], ),
sa.ForeignKeyConstraint(['housing_program'], ['housing_program.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_housing_program_pariticipant_id', 'housing_program_pariticipant', ['id'], unique=False)
# ### end Alembic commands ###
60 changes: 60 additions & 0 deletions api/openapi_server/models/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Data Model

```mermaid
classDiagram
class alembic_version{
*VARCHAR<32> version_num NOT NULL
}
class host{
*INTEGER id NOT NULL
VARCHAR name NOT NULL
}
class housing_program{
*INTEGER id NOT NULL
VARCHAR program_name NOT NULL
INTEGER service_provider NOT NULL
}
class housing_program_service_provider{
*INTEGER id NOT NULL
VARCHAR provider_name NOT NULL
}
class user{
*INTEGER id NOT NULL
VARCHAR email NOT NULL
}
housing_program_service_provider "1" -- "0..n" housing_program
```

## Data Model Generation

Our data model is autogenerated using `eralchemy2`. The `eralchemy2` tool relies on `pygraphviz` and `graphviz` which are not easily installed using pip. The tool is easier to install on linux than windows, but instructions are provided for both operating systems.

### Linux Install

```bash
sudo apt install graphviz libgraphviz-dev pkg-config
python3 -m pip install pygraphviz
python3 -m pip install eralchemy2
```

### Windows Install

```pwsh
# If you don't have the choco package manager then
# exe installers are available https://graphviz.org/download/
choco install graphviz
python -m pip install --use-pep517 `
--config-settings="--global-option=build_ext" `
--config-settings="--global-option="-IC:\Program Files\Graphviz\include" `
--config-settings="--global-option="-LC:\Program Files\Graphviz\lib" `
pygraphviz
python -m pip install eralchemy2
```

### Model Generation

Once `eralchemy2` is installed, you can generate the ER diagram using these commands.

```shell
eralchemy2 -i "sqlite:///./homeuniteus.db" -o "HomeUniteUsDataModel.md"
```
Loading

0 comments on commit fea47a5

Please sign in to comment.