From bb8afd231de7c9beb36b9da1670c6189d64b8c96 Mon Sep 17 00:00:00 2001 From: kim Date: Tue, 11 Feb 2025 14:30:05 +0000 Subject: [PATCH] updates the enum migration to perform a singular update for all values, using an SQL case statement --- internal/db/bundb/migrations/util.go | 42 +++++++++++++++++----------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/internal/db/bundb/migrations/util.go b/internal/db/bundb/migrations/util.go index edf7c1d05..033150ad6 100644 --- a/internal/db/bundb/migrations/util.go +++ b/internal/db/bundb/migrations/util.go @@ -35,6 +35,11 @@ import ( "github.com/uptrace/bun/schema" ) +// formatQuery formats given query + args according to given bun dialect, using for debug logging. +func formatQuery(d schema.Dialect, query string, args ...any) string { + return schema.NewFormatter(d).FormatQuery(query, args...) +} + // convertEnums performs a transaction that converts // a table's column of our old-style enums (strings) to // more performant and space-saving integer types. @@ -82,26 +87,31 @@ func convertEnums[OldType ~string, NewType ~int16]( return gtserror.Newf("error selecting total count: %w", err) } - var updated int + var args []any + var qbuf byteutil.Buffer + + // Prepare a singular UPDATE statement using + // SET $newColumn = (CASE $column WHEN $old THEN $new ... END) + qbuf.WriteString("UPDATE ? SET ? = (CASE ? ") + args = append(args, bun.Ident(table)) + args = append(args, bun.Ident(newColumn)) + args = append(args, bun.Ident(column)) for old, new := range mapping { + qbuf.WriteString("WHEN ? THEN ? ") + args = append(args, old, new) + } + qbuf.WriteString("ELSE ? END)") + args = append(args, *defaultValue) - // Update old to new values. - res, err := tx.NewUpdate(). - Table(table). - Where("? = ?", bun.Ident(column), old). - Set("? = ?", bun.Ident(newColumn), new). - Exec(ctx) - if err != nil { - return gtserror.Newf("error updating old column values: %w", err) - } - - // Count number items updated. - n, _ := res.RowsAffected() - updated += int(n) + // Execute the prepared raw query with arguments. + res, err := tx.NewRaw(qbuf.String(), args...).Exec(ctx) + if err != nil { + return gtserror.Newf("error updating old column values: %w", err) } - // Check total updated. - if total != updated { + // Count number items updated. + updated, _ := res.RowsAffected() + if total != int(updated) { log.Warnf(ctx, "total=%d does not match updated=%d", total, updated) }