-
Notifications
You must be signed in to change notification settings - Fork 5
Normalize Database #82
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work, @tas09009! Initial comments on the database structure below. You should now have access to the prod data, so please download a copy and try this migration locally.
) | ||
op.add_column('nicety', sa.Column('stint', sa.Integer(), nullable=True)) | ||
op.drop_constraint('nicety_author_id_target_id_end_date_key', 'nicety', type_='unique') | ||
op.create_unique_constraint(None, 'nicety', ['author_id', 'target_id']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This constraint needs to include the stint, so that one person can write two niceties for someone who has attended RC twice.
depends_on = None | ||
|
||
|
||
def upgrade(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to migrate existing data here, including finding existing User
s - who may no longer be part of RC, and thus not be in the data returned by the RC API - and populating the new profile
table with that data.
sa.Column('profile_id', sa.Integer(), nullable=True), | ||
sa.Column('type_stint', sa.String(), nullable=True), | ||
sa.Column('start_date', sa.Date(), nullable=True), | ||
sa.Column('end_date', sa.Date(), nullable=True), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all of these are required, and should not be nullable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made these nullable, thanks for catching this. The only exception I found was end_date
since faculty don't have any end date.
update-data.py
Outdated
db.session.commit() | ||
|
||
else: | ||
logging.info(f"Skipping: {id}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we do need to update existing profiles! Particularly with the initial User
migration, but also as people do things like change their interests or upload new photos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made changes to this so it adds/updates every profile, thank you!
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's going to end up being quite a lot more to this downgrade than is here, in order to handle existing data. I also don't think that's a worthwhile use of time - we'll take a database backup before merging this PR, and if the deployment goes wrong, we can roll back and manually restore. We can just drop the downgrade
entirely!
Originally we talked about creating one migration script which includes the schema updates as well as the new models to populate from the RC API. Here is actually the approach I took (so far): In order to normalize the database with
I couldn't combine steps 1 and 3 into one migration script since the database has to be populated with profiles after the
If we don't want two migrations, then I imagine 2 ways to create a single migration:
I also ran into a separate issue: apparently there several niceties written for
which returned the following 4 ids: 1932, 3292, 2218, 2481 I still made changes to the Let me know if this is unclear or the wrong approach to take. Thanks! |
Just asked James about those missing ids and he said they are no longer part of the RC community. I can speak more to this at our Wednesday meeting. |
We will need an access token for the nightly script. @mjec, since the application is using your client credentials, I think it makes the most sense to also have you generate an access token - does that sound right to you? If so, could you please add an environment variable to Heroku named I think the command line would be something like: heroku config:set RC_API_ACCESS_TOKEN=my_token |
|
So quick - thank you so much, @mjec! |
I believe this captures everything we've talked about thus far. Run the following lines on the terminal to upgrade and downgrade the migration:
|
9da6ed5
to
9d05992
Compare
@tas09009 and I paired on restructuring these changes. So far we've pulled two commits out, 448a9c3 and e0b4921. e0b4921 is worth calling out, I think: I reviewed this data-only migration by examining the database by hand. Nicety ID 221 is one of the lost niceties described in #10: the target user changed their end date, and the author created a new nicety (ID 791) that is very similar but not identical, and with the new end date. Relevant queries: SELECT id, author_id, target_id, date_updated, CONVERT_FROM(DECODE(text, 'base64'), 'utf8')
FROM nicety WHERE id IN (221, 791);
SELECT * FROM nicety WHERE author_id = ? AND target_id = ?; Nicety ID 3634 is more complicated. It has a correct end date, but it is the replacement for a previously-written nicety (ID 2956) that was lost due to the target recurser changing their end date. The text of the old nicety has much more detail than the new one, but it also has an incorrect end date. I believe the intent is to clean that up in the subsequent migration that assigns |
Hi @jasonaowen, I didn't send an email for this one because of what you mentioned when comparing the two niceties. But I certainly can if you'd like! |
9d05992
to
83d7635
Compare
83d7635
to
fa95414
Compare
code maintenance. | ||
""" | ||
op.drop_column("user", "anonymous_by_default") | ||
op.drop_column("nicety", "anonymous") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we do still want to allow anonymous niceties! Just not saving the default preference.
connection = op.get_bind() | ||
|
||
""" | ||
The 156 nicetys with null dates can be grouped into 18 profiles |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is 156 niceties with null stint_id, rather than null dates, right?
fa95414
to
bfd6054
Compare
So last we talked, the migrations were in pretty good shape, and the remaining work on this PR is to update the API to use the new database structure. Thanks again for working on this, @tas09009 - I know it's a big change! |
Giving niceties anonymously in bulk is a partially implemented feature for the user. Ultimately want to discourage this feature as well as make it easier for code maintenance. Issue #79: Remove unused anonymous_by_default column
These two niceties were manually reviewed and had substantially similar but not identical content to two other niceties that are from the same author_id to the same target_id. These niceties were "lost" because the target user extended their batch and had a different end_date. Issue #82: Normalize Recurser Profiles Issue #10: Niceties lost when Recursers extend their batch
These two niceties were manually reviewed and had substantially similar but not identical content to two other niceties that are from the same author_id to the same target_id. These niceties were "lost" because the target user extended their batch and had a different end_date. Issue #82: Normalize Recurser Profiles Issue #10: Niceties lost when Recursers extend their batch
"update_data.py" fetches information from the RC API to populate the database and have an up-to-date cache. We can schedule data updates using the Heroku Scheduler. Update the "README.md" to include instructions on creating an access token for the RC API requests and set up a Heroku Scheduler. Issue #68: Normalize Recurser profiles Issue #5: Clearing the cache in a timely fashion Co-authored-by: Jason Owen <jason@jasonaowen.net>
We want to maintain a local copy of the RC API data and make our data model more consistent by including all the relevant information for a nicety. Previously, we were relied on making API calls to populate data we didn't have locally in response to each request to the front end. We are still doing this, but these data models set the stage to stop doing that. Issue #68: Normalize Recurser profiles Co-authored-by: Jason Owen <jason@jasonaowen.net>
Create new tables and models for Profiles and Stints, and populate them with the data from the RC API. Import functions from update_data.py. Following this migration, use the update_data.py module to pull all data from the RC API. Co-authored-by: Jason Owen <jason@jasonaowen.net>
Create Profiles for: - 5 people: ids missing from the Profile table but found in the User table. - 4 people: ids missing from both User and Profile tables. These 4 people have niceties written for them but no profile to connect to. Save their names as "Former Recurser". Co-authored-by: Jason Owen <jason@jasonaowen.net>
The nicety.stint_id column will remain nullable until all profiles are populated with their respective stints in future migrations. Create a foreign key constraint to tie niceties to stints. Change the unique constraint to be between the "author_id," "target_id," and "stint_id." We are still leaving "end_date" alone because we are not yet cleaning up the backend to use "stints" instead of "end_dates." Create a foreign key to tie target_ids to profile_ids. Co-authored-by: Jason Owen <jason@jasonaowen.net>
Populate all nicety.stint_ids based on end dates since it's a required column. This change will exclude 156 niceties due to mismatching end dates. The subsequent migration will address these 156 niceties with null stint_ids.
The 156 niceties with null stint_ids consist of 18 profiles with 18 end dates. Out of the 18 profiles, create stints for the newly created profiles using negative stint ids: - 9 new profiles manually created (4 Former Recurser's + 5 from Users table) - 2 profiles with no niceties written for them, therefore no need to generate stints This leaves 7 profiles with 8 stints, with 2 stints for one profile After this, there will be 68 niceties with null stint_ids left. The subsequent migration will address this.
Populate stint_ids for 68 niceties where nicety.stint_id = null. All niceties are for the target_id's latest stint.
Nicety.stint_id was allowed to be null while populating their values. Now that the 156 nicety.stint_ids are populated, this column won't be null again.
These are the changes to the actual backend files to finally pull data from the database, rather than user RC's API. This is a draft; the files will need to be organized and old code will need to be deleted. This push is simply to have the changes on Github.
Update the external link to set up an RC application and restrict the text width to be less than 85 columns wide. Co-authored-by: Jason Owen <jason@jasonaowen.net>
Remove unused comments, add a downgrade, and change the formatting to match new migrations.
bfd6054
to
121a6ea
Compare
Hi @jasonaowen, While working on the API changes, I realized they could only happen after the database migration since some of the changes we're implementing - switching from batches to stints and removing caching - have to wait until that last migration. You can see some of my WIP in the 3rd to last commit. Do you think we should split this PR up again into two parts? It'll be easier to digest too:
It will also make it easier to push changes to the two PRs as unanticipated code changes come up, such as when we discover that a user's stint changes their |
Changes to the schema
starred
and User:autosave_timeout
andautosave_enabled
This will address Issues Remove unused autosave columns #80 and Remove starred column #34User
toProfile
usingUser.profile_id
target_id
now points toProfile.id
. Added backname
along with other attributes that were normally being called thorough the API.profile_id
for the foreign key connectionfaculty
since that's determined bystint['type']
To use new database:
createdb <database_name>
DATABASE_URL
environment variable in your.env
file to update the database, then runsource .env
on your terminalflask db upgrade
python update-data.py
on the project level directory. The script logs eachProfile
being added so feel free to comment out lines 78 and 83.Here is a link to edit the schema directly