Vincit / objection.js

An SQL-friendly ORM for Node.js
https://vincit.github.io/objection.js
MIT License
7.24k stars 635 forks source link

Subquery value not provided in beforeUpdate #2672

Open eywolfe opened 3 months ago

eywolfe commented 3 months ago

I'm trying to write a static beforeUpdate hook and noticed that when my patch call uses a subquery the value(s) are not included in the inputItems array.

Here is the relevant part of my beforeUpdate definition:

  static async beforeUpdate({
    asFindQuery,
    inputItems,
    transaction,
    context,
  }: StaticHookArguments<Inventory>) {
    console.log("inputItems", inputItems);
    ...
  }

If I call the function like this then I see quantity_in_stock provided in inputItems:

  await Inventory.query(trx)
    .context({ user_profile_uuid: context.currentUserOrgProfile?.uuid })
    .whereIn('id', [...childInventories.map((i) => i.id), inventory.id])
    .patch({
      quantity_in_stock: 2,
      receiving_item_status: 'active',
    });
OUTPUT:
inputItems [
  Inventory {
    quantity_in_stock: 2,
    receiving_item_status: 'depleted',
    updated_at: '2024-06-10T17:32:22.398Z'
  }
]

However if I call the function using a subquery in the patch parameter I don't see quantity_in_stock in inputItems:

  await Inventory.query(trx)
    .context({ user_profile_uuid: context.currentUserOrgProfile?.uuid })
    .whereIn('id', [...childInventories.map((i) => i.id), inventory.id])
    .patch({
      quantity_in_stock: PickedItem.query(trx)
        .findOne({
          inventory_uuid: ref('inventory.uuid'),
          order_uuid: pickedItem.order_uuid,
        })
        .select('quantity'),
      receiving_item_status: 'active',
    });
OUTPUT:
inputItems [
  Inventory {
    receiving_item_status: 'active',
    updated_at: '2024-06-10T17:33:05.020Z'
  }
]

Is there any workaround here other than refactoring to not pass a subquery when calling patch? I can do that in this one instance, but it's not maintainable to assume we won't write code like this in the future. I also tried writing an afterUpdate function instead and ran into the same issue.

kapouer commented 2 weeks ago

That makes sense since PickedItem.query(trx) .findOne({ inventory_uuid: ref('inventory.uuid'), order_uuid: pickedItem.order_uuid, }) .select('quantity') returns a promise, and objection will not resolve it before calling beforeUpdate.