diff options
Diffstat (limited to 'query.go')
| -rw-r--r-- | query.go | 54 |
1 files changed, 53 insertions, 1 deletions
@@ -105,7 +105,59 @@ func (s Store[R]) Insert(db Handle, records ...R) (returnedRecords []R, returned return records, nil } -// TODO: Store.Update +// Update executes an SQL UPDATE statement for each of the provided records, updating all non-primary-key columns with the values in the records. +// Returns [MissingRecordError] if any of the records does not exist in the database, that is, if for any of the records, the database contains no row with the same primary key values. +// +// Returns an error if [NewStore] was called without the [TableNameIs] or [PrimaryKeyIs] options, which are both required to generate a query for this method. +func (s Store[R]) Update(db Handle, records ...R) (returnedError error) { + if s.plan.Update.Query == "" { + return errors.New("cannot execute Update() because query could not be autogenerated") + } + + var ( + argumentIndexes = s.plan.Update.ArgumentIndexes + argumentSlots = make([]any, len(argumentIndexes)) + ) + + var stmt *sql.Stmt + if len(records) >= PrepareThreshold { + var err error + stmt, err = db.Prepare(s.plan.Update.Query) + if err != nil { + return fmt.Errorf("during Prepare(): %w", err) + } + defer func() { + returnedError = mergeCloseError("Stmt", returnedError, stmt.Close()) + }() + } + + for idx, r := range records { + v := reflect.ValueOf(&r).Elem() + for idx, index := range argumentIndexes { + argumentSlots[idx] = v.FieldByIndex(index).Addr().Interface() + } + var ( + result sql.Result + err error + ) + if stmt == nil { + result, err = db.Exec(s.plan.Update.Query, argumentSlots...) + } else { + result, err = stmt.Exec(argumentSlots...) + } + if err != nil { + return fmt.Errorf("during Exec() for record with idx = %d: %w", idx, err) + } + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("during RowsAffected() for record with idx = %d: %w", idx, err) + } + if rowsAffected == 0 { + return MissingRecordError[R]{r, s.plan} + } + } + return nil +} // Delete executes an SQL DELETE statement for each of the provided records, using their primary keys to locate the respective table rows. // |
