package norm import ( "context" "database/sql" "fmt" "strings" ) type update struct { table string or UpdateOr sets []struct { col string val any } where *Expr } type UpdateOr int const ( UpdateNone UpdateOr = iota UpdateAbort UpdateFail UpdateIgnore UpdateReplace UpdateRollback ) func (u UpdateOr) String() string { switch u { case UpdateAbort: return "ABORT" case UpdateFail: return "FAIL" case UpdateIgnore: return "IGNORE" case UpdateReplace: return "REPLACE" case UpdateRollback: return "ROLLBACK" default: return "" } } func Update(table string) update { return update{table: table} } type UpdateOpt func(s *update) func (u update) Or(option UpdateOr) update { u.or = option return u } func (u update) Set(column string, value any) update { u.sets = append(u.sets, struct { col string val any }{ column, value, }) return u } func (u update) Sets(values map[string]any) update { for column, value := range values { u = u.Set(column, value) } return u } func (u update) Where(expr Expr) update { u.where = &expr return u } func (u update) Compile() (string, []any, error) { var sql strings.Builder var args []any sql.WriteString("UPDATE ") orKw := u.or.String() if orKw != "" { sql.WriteString("OR ") sql.WriteString(u.or.String()) sql.WriteString(" ") } if u.table == "" { return "", nil, fmt.Errorf("table name is required") } sql.WriteString(u.table) if len(u.sets) == 0 { return "", nil, fmt.Errorf("no SET clauses supplied") } sql.WriteString(" SET ") for i, set := range u.sets { if i != 0 { sql.WriteString(", ") } sql.WriteString(set.col) sql.WriteString(" = ?") args = append(args, set.val) } if u.where != nil { sql.WriteString(" WHERE ") sql.WriteString(u.where.String()) args = append(args, u.where.Binds()...) } return sql.String(), args, nil } func (u update) MustCompile() (string, []any) { sql, args, err := u.Compile() if err != nil { panic(err) } return sql, args } func (u update) Build(p Database) (*sql.Stmt, []any, error) { return Build(u, p) } func (u update) MustBuild(p Database) (*sql.Stmt, []any) { return MustBuild(u, p) } func (u update) Exec(p Database) (sql.Result, error) { return Exec(u, p) } func (u update) ExecContext(ctx context.Context, p Database) (sql.Result, error) { return ExecContext(ctx, u, p) } func (u update) MustExec(p Database) sql.Result { return MustExec(u, p) } func (u update) MustExecContext(ctx context.Context, p Database) sql.Result { return MustExecContext(ctx, u, p) }