Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(auth): add postgresql enum type for account_tier #1493

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

iulianbarbu
Copy link
Contributor

@iulianbarbu iulianbarbu commented Dec 22, 2023

Description of change

Applied the recommendations here: https://docs.rs/sqlx/latest/sqlx/postgres/types/index.html#enumerations. Also important from a data integrity standpoint, to link PostgreSQL and Rust types.

There are also official PostgreSQL docs referring to type safety, ordering, and implementation details (e.g. how to alter the enum type after it is created): https://www.postgresql.org/docs/current/datatype-enum.html.

How has this been tested? (if applicable)

TODO on staging.

Copy link
Contributor

@chesedo chesedo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are the Rust enums not enough for the tiers? This feels a bit like an overkill cause now we'll have to update two things (the rust enum and the postgres enum) whenever we update the tiers.

@jonaro00
Copy link
Member

If it exists in postgres as well, it is type checked in the database, so mistakes in manual queries are rejected.
I still think you have a good point. I like the path with less maintenance, considering this will be changing a lot.

@Kazy
Copy link
Member

Kazy commented Jan 15, 2024

Like @jonaro00 said, by having enums in the database, sqlx can be certain that the value coming in matches the enum and can reject invalid queries. The main reason for me is that it helps when you're adding or removing possible values in the database. Removing one value from the Rust enum would lead to failure down the line, while with an Postgres one SQLx will scream that you need to change it in the database first. And by experience it does help catch errors.

I'm in favor of the change. I don't think we're going to update the tiers that often, and when we do I don't feel like adding a one line migration when adding a new tier is that much of a burden.

@chesedo
Copy link
Contributor

chesedo commented Jan 16, 2024

Removing one value from the Rust enum would lead to failure down the line, while with an Postgres one SQLx will scream that you need to change it in the database first. And by experience it does help catch errors.

My experience has mostly been that code enums are better than DB enums. The reason being that the code enums are checked at compile time. But the DB enums only fail at runtime. And it's just never fun maintaining two pieces of code that does the same thing. I do agree though that the DB enums help with manual queries.

It will be interesting to know what failures you have seen from adding / removing an enum in Rust only?

@Kazy
Copy link
Member

Kazy commented Jan 16, 2024

I agree they're better (I would rather use the Rust one than the PSQL one), but they aren't mutually exclusive though. I'm advocating for using both.

It will be interesting to know what failures you have seen from adding / removing an enum in Rust only?

It wasn't with Rust but still went through an ORM of some sort (sqlx isn't an ORM, but you see what I mean). Basically they sometimes tried to remove one of the variant but forgot to make sure that this value wasn't used anymore. If you don't have an enum, they you will get a runtime error when you try to query (which might be way later in the future), instead of having the migration fail directly. Just like with static typing, you will get an error anyway, it will just happen before instead of later.

And it's just never fun maintaining two pieces of code that does the same thing.

Again, I don't think the cost of maintaining it is that big. In particular since there is no way for it to go wrong since SQLx will complain if you forgot to do it. And if this becomes a pain, we can always alter it to be a text field again.

@chesedo
Copy link
Contributor

chesedo commented Jan 16, 2024

Just like with static typing, you will get an error anyway, it will just happen before instead of later.

If I understand this correctly then we will get the error during the SQL migration. I still don't understand the adding enum case, but for deleting an enum you are expecting that the migration will fail if the enum variant is still in use. However for Postgres this won't be the case since Postgres does not support removing enums from the type after it was created. This means either having more complex migrations (adding a string column; copy over the enum values to the string column; dropping the enum column; dropping the enum type; recreate the enum type; add the enum column back; copy the string column to the enum; dropping the string column) or being happy with the PG enums not matching our Rust enums.

@Kazy
Copy link
Member

Kazy commented Jan 16, 2024

The migration isn't that complex (you rename the existing type, fix your column, create the new type, alter the column to use the new one, drop the old one, rename the type), but I was expecting it to be more straightforward. I won't push it further, I still think this is a better idea to have it. If we don't have any bug with it then fine, but when we do I'll link back to this discussion :p

@chesedo
Copy link
Contributor

chesedo commented Jan 16, 2024

From my end, I just want to make sure we all realize this is not a free lunch (or at least not as free as it seems). I've just had experiences where I wished the DB did not also have enums because they were a pain to update. So for me this is mostly a preference thing 😄

@oddgrd
Copy link
Contributor

oddgrd commented Jan 18, 2024

Again, I don't think the cost of maintaining it is that big. In particular since there is no way for it to go wrong since SQLx will complain if you forgot to do it. And if this becomes a pain, we can always alter it to be a text field again.

What do you mean by SQLx will complain? Isn't that only the case if you use the compile-time checked sqlx macros?

Personally, and while I see the advantages, I am also leaning towards not having it as an enum in Postgres, at least not yet. The main reason for that is that I am not so confident in us not changing the account tier enum, it has been changed quite a few times since we started working on billing, and this would slow us down when making further changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants