aboutsummaryrefslogtreecommitdiff
path: root/query.go
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2026-04-18 15:44:46 +0200
committerStefan Majewsky <majewsky@gmx.net>2026-04-18 15:45:42 +0200
commit01d2d52fd7dfb64c41f7c94808fe01665ffcb881 (patch)
treecd17477850ee1d34d11b681ef3f10a24b49c04f6 /query.go
parentcfdb06f5ba144aad5d2ebe31ec8bb64e017f4023 (diff)
downloadgo-oblast-01d2d52fd7dfb64c41f7c94808fe01665ffcb881.tar.gz
more test coverage, forbid non-zero auto columns during Insert()
Diffstat (limited to 'query.go')
-rw-r--r--query.go18
1 files changed, 15 insertions, 3 deletions
diff --git a/query.go b/query.go
index 2ed113a..04ba647 100644
--- a/query.go
+++ b/query.go
@@ -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 {