Skip to content

Resolve lazy values when bulk updating - #35

Open
kac-axelor wants to merge 1 commit into
axelor:devfrom
kac-axelor:bulk-update-lazy-fields
Open

kac-axelor wants to merge 1 commit into
axelor:devfrom
kac-axelor:bulk-update-lazy-fields

Conversation

@kac-axelor

Copy link
Copy Markdown
Contributor

updateAll never resolved lazy values. create and update route every
non-relation value through resolveLazy; updateAll used valueOrID alone,
so a promise reached the query builder and pg serialized it as {}:

const source = await client.contact.findOne({
  where: { id },
  select: { notes: true },
});

await client.contact.updateAll({
  set: { notes: source.notes },  // a promise — lazy fields always are
  where: { lastName: { eq: "Smith" } },
});
// every matched row's notes column now holds the two characters {}

Nothing warns you: Text is Promise<string | null>, so the promise is the
declared type for a bulk set and the round trip above typechecks with no cast.
Text and json were silently overwritten with {}; binary failed outright with
invalid input syntax for type oid: "{}".

createAll is unaffected — it builds rows with #handleCreate and inherits the
resolution.

Non-relations now go through resolveLazy, which also creates the large object
for oid columns — so binary bulk updates work instead of erroring. Confining
valueOrID to relations additionally stops it collapsing a json value that
carries an id key down to just that id.

Tests

Five e2e tests in the bulk suite; three fail on dev:

  • text and json set from promises — fails on dev ({})
  • a lazy value read from one record fed into updateAll — fails on dev ({})
  • clearing with null — passes on dev, pins the working path
  • binary across two matched records — fails on dev (oid syntax error)
  • rewriting one record's binary afterwards, asserting its sibling is untouched

Notes

Bulk-updating a binary column points every matched row at one large object,
where update() gives each row its own. Safe under the ORM, since every write
allocates a fresh oid — rewriting one row repoints only that row, which the
last test pins — and under vacuumlo, which unlinks by reference scan.

A no-match bulk update still creates its large object. One instance of a wider
gap: nothing here ever reclaims a large object, on any path, and lo_unlink is
itself broken (src/client/fields/lob.ts:37). Its own change.

Left out: updateAll never calls rejectProtectedFields, so internal and
readonly fields can be written in bulk. Pre-existing, orthogonal, and
tightening it is a behaviour change that deserves its own PR.

- Bulk updates now write text, json and binary fields correctly instead
  of storing an empty object for them.
- A lazy value read from one record can be passed straight into
  updateAll, which previously stored "{}".
- Binary fields can be bulk updated; before they failed outright.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant