diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2026-04-18 15:44:46 +0200 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2026-04-18 15:45:42 +0200 |
| commit | 01d2d52fd7dfb64c41f7c94808fe01665ffcb881 (patch) | |
| tree | cd17477850ee1d34d11b681ef3f10a24b49c04f6 /query.go | |
| parent | cfdb06f5ba144aad5d2ebe31ec8bb64e017f4023 (diff) | |
| download | go-oblast-01d2d52fd7dfb64c41f7c94808fe01665ffcb881.tar.gz | |
more test coverage, forbid non-zero auto columns during Insert()
Diffstat (limited to 'query.go')
| -rw-r--r-- | query.go | 18 |
1 files changed, 15 insertions, 3 deletions
@@ -75,6 +75,9 @@ func (s preparedStatement) QueryRow(args ...any) *sql.Row { // On success, returns the original set of records, updated thusly. // // Returns an error if [NewStore] was called without the [TableNameIs] option, which is required to generate a query for this method. +// +// Returns an error if any of the `records` has a non-zero value in any column marked as `db:",auto"`. +// Records that already exist in the database should be handled with [Store.Update] instead. func (s Store[R]) Insert(db Handle, records ...R) ([]R, error) { // NOTE: This function body should be as short as possible to reduce the binary size after monomorphization. // Any expression that does not depend on type R should be factored out into a reusable function. @@ -117,6 +120,11 @@ func insertRecordUsingLastInsertID(v reflect.Value, recordIndex int, stmt prepar for idx, index := range argumentIndexes { argumentSlots[idx] = v.FieldByIndex(index).Interface() } + scanField := v.FieldByIndex(scanIndex) + if !scanField.IsZero() { + return fmt.Errorf(`refusing to INSERT record with idx = %d that already has non-zero values in its "auto" columns`, recordIndex) + } + result, err := stmt.Exec(argumentSlots...) if err != nil { return fmt.Errorf("during Exec() for record with idx = %d: %w", recordIndex, err) @@ -126,12 +134,12 @@ func insertRecordUsingLastInsertID(v reflect.Value, recordIndex int, stmt prepar return fmt.Errorf("during LastInsertId() for record with idx = %d: %w", recordIndex, err) } if plan.FillIDWithSetInt { - v.FieldByIndex(scanIndex).SetInt(id) + scanField.SetInt(id) } else if plan.FillIDWithSetUint { if id < 0 { return fmt.Errorf("LastInsertId() = %d for record with idx = %d cannot be converted to uint", id, recordIndex) } - v.FieldByIndex(scanIndex).SetUint(uint64(id)) + scanField.SetUint(uint64(id)) } return nil } @@ -168,7 +176,11 @@ func insertRecordUsingReturningClause(v reflect.Value, recordIndex int, stmt pre argumentSlots[idx] = v.FieldByIndex(index).Interface() } for idx, index := range scanIndexes { - scanSlots[idx] = v.FieldByIndex(index).Addr().Interface() + f := v.FieldByIndex(index) + if !f.IsZero() { + return fmt.Errorf(`refusing to INSERT record with idx = %d that already has non-zero values in its "auto" columns`, recordIndex) + } + scanSlots[idx] = f.Addr().Interface() } err := stmt.QueryRow(argumentSlots...).Scan(scanSlots...) if err != nil { |
