prisma / prisma

Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server, SQLite, MongoDB and CockroachDB
https://www.prisma.io
Apache License 2.0
39.01k stars 1.53k forks source link

Incorrect logging for `upsert` error with `Infinity` #19966

Open jakeleventhal opened 1 year ago

jakeleventhal commented 1 year ago

Bug description

When I use upsert with an invalid payload, I am getting the wrong error message.

Screenshot 2023-06-26 at 9 25 22 AM

The problem is clearly that listingPrice is being set to Infinity, but the error is reporting that marketplaceIntegration is missing, even though it isn't.

How to reproduce

See screenshot

Expected behavior

No response

Prisma information

          const inventoryItemData: Prisma.InventoryItemUncheckedCreateInput | Prisma.InventoryItemUpdateInput = {
            asin,
            dead: deadProduct,
            fnsku,
            fulfillment: 'FBA',
            groupId: fnsku,
            listingCurrency: MarketplaceUtils.getCurrencyCode(marketplace),
            listingPrice: Number.isFinite(calculatedPrice) ? calculatedPrice : 0,
            marketplace,
            marketplaceIntegrationId: mpClient.id,
            productId: sku,
            sku,
            title: shipment['product-name'],
            userId: mpClient.userId
          };
          inventoryItem = await prisma.inventoryItem.upsert({
            create: inventoryItemData,
            update: inventoryItemData,
            where: {
              marketplaceIntegrationId_marketplace_productId: {
                marketplace,
                marketplaceIntegrationId: mpClient.id,
                productId: sku
              }
            }
          });

Environment & setup

Prisma Version

4.16.1
SevInf commented 1 year ago

@jakeleventhal couple of questions:

  1. Are you using jsonProtocol preview feature?
  2. Could you share the schema for InventoryItem model?
jakeleventhal commented 1 year ago
  1. yes

    generator client {
    provider        = "prisma-client-js"
    output          = "../../../../node_modules/@prisma/client/ecominate"
    previewFeatures = ["fullTextSearch", "jsonProtocol"]
    binaryTargets   = ["native", "rhel-openssl-1.0.x"]
    }
  2. sure

    model InventoryItem {
    id String @id @default(uuid())
    
    /// The inventory item's asin.
    ///
    /// This is only available for Amazon.
    asin            String?
    /// Whether or not the user manually archived the inventory item.
    archived        Boolean      @default(false)
    /// Whether or not the the inventory item is no longer an active product.
    ///
    /// This means that the product used to exist in inventory reports but no longer does.
    /// This can also occur if an order is encountered for a product that doesn't appear in inventory reports.
    dead            Boolean      @default(false)
    /// The fulfillment SKU for the inventory item.
    ///
    /// This is only available for Amazon FBA products.
    fnsku           String?
    /// The id used to group the inventory item for the sake of mapping to master products.
    ///
    /// This is only relevant for the sake of ensuring that Amazon FBA products are linked when mapping to master products.
    groupId         String
    /// The inventory item's fulfillment method.
    fulfillment     String
    /// The last time that the inventory item was updated.
    updatedAt       DateTime     @updatedAt
    /// The currency that the inventory item's listing uses.
    listingCurrency CurrencyCode
    /// The price of the inventory item's listing.
    listingPrice    Float
    /// The marketplace that the inventory item belongs to.
    marketplace     String
    /// The inventory item's product title.
    title           String
    /// The inventory item's SKU.
    sku             String
    /// The inventory item's unique product identifier used to distinguish it on the marketplace.
    ///
    /// When marketplaces don't have product ids, the SKU is used instead.
    productId       String
    /// The url for the inventory item's product image.
    image           String?
    /// The id that the marketplace assigns to the product's listing.
    ///
    /// This is only available for Etsy.
    listingId       Int?
    
    /// The master product that the inventory item belongs to, if any.
    masterProduct            MasterProduct?         @relation(fields: [masterProductId], references: [id], onDelete: SetNull)
    /// The id of the master product that the inventory item belongs to, if any.
    masterProductId          String?
    /// The marketplace integration that the inventory item belongs to.
    marketplaceIntegration   MarketplaceIntegration @relation(fields: [marketplaceIntegrationId], references: [id], onDelete: Cascade)
    /// The id of the marketplace integration that the inventory item belongs to.
    marketplaceIntegrationId String
    /// The user that the inventory item belongs to.
    user                     User                   @relation(fields: [userId], references: [id], onDelete: Cascade)
    /// The id of the user that the inventory item belongs to.
    userId                   String
    
    @@unique([marketplaceIntegrationId, marketplace, productId])
    }
SevInf commented 1 year ago

In 5.1, the error message correctly points to listingPrice being the problem, but it says it is missing rather then Infinity:

> basic-sqlite@ test /Users/serhii/projects/prisma/reproductions/workbench
> ts-node index.ts

Invalid `prisma.inventoryItem.upsert()` invocation in
/Users/serhii/projects/prisma/reproductions/workbench/index.ts:19:52

  16   title: '', //shipment['product-name'],
  17   userId: '',
  18 }
→ 19 const inventoryItem = await prisma.inventoryItem.upsert({
       create: {
         asin: "",
         dead: false,
         fnsku: "",
         fulfillment: "FBA",
         groupId: "",
         marketplaceIntegrationId: "",
         marketplace: "",
         productId: "",
         sku: "",
         title: "",
         userId: "",
     +   listingPrice: Float
       },
       update: {
         asin: "",
         dead: false,
         fnsku: "",
         fulfillment: "FBA",
         groupId: "",
         listingPrice: Infinity,
         marketplaceIntegrationId: "",
         marketplace: "",
         productId: "",
         sku: "",
         title: "",
         userId: ""
       },
       where: {
         marketplaceIntegrationId_marketplace_productId: {
           marketplace: "",
           marketplaceIntegrationId: "",
           productId: ""
         }
       }
     })

Argument `listingPrice` is missing.

I think, we generally have a problem with serializing Infinity: on protocol level, it silently turns to null. For GraphQL protocol, it was not that much better, the error message in that case is:

Argument `listingPrice`: Invalid value provided. Expected Float or Float, provided Enum.