Skip to content

Fix generics model pointer usage and add query APIs#7730

Open
MarlinKuhn wants to merge 14 commits intogo-gorm:masterfrom
MarlinKuhn:master
Open

Fix generics model pointer usage and add query APIs#7730
MarlinKuhn wants to merge 14 commits intogo-gorm:masterfrom
MarlinKuhn:master

Conversation

@MarlinKuhn
Copy link

  • Do only one thing
  • Non breaking API changes
  • Tested

What did this pull request do?

Fixes #7713

User Case Description

If you use generics and want to use the Set to update values on a model with hooks it fails currently.

@propel-code-bot
Copy link
Contributor

propel-code-bot bot commented Mar 12, 2026

Fix generics model pointer usage and add query APIs

This PR updates the generics query helpers to use pointer models (new(T)) for update, set, create, and association operations, aligning with hook behavior expectations. It also expands the generics query surface by adding Clauses, Unscoped, Join, and Pluck support across interfaces and builders, and introduces a schema.TableName helper plus model-based join table resolution.

Key Changes

• Switches generics model usage to pointers (e.g., new(T)) in Update, Set operations, and association handling in generics.go
• Adds new API methods (Clauses, Unscoped, Join, Pluck) to CreateInterface, ChainInterface, ExecInterface, and PreloadBuilder in generics.go
• Implements model-based join table name resolution using schema.TableName and extends clause.JoinTarget with Model support
• Adjusts Count to avoid unnecessary Select for * and updates Scan to use Model(r).Scan

Affected Areas

generics.go
schema/schema.go
clause/joins.go

This summary was automatically generated by @propel-code-bot

@propel-code-bot propel-code-bot bot changed the title Generics: Fix Hooks not working on update/create Fix generics hooks for update/create and add Join Mar 13, 2026
propel-code-bot[bot]

This comment was marked as outdated.

@propel-code-bot propel-code-bot bot changed the title Fix generics hooks for update/create and add Join Fix generics model handling for updates and add Join Mar 13, 2026
Copy link
Contributor

@propel-code-bot propel-code-bot bot left a comment

Choose a reason for hiding this comment

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

Join handling may drop subqueries, requiring adjustment for correctness.

Status: Changes Suggested | Risk: Medium

Issues Identified & Suggestions
  • Handle subquery joins in Join to avoid silent drops: generics.go
Review Details

📁 1 files reviewed | 💬 1 comments

👍 / 👎 individual comments to help improve reviews for you

}
}

join := clause.Join{
Copy link
Contributor

Choose a reason for hiding this comment

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

Important

[Logic] Join ignores jt.Subquery. If callers use JoinTarget.AssociationFrom or populate Subquery, this will silently drop the subquery and join on jt.Association as a table name. Is that intentional? If subquery joins should work here, add handling similar to Joins (building join.Expression with a NamedExpr over jt.Subquery).

Context for Agents
`Join` ignores `jt.Subquery`. If callers use `JoinTarget.AssociationFrom` or populate `Subquery`, this will silently drop the subquery and join on `jt.Association` as a table name. Is that intentional? If subquery joins should work here, add handling similar to `Joins` (building `join.Expression` with a `NamedExpr` over `jt.Subquery`).

File: generics.go
Line: 452

propel-code-bot[bot]

This comment was marked as outdated.

@propel-code-bot propel-code-bot bot changed the title Fix generics model handling for updates and add Join Fix generics model pointers for updates and add Join method Mar 16, 2026
@propel-code-bot propel-code-bot bot changed the title Fix generics model pointers for updates and add Join method Fix generics model pointers in updates and add join/clauses APIs Mar 16, 2026
propel-code-bot[bot]

This comment was marked as outdated.

propel-code-bot[bot]

This comment was marked as outdated.

@propel-code-bot propel-code-bot bot changed the title Fix generics model pointers in updates and add join/clauses APIs Fix generics model pointer usage and add query APIs Mar 18, 2026
propel-code-bot[bot]

This comment was marked as outdated.

Copy link
Contributor

@propel-code-bot propel-code-bot bot left a comment

Choose a reason for hiding this comment

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

Review found a critical logic bug where unscoped behavior isn’t applied in new preload helper.

Status: Action Required | Risk: High

Issues Identified & Suggestions
  • Unscoped ignores returned DB; assign to apply unscoped query: generics.go
Review Details

📁 1 files reviewed | 💬 1 comments

👍 / 👎 individual comments to help improve reviews for you

}

func (q *preloadBuilder) Unscoped() PreloadBuilder {
q.db.Unscoped()
Copy link
Contributor

Choose a reason for hiding this comment

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

Critical

[Logic] The new PreloadBuilder.Unscoped() doesn't actually apply unscoped behavior. db.Unscoped() returns a new *DB instance, but the result is ignored here, so the preload query remains scoped.

Fix: assign the returned *DB back to q.db.

Suggested change
q.db.Unscoped()
q.db = q.db.Unscoped()
Context for Agents
The new `PreloadBuilder.Unscoped()` doesn't actually apply unscoped behavior. `db.Unscoped()` returns a new *DB instance, but the result is ignored here, so the preload query remains scoped.

Fix: assign the returned *DB back to `q.db`.
```suggestion
	q.db = q.db.Unscoped()
```

File: generics.go
Line: 373

Copy link
Contributor

@propel-code-bot propel-code-bot bot left a comment

Choose a reason for hiding this comment

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

One logic concern: switching to UpdateColumns bypasses update hooks and callbacks.

Status: Changes Suggested | Risk: Medium

Issues Identified & Suggestions
  • UpdateColumns skips update hooks; use Updates to keep callbacks: generics.go
Review Details

📁 1 files reviewed | 💬 1 comments

👍 / 👎 individual comments to help improve reviews for you

var r T
res := s.c.g.apply(ctx).Model(r).Clauses(clause.Set(s.assigns)).Updates(map[string]interface{}{})
r := new(T)
res := s.c.g.apply(ctx).Model(r).Clauses(clause.Set(s.assigns)).UpdateColumns(map[string]interface{}{})
Copy link
Contributor

Choose a reason for hiding this comment

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

Important

[Logic] UpdateColumns skips update hooks and Before/AfterUpdate callbacks. The prior Updates(...) path would run hooks, and the PR intent mentions fixing Set with hooks. With this change, Set(...).Update() will not trigger hooks anymore.

If hooks should still run, switch back to Updates so callbacks execute.

Suggested change
res := s.c.g.apply(ctx).Model(r).Clauses(clause.Set(s.assigns)).UpdateColumns(map[string]interface{}{})
res := s.c.g.apply(ctx).Model(r).Clauses(clause.Set(s.assigns)).Updates(map[string]interface{}{})
Context for Agents
`UpdateColumns` skips update hooks and `Before/AfterUpdate` callbacks. The prior `Updates(...)` path would run hooks, and the PR intent mentions fixing `Set` with hooks. With this change, `Set(...).Update()` will not trigger hooks anymore.

If hooks should still run, switch back to `Updates` so callbacks execute.
```suggestion
		res := s.c.g.apply(ctx).Model(r).Clauses(clause.Set(s.assigns)).Updates(map[string]interface{}{})
```

File: generics.go
Line: 800

propel-code-bot[bot]

This comment was marked as outdated.

Copy link
Contributor

@propel-code-bot propel-code-bot bot left a comment

Choose a reason for hiding this comment

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

One important logic issue found regarding join association assignment on error.

Status: Changes Suggested | Risk: Medium

Issues Identified & Suggestions
  • Avoid overwriting association on table-name error; return early: generics.go
Review Details

📁 3 files reviewed | 💬 1 comments

👍 / 👎 individual comments to help improve reviews for you

Comment on lines +490 to +497
if jt.Model != nil {
tableName, err := schema.TableName(jt.Model, db.cacheStore, db.NamingStrategy)
if err != nil {
db.AddError(errors.New("failed to get table name from model"))
}

jt.Association = tableName
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Important

[Logic] If schema.TableName returns an error, this still overwrites jt.Association with an empty string, which then produces a join on an empty table name (and discards any association the caller may have set). This will generate invalid SQL while only recording the error. Return early or only set jt.Association on success.

Suggested change
if jt.Model != nil {
tableName, err := schema.TableName(jt.Model, db.cacheStore, db.NamingStrategy)
if err != nil {
db.AddError(errors.New("failed to get table name from model"))
}
jt.Association = tableName
}
if jt.Model != nil {
tableName, err := schema.TableName(jt.Model, db.cacheStore, db.NamingStrategy)
if err != nil {
db.AddError(errors.New("failed to get table name from model"))
return db
}
jt.Association = tableName
}
Context for Agents
If `schema.TableName` returns an error, this still overwrites `jt.Association` with an empty string, which then produces a join on an empty table name (and discards any association the caller may have set). This will generate invalid SQL while only recording the error. Return early or only set `jt.Association` on success.

```suggestion
		if jt.Model != nil {
			tableName, err := schema.TableName(jt.Model, db.cacheStore, db.NamingStrategy)
			if err != nil {
				db.AddError(errors.New("failed to get table name from model"))
				return db
			}

			jt.Association = tableName
		}
```

File: generics.go
Line: 497

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.

Generics API: Updates ( ctx, t ) and Hook cannot be used together

1 participant