[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/technologize/otel-go-contrib v1.1.1
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/ulule/limiter/v3 v3.11.2 github.com/ulule/limiter/v3 v3.11.2
github.com/uptrace/bun v1.1.17 github.com/uptrace/bun v1.2.1
github.com/uptrace/bun/dialect/pgdialect v1.1.17 github.com/uptrace/bun/dialect/pgdialect v1.2.1
github.com/uptrace/bun/dialect/sqlitedialect v1.1.17 github.com/uptrace/bun/dialect/sqlitedialect v1.2.1
github.com/uptrace/bun/extra/bunotel v1.1.17 github.com/uptrace/bun/extra/bunotel v1.2.1
github.com/wagslane/go-password-validator v0.3.0 github.com/wagslane/go-password-validator v0.3.0
github.com/yuin/goldmark v1.7.1 github.com/yuin/goldmark v1.7.1
go.opentelemetry.io/otel v1.25.0 go.opentelemetry.io/otel v1.25.0
@ -201,7 +201,7 @@ require (
github.com/toqueteos/webbrowser v1.2.0 // indirect github.com/toqueteos/webbrowser v1.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // 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/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
go.mongodb.org/mongo-driver v1.14.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/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 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA=
github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI= 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.2.1 h1:2ENAcfeCfaY5+2e7z5pXrzFKy3vS8VXvkCag6N2Yzfk=
github.com/uptrace/bun v1.1.17/go.mod h1:hATAzivtTIRsSJR4B8AXR+uABqnQxr3myKDKEf5iQ9U= github.com/uptrace/bun v1.2.1/go.mod h1:cNg+pWBUMmJ8rHnETgf65CEvn3aIKErrwOD6IA8e+Ec=
github.com/uptrace/bun/dialect/pgdialect v1.1.17 h1:NsvFVHAx1Az6ytlAD/B6ty3cVE6j9Yp82bjqd9R9hOs= github.com/uptrace/bun/dialect/pgdialect v1.2.1 h1:ceP99r03u+s8ylaDE/RzgcajwGiC76Jz3nS2ZgyPQ4M=
github.com/uptrace/bun/dialect/pgdialect v1.1.17/go.mod h1:fLBDclNc7nKsZLzNjFL6BqSdgJzbj2HdnyOnLoDvAME= github.com/uptrace/bun/dialect/pgdialect v1.2.1/go.mod h1:mv6B12cisvSc6bwKm9q9wcrr26awkZK8QXM+nso9n2U=
github.com/uptrace/bun/dialect/sqlitedialect v1.1.17 h1:i8NFU9r8YuavNFaYlNqi4ppn+MgoHtqLgpWQDrVTjm0= github.com/uptrace/bun/dialect/sqlitedialect v1.2.1 h1:IprvkIKUjEjvt4VKpcmLpbMIucjrsmUPJOSlg19+a0Q=
github.com/uptrace/bun/dialect/sqlitedialect v1.1.17/go.mod h1:YF0FO4VVnY9GHNH6rM4r3STlVEBxkOc6L88Bm5X5mzA= github.com/uptrace/bun/dialect/sqlitedialect v1.2.1/go.mod h1:mMQf4NUpgY8bnOanxGmxNiHCdALOggS4cZ3v63a9D/o=
github.com/uptrace/bun/extra/bunotel v1.1.17 h1:RLEJdHH06RI9BLg06Vu1JHJ3KNHQCfwa2Fa3x+56qkk= github.com/uptrace/bun/extra/bunotel v1.2.1 h1:5oTy3Jh7Q1bhCd5vnPszBmJgYouw+PuuZ8iSCm+uNCQ=
github.com/uptrace/bun/extra/bunotel v1.1.17/go.mod h1:xV7AYrCFji4Sio6N9X+Cz+XJ+JuHq6TQQjuxaVbsypk= github.com/uptrace/bun/extra/bunotel v1.2.1/go.mod h1:SWW3HyjiXPYM36q0QSpdtTP8v21nWHnTCxu4lYkpO90=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3 h1:LNi0Qa7869/loPjz2kmMvp/jwZZnMZ9scMJKhDJ1DIo= github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4 h1:x3omFAG2XkvWFg1hvXRinY2ExAL1Aacl7W9ZlYjo6gc=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3/go.mod h1:jyigonKik3C5V895QNiAGpKYKEvFuqjw9qAEZks1mUg= 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 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE= 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) ## [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}"; \ echo "go mod tidy in $${dir}"; \
(cd "$${dir}" && \ (cd "$${dir}" && \
go get -u ./... && \ go get -u ./... && \
go mod tidy -go=1.19); \ go mod tidy -go=1.21); \
done done
fmt: fmt:

View file

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

View file

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

View file

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

View file

@ -6,14 +6,26 @@
"os" "os"
) )
var Warn = log.New(os.Stderr, "WARN: bun: ", log.LstdFlags)
var Deprecated = log.New(os.Stderr, "DEPRECATED: bun: ", log.LstdFlags)
type Logging interface { type Logging interface {
Printf(format string, v ...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 { type logger struct {
log *log.Logger log *log.Logger
} }
@ -22,6 +34,21 @@ func (l *logger) Printf(format string, v ...interface{}) {
_ = l.log.Output(2, fmt.Sprintf(format, v...)) _ = l.log.Output(2, fmt.Sprintf(format, v...))
} }
var Logger Logging = &logger{ type wrapper struct {
log: log.New(os.Stderr, "bun: ", log.LstdFlags|log.Lshortfile), 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 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 { if err != nil {
return nil, err 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -83,9 +83,9 @@ func (m *hasManyModel) Scan(src interface{}) error {
column := m.columns[m.scanIndex] column := m.columns[m.scanIndex]
m.scanIndex++ m.scanIndex++
field, err := m.table.Field(column) field := m.table.LookupField(column)
if err != nil { if field == nil {
return err return fmt.Errorf("bun: %s does not have column %q", m.table.TypeName, column)
} }
if err := field.ScanValue(m.strct, src); err != nil { 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() { if m.table.HasBeforeScanRowHook() {
return m.strct.Addr().Interface().(schema.BeforeScanRowHook).BeforeScanRow(ctx) return m.strct.Addr().Interface().(schema.BeforeScanRowHook).BeforeScanRow(ctx)
} }
if m.table.HasBeforeScanHook() {
return m.strct.Addr().Interface().(schema.BeforeScanHook).BeforeScan(ctx)
}
return nil return nil
} }
@ -144,21 +141,6 @@ func (m *structTableModel) AfterScanRow(ctx context.Context) error {
return firstErr 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 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() { if src == nil && m.isNil() {
return true, nil return true, nil
} }

View file

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

View file

@ -51,6 +51,7 @@ type IDB interface {
NewInsert() *InsertQuery NewInsert() *InsertQuery
NewUpdate() *UpdateQuery NewUpdate() *UpdateQuery
NewDelete() *DeleteQuery NewDelete() *DeleteQuery
NewMerge() *MergeQuery
NewRaw(query string, args ...interface{}) *RawQuery NewRaw(query string, args ...interface{}) *RawQuery
NewCreateTable() *CreateTableQuery NewCreateTable() *CreateTableQuery
NewDropTable() *DropTableQuery 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...) 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, '.') b = append(b, '.')
field := j.JoinModel.Table().SoftDeleteField field := j.JoinModel.Table().SoftDeleteField

View file

@ -44,6 +44,15 @@ func (f *Field) String() string {
return f.Name 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 { func (f *Field) Clone() *Field {
cp := *f cp := *f
cp.Index = cp.Index[:len(f.Index):len(f.Index)] 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) 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 { func (f *Field) ScanValue(strct reflect.Value, src interface{}) error {
if src == nil { if src == nil {
if fv, ok := fieldByIndex(strct, f.Index); ok { 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) 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 { func (f *Field) SkipUpdate() bool {
return f.Tag.HasOption("skipupdate") 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 { type BeforeScanRowHook interface {
BeforeScanRow(context.Context) error BeforeScanRow(context.Context) error
} }

View file

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

View file

@ -6,48 +6,19 @@
"sync" "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 { type Tables struct {
dialect Dialect dialect Dialect
tables sync.Map tables sync.Map
mu sync.RWMutex mu sync.RWMutex
seen map[reflect.Type]*Table
inProgress map[reflect.Type]*tableInProgress inProgress map[reflect.Type]*tableInProgress
} }
func NewTables(dialect Dialect) *Tables { func NewTables(dialect Dialect) *Tables {
return &Tables{ return &Tables{
dialect: dialect, dialect: dialect,
seen: make(map[reflect.Type]*Table),
inProgress: make(map[reflect.Type]*tableInProgress), inProgress: make(map[reflect.Type]*tableInProgress),
} }
} }
@ -62,7 +33,7 @@ func (t *Tables) Get(typ reflect.Type) *Table {
return t.table(typ, false) 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) return t.table(typ, true)
} }
@ -87,7 +58,7 @@ func (t *Tables) table(typ reflect.Type, allowInProgress bool) *Table {
inProgress := t.inProgress[typ] inProgress := t.inProgress[typ]
if inProgress == nil { if inProgress == nil {
table = newTable(t.dialect, typ) table = newTable(t.dialect, typ, t.seen, false)
inProgress = newTableInProgress(table) inProgress = newTableInProgress(table)
t.inProgress[typ] = inProgress t.inProgress[typ] = inProgress
} else { } else {
@ -96,12 +67,11 @@ func (t *Tables) table(typ reflect.Type, allowInProgress bool) *Table {
t.mu.Unlock() t.mu.Unlock()
inProgress.init1()
if allowInProgress { if allowInProgress {
return table return table
} }
if !inProgress.init2() { if !inProgress.init() {
return table return table
} }
@ -149,3 +119,24 @@ func (t *Tables) ByName(name string) *Table {
}) })
return found 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. // Version is the current release version.
func Version() string { 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.WithSpanKind(trace.SpanKindClient),
trace.WithAttributes(attrs...)) trace.WithAttributes(attrs...))
err := fn(ctx, span) err := fn(ctx, span)
span.End() defer span.End()
if query != "" { if query != "" {
t.queryHistogram.Record(ctx, time.Since(startTime).Milliseconds(), metric.WithAttributes(t.attrs...)) t.queryHistogram.Record(ctx, time.Since(startTime).Milliseconds(), metric.WithAttributes(t.attrs...))

View file

@ -2,5 +2,5 @@
// Version is the current release version. // Version is the current release version.
func Version() string { 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
github.com/ulule/limiter/v3/drivers/store/common github.com/ulule/limiter/v3/drivers/store/common
github.com/ulule/limiter/v3/drivers/store/memory github.com/ulule/limiter/v3/drivers/store/memory
# github.com/uptrace/bun v1.1.17 # github.com/uptrace/bun v1.2.1
## explicit; go 1.19 ## explicit; go 1.21
github.com/uptrace/bun github.com/uptrace/bun
github.com/uptrace/bun/dialect github.com/uptrace/bun/dialect
github.com/uptrace/bun/dialect/feature 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/internal/tagparser
github.com/uptrace/bun/migrate github.com/uptrace/bun/migrate
github.com/uptrace/bun/schema github.com/uptrace/bun/schema
# github.com/uptrace/bun/dialect/pgdialect v1.1.17 # github.com/uptrace/bun/dialect/pgdialect v1.2.1
## explicit; go 1.19 ## explicit; go 1.21
github.com/uptrace/bun/dialect/pgdialect github.com/uptrace/bun/dialect/pgdialect
# github.com/uptrace/bun/dialect/sqlitedialect v1.1.17 # github.com/uptrace/bun/dialect/sqlitedialect v1.2.1
## explicit; go 1.19 ## explicit; go 1.21
github.com/uptrace/bun/dialect/sqlitedialect github.com/uptrace/bun/dialect/sqlitedialect
# github.com/uptrace/bun/extra/bunotel v1.1.17 # github.com/uptrace/bun/extra/bunotel v1.2.1
## explicit; go 1.19 ## explicit; go 1.21
github.com/uptrace/bun/extra/bunotel github.com/uptrace/bun/extra/bunotel
# github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3 # github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4
## explicit; go 1.18 ## explicit; go 1.21
github.com/uptrace/opentelemetry-go-extra/otelsql github.com/uptrace/opentelemetry-go-extra/otelsql
# github.com/vmihailenco/msgpack/v5 v5.4.1 # github.com/vmihailenco/msgpack/v5 v5.4.1
## explicit; go 1.19 ## explicit; go 1.19