diff --git a/go.mod b/go.mod index c0af26f6d..552641e17 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( gorm.io/datatypes v1.2.7 gorm.io/driver/mysql v1.6.0 gorm.io/driver/sqlite v1.6.0 - gorm.io/gorm v1.31.0 + gorm.io/gorm v1.31.1 ) replace github.com/mattn/go-sqlite3 => github.com/gabriel-samfira/go-sqlite3 v0.0.0-20251005121134-bc61ecf9b4c7 diff --git a/go.sum b/go.sum index be14d8f2c..1acdee8f8 100644 --- a/go.sum +++ b/go.sum @@ -276,5 +276,5 @@ gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc= gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw= -gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY= -gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= +gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= +gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/vendor/gorm.io/gorm/README.md b/vendor/gorm.io/gorm/README.md index 745dad60b..24eb84c9c 100644 --- a/vendor/gorm.io/gorm/README.md +++ b/vendor/gorm.io/gorm/README.md @@ -3,7 +3,7 @@ The fantastic ORM library for Golang, aims to be developer friendly. [![go report card](https://goreportcard.com/badge/github.com/go-gorm/gorm "go report card")](https://goreportcard.com/report/github.com/go-gorm/gorm) -[![test status](https://github.com/go-gorm/gorm/workflows/tests/badge.svg?branch=master "test status")](https://github.com/go-gorm/gorm/actions) +[![test status](https://github.com/go-gorm/gorm/actions/workflows/tests.yml/badge.svg)](https://github.com/go-gorm/gorm/actions) [![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) [![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-blue?logo=go&logoColor=white)](https://pkg.go.dev/gorm.io/gorm?tab=doc) diff --git a/vendor/gorm.io/gorm/association.go b/vendor/gorm.io/gorm/association.go index f210ca0a6..3a4e0e255 100644 --- a/vendor/gorm.io/gorm/association.go +++ b/vendor/gorm.io/gorm/association.go @@ -99,7 +99,7 @@ func (association *Association) Replace(values ...interface{}) error { return association.Error } - // set old associations's foreign key to null + // set old association's foreign key to null switch rel.Type { case schema.BelongsTo: if len(values) == 0 { @@ -304,7 +304,7 @@ func (association *Association) Delete(values ...interface{}) error { } if association.Error == nil { - // clean up deleted values's foreign key + // clean up deleted values' foreign key relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields) cleanUpDeletedRelations := func(data reflect.Value) { diff --git a/vendor/gorm.io/gorm/chainable_api.go b/vendor/gorm.io/gorm/chainable_api.go index 8a6aea343..8f6113cc1 100644 --- a/vendor/gorm.io/gorm/chainable_api.go +++ b/vendor/gorm.io/gorm/chainable_api.go @@ -178,7 +178,7 @@ func (db *DB) Omit(columns ...string) (tx *DB) { tx = db.getInstance() if len(columns) == 1 && strings.ContainsRune(columns[0], ',') { - tx.Statement.Omits = strings.FieldsFunc(columns[0], utils.IsValidDBNameChar) + tx.Statement.Omits = strings.FieldsFunc(columns[0], utils.IsInvalidDBNameChar) } else { tx.Statement.Omits = columns } @@ -283,7 +283,7 @@ func joins(db *DB, joinType clause.JoinType, query string, args ...interface{}) func (db *DB) Group(name string) (tx *DB) { tx = db.getInstance() - fields := strings.FieldsFunc(name, utils.IsValidDBNameChar) + fields := strings.FieldsFunc(name, utils.IsInvalidDBNameChar) tx.Statement.AddClause(clause.GroupBy{ Columns: []clause.Column{{Name: name, Raw: len(fields) != 1}}, }) diff --git a/vendor/gorm.io/gorm/finisher_api.go b/vendor/gorm.io/gorm/finisher_api.go index e601fe66a..e9e35f1bf 100644 --- a/vendor/gorm.io/gorm/finisher_api.go +++ b/vendor/gorm.io/gorm/finisher_api.go @@ -465,7 +465,7 @@ func (db *DB) Count(count *int64) (tx *DB) { if len(tx.Statement.Selects) == 1 { dbName := tx.Statement.Selects[0] - fields := strings.FieldsFunc(dbName, utils.IsValidDBNameChar) + fields := strings.FieldsFunc(dbName, utils.IsInvalidDBNameChar) if len(fields) == 1 || (len(fields) == 3 && (strings.ToUpper(fields[1]) == "AS" || fields[1] == ".")) { if tx.Statement.Parse(tx.Statement.Model) == nil { if f := tx.Statement.Schema.LookUpField(dbName); f != nil { @@ -564,7 +564,7 @@ func (db *DB) Pluck(column string, dest interface{}) (tx *DB) { } if len(tx.Statement.Selects) != 1 { - fields := strings.FieldsFunc(column, utils.IsValidDBNameChar) + fields := strings.FieldsFunc(column, utils.IsInvalidDBNameChar) tx.Statement.AddClauseIfNotExists(clause.Select{ Distinct: tx.Statement.Distinct, Columns: []clause.Column{{Name: column, Raw: len(fields) != 1}}, diff --git a/vendor/gorm.io/gorm/generics.go b/vendor/gorm.io/gorm/generics.go index 79238d5f6..166d1520d 100644 --- a/vendor/gorm.io/gorm/generics.go +++ b/vendor/gorm.io/gorm/generics.go @@ -39,7 +39,7 @@ type Interface[T any] interface { type CreateInterface[T any] interface { ExecInterface[T] - // chain methods available at start; return ChainInterface + // chain methods available at start; Select/Omit keep CreateInterface to allow Create chaining Scopes(scopes ...func(db *Statement)) ChainInterface[T] Where(query interface{}, args ...interface{}) ChainInterface[T] Not(query interface{}, args ...interface{}) ChainInterface[T] @@ -48,8 +48,8 @@ type CreateInterface[T any] interface { Offset(offset int) ChainInterface[T] Joins(query clause.JoinTarget, on func(db JoinBuilder, joinTable clause.Table, curTable clause.Table) error) ChainInterface[T] Preload(association string, query func(db PreloadBuilder) error) ChainInterface[T] - Select(query string, args ...interface{}) ChainInterface[T] - Omit(columns ...string) ChainInterface[T] + Select(query string, args ...interface{}) CreateInterface[T] + Omit(columns ...string) CreateInterface[T] MapColumns(m map[string]string) ChainInterface[T] Distinct(args ...interface{}) ChainInterface[T] Group(name string) ChainInterface[T] @@ -203,6 +203,18 @@ func (c createG[T]) Table(name string, args ...interface{}) CreateInterface[T] { })} } +func (c createG[T]) Select(query string, args ...interface{}) CreateInterface[T] { + return createG[T]{c.with(func(db *DB) *DB { + return db.Select(query, args...) + })} +} + +func (c createG[T]) Omit(columns ...string) CreateInterface[T] { + return createG[T]{c.with(func(db *DB) *DB { + return db.Omit(columns...) + })} +} + func (c createG[T]) Set(assignments ...clause.Assigner) SetCreateOrUpdateInterface[T] { return c.processSet(assignments...) } diff --git a/vendor/gorm.io/gorm/logger/slog.go b/vendor/gorm.io/gorm/logger/slog.go index 613234cac..27c746831 100644 --- a/vendor/gorm.io/gorm/logger/slog.go +++ b/vendor/gorm.io/gorm/logger/slog.go @@ -8,6 +8,8 @@ import ( "fmt" "log/slog" "time" + + "gorm.io/gorm/utils" ) type slogLogger struct { @@ -37,19 +39,19 @@ func (l *slogLogger) LogMode(level LogLevel) Interface { func (l *slogLogger) Info(ctx context.Context, msg string, data ...interface{}) { if l.LogLevel >= Info { - l.Logger.InfoContext(ctx, msg, slog.Any("data", data)) + l.log(ctx, slog.LevelInfo, msg, slog.Any("data", data)) } } func (l *slogLogger) Warn(ctx context.Context, msg string, data ...interface{}) { if l.LogLevel >= Warn { - l.Logger.WarnContext(ctx, msg, slog.Any("data", data)) + l.log(ctx, slog.LevelWarn, msg, slog.Any("data", data)) } } func (l *slogLogger) Error(ctx context.Context, msg string, data ...interface{}) { if l.LogLevel >= Error { - l.Logger.ErrorContext(ctx, msg, slog.Any("data", data)) + l.log(ctx, slog.LevelError, msg, slog.Any("data", data)) } } @@ -72,25 +74,39 @@ func (l *slogLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql switch { case err != nil && (!l.IgnoreRecordNotFoundError || !errors.Is(err, ErrRecordNotFound)): fields = append(fields, slog.String("error", err.Error())) - l.Logger.ErrorContext(ctx, "SQL executed", slog.Attr{ + l.log(ctx, slog.LevelError, "SQL executed", slog.Attr{ Key: "trace", Value: slog.GroupValue(fields...), }) case l.SlowThreshold != 0 && elapsed > l.SlowThreshold: - l.Logger.WarnContext(ctx, "SQL executed", slog.Attr{ + l.log(ctx, slog.LevelWarn, "SQL executed", slog.Attr{ Key: "trace", Value: slog.GroupValue(fields...), }) case l.LogLevel >= Info: - l.Logger.InfoContext(ctx, "SQL executed", slog.Attr{ + l.log(ctx, slog.LevelInfo, "SQL executed", slog.Attr{ Key: "trace", Value: slog.GroupValue(fields...), }) } } +func (l *slogLogger) log(ctx context.Context, level slog.Level, msg string, args ...any) { + if ctx == nil { + ctx = context.Background() + } + + if !l.Logger.Enabled(ctx, level) { + return + } + + r := slog.NewRecord(time.Now(), level, msg, utils.CallerFrame().PC) + r.Add(args...) + _ = l.Logger.Handler().Handle(ctx, r) +} + // ParamsFilter filter params func (l *slogLogger) ParamsFilter(ctx context.Context, sql string, params ...interface{}) (string, []interface{}) { if l.Parameterized { diff --git a/vendor/gorm.io/gorm/migrator/migrator.go b/vendor/gorm.io/gorm/migrator/migrator.go index 50a36d103..35107d572 100644 --- a/vendor/gorm.io/gorm/migrator/migrator.go +++ b/vendor/gorm.io/gorm/migrator/migrator.go @@ -560,6 +560,10 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy v1, _ := strconv.ParseBool(dv) v2, _ := strconv.ParseBool(field.DefaultValue) alterColumn = v1 != v2 + case schema.String: + if dv != field.DefaultValue && dv != strings.Trim(field.DefaultValue, "'\"") { + alterColumn = true + } default: alterColumn = dv != field.DefaultValue } diff --git a/vendor/gorm.io/gorm/schema/schema.go b/vendor/gorm.io/gorm/schema/schema.go index 9419846be..09697a7ab 100644 --- a/vendor/gorm.io/gorm/schema/schema.go +++ b/vendor/gorm.io/gorm/schema/schema.go @@ -82,6 +82,16 @@ func (schema *Schema) LookUpField(name string) *Field { if field, ok := schema.FieldsByName[name]; ok { return field } + + // Lookup field using namer-driven ColumnName + if schema.namer == nil { + return nil + } + namerColumnName := schema.namer.ColumnName(schema.Table, name) + if field, ok := schema.FieldsByDBName[namerColumnName]; ok { + return field + } + return nil } diff --git a/vendor/gorm.io/gorm/schema/serializer.go b/vendor/gorm.io/gorm/schema/serializer.go index 0fafbcba0..d774a8edd 100644 --- a/vendor/gorm.io/gorm/schema/serializer.go +++ b/vendor/gorm.io/gorm/schema/serializer.go @@ -8,6 +8,7 @@ import ( "encoding/gob" "encoding/json" "fmt" + "math" "reflect" "strings" "sync" @@ -127,16 +128,31 @@ func (UnixSecondSerializer) Scan(ctx context.Context, field *Field, dst reflect. // Value implements serializer interface func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (result interface{}, err error) { rv := reflect.ValueOf(fieldValue) - switch v := fieldValue.(type) { - case int64, int, uint, uint64, int32, uint32, int16, uint16: - result = time.Unix(reflect.Indirect(rv).Int(), 0).UTC() - case *int64, *int, *uint, *uint64, *int32, *uint32, *int16, *uint16: + switch fieldValue.(type) { + case int, int8, int16, int32, int64: + result = time.Unix(rv.Int(), 0).UTC() + case uint, uint8, uint16, uint32, uint64: + if uv := rv.Uint(); uv > math.MaxInt64 { + err = fmt.Errorf("integer overflow conversion uint64(%d) -> int64", uv) + } else { + result = time.Unix(int64(uv), 0).UTC() //nolint:gosec + } + case *int, *int8, *int16, *int32, *int64: if rv.IsZero() { return nil, nil } - result = time.Unix(reflect.Indirect(rv).Int(), 0).UTC() + result = time.Unix(rv.Elem().Int(), 0).UTC() + case *uint, *uint8, *uint16, *uint32, *uint64: + if rv.IsZero() { + return nil, nil + } + if uv := rv.Elem().Uint(); uv > math.MaxInt64 { + err = fmt.Errorf("integer overflow conversion uint64(%d) -> int64", uv) + } else { + result = time.Unix(int64(uv), 0).UTC() //nolint:gosec + } default: - err = fmt.Errorf("invalid field type %#v for UnixSecondSerializer, only int, uint supported", v) + err = fmt.Errorf("invalid field type %#v for UnixSecondSerializer, only int, uint supported", fieldValue) } return } diff --git a/vendor/gorm.io/gorm/schema/utils.go b/vendor/gorm.io/gorm/schema/utils.go index d4fe252e2..86305d7b3 100644 --- a/vendor/gorm.io/gorm/schema/utils.go +++ b/vendor/gorm.io/gorm/schema/utils.go @@ -17,25 +17,23 @@ func ParseTagSetting(str string, sep string) map[string]string { settings := map[string]string{} names := strings.Split(str, sep) + var parsedNames []string for i := 0; i < len(names); i++ { - j := i - if len(names[j]) > 0 { - for { - if names[j][len(names[j])-1] == '\\' { - i++ - names[j] = names[j][0:len(names[j])-1] + sep + names[i] - names[i] = "" - } else { - break - } - } + s := names[i] + for strings.HasSuffix(s, "\\") && i+1 < len(names) { + i++ + s = s[:len(s)-1] + sep + names[i] } + parsedNames = append(parsedNames, s) + } - values := strings.Split(names[j], ":") + for _, tag := range parsedNames { + values := strings.Split(tag, ":") k := strings.TrimSpace(strings.ToUpper(values[0])) - if len(values) >= 2 { - settings[k] = strings.Join(values[1:], ":") + val := strings.Join(values[1:], ":") + val = strings.ReplaceAll(val, `\"`, `"`) + settings[k] = val } else if k != "" { settings[k] = k } diff --git a/vendor/gorm.io/gorm/utils/utils.go b/vendor/gorm.io/gorm/utils/utils.go index fc615d73b..7e59264be 100644 --- a/vendor/gorm.io/gorm/utils/utils.go +++ b/vendor/gorm.io/gorm/utils/utils.go @@ -30,8 +30,12 @@ func sourceDir(file string) string { return filepath.ToSlash(s) + "/" } -// FileWithLineNum return the file name and line number of the current file -func FileWithLineNum() string { +// CallerFrame retrieves the first relevant stack frame outside of GORM's internal implementation files. +// It skips: +// - GORM's core source files (identified by gormSourceDir prefix) +// - Exclude test files (*_test.go) +// - go-gorm/gen's Generated files (*.gen.go) +func CallerFrame() runtime.Frame { pcs := [13]uintptr{} // the third caller usually from gorm internal len := runtime.Callers(3, pcs[:]) @@ -41,14 +45,24 @@ func FileWithLineNum() string { frame, _ := frames.Next() if (!strings.HasPrefix(frame.File, gormSourceDir) || strings.HasSuffix(frame.File, "_test.go")) && !strings.HasSuffix(frame.File, ".gen.go") { - return string(strconv.AppendInt(append([]byte(frame.File), ':'), int64(frame.Line), 10)) + return frame } } + return runtime.Frame{} +} + +// FileWithLineNum return the file name and line number of the current file +func FileWithLineNum() string { + frame := CallerFrame() + if frame.PC != 0 { + return string(strconv.AppendInt(append([]byte(frame.File), ':'), int64(frame.Line), 10)) + } + return "" } -func IsValidDBNameChar(c rune) bool { +func IsInvalidDBNameChar(c rune) bool { return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '*' && c != '_' && c != '$' && c != '@' } diff --git a/vendor/modules.txt b/vendor/modules.txt index 9f6e3b1d5..4a86fa06f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -443,7 +443,7 @@ gorm.io/driver/mysql # gorm.io/driver/sqlite v1.6.0 ## explicit; go 1.20 gorm.io/driver/sqlite -# gorm.io/gorm v1.31.0 +# gorm.io/gorm v1.31.1 ## explicit; go 1.18 gorm.io/gorm gorm.io/gorm/callbacks