Changing `id` type from serial to uuid, causing error.
I'm sorry, I'm new to Drizzle, but I've read through the documentation and discord and cannot find a solution to my problem.
I'm using Next.js 14, Postgresql through Vercel.
When I first started, I built a test
UsersTable
but now I want to change the id
from a serial
to a uuid
. Everytime I try to generate:pg
it works, but push:pg
fails, giving the following error:
Could you please tell me how I'm supposed to update my table?
54 Replies
it's not well documented in Drizzle yet, but I think you're expected to modify the migrations if there's no way to do them automatically. In this case, a serial is an int, which cannot be automatically converted to UUID. The error you're getting seesm to be trying to convert "id", which was a serial/int, to a type uuid. You'll need to specify how to convert old values:
https://stackoverflow.com/a/7162961
ALTER TABLE tbl_name ALTER COLUMN id TYPE uuid USING some_expression;
Stack Overflow
How to alter a column's data type in a PostgreSQL table?
Entering the following command into a PostgreSQL interactive terminal results in an error:
ALTER TABLE tbl_name ALTER COLUMN col_name varchar (11);
What is the correct command to alter the data t...
i don't know how foreign keys will work though
serial
is a different type than uuid
- as the error message suggests you could cast it.
Like @ColdRiver suggests you could just change the migration assuming you're not in production yet? I would probably just reset the db schema if you're still in dev.How am I supposed to push the change? I was trying
bunx drizzle-kit push:pg
but this didn't work. I was able to just drop the table directly from Vercel and push a new migration, but at some point, it's not going to be easy.
So, how do I use the SQL? I can write the sql code, where am I supposed to put it?if i put it in here, i was just getting "No changes made" or something like this when I ran
bunx drizzle-kit push:pg
.here's what I'd get if I edited the sql file.
I would drop all migrations, and start from scratch
drizzle-kit drop
(multiple times if you have multiple migration files)
then
drizzle-kit generate:pg
to get a fresh migration file
lastly you want push that change up to your database, ie run all migration files-- that kind of depends on what service you're using to host your DB.I'm using Vercel/Postgresql, so it's
bunx drizzle-kit push:pg
but, when I drop migrations, it only drops it from my repository, not from the actual db itself. the issue is if I drop the migration, then generate:pg
/ push:pg
that's where I encounter the error of mismatching types.
I'm wondering where I'm supposed to put the ALTER TABLE "users" ALTER COLUMN "id" uuid
code.
I was able to do it directly on vercel by "querying" that 😄 but, I was wondering where I can run SQL on drizzle.
or, maybe that's not the scope of drizzle and my issue is w/ vercel.as samson said, there's two options:
1. reset the whole migrations and lose all your data
2. edit the migration to work and then run it
If you're doing 1, that's what dropping the migrations and then generating the new one, and then pushing the change would look like.
If you're doing 2, that's when you would edit the migration file and put the ALTER TABLE ... USING ... statement. You'd put it in the last migration file, replacing the ALTER TABLE statement in there. It would have the largest number as a preifx.
got it, so after I
generate:pg
I should edit the .sql
file before using push:pg
?
by the way, i appreciate the help a lot.im not sure about push:pg because im using the beta which includes a migrate command. but yes, you edit the .sql file immediately after generate:pg
migth be this one
Drizzle ORM - List of commands
Drizzle ORM is a lightweight and performant TypeScript ORM with developer experience in mind.
bunx drizzle-kit up:pg
to give you some context, what happens under the hood is that Drizzle executes all your migration files one by one, from start to finish.
You probably just have one file right now. And if you did what I suggested (drop all migrations, then generate one fresh one), then there's no need to add any SQL to it, since the file will have the correct type for your id.
For your change to be reflected in your production database, you need to probably tell Vercel to re-run your migration files -- I'm not familiar with how to trigger this on Vercel's end, it might be that you just connect your Github account or whatever and it detects any changes.
the issue is I was getting this error when trying to
push:pg
the fresh and only migration.huh that's weird
I think ALTERING ids is not a good idea in general
i wouldnt expect any ALTER statements in the first migration file
The issue is i'm somewhat new to dbs 😄 so I'm going to make mistakes. This is for a proejct to learn on.
all good- as ColdRiver said, check your migration file
Is the real strategy, get it right the first time?
Does it have "ALTER..." in it?
hmmm , let me recreate the problem, 1s.
no
i droped the table on vercel, and started over.
but, i was wondering if i had the issue how to fix 😄
Changing the type of an ID is kind of a complicated thing -- you might reference that same ID in other tables and be using the wrong type when you reference it. That may cause an error.
So I don't think this is something you need to know "how to fix"
got it, so what should i do in cases like this.
let's say i set the wrong type, do i just create a new type and copy over the data and ignroe the old type?
depends on what the old vs new type is. Imagine you change from string to number -- that won't work
I generally
1. create a new column (
myColumn_NEW
)
2. copy over all the data (may need to cast/transform the data)
3. then drop the old column
4.then rename the new column.
1, 3, 4 are each migrationshmmm, this is going to require a new and improved way of thinking. i'll have to be more careful.
ahh, very good.
okay, this makes sense.
@samson , why not use the USING clause in Postgres?
to make 1-step instead of 4
yeah totally
i'm learnign i need to relearn postgres
just trying to lay out the logical steps
i appreciate it, thank you for explaining the thoughts.
i also now better understand the dangers of not doing this.
ah right. i think what you said is needed in other databases anyway
for reference, to change the type of an ID when using PostgreSQL i think you should be able to:
0. get a lock on the target table and all tables that reference it
1. disable foreign key checks
2. alter the column, with a USING clause if needed
3. update all tables that have a foreign key relationship that references that ID column to use the new ID values
4. re-enable foreign key checks
5. release lock on the tables
in other words, try not to do it. just delete all the data and start over, if you're still in development.
haha kk 😄
and if you do need to do this in production, make sure to do it in a staging environment first because I and you probably missed something in that playbook 😛
well, how's my schema look, did i make any terrible mistakes?
you probably want to use $updateFn instead of (or in addition to) default for updatedAt
i think the check is invalid, checks can only take into account the row being inserted or updated. From the documentation (https://www.postgresql.org/docs/current/ddl-constraints.html):
Note
PostgreSQL does not support CHECK constraints that reference table data other than the new or updated row being checked. While a CHECK constraint that violates this rule may appear to work in simple tests, it cannot guarantee that the database will not reach a state in which the constraint condition is false (due to subsequent changes of the other row(s) involved). This would cause a database dump and restore to fail. The restore could fail even when the complete database state is consistent with the constraint, due to rows not being loaded in an order that will satisfy the constraint. If possible, use UNIQUE, EXCLUDE, or FOREIGN KEY constraints to express cross-row and cross-table restrictions.
If what you desire is a one-time check against other rows at row insertion, rather than a continuously-maintained consistency guarantee, a custom trigger can be used to implement that. (This approach avoids the dump/restore problem because pg_dump does not reinstall triggers until after restoring data, so that the check will not be enforced during a dump/restore.)
got it, so should I just have a counter for the user which counts up, and rejects when a sixth comes?
and it's fine for learning if you're not doing this already, but you'll want to make sure you don't store passwords in plain text, but rather a cryptographic hash
I was going to try this 😄
ok great good
it's just a stupid terminal app which plays a sound at an interval to remind you to do something
Reminder App
Never Forget
so far, the only commands are "help" "hi" and "bye" 😄
i was going to add the features after i figured out the orm/db part, which was harder than i thought.
i bought a domain b/c i figured i'd share w/ others 😄
i built a CLI tool for myself, which I use to do this 😄 i thought it would be good practice to turn it into an app.
you would normally do something like this:
1. start transaction
2. check how many reminders. if more than allowed, abort transaction
3. insert reminder
4. commit transaction
ahhh, i got you.
easy enough then.
thhank you for your help @samson and @ColdRiver
you both taught me a lot today.
you're welcome! good luck in your project!