Files
payload/packages/drizzle/src/updateOne.ts
Alessio Gravili 7cd682c66a perf(drizzle): further optimize postgres row updates (#13184)
This is a follow-up to https://github.com/payloadcms/payload/pull/13060.

There are a bunch of other db adapter methods that use `upsertRow` for
updates: `updateGlobal`, `updateGlobalVersion`, `updateJobs`,
`updateMany`, `updateVersion`.

The previous PR had the logic for using the optimized row updating logic
inside the `updateOne` adapter. This PR moves that logic to the original
`upsertRow` function. Benefits:
- all the other db methods will benefit from this massive optimization
as well. This will be especially relevant for optimizing postgres job
queue initial updates - we should be able to close
https://github.com/payloadcms/payload/pull/11865 after another follow-up
PR
- easier to read db adapter methods due to less code.

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210803039809810
2025-07-16 09:45:02 -07:00

97 lines
2.3 KiB
TypeScript

import type { LibSQLDatabase } from 'drizzle-orm/libsql'
import type { UpdateOne } from 'payload'
import toSnakeCase from 'to-snake-case'
import type { DrizzleAdapter } from './types.js'
import { buildQuery } from './queries/buildQuery.js'
import { selectDistinct } from './queries/selectDistinct.js'
import { upsertRow } from './upsertRow/index.js'
import { getTransaction } from './utilities/getTransaction.js'
export const updateOne: UpdateOne = async function updateOne(
this: DrizzleAdapter,
{
id,
collection: collectionSlug,
data,
joins: joinQuery,
locale,
options = { upsert: false },
req,
returning,
select,
where: whereArg,
},
) {
const db = await getTransaction(this, req)
const collection = this.payload.collections[collectionSlug].config
const tableName = this.tableNameMap.get(toSnakeCase(collection.slug))
let idToUpdate = id
if (!idToUpdate) {
const { joins, selectFields, where } = buildQuery({
adapter: this,
fields: collection.flattenedFields,
locale,
tableName,
where: whereArg,
})
// selectDistinct will only return if there are joins
const selectDistinctResult = await selectDistinct({
adapter: this,
db,
joins,
query: ({ query }) => query.limit(1),
selectFields,
tableName,
where,
})
if (selectDistinctResult?.[0]?.id) {
idToUpdate = selectDistinctResult?.[0]?.id
// If id wasn't passed but `where` without any joins, retrieve it with findFirst
} else if (whereArg && !joins.length) {
const table = this.tables[tableName]
const docsToUpdate = await (db as LibSQLDatabase)
.select({
id: table.id,
})
.from(table)
.where(where)
.limit(1)
idToUpdate = docsToUpdate?.[0]?.id
}
}
if (!idToUpdate && !options.upsert) {
// TODO: In 4.0, if returning === false, we should differentiate between:
// - No document found to update
// - Document found, but returning === false
return null
}
const result = await upsertRow({
id: idToUpdate,
adapter: this,
data,
db,
fields: collection.flattenedFields,
ignoreResult: returning === false,
joinQuery,
operation: 'update',
req,
select,
tableName,
})
if (returning === false) {
return null
}
return result
}