Conversation
a631807682
left a comment
There was a problem hiding this comment.
It may be necessary to add unit tests for nested join/preload.
For generics API, how should we reuse it? (Similar to the original Session)
There are two ways to reuse db:
Do you have any suggestions? |
There was a problem hiding this comment.
Pull Request Overview
This PR implements a type-safe, generic API layer on top of GORM to enable generic CRUD and query operations. Key changes include:
- Removal of DB.Debug() calls in tests to simplify logging.
- Upgrades of dependency versions in tests/go.mod.
- Significant refactoring in core files (e.g. statement.go, callbacks/*) to support generic interfaces and result handling.
Reviewed Changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/joins_test.go | Removed Debug() calls from Preload chains in join tests. |
| tests/go.mod | Upgraded GORM and related dependency versions. |
| tests/connpool_test.go | Assigned Logger to db immediately after connection open. |
| statement.go | Refactored GetInstance logic and BuildCondition to properly use table context and result propagation. |
| clause/joins.go | Added helper functions for join target creation and aliasing. |
| callbacks/* | Updated CRUD and query callbacks to set and propagate Result fields. |
| chainable_api.go | Added documentation for Unscoped usage. |
| db.Logger = DB.Logger | ||
| if err != nil { | ||
| t.Fatalf("Should open db success, but got %v", err) | ||
| } |
There was a problem hiding this comment.
Assigning the Logger immediately after opening the DB may lead to a nil pointer if an error occurs. Consider checking the error before setting db.Logger.
| db.Logger = DB.Logger | |
| if err != nil { | |
| t.Fatalf("Should open db success, but got %v", err) | |
| } | |
| if err != nil { | |
| t.Fatalf("Should open db success, but got %v", err) | |
| } | |
| db.Logger = DB.Logger |
| case *DB: | ||
| subdb := v.Session(&Session{Logger: logger.Discard, DryRun: true}).getInstance() | ||
| if v.Statement.SQL.Len() > 0 { | ||
| case interface{ getInstance() *DB }: |
There was a problem hiding this comment.
[nitpick] Consider defining and using a named interface for types that provide the getInstance() method to enhance readability and maintainability.
| case interface{ getInstance() *DB }: | |
| case InstanceProvider: |
II think the generics API is simple enough without polluting the db. |
|
I am currently adopting to the generics branch and noticed that there is no .ToSQL() method. Would be nice to see that added as well, to basicly stay method compatible with the old api. |
@NeariX67 you can write it like this https://github.com/go-gorm/gorm/blob/generics/tests/generics_test.go#L842-L847 |
|
@jinzhu Are you going to implement |
We are not planning to implement those methods. Also, for With the generics API, our goal is to take a more restrained approach to API design to help avoid potential misuse. |
|
@jinzhu A small bug that prevents the correct execution of Updates(ctx context.Context, t T) (rowsAffected int, err error)should be a pointer like so; Updates(ctx context.Context, t *T) (rowsAffected int, err error)This doesn't show up as a mistake because the internal |
|
Noticed that as well. With some objects it will work fine, but some require a pointer and it will throw an error. I have not yet figured out what caused this. gorm.G[*User](DB).Updates(ctx, &user) |
|
Transaction would logically also be a feature for Generics? So that the |
What issue might occur if a pointer is not passed in? |
Transactions are used like this: https://github.com/go-gorm/gorm/blob/master/tests/generics_test.go#L813-L819 or db.Transaction(func(tx *DB) error {
users, err gorm.G[User](tx).Find(ctx)
return err
}) |
The error that the library throws is explicitly that it expects to receive func (s *Store) Upsert(data *model.User, userID uint) error {
ctx := context.WithValue(context.Background(), model.UserIDKey, userID)
if data.ID == 0 {
return errors.Trace(s.creatorDB.Create(ctx, data))
}
rowsAffected, err := s.updaterDB.Updates(ctx, data)
if err != nil {
return errors.Trace(err)
}
if rowsAffected == 0 {
return errors.Trace(ErrUpsertDidntModifyData)
}
return nil
}If I call |
|
Also the if err := s.osDeleterDB.WithContext(ctx).Model(&data).Association("GameGameOSs").
Delete(operatingSystem); err != nil {
return errors.Trace(err)
} |
Can you write a playground PR that reproduce the issue? https://github.com/go-gorm/playground/pulls Seems it works for this test case https://github.com/go-gorm/gorm/blob/master/tests/generics_test.go#L144 |
Yes, it’s not included yet—I’m still considering if there’s a better way to handle associations. |
* Implement Generics API * Add more generics tests * Add more tests and Take method * use delayed‑ops pipeline for generics API * fix generics tests for mysql * Support SubQuery for Generics * Add clause.JoinTable helper method * Fix golangci-lint error * Complete the design and implementation of generic version Join * improve generics version Joins support * allow configuring select/omit columns for joins via subqueries * finish generic version Preload * handle error of generics Joins/Preload * fix tests * Add LimitPerRecord for generic version Preload * fix tests for mysql 5.7 * test for nested generic version Join/Preload * Add WithResult support for generics API * test reuse generics db conditions * fix data race * remove ExampleLRU test * Add default transaction timeout support * fix test
feat(gorm): add generic CRUD & query interfaces
This commit introduces a type-safe, generic API layer on top of GORM that
allows you to perform Create, Read, Update, Delete and raw SQL operations
Helper constructor:
Basic usage: