From d964c2be59a73e6b21ce1a8031fe913588bddf66 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Thu, 16 Apr 2026 21:18:04 +0200 Subject: add Store.Update() --- query.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'query.go') diff --git a/query.go b/query.go index 88c2987..41d61c7 100644 --- a/query.go +++ b/query.go @@ -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. // -- cgit v1.2.3