Skip to content

fix(contrib/drivers/sqlite): infer save conflict from primary keys#4766

Open
gqcn wants to merge 1 commit into
masterfrom
fix/sqlite-save-primary-conflict
Open

fix(contrib/drivers/sqlite): infer save conflict from primary keys#4766
gqcn wants to merge 1 commit into
masterfrom
fix/sqlite-save-primary-conflict

Conversation

@gqcn
Copy link
Copy Markdown
Member

@gqcn gqcn commented May 8, 2026

This pull request improves the upsert (Save) behavior for both SQLite and SQLiteCGO drivers by allowing them to automatically infer primary key columns as conflict targets when OnConflict is not explicitly specified. This brings their behavior in line with other upsert-capable drivers, enhancing usability and reducing the need for manual configuration. The implementation includes new logic in the drivers, updated tests to verify the new behavior, and documentation/spec updates.

SQLite/SQLiteCGO Driver Improvements:

  • Both sqlite and sqlitecgo drivers now automatically detect and use table primary keys as conflict columns for Save operations if OnConflict is not provided, and return a clear error if no usable primary key is present in the data. [1] [2]

Testing Enhancements:

  • Unit tests for both drivers are updated to verify that Save works as expected when primary keys are present, updates existing rows, and returns an error if required primary keys are missing. [1] [2]

Specification and Documentation:

  • Added a specification describing the new upsert conflict inference behavior for SQLite/SQLiteCGO drivers, including scenarios for success and error cases.
  • Provided a design document explaining the approach and rationale for the change.
  • Added a proposal summarizing the motivation and expected alignment with other drivers.
  • Marked the feedback task for this feature as complete.
  • Registered the change in the OpenSpec changelog.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR updates the SQLite and SQLiteCGO drivers’ Save (upsert) behavior to infer conflict targets from table primary keys when OnConflict(...) is omitted, aligning behavior with other upsert-capable drivers.

Changes:

  • Add driver-specific DoInsert overrides for SQLite/SQLiteCGO to infer OnConflict from primary keys for InsertOptionSave.
  • Update unit tests for SQLite/SQLiteCGO Save to assert successful insert+update behavior and error on missing primary key data.
  • Add OpenSpec proposal/design/spec/task/changelog artifacts documenting the new behavior.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
openspec/changes/sqlite-save-primary-conflict/tasks.md Marks the feedback task as completed for the new behavior.
openspec/changes/sqlite-save-primary-conflict/specs/sqlite-upsert/spec.md Specifies required upsert-conflict inference behavior and error cases.
openspec/changes/sqlite-save-primary-conflict/proposal.md Summarizes motivation and desired alignment with other drivers.
openspec/changes/sqlite-save-primary-conflict/design.md Describes the implementation approach at a high level.
openspec/changes/sqlite-save-primary-conflict/.openspec.yaml Adds OpenSpec metadata for the change.
contrib/drivers/sqlitecgo/sqlitecgo_z_unit_core_test.go Updates SQLiteCGO Save unit test expectations for inferred conflicts.
contrib/drivers/sqlitecgo/sqlitecgo_do_insert.go Adds DoInsert override to infer conflict columns from PKs for Save.
contrib/drivers/sqlite/sqlite_z_unit_core_test.go Updates SQLite Save unit test expectations for inferred conflicts.
contrib/drivers/sqlite/sqlite_do_insert.go Adds DoInsert override to infer conflict columns from PKs for Save.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +48 to +58
func saveDataHasPrimaryKeys(list gdb.List, primaryKeys []string) bool {
if len(list) == 0 || len(primaryKeys) == 0 {
return false
}
for _, primaryKey := range primaryKeys {
if !saveDataHasKey(list[0], primaryKey) {
return false
}
}
return true
}
Comment on lines +48 to +58
func saveDataHasPrimaryKeys(list gdb.List, primaryKeys []string) bool {
if len(list) == 0 || len(primaryKeys) == 0 {
return false
}
for _, primaryKey := range primaryKeys {
if !saveDataHasKey(list[0], primaryKey) {
return false
}
}
return true
}
Comment on lines +47 to +68
// saveDataHasPrimaryKeys reports whether the first save record contains all primary keys.
func saveDataHasPrimaryKeys(list gdb.List, primaryKeys []string) bool {
if len(list) == 0 || len(primaryKeys) == 0 {
return false
}
for _, primaryKey := range primaryKeys {
if !saveDataHasKey(list[0], primaryKey) {
return false
}
}
return true
}

// saveDataHasKey reports whether the save data contains the given key case-insensitively.
func saveDataHasKey(data gdb.Map, key string) bool {
for dataKey := range data {
if strings.EqualFold(dataKey, key) {
return true
}
}
return false
}
return nil, gerror.NewCodef(
gcode.CodeMissingParameter,
`Save operation requires conflict detection: `+
`either specify OnConflict() columns or ensure table '%s' has primary keys in the data`,
Comment on lines +446 to +453
t.Assert(rowsAffected, 1)

data["nickname"] = "T10-updated"
result, err = db.Save(ctx, "t_user", data, 10)
t.AssertNil(err)
rowsAffected, err = result.RowsAffected()
t.AssertNil(err)
t.Assert(rowsAffected, 1)
Comment on lines +446 to +453
t.Assert(rowsAffected, 1)

data["nickname"] = "T10-updated"
result, err = db.Save(ctx, "t_user", data, 10)
t.AssertNil(err)
rowsAffected, err = result.RowsAffected()
t.AssertNil(err)
t.Assert(rowsAffected, 1)
Comment on lines +442 to +443
result, err := db.Save(ctx, "t_user", data, 10)
t.AssertNil(err)
@LanceAdd
Copy link
Copy Markdown
Member

LanceAdd commented May 8, 2026

我看改动以后sqlite如果遇到复合主键必须所有字段都存在,但是在pgsql或者dm中的逻辑是复合主键只要遇到其中有一个就行了,几个TODO consider composite primary keys的todo注释也证明了这一点,是否需要让其他pgsql/dm/oracle遇到复合主键也走严格检查?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants