Replace xmax upsert trick with RETURNING full row
Upsert methods now RETURNING all struct columns and scan the result back into the pointer receiver, keeping the caller in sync with the actual DB state (id, created_at, etc. from the existing row on conflict). Insert detection compares the saved original ID with the returned ID instead of relying on the PostgreSQL-internal xmax column. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -189,10 +189,10 @@ INSERT INTO common_tracker_patterns (
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p CommonTrackerPattern) Upsert(
|
||||
func (p *CommonTrackerPattern) Upsert(
|
||||
ctx context.Context,
|
||||
conn pg.Tx,
|
||||
) (actualID gid.GID, inserted bool, err error) {
|
||||
) (inserted bool, err error) {
|
||||
q := `
|
||||
INSERT INTO common_tracker_patterns (
|
||||
id,
|
||||
@@ -224,9 +224,21 @@ SET
|
||||
description = EXCLUDED.description,
|
||||
confidence = EXCLUDED.confidence,
|
||||
updated_at = EXCLUDED.updated_at
|
||||
RETURNING id, (xmax = 0) AS inserted
|
||||
RETURNING
|
||||
id,
|
||||
common_third_party_id,
|
||||
tracker_type,
|
||||
pattern,
|
||||
match_type,
|
||||
description,
|
||||
max_age_seconds,
|
||||
confidence,
|
||||
created_at,
|
||||
updated_at
|
||||
`
|
||||
|
||||
originalID := p.ID
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"id": p.ID,
|
||||
"common_third_party_id": p.CommonThirdPartyID,
|
||||
@@ -242,27 +254,18 @@ RETURNING id, (xmax = 0) AS inserted
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return gid.GID{}, false, fmt.Errorf("cannot upsert common tracker pattern: %w", err)
|
||||
return false, fmt.Errorf("cannot upsert common tracker pattern: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
type upsertResult struct {
|
||||
ID gid.GID
|
||||
Inserted bool
|
||||
}
|
||||
|
||||
res, err := pgx.CollectExactlyOneRow(
|
||||
rows,
|
||||
func(row pgx.CollectableRow) (upsertResult, error) {
|
||||
var r upsertResult
|
||||
return r, row.Scan(&r.ID, &r.Inserted)
|
||||
},
|
||||
)
|
||||
row, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[CommonTrackerPattern])
|
||||
if err != nil {
|
||||
return gid.GID{}, false, fmt.Errorf("cannot collect upsert result: %w", err)
|
||||
return false, fmt.Errorf("cannot collect upsert result: %w", err)
|
||||
}
|
||||
|
||||
return res.ID, res.Inserted, nil
|
||||
*p = row
|
||||
|
||||
return originalID == p.ID, nil
|
||||
}
|
||||
|
||||
func (p CommonTrackerPattern) Delete(
|
||||
|
||||
Reference in New Issue
Block a user