Improve raw update (#7160)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2024-11-12 12:37:08 +05:00 committed by GitHub
parent 8bec20e0c5
commit 1afe8ef326
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -296,13 +296,17 @@ abstract class PostgresAdapterBase implements DbAdapter {
if ((operations as any).$set !== undefined) { if ((operations as any).$set !== undefined) {
;(operations as any) = { ...(operations as any).$set } ;(operations as any) = { ...(operations as any).$set }
} }
const isOps = isOperator(operations)
if ((operations as any)['%hash%'] === undefined) { if ((operations as any)['%hash%'] === undefined) {
;(operations as any)['%hash%'] = null ;(operations as any)['%hash%'] = null
} }
if (isOps) {
const conn = await this.client.reserve() const conn = await this.client.reserve()
try { try {
await this.retryTxn(conn, async (client) => { await this.retryTxn(conn, async (client) => {
const res = await client.unsafe(`SELECT * FROM ${translateDomain(domain)} WHERE ${translatedQuery} FOR UPDATE`) const res = await client.unsafe(
`SELECT * FROM ${translateDomain(domain)} WHERE ${translatedQuery} FOR UPDATE`
)
const docs = res.map((p) => parseDoc(p as any)) const docs = res.map((p) => parseDoc(p as any))
for (const doc of docs) { for (const doc of docs) {
if (doc === undefined) continue if (doc === undefined) continue
@ -339,6 +343,51 @@ abstract class PostgresAdapterBase implements DbAdapter {
} finally { } finally {
conn.release() conn.release()
} }
} else {
await this.rawUpdateDoc(domain, query, operations)
}
}
private async rawUpdateDoc<T extends Doc>(
domain: Domain,
query: DocumentQuery<T>,
operations: DocumentUpdate<T>
): Promise<void> {
const translatedQuery = this.buildRawQuery(domain, query)
const updates: string[] = []
const params: any[] = []
let paramsIndex = 5
const { extractedFields, remainingData } = parseUpdate(domain, operations)
const { space, attachedTo, ...ops } = operations as any
for (const key in extractedFields) {
updates.push(`"${key}" = $${paramsIndex++}`)
params.push((extractedFields as any)[key])
}
let from = 'data'
let dataUpdated = false
for (const key in remainingData) {
if (ops[key] === undefined) continue
const val = (remainingData as any)[key]
from = `jsonb_set(${from}, '{${key}}', coalesce(to_jsonb($${paramsIndex++}${inferType(val)}), 'null') , true)`
params.push(val)
dataUpdated = true
}
if (dataUpdated) {
updates.push(`data = ${from}`)
}
const conn = await this.client.reserve()
try {
await this.retryTxn(conn, async (client) => {
await client.unsafe(
`UPDATE ${translateDomain(domain)} SET ${updates.join(', ')} WHERE ${translatedQuery}`,
params
)
})
} catch (err) {
console.error(err, { domain, params, updates })
} finally {
conn.release()
}
} }
async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> { async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {