Cannot do a Prisma migration due to null value - prisma

I want to add a column to an table but the migration is failing:
The model:
model Notification {
id Int #id #default(autoincrement())
movie Movie? #relation(fields: [movieId], references: [id])
movieId Int?
movieRating MovieRating? #relation(fields: [movieRatingId], references: [id])
movieRatingId Int?
user User? #relation(fields: [userId], references: [id])
userId Int?
followedUser User? #relation("FollowedUser", fields: [followedUserId], references: [id])
followedUserId Int?
action String
value String?
watched Boolean #default(false)
}
The error:
Database error:
ERROR: column "value" of relation "Notification" contains null values
DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("23502"), message: "column "value" of relation "Notification" contains null values", detail: None, hint: None, position: None, where_: None, schema: Some("public"), table: Some("Notification"), column: Some("value"), datatype: None, constraint: None, file: Some("tablecmds.c"), line: Some(5450), routine: Some("ATRewriteTable") }
Screengrab of the table:
I understand that if the value column that I want to add is required that this would show an error, but the String? makes it's optional right?

Took a closer look in my migrations and I added the value column in 2 steps. First I added it without the optional ? but since my local db was empty there was no issue. Then I made it optional, but on production it was the first migration (adding the value without optional) that failed.
My first migration was:
AlterTable ALTER TABLE "Notification" ADD COLUMN "value" TEXT NOT NULL;
After that I created another migration:
ALTER TABLE "Notification" ALTER COLUMN "value" DROP NOT NULL;
So this is what caused the error.
I resolved it by rolling back the first migration: npx prisma migrate resolve --rolled-back "20220515174738_added_value_field_to_notificaion"
Then I changed the first migration file:
AlterTable ALTER TABLE "Notification" ADD COLUMN "value" TEXT; and I removed the second migration.
Now I can deploy the migrations again :)

Related

Prisma model typing issue - expected non-nullable type "String", found incompatible value of "null"

Problem
I am using Prisma as an ORM for a psql database. When I try to delete a row from a table (Plant) that my current table (Pod) references I get the error:
Error converting field "plantId" of expected non-nullable type "String", found incompatible value of "null".
My intention is, when the underlying Plant row is deleted, the reference or foreign_key on the Pod rows that reference it, are set to null. However, I can't seem to set it up correctly. I thought by typing it with plantId: String? it would be able to handle that since the ? set's the row to either <type>|null.
I could really use some help, I'm not sure where I'm going wrong.
// Plant
model Plant {
id Int #id #default(autoincrement())
plantId String #unique #default(uuid())
name String #unique
pods Pod[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
// Pod
model Pod {
id Int #id #default(autoincrement())
podId String #unique #default(uuid())
name String #db.VarChar(200)
hasAlert Boolean
plant Plant? #relation(fields: [plantId], references: [plantId], onDelete: SetNull)
plantId String?
batch Batch #relation(fields: [batchId], references: [batchId], onDelete: Cascade)
batchId String
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
Prisma Studio walk through:
Pod has a foreign key pointing to Plant (named broccoli)
In Plant table, I delete the referenced Plant (broccoli) that we saw in Pod
Upon returning to the Pod table, we get the following error:

db error: ERROR: column 'postId' in relation 'Comment' already exists P3006 prisma error

I would like to modify a table in my PostgreSQL database using prisma. But, when I use the command npx prisma migrate dev --name initial-migration --create-only, I obtain the following error:
Error: P3006
Migration `20220803234538_initial_migration` failed to apply cleanly to the shadow database.
Error:
db error: ERROR: column 'postId' in relation 'Comment' already exists
0: sql_migration_connector::flavour::postgres::sql_schema_from_migration_history
at migration-engine\connectors\sql-migration-connector\src\flavour\postgres.rs:340
1: migration_core::state::DevDiagnostic
at migration-engine\core\src\state.rs:178
Here is my table content:
model Comment {
id String #id #default(uuid())
createdAt DateTime #default(now())
content String
user User #relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
post Post #relation(fields: [postId], references: [id], onDelete: Cascade)
groupPost GroupPost? #relation(fields: [groupPostId], references: [id], onDelete: Cascade)
postId String
groupPostId String
}
It's true that the postId column of the comment table already existed in the database, but it's not like I created two postId columns. I just accidentally changed the postId column declaration line and fixed my typo. I don't see why I'm getting this error and when I search the Internet I don't get any solution.

Reuse same model for two fields in Prisma

My goal is for this:
I have a table of professions. A person can have two professions - a primary and secondary profession.
model Person {
id String #id #default(cuid())
PrimaryProfessionId String?
Secondary String?
PrimaryProfession Profession #relation(fields: [PrimaryProfessionId], references: [id])
SecondaryProfession Profession #relation(fields: [SecondaryProfessionId], references: [id], name: "secondaryProfession")
}
model Profession {
id String #id #default(cuid())
name String
Primary Person?
Secondary Person? #relation("secondaryProfession")
}
Trying to copy this: Prisma - How to point two fields to same model? but it doesnt work.
With current code I am getting error: Error parsing attribute "#relation": A one-to-one relation must use unique fields on the defining side.
What should I fix to make this work?

Prisma inserting null value for foreign key on a one-on-one relation

Relevant schema parts.
model ShopifyOfflineStoreSession {
pk String #id(map: "PK_d371917bab72a48d6cce7880fc5") #default(dbgenerated("uuid_generate_v4()")) #db.Uuid
id String #unique(map: "UQ_91ede9e23efbd7ee27b37bdd9ba") #db.VarChar
store Store? #relation(fields: [pk], references: [shopifyOfflineSessionPk], onDelete: Cascade, onUpdate: Cascade, map: "FK_901a837fbbf20119aded3682f90")
##map("shopify_store_session")
}
model Store {
id Int #id(map: "PK_f3172007d4de5ae8e7692759d79") #default(autoincrement())
shopifyOfflineSessionPk String? #unique(map: "UQ_901a837fbbf20119aded3682f90") #db.Uuid
shopifyOfflineSession ShopifyOfflineStoreSession?
##map("store")
}
This query fails:
await this.prisma.shopifyOfflineStoreSession.create({
data: {
...session,
store: { connect: { id: store.id } },
},
});
Error:
2022-06-10 16:41:02.035 UTC [15541] ERROR: null value in column "pk" violates not-null constraint
2022-06-10 16:41:02.035 UTC [15541] DETAIL: Failing row contains (null, offline_subbooks2.myshopify.com, 2022-06-10 16:41:02.033, 2022-06-10 16:41:02.033, null, subbooks2.myshopify.com, 005148992241858, f, null, null, null).
2022-06-10 16:41:02.035 UTC [15541] STATEMENT: INSERT INTO "public"."shopify_store_session" ("pk","id","createdAt","updatedAt","shop","state","isOnline") VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING "public"."shopify_store_session"."pk"
Issue saving Shopify offline token. Err: PrismaClientKnownRequestError:
Invalid `this.prisma.shopifyOfflineStoreSession.create()` invocation in
/usr/src/api/src/store/store.service.ts:576:52
573 data: session,
574 });
575 } else {
→ 576 await this.prisma.shopifyOfflineStoreSession.create(
Null constraint violation on the fields: (`pk`)
at cb (/usr/src/api/node_modules/#prisma/client/runtime/index.js:38683:17) {
code: 'P2011',
clientVersion: '3.6.0',
meta: { constraint: [ 'pk' ] }
}
query: DELETE FROM "store" WHERE "id" IN ($1) -- PARAMETERS: [18]
I don’t understand why prisma is setting pk on shopifyOfflineStoreSession to null. Can someone help me understand what’s causing this error?
The Prisma docs state:
In a one-to-one relation, the side of the relation without a relation scalar (the field representing the foreign key in the database) must be optional.
For me, I wanted a Store record to be able to exist without a ShopifyOfflineStoreSession which means I have to put the relation scalar on ShopifyOfflineStoreSession instead of Store.
This is how the final state looks now and there's no issues:
model Store {
id Int #id(map: "PK_f3172007d4de5ae8e7692759d79") #default(autoincrement())
shopifyOfflineSession ShopifyOfflineStoreSession?
##map("store")
}
model ShopifyOfflineStoreSession {
pk String #id(map: "PK_d371917bab72a48d6cce7880fc5") #default(dbgenerated("uuid_generate_v4()")) #db.Uuid
id String #unique(map: "UQ_91ede9e23efbd7ee27b37bdd9ba") #db.VarChar
store Store #relation(fields: [storeId], references: [id], onDelete: Cascade, onUpdate: Cascade, map: "FK_901a837fbbf20119aded3682f90")
storeId Int #unique
##map("shopify_store_session")
}
I had to execute a few migrations to achieve this:
create storeId (nullable) in ShopifyOfflineStoreSession
add appropriate ids from Store to it
make storeId non null
change FK from Store to ShopifyOfflineStoreSession
drop original FK (shopifyOfflineSessionPk) from Store.
If you want more details on these migration, ask in a comment.

Updating many-to-many relations in Prisma

I have a group of checkboxes for skin concerns. Users can check/uncheck them before submitting, which means the set of skin concerns submitted can be different every time.
I modeled it in Prisma schema as an 'explicit' many-to-many relation.
model User {
id String #id #default(cuid())
name String?
nickname String? #unique
...
skinConcerns SkinConcernsForUsers[]
...
}
model SkinConcern {
id Int #id #default(autoincrement())
name String #unique
user SkinConcernsForUsers[]
}
model SkinConcernsForUsers {
user User #relation(fields: [userId], references: [id])
userId String
skinConcern SkinConcern #relation(fields: [skinConcernId], references: [id])
skinConcernId Int
##id([userId, skinConcernId])
}
Then, SkinConcerns table is seeded with the following values, using prisma.skinConcern.createMany:
"ACNE",
"DRYNESS",
"OILY_SKIN",
"PIGMENTATION",
"REDNESS",
"WRINKLES",
SkinConcerns in Update mutation input comes in the form of array of strings, e.g. ["PIGMENTATION", "REDNESS"].
I want to update the skin concerns for users (SkinConcernsForUsers) from the prisma.user.update query, but it's tricky, since I'm not merely creating SkinConcerns, but have to connect to existing set of skin concerns.
I've tried directly setting skinConcerns in user, like
await prisma.user.update({
where: { nickname },
data: {
// ... other user data
skinConcerns: {
set: [
{
skinConcern: {
connect: { name: "PIGMENTATION" },
},
},
{
skinConcern: {
connect: { name: "REDNESS" },
},
},
],
},
// ... other user data
}
});
among many other things, but of course this is not a correct argument and fails with error
Unknown arg `connect` in data.skinConcerns.update.0.where.connect for type SkinConcernsForUsersWhereUniqueInput. Did you mean `select`?
Argument data for data.skinConcerns.update.0.data is missing.
Unknown arg `connect` in data.skinConcerns.update.1.where.connect for type SkinConcernsForUsersWhereUniqueInput. Did you mean `select`?
Argument data for data.skinConcerns.update.1.data is missing.
Is there a way to do this? Is it even possible to update this in prisma.user.update?
I guess I could directly update SkinConcernsForUsers. In that case, should I just delete all rows associated to the user that are not in the user input ["PIGMENTATION", "REDNESS"], then create rows that don't already exist? What will it look like in prisma code?
First I would change your schema for SkinConcern. The id field is not necessary and will create complications in queries (you would needlessly need to map each name to id when trying to connect/disconnect records.
The name field is sufficient as the primary key, as it is always unique for a certain record.
The changed schema looks like this
model SkinConcern {
name String #id // name is the new #id.
user SkinConcernsForUsers[]
}
model SkinConcernsForUsers {
user User #relation(fields: [userId], references: [id])
userId String
skinConcern SkinConcern #relation(fields: [skinConcernName], references: [name])
skinConcernName String
##id([userId, skinConcernName])
}
The query you want to do can be executed in two steps with the SkinConcernsForUsers model.
Step 1: Remove existing SkinConcernsForUsers records a user is connected to. These are no longer relevant, as you want to overwrite the previous selection.
Step 2: Create new SkinConcernsForUsers records with the new choices.
Here is what the code looks like
// step 1
await prisma.skinConcernsForUsers.deleteMany({
where: {
userId: "1",
},
});
// step 2
await prisma.skinConcernsForUsers.createMany({
data: [
{
userId: "1",
skinConcernName: "REDNESS",
},
{
userId: "1",
skinConcernName: "PIGMENTATION",
},
],
});