Prisma Upsert with Foreign Key constraint

Viewed 23

I have a Lambda function with a Postgres DB, where I am using Prisma to upsert a parent charge object with multiple charge_item children. At first, I initially tried to upsert the charge first and then upsert the charge_items, but on doing so I kept getting the error:

Foreign key constraint failed on the field: charge_items_charge_id_fkey (index)

I changed my approach to upserting the children first then the parent, but still, I am seeing the same error.

Here is the models:

model charges {
  id               Int            @id @default(autoincrement())
  charge_id        BigInt         @unique
  address_id       BigInt
  customer_id      BigInt
  order_id         BigInt?
  subscription_ids Json           @default("[]")
  charge_items     charge_items[]
  created_at       DateTime       @default(now())
  updated_at       DateTime       @default(now())
}

model charge_items {
  id                 Int           @id @default(autoincrement())
  charge_id          BigInt
  subscription_id    BigInt        @unique
  product_id         BigInt
  variant_id         BigInt
  purchase_item_type String
  quantity           Int
  total_price        String
  unit_price         String
  product            products      @relation(fields: [product_id], references: [product_id], onDelete: Cascade, onUpdate: Cascade)
  variant            variants      @relation(fields: [variant_id], references: [variant_id], onDelete: Cascade, onUpdate: Cascade)
  subscription       subscriptions @relation(fields: [subscription_id], references: [subscription_id], onDelete: Cascade, onUpdate: Cascade)
  charge             charges       @relation(fields: [charge_id], references: [charge_id], onDelete: Cascade, onUpdate: Cascade)
  created_at         DateTime      @default(now())
  updated_at         DateTime      @default(now())
}

And here is the current logic:

items.forEach(async (item) => {
      await prisma.charge_items.upsert({
        where: {
          subscription_id: item.purchase_item_id
        },
        update: {
          purchase_item_type: item.purchase_item_type,
          quantity: item.quantity,
          total_price: item.total_price,
          unit_price: item.unit_price,
          updated_at: item.updated_at
        },
        create: {
          charge_id: charge.id,
          subscription_id: item.purchase_item_id,
          product_id: parseInt(item.external_product_id.ecommerce),
          variant_id: parseInt(item.external_variant_id.ecommerce),
          purchase_item_type: item.purchase_item_type,
          quantity: item.quantity,
          total_price: item.total_price,
          unit_price: item.unit_price,
          charge: {
            create: {
              charge_id: charge.id,
              address_id: charge.address_id,
              customer_id: charge.customer?.external_customer_id?.ecommerce
                ? parseInt(charge.customer?.external_customer_id?.ecommerce)
                : undefined,
              order_id: charge.external_order_id.ecommerce
                ? parseInt(charge.external_order_id.ecommerce)
                : undefined,
              subscription_ids: items.map((x) => {
                return x.purchase_item_id
              }),
              updated_at: charge.updated_at,
              created_at: charge.created_at
            }
          },
          created_at: charge.created_at,
          updated_at: charge.updated_at
        }
      })
    })

    await prisma.charges.upsert({
      where: {
        charge_id: charge.id
      },
      update: {
        order_id: charge.external_order_id.ecommerce
          ? parseInt(charge.external_order_id.ecommerce)
          : undefined,
        subscription_ids: items.map((x) => {
          return x.purchase_item_id
        }),
        updated_at: charge.updated_at
      },
      create: {
        charge_id: charge.id,
        address_id: charge.address_id,
        customer_id: charge.customer?.external_customer_id?.ecommerce
          ? parseInt(charge.customer?.external_customer_id?.ecommerce)
          : undefined,
        order_id: charge.external_order_id.ecommerce
          ? parseInt(charge.external_order_id.ecommerce)
          : undefined,
        subscription_ids: items.map((x) => {
          return x.purchase_item_id
        }),
        updated_at: charge.updated_at,
        created_at: charge.created_at
      }
    })

My question is, how can I safely create or update both the parent and child row(s) and prevent this restraint from failing in the future? I've seen documentation on implementing createOrConnect, but only in the .create() function, not upserts. Would createOrConnect still work for upserts? Or is there a better approach?

0 Answers
Related