[chore] bump bun library versions (#2837)

This commit is contained in:
kim 2024-04-15 11:01:20 +01:00 committed by GitHub
parent 6bb43f3f9b
commit 1018cde107
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 403 additions and 388 deletions

10
go.mod
View file

@ -56,10 +56,10 @@ require (
github.com/technologize/otel-go-contrib v1.1.1
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/ulule/limiter/v3 v3.11.2
github.com/uptrace/bun v1.1.17
github.com/uptrace/bun/dialect/pgdialect v1.1.17
github.com/uptrace/bun/dialect/sqlitedialect v1.1.17
github.com/uptrace/bun/extra/bunotel v1.1.17
github.com/uptrace/bun v1.2.1
github.com/uptrace/bun/dialect/pgdialect v1.2.1
github.com/uptrace/bun/dialect/sqlitedialect v1.2.1
github.com/uptrace/bun/extra/bunotel v1.2.1
github.com/wagslane/go-password-validator v0.3.0
github.com/yuin/goldmark v1.7.1
go.opentelemetry.io/otel v1.25.0
@ -201,7 +201,7 @@ require (
github.com/toqueteos/webbrowser v1.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3 // indirect
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect

20
go.sum
View file

@ -667,16 +667,16 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA=
github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI=
github.com/uptrace/bun v1.1.17 h1:qxBaEIo0hC/8O3O6GrMDKxqyT+mw5/s0Pn/n6xjyGIk=
github.com/uptrace/bun v1.1.17/go.mod h1:hATAzivtTIRsSJR4B8AXR+uABqnQxr3myKDKEf5iQ9U=
github.com/uptrace/bun/dialect/pgdialect v1.1.17 h1:NsvFVHAx1Az6ytlAD/B6ty3cVE6j9Yp82bjqd9R9hOs=
github.com/uptrace/bun/dialect/pgdialect v1.1.17/go.mod h1:fLBDclNc7nKsZLzNjFL6BqSdgJzbj2HdnyOnLoDvAME=
github.com/uptrace/bun/dialect/sqlitedialect v1.1.17 h1:i8NFU9r8YuavNFaYlNqi4ppn+MgoHtqLgpWQDrVTjm0=
github.com/uptrace/bun/dialect/sqlitedialect v1.1.17/go.mod h1:YF0FO4VVnY9GHNH6rM4r3STlVEBxkOc6L88Bm5X5mzA=
github.com/uptrace/bun/extra/bunotel v1.1.17 h1:RLEJdHH06RI9BLg06Vu1JHJ3KNHQCfwa2Fa3x+56qkk=
github.com/uptrace/bun/extra/bunotel v1.1.17/go.mod h1:xV7AYrCFji4Sio6N9X+Cz+XJ+JuHq6TQQjuxaVbsypk=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3 h1:LNi0Qa7869/loPjz2kmMvp/jwZZnMZ9scMJKhDJ1DIo=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3/go.mod h1:jyigonKik3C5V895QNiAGpKYKEvFuqjw9qAEZks1mUg=
github.com/uptrace/bun v1.2.1 h1:2ENAcfeCfaY5+2e7z5pXrzFKy3vS8VXvkCag6N2Yzfk=
github.com/uptrace/bun v1.2.1/go.mod h1:cNg+pWBUMmJ8rHnETgf65CEvn3aIKErrwOD6IA8e+Ec=
github.com/uptrace/bun/dialect/pgdialect v1.2.1 h1:ceP99r03u+s8ylaDE/RzgcajwGiC76Jz3nS2ZgyPQ4M=
github.com/uptrace/bun/dialect/pgdialect v1.2.1/go.mod h1:mv6B12cisvSc6bwKm9q9wcrr26awkZK8QXM+nso9n2U=
github.com/uptrace/bun/dialect/sqlitedialect v1.2.1 h1:IprvkIKUjEjvt4VKpcmLpbMIucjrsmUPJOSlg19+a0Q=
github.com/uptrace/bun/dialect/sqlitedialect v1.2.1/go.mod h1:mMQf4NUpgY8bnOanxGmxNiHCdALOggS4cZ3v63a9D/o=
github.com/uptrace/bun/extra/bunotel v1.2.1 h1:5oTy3Jh7Q1bhCd5vnPszBmJgYouw+PuuZ8iSCm+uNCQ=
github.com/uptrace/bun/extra/bunotel v1.2.1/go.mod h1:SWW3HyjiXPYM36q0QSpdtTP8v21nWHnTCxu4lYkpO90=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4 h1:x3omFAG2XkvWFg1hvXRinY2ExAL1Aacl7W9ZlYjo6gc=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4/go.mod h1:qMKJr5fTnY0p7hqCQMNrAk62bCARWR5rAbTrGUFRuh4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE=

View file

@ -1,3 +1,25 @@
## [1.2.1](https://github.com/uptrace/bun/compare/v1.2.0...v1.2.1) (2024-04-02)
# [1.2.0](https://github.com/uptrace/bun/compare/v1.1.17...v1.2.0) (2024-04-02)
### Bug Fixes
* embedding of scanonly fields ([ed6ed74](https://github.com/uptrace/bun/commit/ed6ed74d5379ea6badb09cc37709211a51f5792b))
* **table:** allow alt annotation ([#956](https://github.com/uptrace/bun/issues/956)) ([8a0397b](https://github.com/uptrace/bun/commit/8a0397b6e2219909d6b00d258eb7934170058edd))
* transactional migration file extension ([#959](https://github.com/uptrace/bun/issues/959)) ([921b15b](https://github.com/uptrace/bun/commit/921b15b80110d28251a9210c77397d29924ffbc5))
### Features
* Allow overiding of Warn and Deprecated loggers ([#952](https://github.com/uptrace/bun/issues/952)) ([0e9d737](https://github.com/uptrace/bun/commit/0e9d737e4ca2deb86930237ee32a39cf3f7e8157))
* enable SNI ([#953](https://github.com/uptrace/bun/issues/953)) ([4071ffb](https://github.com/uptrace/bun/commit/4071ffb5bcb1b233cda239c92504d8139dcf1d2f))
* **idb:** add NewMerge method to IDB ([#966](https://github.com/uptrace/bun/issues/966)) ([664e2f1](https://github.com/uptrace/bun/commit/664e2f154f1153d2a80cd062a5074f1692edaee7))
## [1.1.17](https://github.com/uptrace/bun/compare/v1.1.16...v1.1.17) (2024-01-11)

View file

@ -15,7 +15,7 @@ go_mod_tidy:
echo "go mod tidy in $${dir}"; \
(cd "$${dir}" && \
go get -u ./... && \
go mod tidy -go=1.19); \
go mod tidy -go=1.21); \
done
fmt:

View file

@ -20,11 +20,6 @@
BeforeScanRowHook = schema.BeforeScanRowHook
AfterScanRowHook = schema.AfterScanRowHook
// DEPRECATED. Use BeforeScanRowHook instead.
BeforeScanHook = schema.BeforeScanHook
// DEPRECATED. Use AfterScanRowHook instead.
AfterScanHook = schema.AfterScanHook
)
type BeforeSelectHook interface {
@ -77,7 +72,7 @@ type AfterDropTableHook interface {
// SetLogger overwriters default Bun logger.
func SetLogger(logger internal.Logging) {
internal.Logger = logger
internal.SetLogger(logger)
}
func In(slice interface{}) schema.QueryAppender {

View file

@ -2,5 +2,5 @@
// Version is the current release version.
func Version() string {
return "1.1.17"
return "1.2.1"
}

View file

@ -2,5 +2,5 @@
// Version is the current release version.
func Version() string {
return "1.1.17"
return "1.2.1"
}

View file

@ -6,14 +6,26 @@
"os"
)
var Warn = log.New(os.Stderr, "WARN: bun: ", log.LstdFlags)
var Deprecated = log.New(os.Stderr, "DEPRECATED: bun: ", log.LstdFlags)
type Logging interface {
Printf(format string, v ...interface{})
}
var defaultLogger = log.New(os.Stderr, "", log.LstdFlags)
var Logger Logging = &logger{
log: defaultLogger,
}
var Warn = &wrapper{
prefix: "WARN: bun: ",
logger: Logger,
}
var Deprecated = &wrapper{
prefix: "DEPRECATED: bun: ",
logger: Logger,
}
type logger struct {
log *log.Logger
}
@ -22,6 +34,21 @@ func (l *logger) Printf(format string, v ...interface{}) {
_ = l.log.Output(2, fmt.Sprintf(format, v...))
}
var Logger Logging = &logger{
log: log.New(os.Stderr, "bun: ", log.LstdFlags|log.Lshortfile),
type wrapper struct {
prefix string
logger Logging
}
func (w *wrapper) Printf(format string, v ...interface{}) {
w.logger.Printf(w.prefix+format, v...)
}
func SetLogger(newLogger Logging) {
if newLogger == nil {
Logger = &logger{log: defaultLogger}
} else {
Logger = newLogger
}
Warn.logger = Logger
Deprecated.logger = Logger
}

View file

@ -274,12 +274,12 @@ func (m *Migrator) CreateTxSQLMigrations(ctx context.Context, name string) ([]*M
return nil, err
}
up, err := m.createSQL(ctx, name+".up.tx.sql", true)
up, err := m.createSQL(ctx, name+".tx.up.sql", true)
if err != nil {
return nil, err
}
down, err := m.createSQL(ctx, name+".down.tx.sql", true)
down, err := m.createSQL(ctx, name+".tx.down.sql", true)
if err != nil {
return nil, err
}

View file

@ -83,9 +83,9 @@ func (m *hasManyModel) Scan(src interface{}) error {
column := m.columns[m.scanIndex]
m.scanIndex++
field, err := m.table.Field(column)
if err != nil {
return err
field := m.table.LookupField(column)
if field == nil {
return fmt.Errorf("bun: %s does not have column %q", m.table.TypeName, column)
}
if err := field.ScanValue(m.strct, src); err != nil {

View file

@ -116,9 +116,6 @@ func (m *structTableModel) BeforeScanRow(ctx context.Context) error {
if m.table.HasBeforeScanRowHook() {
return m.strct.Addr().Interface().(schema.BeforeScanRowHook).BeforeScanRow(ctx)
}
if m.table.HasBeforeScanHook() {
return m.strct.Addr().Interface().(schema.BeforeScanHook).BeforeScan(ctx)
}
return nil
}
@ -144,21 +141,6 @@ func (m *structTableModel) AfterScanRow(ctx context.Context) error {
return firstErr
}
if m.table.HasAfterScanHook() {
firstErr := m.strct.Addr().Interface().(schema.AfterScanHook).AfterScan(ctx)
for _, j := range m.joins {
switch j.Relation.Type {
case schema.HasOneRelation, schema.BelongsToRelation:
if err := j.JoinModel.AfterScanRow(ctx); err != nil && firstErr == nil {
firstErr = err
}
}
}
return firstErr
}
return nil
}
@ -325,7 +307,7 @@ func (m *structTableModel) scanColumn(column string, src interface{}) (bool, err
}
}
if field, ok := m.table.FieldMap[column]; ok {
if field := m.table.LookupField(column); field != nil {
if src == nil && m.isNil() {
return true, nil
}

View file

@ -1,6 +1,6 @@
{
"name": "gobun",
"version": "1.1.17",
"version": "1.2.1",
"main": "index.js",
"repository": "git@github.com:uptrace/bun.git",
"author": "Vladimir Mihailenco <vladimir.webdev@gmail.com>",

View file

@ -51,6 +51,7 @@ type IDB interface {
NewInsert() *InsertQuery
NewUpdate() *UpdateQuery
NewDelete() *DeleteQuery
NewMerge() *MergeQuery
NewRaw(query string, args ...interface{}) *RawQuery
NewCreateTable() *CreateTableQuery
NewDropTable() *DropTableQuery

View file

@ -262,7 +262,9 @@ func (j *relationJoin) appendBaseAlias(fmter schema.Formatter, b []byte) []byte
return append(b, j.BaseModel.Table().SQLAlias...)
}
func (j *relationJoin) appendSoftDelete(fmter schema.Formatter, b []byte, flags internal.Flag) []byte {
func (j *relationJoin) appendSoftDelete(
fmter schema.Formatter, b []byte, flags internal.Flag,
) []byte {
b = append(b, '.')
field := j.JoinModel.Table().SoftDeleteField

View file

@ -44,6 +44,15 @@ func (f *Field) String() string {
return f.Name
}
func (f *Field) WithIndex(path []int) *Field {
if len(path) == 0 {
return f
}
clone := *f
clone.Index = makeIndex(path, f.Index)
return &clone
}
func (f *Field) Clone() *Field {
cp := *f
cp.Index = cp.Index[:len(f.Index):len(f.Index)]
@ -103,13 +112,6 @@ func (f *Field) AppendValue(fmter Formatter, b []byte, strct reflect.Value) []by
return f.Append(fmter, b, fv)
}
func (f *Field) ScanWithCheck(fv reflect.Value, src interface{}) error {
if f.Scan == nil {
return fmt.Errorf("bun: Scan(unsupported %s)", f.IndirectType)
}
return f.Scan(fv, src)
}
func (f *Field) ScanValue(strct reflect.Value, src interface{}) error {
if src == nil {
if fv, ok := fieldByIndex(strct, f.Index); ok {
@ -122,18 +124,13 @@ func (f *Field) ScanValue(strct reflect.Value, src interface{}) error {
return f.ScanWithCheck(fv, src)
}
func (f *Field) ScanWithCheck(fv reflect.Value, src interface{}) error {
if f.Scan == nil {
return fmt.Errorf("bun: Scan(unsupported %s)", f.IndirectType)
}
return f.Scan(fv, src)
}
func (f *Field) SkipUpdate() bool {
return f.Tag.HasOption("skipupdate")
}
func indexEqual(ind1, ind2 []int) bool {
if len(ind1) != len(ind2) {
return false
}
for i, ind := range ind1 {
if ind != ind2[i] {
return false
}
}
return true
}

View file

@ -28,22 +28,6 @@ type BeforeAppendModelHook interface {
//------------------------------------------------------------------------------
type BeforeScanHook interface {
BeforeScan(context.Context) error
}
var beforeScanHookType = reflect.TypeOf((*BeforeScanHook)(nil)).Elem()
//------------------------------------------------------------------------------
type AfterScanHook interface {
AfterScan(context.Context) error
}
var afterScanHookType = reflect.TypeOf((*AfterScanHook)(nil)).Elem()
//------------------------------------------------------------------------------
type BeforeScanRowHook interface {
BeforeScanRow(context.Context) error
}

View file

@ -5,7 +5,6 @@
"fmt"
"reflect"
"strings"
"sync"
"time"
"github.com/jinzhu/inflection"
@ -52,12 +51,14 @@ type Table struct {
Alias string
SQLAlias Safe
allFields []*Field // all fields including scanonly
Fields []*Field // PKs + DataFields
PKs []*Field
DataFields []*Field
relFields []*Field
fieldsMapMu sync.RWMutex
FieldMap map[string]*Field
FieldMap map[string]*Field
StructMap map[string]*structField
Relations map[string]*Relation
Unique map[string][]*Field
@ -65,23 +66,38 @@ type Table struct {
SoftDeleteField *Field
UpdateSoftDeleteField func(fv reflect.Value, tm time.Time) error
allFields []*Field // read only
flags internal.Flag
}
func newTable(dialect Dialect, typ reflect.Type) *Table {
t := new(Table)
t.dialect = dialect
t.Type = typ
t.ZeroValue = reflect.New(t.Type).Elem()
t.ZeroIface = reflect.New(t.Type).Interface()
t.TypeName = internal.ToExported(t.Type.Name())
t.ModelName = internal.Underscore(t.Type.Name())
tableName := tableNameInflector(t.ModelName)
t.setName(tableName)
t.Alias = t.ModelName
t.SQLAlias = t.quoteIdent(t.ModelName)
type structField struct {
Index []int
Table *Table
}
func newTable(
dialect Dialect, typ reflect.Type, seen map[reflect.Type]*Table, canAddr bool,
) *Table {
if table, ok := seen[typ]; ok {
return table
}
table := new(Table)
seen[typ] = table
table.dialect = dialect
table.Type = typ
table.ZeroValue = reflect.New(table.Type).Elem()
table.ZeroIface = reflect.New(table.Type).Interface()
table.TypeName = internal.ToExported(table.Type.Name())
table.ModelName = internal.Underscore(table.Type.Name())
tableName := tableNameInflector(table.ModelName)
table.setName(tableName)
table.Alias = table.ModelName
table.SQLAlias = table.quoteIdent(table.ModelName)
table.Fields = make([]*Field, 0, typ.NumField())
table.FieldMap = make(map[string]*Field, typ.NumField())
table.processFields(typ, seen, canAddr)
hooks := []struct {
typ reflect.Type
@ -89,45 +105,168 @@ func newTable(dialect Dialect, typ reflect.Type) *Table {
}{
{beforeAppendModelHookType, beforeAppendModelHookFlag},
{beforeScanHookType, beforeScanHookFlag},
{afterScanHookType, afterScanHookFlag},
{beforeScanRowHookType, beforeScanRowHookFlag},
{afterScanRowHookType, afterScanRowHookFlag},
}
typ = reflect.PtrTo(t.Type)
typ = reflect.PtrTo(table.Type)
for _, hook := range hooks {
if typ.Implements(hook.typ) {
t.flags = t.flags.Set(hook.flag)
table.flags = table.flags.Set(hook.flag)
}
}
// Deprecated.
deprecatedHooks := []struct {
typ reflect.Type
flag internal.Flag
msg string
}{
{beforeScanHookType, beforeScanHookFlag, "rename BeforeScan hook to BeforeScanRow"},
{afterScanHookType, afterScanHookFlag, "rename AfterScan hook to AfterScanRow"},
return table
}
func (t *Table) init() {
for _, field := range t.relFields {
t.processRelation(field)
}
for _, hook := range deprecatedHooks {
if typ.Implements(hook.typ) {
internal.Deprecated.Printf("%s: %s", t.TypeName, hook.msg)
t.flags = t.flags.Set(hook.flag)
t.relFields = nil
}
func (t *Table) processFields(
typ reflect.Type,
seen map[reflect.Type]*Table,
canAddr bool,
) {
type embeddedField struct {
prefix string
index []int
unexported bool
subtable *Table
subfield *Field
}
names := make(map[string]struct{})
embedded := make([]embeddedField, 0, 10)
for i, n := 0, typ.NumField(); i < n; i++ {
sf := typ.Field(i)
unexported := sf.PkgPath != ""
tagstr := sf.Tag.Get("bun")
if tagstr == "-" {
names[sf.Name] = struct{}{}
continue
}
tag := tagparser.Parse(tagstr)
if unexported && !sf.Anonymous { // unexported
continue
}
if sf.Anonymous {
if sf.Name == "BaseModel" && sf.Type == baseModelType {
t.processBaseModelField(sf)
continue
}
sfType := sf.Type
if sfType.Kind() == reflect.Ptr {
sfType = sfType.Elem()
}
if sfType.Kind() != reflect.Struct { // ignore unexported non-struct types
continue
}
subtable := newTable(t.dialect, sfType, seen, canAddr)
for _, subfield := range subtable.allFields {
embedded = append(embedded, embeddedField{
index: sf.Index,
unexported: unexported,
subtable: subtable,
subfield: subfield,
})
}
if tagstr != "" {
tag := tagparser.Parse(tagstr)
if tag.HasOption("inherit") || tag.HasOption("extend") {
t.Name = subtable.Name
t.TypeName = subtable.TypeName
t.SQLName = subtable.SQLName
t.SQLNameForSelects = subtable.SQLNameForSelects
t.Alias = subtable.Alias
t.SQLAlias = subtable.SQLAlias
t.ModelName = subtable.ModelName
}
}
continue
}
if prefix, ok := tag.Option("embed"); ok {
fieldType := indirectType(sf.Type)
if fieldType.Kind() != reflect.Struct {
panic(fmt.Errorf("bun: embed %s.%s: got %s, wanted reflect.Struct",
t.TypeName, sf.Name, fieldType.Kind()))
}
subtable := newTable(t.dialect, fieldType, seen, canAddr)
for _, subfield := range subtable.allFields {
embedded = append(embedded, embeddedField{
prefix: prefix,
index: sf.Index,
unexported: unexported,
subtable: subtable,
subfield: subfield,
})
}
continue
}
field := t.newField(sf, tag)
t.addField(field)
names[field.Name] = struct{}{}
if field.IndirectType.Kind() == reflect.Struct {
if t.StructMap == nil {
t.StructMap = make(map[string]*structField)
}
t.StructMap[field.Name] = &structField{
Index: field.Index,
Table: newTable(t.dialect, field.IndirectType, seen, canAddr),
}
}
}
return t
}
// Only unambiguous embedded fields must be serialized.
ambiguousNames := make(map[string]int)
ambiguousTags := make(map[string]int)
func (t *Table) init1() {
t.initFields()
}
// Embedded types can never override a field that was already present at
// the top-level.
for name := range names {
ambiguousNames[name]++
ambiguousTags[name]++
}
func (t *Table) init2() {
t.initRelations()
for _, f := range embedded {
ambiguousNames[f.prefix+f.subfield.Name]++
if !f.subfield.Tag.IsZero() {
ambiguousTags[f.prefix+f.subfield.Name]++
}
}
for _, embfield := range embedded {
subfield := embfield.subfield.Clone()
if ambiguousNames[subfield.Name] > 1 &&
!(!subfield.Tag.IsZero() && ambiguousTags[subfield.Name] == 1) {
continue // ambiguous embedded field
}
subfield.Index = makeIndex(embfield.index, subfield.Index)
if embfield.prefix != "" {
subfield.Name = embfield.prefix + subfield.Name
subfield.SQLName = t.quoteIdent(subfield.Name)
}
t.addField(subfield)
}
}
func (t *Table) setName(name string) {
@ -152,30 +291,67 @@ func (t *Table) CheckPKs() error {
}
func (t *Table) addField(field *Field) {
t.allFields = append(t.allFields, field)
if field.Tag.HasOption("rel") || field.Tag.HasOption("m2m") {
t.relFields = append(t.relFields, field)
return
}
if field.Tag.HasOption("join") {
internal.Warn.Printf(
`%s.%s "join" option must come together with "rel" option`,
t.TypeName, field.GoName,
)
}
t.FieldMap[field.Name] = field
if altName, ok := field.Tag.Option("alt"); ok {
t.FieldMap[altName] = field
}
if field.Tag.HasOption("scanonly") {
return
}
if _, ok := field.Tag.Options["soft_delete"]; ok {
t.SoftDeleteField = field
t.UpdateSoftDeleteField = softDeleteFieldUpdater(field)
}
t.Fields = append(t.Fields, field)
if field.IsPK {
t.PKs = append(t.PKs, field)
} else {
t.DataFields = append(t.DataFields, field)
}
t.FieldMap[field.Name] = field
}
func (t *Table) removeField(field *Field) {
t.Fields = removeField(t.Fields, field)
if field.IsPK {
t.PKs = removeField(t.PKs, field)
} else {
t.DataFields = removeField(t.DataFields, field)
func (t *Table) LookupField(name string) *Field {
if field, ok := t.FieldMap[name]; ok {
return field
}
delete(t.FieldMap, field.Name)
}
func (t *Table) fieldWithLock(name string) *Field {
t.fieldsMapMu.RLock()
field := t.FieldMap[name]
t.fieldsMapMu.RUnlock()
return field
table := t
var index []int
for {
structName, columnName, ok := strings.Cut(name, "__")
if !ok {
field, ok := table.FieldMap[name]
if !ok {
return nil
}
return field.WithIndex(index)
}
name = columnName
strct := table.StructMap[structName]
if strct == nil {
return nil
}
table = strct.Table
index = append(index, strct.Index...)
}
}
func (t *Table) HasField(name string) bool {
@ -200,59 +376,6 @@ func (t *Table) fieldByGoName(name string) *Field {
return nil
}
func (t *Table) initFields() {
t.Fields = make([]*Field, 0, t.Type.NumField())
t.FieldMap = make(map[string]*Field, t.Type.NumField())
t.addFields(t.Type, "", nil)
}
func (t *Table) addFields(typ reflect.Type, prefix string, index []int) {
for i := 0; i < typ.NumField(); i++ {
f := typ.Field(i)
unexported := f.PkgPath != ""
if unexported && !f.Anonymous { // unexported
continue
}
if f.Tag.Get("bun") == "-" {
continue
}
if f.Anonymous {
if f.Name == "BaseModel" && f.Type == baseModelType {
if len(index) == 0 {
t.processBaseModelField(f)
}
continue
}
// If field is an embedded struct, add each field of the embedded struct.
fieldType := indirectType(f.Type)
if fieldType.Kind() == reflect.Struct {
t.addFields(fieldType, "", withIndex(index, f.Index))
tag := tagparser.Parse(f.Tag.Get("bun"))
if tag.HasOption("inherit") || tag.HasOption("extend") {
embeddedTable := t.dialect.Tables().Ref(fieldType)
t.TypeName = embeddedTable.TypeName
t.SQLName = embeddedTable.SQLName
t.SQLNameForSelects = embeddedTable.SQLNameForSelects
t.Alias = embeddedTable.Alias
t.SQLAlias = embeddedTable.SQLAlias
t.ModelName = embeddedTable.ModelName
}
continue
}
}
// If field is not a struct, add it.
// This will also add any embedded non-struct type as a field.
if field := t.newField(f, prefix, index); field != nil {
t.addField(field)
}
}
}
func (t *Table) processBaseModelField(f reflect.StructField) {
tag := tagparser.Parse(f.Tag.Get("bun"))
@ -288,58 +411,34 @@ func (t *Table) processBaseModelField(f reflect.StructField) {
}
// nolint
func (t *Table) newField(f reflect.StructField, prefix string, index []int) *Field {
tag := tagparser.Parse(f.Tag.Get("bun"))
if nextPrefix, ok := tag.Option("embed"); ok {
fieldType := indirectType(f.Type)
if fieldType.Kind() != reflect.Struct {
panic(fmt.Errorf("bun: embed %s.%s: got %s, wanted reflect.Struct",
t.TypeName, f.Name, fieldType.Kind()))
}
t.addFields(fieldType, prefix+nextPrefix, withIndex(index, f.Index))
return nil
}
sqlName := internal.Underscore(f.Name)
func (t *Table) newField(sf reflect.StructField, tag tagparser.Tag) *Field {
sqlName := internal.Underscore(sf.Name)
if tag.Name != "" && tag.Name != sqlName {
if isKnownFieldOption(tag.Name) {
internal.Warn.Printf(
"%s.%s tag name %q is also an option name, is it a mistake? Try column:%s.",
t.TypeName, f.Name, tag.Name, tag.Name,
t.TypeName, sf.Name, tag.Name, tag.Name,
)
}
sqlName = tag.Name
}
if s, ok := tag.Option("column"); ok {
sqlName = s
}
sqlName = prefix + sqlName
for name := range tag.Options {
if !isKnownFieldOption(name) {
internal.Warn.Printf("%s.%s has unknown tag option: %q", t.TypeName, f.Name, name)
internal.Warn.Printf("%s.%s has unknown tag option: %q", t.TypeName, sf.Name, name)
}
}
index = withIndex(index, f.Index)
if field := t.fieldWithLock(sqlName); field != nil {
if indexEqual(field.Index, index) {
return field
}
t.removeField(field)
}
field := &Field{
StructField: f,
IsPtr: f.Type.Kind() == reflect.Ptr,
StructField: sf,
IsPtr: sf.Type.Kind() == reflect.Ptr,
Tag: tag,
IndirectType: indirectType(f.Type),
Index: index,
IndirectType: indirectType(sf.Type),
Index: sf.Index,
Name: sqlName,
GoName: f.Name,
GoName: sf.Name,
SQLName: t.quoteIdent(sqlName),
}
@ -386,63 +485,21 @@ func (t *Table) newField(f reflect.StructField, prefix string, index []int) *Fie
field.Scan = FieldScanner(t.dialect, field)
field.IsZero = zeroChecker(field.StructField.Type)
if v, ok := tag.Option("alt"); ok {
t.FieldMap[v] = field
}
t.allFields = append(t.allFields, field)
if tag.HasOption("scanonly") {
t.FieldMap[field.Name] = field
if field.IndirectType.Kind() == reflect.Struct {
t.inlineFields(field, nil)
}
return nil
}
if _, ok := tag.Options["soft_delete"]; ok {
t.SoftDeleteField = field
t.UpdateSoftDeleteField = softDeleteFieldUpdater(field)
}
return field
}
//---------------------------------------------------------------------------------------
func (t *Table) initRelations() {
for i := 0; i < len(t.Fields); {
f := t.Fields[i]
if t.tryRelation(f) {
t.Fields = removeField(t.Fields, f)
t.DataFields = removeField(t.DataFields, f)
} else {
i++
}
if f.IndirectType.Kind() == reflect.Struct {
t.inlineFields(f, nil)
}
}
}
func (t *Table) tryRelation(field *Field) bool {
func (t *Table) processRelation(field *Field) {
if rel, ok := field.Tag.Option("rel"); ok {
t.initRelation(field, rel)
return true
return
}
if field.Tag.HasOption("m2m") {
t.addRelation(t.m2mRelation(field))
return true
return
}
if field.Tag.HasOption("join") {
internal.Warn.Printf(
`%s.%s "join" option must come together with "rel" option`,
t.TypeName, field.GoName,
)
}
return false
panic("not reached")
}
func (t *Table) initRelation(field *Field, rel string) {
@ -470,7 +527,7 @@ func (t *Table) addRelation(rel *Relation) {
}
func (t *Table) belongsToRelation(field *Field) *Relation {
joinTable := t.dialect.Tables().Ref(field.IndirectType)
joinTable := t.dialect.Tables().InProgress(field.IndirectType)
if err := joinTable.CheckPKs(); err != nil {
panic(err)
}
@ -519,7 +576,7 @@ func (t *Table) belongsToRelation(field *Field) *Relation {
for i, baseColumn := range baseColumns {
joinColumn := joinColumns[i]
if f := t.fieldWithLock(baseColumn); f != nil {
if f := t.FieldMap[baseColumn]; f != nil {
rel.BaseFields = append(rel.BaseFields, f)
} else {
panic(fmt.Errorf(
@ -528,7 +585,7 @@ func (t *Table) belongsToRelation(field *Field) *Relation {
))
}
if f := joinTable.fieldWithLock(joinColumn); f != nil {
if f := joinTable.FieldMap[joinColumn]; f != nil {
rel.JoinFields = append(rel.JoinFields, f)
} else {
panic(fmt.Errorf(
@ -544,12 +601,12 @@ func (t *Table) belongsToRelation(field *Field) *Relation {
fkPrefix := internal.Underscore(field.GoName) + "_"
for _, joinPK := range joinTable.PKs {
fkName := fkPrefix + joinPK.Name
if fk := t.fieldWithLock(fkName); fk != nil {
if fk := t.FieldMap[fkName]; fk != nil {
rel.BaseFields = append(rel.BaseFields, fk)
continue
}
if fk := t.fieldWithLock(joinPK.Name); fk != nil {
if fk := t.FieldMap[joinPK.Name]; fk != nil {
rel.BaseFields = append(rel.BaseFields, fk)
continue
}
@ -568,7 +625,7 @@ func (t *Table) hasOneRelation(field *Field) *Relation {
panic(err)
}
joinTable := t.dialect.Tables().Ref(field.IndirectType)
joinTable := t.dialect.Tables().InProgress(field.IndirectType)
rel := &Relation{
Type: HasOneRelation,
Field: field,
@ -582,7 +639,7 @@ func (t *Table) hasOneRelation(field *Field) *Relation {
if join, ok := field.Tag.Options["join"]; ok {
baseColumns, joinColumns := parseRelationJoin(join)
for i, baseColumn := range baseColumns {
if f := t.fieldWithLock(baseColumn); f != nil {
if f := t.FieldMap[baseColumn]; f != nil {
rel.BaseFields = append(rel.BaseFields, f)
} else {
panic(fmt.Errorf(
@ -592,7 +649,7 @@ func (t *Table) hasOneRelation(field *Field) *Relation {
}
joinColumn := joinColumns[i]
if f := joinTable.fieldWithLock(joinColumn); f != nil {
if f := joinTable.FieldMap[joinColumn]; f != nil {
rel.JoinFields = append(rel.JoinFields, f)
} else {
panic(fmt.Errorf(
@ -608,12 +665,12 @@ func (t *Table) hasOneRelation(field *Field) *Relation {
fkPrefix := internal.Underscore(t.ModelName) + "_"
for _, pk := range t.PKs {
fkName := fkPrefix + pk.Name
if f := joinTable.fieldWithLock(fkName); f != nil {
if f := joinTable.FieldMap[fkName]; f != nil {
rel.JoinFields = append(rel.JoinFields, f)
continue
}
if f := joinTable.fieldWithLock(pk.Name); f != nil {
if f := joinTable.FieldMap[pk.Name]; f != nil {
rel.JoinFields = append(rel.JoinFields, f)
continue
}
@ -638,7 +695,7 @@ func (t *Table) hasManyRelation(field *Field) *Relation {
))
}
joinTable := t.dialect.Tables().Ref(indirectType(field.IndirectType.Elem()))
joinTable := t.dialect.Tables().InProgress(indirectType(field.IndirectType.Elem()))
polymorphicValue, isPolymorphic := field.Tag.Option("polymorphic")
rel := &Relation{
Type: HasManyRelation,
@ -662,7 +719,7 @@ func (t *Table) hasManyRelation(field *Field) *Relation {
continue
}
if f := t.fieldWithLock(baseColumn); f != nil {
if f := t.FieldMap[baseColumn]; f != nil {
rel.BaseFields = append(rel.BaseFields, f)
} else {
panic(fmt.Errorf(
@ -671,7 +728,7 @@ func (t *Table) hasManyRelation(field *Field) *Relation {
))
}
if f := joinTable.fieldWithLock(joinColumn); f != nil {
if f := joinTable.FieldMap[joinColumn]; f != nil {
rel.JoinFields = append(rel.JoinFields, f)
} else {
panic(fmt.Errorf(
@ -689,12 +746,12 @@ func (t *Table) hasManyRelation(field *Field) *Relation {
for _, pk := range t.PKs {
joinColumn := fkPrefix + pk.Name
if fk := joinTable.fieldWithLock(joinColumn); fk != nil {
if fk := joinTable.FieldMap[joinColumn]; fk != nil {
rel.JoinFields = append(rel.JoinFields, fk)
continue
}
if fk := joinTable.fieldWithLock(pk.Name); fk != nil {
if fk := joinTable.FieldMap[pk.Name]; fk != nil {
rel.JoinFields = append(rel.JoinFields, fk)
continue
}
@ -708,7 +765,7 @@ func (t *Table) hasManyRelation(field *Field) *Relation {
}
if isPolymorphic {
rel.PolymorphicField = joinTable.fieldWithLock(polymorphicColumn)
rel.PolymorphicField = joinTable.FieldMap[polymorphicColumn]
if rel.PolymorphicField == nil {
panic(fmt.Errorf(
"bun: %s has-many %s: %s must have polymorphic column %s",
@ -732,7 +789,7 @@ func (t *Table) m2mRelation(field *Field) *Relation {
t.TypeName, field.GoName, field.IndirectType.Kind(),
))
}
joinTable := t.dialect.Tables().Ref(indirectType(field.IndirectType.Elem()))
joinTable := t.dialect.Tables().InProgress(indirectType(field.IndirectType.Elem()))
if err := t.CheckPKs(); err != nil {
panic(err)
@ -805,40 +862,6 @@ func (t *Table) m2mRelation(field *Field) *Relation {
return rel
}
func (t *Table) inlineFields(field *Field, seen map[reflect.Type]struct{}) {
if seen == nil {
seen = map[reflect.Type]struct{}{t.Type: {}}
}
if _, ok := seen[field.IndirectType]; ok {
return
}
seen[field.IndirectType] = struct{}{}
joinTable := t.dialect.Tables().Ref(field.IndirectType)
for _, f := range joinTable.allFields {
f = f.Clone()
f.GoName = field.GoName + "_" + f.GoName
f.Name = field.Name + "__" + f.Name
f.SQLName = t.quoteIdent(f.Name)
f.Index = withIndex(field.Index, f.Index)
t.fieldsMapMu.Lock()
if _, ok := t.FieldMap[f.Name]; !ok {
t.FieldMap[f.Name] = f
}
t.fieldsMapMu.Unlock()
if f.IndirectType.Kind() != reflect.Struct {
continue
}
if _, ok := seen[f.IndirectType]; !ok {
t.inlineFields(f, seen)
}
}
}
//------------------------------------------------------------------------------
func (t *Table) Dialect() Dialect { return t.dialect }
@ -890,7 +913,7 @@ func isKnownTableOption(name string) bool {
func isKnownFieldOption(name string) bool {
switch name {
case "column",
"alias",
"alt",
"type",
"array",
"hstore",
@ -931,15 +954,6 @@ func isKnownFKRule(name string) bool {
return false
}
func removeField(fields []*Field, field *Field) []*Field {
for i, f := range fields {
if f == field {
return append(fields[:i], fields[i+1:]...)
}
}
return fields
}
func parseRelationJoin(join []string) ([]string, []string) {
var ss []string
if len(join) == 1 {
@ -1026,7 +1040,7 @@ func softDeleteFieldUpdaterFallback(field *Field) func(fv reflect.Value, tm time
}
}
func withIndex(a, b []int) []int {
func makeIndex(a, b []int) []int {
dest := make([]int, 0, len(a)+len(b))
dest = append(dest, a...)
dest = append(dest, b...)

View file

@ -6,48 +6,19 @@
"sync"
)
type tableInProgress struct {
table *Table
init1Once sync.Once
init2Once sync.Once
}
func newTableInProgress(table *Table) *tableInProgress {
return &tableInProgress{
table: table,
}
}
func (inp *tableInProgress) init1() bool {
var inited bool
inp.init1Once.Do(func() {
inp.table.init1()
inited = true
})
return inited
}
func (inp *tableInProgress) init2() bool {
var inited bool
inp.init2Once.Do(func() {
inp.table.init2()
inited = true
})
return inited
}
type Tables struct {
dialect Dialect
tables sync.Map
mu sync.RWMutex
seen map[reflect.Type]*Table
inProgress map[reflect.Type]*tableInProgress
}
func NewTables(dialect Dialect) *Tables {
return &Tables{
dialect: dialect,
seen: make(map[reflect.Type]*Table),
inProgress: make(map[reflect.Type]*tableInProgress),
}
}
@ -62,7 +33,7 @@ func (t *Tables) Get(typ reflect.Type) *Table {
return t.table(typ, false)
}
func (t *Tables) Ref(typ reflect.Type) *Table {
func (t *Tables) InProgress(typ reflect.Type) *Table {
return t.table(typ, true)
}
@ -87,7 +58,7 @@ func (t *Tables) table(typ reflect.Type, allowInProgress bool) *Table {
inProgress := t.inProgress[typ]
if inProgress == nil {
table = newTable(t.dialect, typ)
table = newTable(t.dialect, typ, t.seen, false)
inProgress = newTableInProgress(table)
t.inProgress[typ] = inProgress
} else {
@ -96,12 +67,11 @@ func (t *Tables) table(typ reflect.Type, allowInProgress bool) *Table {
t.mu.Unlock()
inProgress.init1()
if allowInProgress {
return table
}
if !inProgress.init2() {
if !inProgress.init() {
return table
}
@ -149,3 +119,24 @@ func (t *Tables) ByName(name string) *Table {
})
return found
}
type tableInProgress struct {
table *Table
initOnce sync.Once
}
func newTableInProgress(table *Table) *tableInProgress {
return &tableInProgress{
table: table,
}
}
func (inp *tableInProgress) init() bool {
var inited bool
inp.initOnce.Do(func() {
inp.table.init()
inited = true
})
return inited
}

View file

@ -2,5 +2,5 @@
// Version is the current release version.
func Version() string {
return "1.1.17"
return "1.2.1"
}

View file

@ -101,7 +101,7 @@ func (t *dbInstrum) withSpan(
trace.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attrs...))
err := fn(ctx, span)
span.End()
defer span.End()
if query != "" {
t.queryHistogram.Record(ctx, time.Since(startTime).Milliseconds(), metric.WithAttributes(t.attrs...))

View file

@ -2,5 +2,5 @@
// Version is the current release version.
func Version() string {
return "0.2.3"
return "0.2.4"
}

20
vendor/modules.txt vendored
View file

@ -852,8 +852,8 @@ github.com/ugorji/go/codec
github.com/ulule/limiter/v3
github.com/ulule/limiter/v3/drivers/store/common
github.com/ulule/limiter/v3/drivers/store/memory
# github.com/uptrace/bun v1.1.17
## explicit; go 1.19
# github.com/uptrace/bun v1.2.1
## explicit; go 1.21
github.com/uptrace/bun
github.com/uptrace/bun/dialect
github.com/uptrace/bun/dialect/feature
@ -864,17 +864,17 @@ github.com/uptrace/bun/internal/parser
github.com/uptrace/bun/internal/tagparser
github.com/uptrace/bun/migrate
github.com/uptrace/bun/schema
# github.com/uptrace/bun/dialect/pgdialect v1.1.17
## explicit; go 1.19
# github.com/uptrace/bun/dialect/pgdialect v1.2.1
## explicit; go 1.21
github.com/uptrace/bun/dialect/pgdialect
# github.com/uptrace/bun/dialect/sqlitedialect v1.1.17
## explicit; go 1.19
# github.com/uptrace/bun/dialect/sqlitedialect v1.2.1
## explicit; go 1.21
github.com/uptrace/bun/dialect/sqlitedialect
# github.com/uptrace/bun/extra/bunotel v1.1.17
## explicit; go 1.19
# github.com/uptrace/bun/extra/bunotel v1.2.1
## explicit; go 1.21
github.com/uptrace/bun/extra/bunotel
# github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3
## explicit; go 1.18
# github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4
## explicit; go 1.21
github.com/uptrace/opentelemetry-go-extra/otelsql
# github.com/vmihailenco/msgpack/v5 v5.4.1
## explicit; go 1.19