diff options
Diffstat (limited to 'vendor/github.com')
30 files changed, 1329 insertions, 103 deletions
diff --git a/vendor/github.com/uptrace/bun/CHANGELOG.md b/vendor/github.com/uptrace/bun/CHANGELOG.md index 8529ac99f..1738c901a 100644 --- a/vendor/github.com/uptrace/bun/CHANGELOG.md +++ b/vendor/github.com/uptrace/bun/CHANGELOG.md @@ -1,17 +1,86 @@ -# [](https://github.com/uptrace/bun/compare/v1.1.2...v) (2022-03-29) +## [1.1.7](https://github.com/uptrace/bun/compare/v1.1.6...v1.1.7) (2022-07-29) ### Bug Fixes -* fix panic message when has-many encounter an error ([cfd2747](https://github.com/uptrace/bun/commit/cfd27475fac89a1c8cf798bfa64898bd77bbba79)) -* **migrate:** change rollback to match migrate behavior ([df5af9c](https://github.com/uptrace/bun/commit/df5af9c9cbdf54ce243e037bbb2c7b154f8422b3)) +* change ScanAndCount without a limit to select all rows ([de5c570](https://github.com/uptrace/bun/commit/de5c5704166563aea41a82f7863f2db88ff108e2)) + + + +## [1.1.6](https://github.com/uptrace/bun/compare/v1.1.5...v1.1.6) (2022-07-10) + + +### Bug Fixes + +* bunotel add set attributes to query metrics ([dae82cc](https://github.com/uptrace/bun/commit/dae82cc0e3af49be1e474027b55c34364676985d)) +* **db.ScanRows:** ensure rows.Close is called ([9ffbc6a](https://github.com/uptrace/bun/commit/9ffbc6a46e24b908742b6973f33ef8e5b17cc12b)) +* merge apply ([3081849](https://github.com/uptrace/bun/commit/30818499eacddd3b1a3e749091ba6a1468125641)) +* **migrate:** close conn/tx on error ([7b168ea](https://github.com/uptrace/bun/commit/7b168eabfe0f844bcbf8dc89629d04c385b9f58c)) +* **migrate:** type Migration should be used as a value rather than a pointer ([fb43935](https://github.com/uptrace/bun/commit/fb4393582b49fe528800a66aac5fb1c9a6033048)) +* **migrate:** type MigrationGroup should be used as a value rather than a pointer ([649da1b](https://github.com/uptrace/bun/commit/649da1b3c158060add9b61b32c289260daafa65a)) +* mssql cursor pagination ([#589](https://github.com/uptrace/bun/issues/589)) ([b34ec97](https://github.com/uptrace/bun/commit/b34ec97ddda95629f73762721d60fd3e00e7e99f)) + + +### Features + +* "skipupdate" model field tag ([#565](https://github.com/uptrace/bun/issues/565)) ([9288294](https://github.com/uptrace/bun/commit/928829482c718a0c215aa4f4adfa6f3fb3ed4302)) +* add pgdriver write error to log ([5ddda3d](https://github.com/uptrace/bun/commit/5ddda3de31cd08ceee4bdea64ceae8d15eace07b)) +* add query string representation ([520da7e](https://github.com/uptrace/bun/commit/520da7e1d6dbf7b06846f6b39a7f99e8753c1466)) +* add relation condition with tag ([fe5bbf6](https://github.com/uptrace/bun/commit/fe5bbf64f33d25b310e5510ece7d705b9eb3bfea)) +* add support for ON UPDATE and ON DELETE rules on belongs-to relationships from struct tags ([#533](https://github.com/uptrace/bun/issues/533)) ([a327b2a](https://github.com/uptrace/bun/commit/a327b2ae216abb55a705626296c0cdbf8d648697)) +* add tx methods to IDB ([#587](https://github.com/uptrace/bun/issues/587)) ([feab313](https://github.com/uptrace/bun/commit/feab313c0358200b6e270ac70f4551b011ab5276)) +* added raw query calls ([#596](https://github.com/uptrace/bun/issues/596)) ([127644d](https://github.com/uptrace/bun/commit/127644d2eea443736fbd6bed3417595d439e4639)) +* **bunotel:** add option to enable formatting of queries ([#547](https://github.com/uptrace/bun/issues/547)) ([b9c768c](https://github.com/uptrace/bun/commit/b9c768cec3b5dea36c3c9c344d1e76e0ffad1369)) +* **config.go:** add sslrootcert support to DSN parameters ([3bd5d69](https://github.com/uptrace/bun/commit/3bd5d692d7df4f30d07b835d6a46fc7af382489a)) +* create an extra module for newrelic ([#599](https://github.com/uptrace/bun/issues/599)) ([6c676ce](https://github.com/uptrace/bun/commit/6c676ce13f05fe763471fbec2d5a2db48bc88650)) +* **migrate:** add WithMarkAppliedOnSuccess ([31b2cc4](https://github.com/uptrace/bun/commit/31b2cc4f5ccd794a436d081073d4974835d3780d)) +* **pgdialect:** add hstore support ([66b44f7](https://github.com/uptrace/bun/commit/66b44f7c0edc205927fb8be96aaf263b31828fa1)) +* **pgdialect:** add identity support ([646251e](https://github.com/uptrace/bun/commit/646251ec02a1e2ec717e907e6f128d8b51f17c6d)) +* **pgdriver:** expose pgdriver.ParseTime ([405a7d7](https://github.com/uptrace/bun/commit/405a7d78d8f60cf27e8f175deaf95db5877d84be)) + + + +## [1.1.5](https://github.com/uptrace/bun/compare/v1.1.4...v1.1.5) (2022-05-12) + + +### Bug Fixes + +* **driver/sqliteshim:** make it work with recent version of modernc sqlite ([2360584](https://github.com/uptrace/bun/commit/23605846c20684e39bf1eaac50a2147a1b68a729)) + + + +## [1.1.4](https://github.com/uptrace/bun/compare/v1.1.3...v1.1.4) (2022-04-20) + + +### Bug Fixes + +* automatically set nullzero when there is default:value option ([72c44ae](https://github.com/uptrace/bun/commit/72c44aebbeec3a83ed97ea25a3262174d744df65)) +* fix ForceDelete on live/undeleted rows ([1a33250](https://github.com/uptrace/bun/commit/1a33250f27f00e752a735ce10311ac95dcb0c968)) +* fix OmitZero and value overriding ([087ea07](https://github.com/uptrace/bun/commit/087ea0730551f1e841bacb6ad2fa3afd512a1df8)) +* rename Query to QueryBuilder ([98d111b](https://github.com/uptrace/bun/commit/98d111b7cc00fa61b6b2cec147f43285f4baadb4)) ### Features -* added QueryBuilder interface for SelectQuery, UpdateQuery, DeleteQuery ([#499](https://github.com/uptrace/bun/issues/499)) ([59fef48](https://github.com/uptrace/bun/commit/59fef48f6b3ec7f32bdda779b6693c333ff1dfdb)) +* add ApplyQueryBuilder ([582eca0](https://github.com/uptrace/bun/commit/582eca09cf2b59e67c2e4a2ad24f1a74cb53addd)) +* **config.go:** add connect_timeout to DSN parsable params ([998b04d](https://github.com/uptrace/bun/commit/998b04d51a9a4f182ac3458f90db8dbf9185c4ba)), closes [#505](https://github.com/uptrace/bun/issues/505) + + + +# [1.1.3](https://github.com/uptrace/bun/compare/v1.1.2...v) (2022-03-29) +### Bug Fixes + +- fix panic message when has-many encounter an error + ([cfd2747](https://github.com/uptrace/bun/commit/cfd27475fac89a1c8cf798bfa64898bd77bbba79)) +- **migrate:** change rollback to match migrate behavior + ([df5af9c](https://github.com/uptrace/bun/commit/df5af9c9cbdf54ce243e037bbb2c7b154f8422b3)) + +### Features +- added QueryBuilder interface for SelectQuery, UpdateQuery, DeleteQuery + ([#499](https://github.com/uptrace/bun/issues/499)) + ([59fef48](https://github.com/uptrace/bun/commit/59fef48f6b3ec7f32bdda779b6693c333ff1dfdb)) # [1.1.2](https://github.com/uptrace/bun/compare/v1.1.2...v) (2022-03-22) diff --git a/vendor/github.com/uptrace/bun/README.md b/vendor/github.com/uptrace/bun/README.md index 0e23122c7..0d1c2c6c2 100644 --- a/vendor/github.com/uptrace/bun/README.md +++ b/vendor/github.com/uptrace/bun/README.md @@ -1,13 +1,14 @@ -# SQL-first Go ORM for PostgreSQL, MySQL, MSSQL, and SQLite +# SQL-first Golang ORM for PostgreSQL, MySQL, MSSQL, and SQLite [](https://github.com/uptrace/bun/actions) [](https://pkg.go.dev/github.com/uptrace/bun) [](https://bun.uptrace.dev/) [](https://discord.gg/rWtp5Aj) -Bun is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace). Uptrace -is an open source and blazingly fast **distributed tracing** backend powered by OpenTelemetry and -ClickHouse. Give it a star as well! +> Bun is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace). Uptrace +> is an open source and blazingly fast +> [distributed tracing tool](https://get.uptrace.dev/compare/distributed-tracing-tools.html) powered +> by OpenTelemetry and ClickHouse. Give it a star as well! ## Features @@ -26,7 +27,7 @@ ClickHouse. Give it a star as well! Resources: -- [**Get started**](https://bun.uptrace.dev/guide/getting-started.html) +- [**Get started**](https://bun.uptrace.dev/guide/golang-orm.html) - [Examples](https://github.com/uptrace/bun/tree/master/example) - [Discussions](https://github.com/uptrace/bun/discussions) - [Chat](https://discord.gg/rWtp5Aj) @@ -253,7 +254,7 @@ topRegions := db.NewSelect(). TableExpr("regional_sales"). Where("total_sales > (SELECT SUM(total_sales) / 10 FROM regional_sales)") -var items map[string]interface{} +var items []map[string]interface{} err := db.NewSelect(). With("regional_sales", regionalSales). With("top_regions", topRegions). @@ -301,9 +302,15 @@ if err := db.NewSelect().Model(user1).Where("id = ?", 1).Scan(ctx); err != nil { } ``` -See [**Getting started**](https://bun.uptrace.dev/guide/getting-started.html) guide and check +See [**Getting started**](https://bun.uptrace.dev/guide/golang-orm.html) guide and check [examples](example). +## See also + +- [Golang HTTP router](https://github.com/uptrace/bunrouter) +- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse) +- [Golang msgpack](https://github.com/vmihailenco/msgpack) + ## Contributors Thanks to all the people who already contributed! diff --git a/vendor/github.com/uptrace/bun/db.go b/vendor/github.com/uptrace/bun/db.go index 78969c019..47e654655 100644 --- a/vendor/github.com/uptrace/bun/db.go +++ b/vendor/github.com/uptrace/bun/db.go @@ -2,7 +2,9 @@ package bun import ( "context" + "crypto/rand" "database/sql" + "encoding/hex" "fmt" "reflect" "strings" @@ -141,13 +143,19 @@ func (db *DB) Dialect() schema.Dialect { } func (db *DB) ScanRows(ctx context.Context, rows *sql.Rows, dest ...interface{}) error { + defer rows.Close() + model, err := newModel(db, dest) if err != nil { return err } _, err = model.ScanRows(ctx, rows) - return err + if err != nil { + return err + } + + return rows.Err() } func (db *DB) ScanRow(ctx context.Context, rows *sql.Rows, dest ...interface{}) error { @@ -362,6 +370,46 @@ func (c Conn) NewDropColumn() *DropColumnQuery { return NewDropColumnQuery(c.db).Conn(c) } +// RunInTx runs the function in a transaction. If the function returns an error, +// the transaction is rolled back. Otherwise, the transaction is committed. +func (c Conn) RunInTx( + ctx context.Context, opts *sql.TxOptions, fn func(ctx context.Context, tx Tx) error, +) error { + tx, err := c.BeginTx(ctx, opts) + if err != nil { + return err + } + + var done bool + + defer func() { + if !done { + _ = tx.Rollback() + } + }() + + if err := fn(ctx, tx); err != nil { + return err + } + + done = true + return tx.Commit() +} + +func (c Conn) BeginTx(ctx context.Context, opts *sql.TxOptions) (Tx, error) { + ctx, event := c.db.beforeQuery(ctx, nil, "BEGIN", nil, "BEGIN", nil) + tx, err := c.Conn.BeginTx(ctx, opts) + c.db.afterQuery(ctx, event, nil, err) + if err != nil { + return Tx{}, err + } + return Tx{ + ctx: ctx, + db: c.db, + Tx: tx, + }, nil +} + //------------------------------------------------------------------------------ type Stmt struct { @@ -385,6 +433,8 @@ func (db *DB) PrepareContext(ctx context.Context, query string) (Stmt, error) { type Tx struct { ctx context.Context db *DB + // name is the name of a savepoint + name string *sql.Tx } @@ -433,19 +483,51 @@ func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (Tx, error) { } func (tx Tx) Commit() error { + if tx.name == "" { + return tx.commitTX() + } + return tx.commitSP() +} + +func (tx Tx) commitTX() error { ctx, event := tx.db.beforeQuery(tx.ctx, nil, "COMMIT", nil, "COMMIT", nil) err := tx.Tx.Commit() tx.db.afterQuery(ctx, event, nil, err) return err } +func (tx Tx) commitSP() error { + if tx.Dialect().Features().Has(feature.MSSavepoint) { + return nil + } + query := "RELEASE SAVEPOINT " + tx.name + _, err := tx.ExecContext(tx.ctx, query) + return err +} + func (tx Tx) Rollback() error { + if tx.name == "" { + return tx.rollbackTX() + } + return tx.rollbackSP() +} + +func (tx Tx) rollbackTX() error { ctx, event := tx.db.beforeQuery(tx.ctx, nil, "ROLLBACK", nil, "ROLLBACK", nil) err := tx.Tx.Rollback() tx.db.afterQuery(ctx, event, nil, err) return err } +func (tx Tx) rollbackSP() error { + query := "ROLLBACK TO SAVEPOINT " + tx.name + if tx.Dialect().Features().Has(feature.MSSavepoint) { + query = "ROLLBACK TRANSACTION " + tx.name + } + _, err := tx.ExecContext(tx.ctx, query) + return err +} + func (tx Tx) Exec(query string, args ...interface{}) (sql.Result, error) { return tx.ExecContext(context.TODO(), query, args...) } @@ -488,6 +570,60 @@ func (tx Tx) QueryRowContext(ctx context.Context, query string, args ...interfac //------------------------------------------------------------------------------ +func (tx Tx) Begin() (Tx, error) { + return tx.BeginTx(tx.ctx, nil) +} + +// BeginTx will save a point in the running transaction. +func (tx Tx) BeginTx(ctx context.Context, _ *sql.TxOptions) (Tx, error) { + // mssql savepoint names are limited to 32 characters + sp := make([]byte, 14) + _, err := rand.Read(sp) + if err != nil { + return Tx{}, err + } + + qName := "SP_" + hex.EncodeToString(sp) + query := "SAVEPOINT " + qName + if tx.Dialect().Features().Has(feature.MSSavepoint) { + query = "SAVE TRANSACTION " + qName + } + _, err = tx.ExecContext(ctx, query) + if err != nil { + return Tx{}, err + } + return Tx{ + ctx: ctx, + db: tx.db, + Tx: tx.Tx, + name: qName, + }, nil +} + +func (tx Tx) RunInTx( + ctx context.Context, _ *sql.TxOptions, fn func(ctx context.Context, tx Tx) error, +) error { + sp, err := tx.BeginTx(ctx, nil) + if err != nil { + return err + } + + var done bool + + defer func() { + if !done { + _ = sp.Rollback() + } + }() + + if err := fn(ctx, sp); err != nil { + return err + } + + done = true + return sp.Commit() +} + func (tx Tx) Dialect() schema.Dialect { return tx.db.Dialect() } diff --git a/vendor/github.com/uptrace/bun/dialect/feature/feature.go b/vendor/github.com/uptrace/bun/dialect/feature/feature.go index 510d6e5de..956dc4985 100644 --- a/vendor/github.com/uptrace/bun/dialect/feature/feature.go +++ b/vendor/github.com/uptrace/bun/dialect/feature/feature.go @@ -29,4 +29,6 @@ const ( OffsetFetch SelectExists UpdateFromTable + MSSavepoint + GeneratedIdentity ) diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/append.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/append.go index d5e0d0a57..a60bf5de2 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/append.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/append.go @@ -307,3 +307,58 @@ func arrayAppendString(b []byte, s string) []byte { b = append(b, '"') return b } + +//------------------------------------------------------------------------------ + +var mapStringStringType = reflect.TypeOf(map[string]string(nil)) + +func (d *Dialect) hstoreAppender(typ reflect.Type) schema.AppenderFunc { + kind := typ.Kind() + + switch kind { + case reflect.Ptr: + if fn := d.hstoreAppender(typ.Elem()); fn != nil { + return schema.PtrAppender(fn) + } + case reflect.Map: + // ok: + default: + return nil + } + + if typ.Key() == stringType && typ.Elem() == stringType { + return appendMapStringStringValue + } + + return func(fmter schema.Formatter, b []byte, v reflect.Value) []byte { + err := fmt.Errorf("bun: Hstore(unsupported %s)", v.Type()) + return dialect.AppendError(b, err) + } +} + +func appendMapStringString(b []byte, m map[string]string) []byte { + if m == nil { + return dialect.AppendNull(b) + } + + b = append(b, '\'') + + for key, value := range m { + b = arrayAppendString(b, key) + b = append(b, '=', '>') + b = arrayAppendString(b, value) + b = append(b, ',') + } + if len(m) > 0 { + b = b[:len(b)-1] // Strip trailing comma. + } + + b = append(b, '\'') + + return b +} + +func appendMapStringStringValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte { + m := v.Convert(mapStringStringType).Interface().(map[string]string) + return appendMapStringString(b, m) +} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/array_parser.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/array_parser.go index 0dff754f8..a8358337e 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/array_parser.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/array_parser.go @@ -8,17 +8,13 @@ import ( ) type arrayParser struct { - b []byte - i int - - buf []byte + *streamParser err error } func newArrayParser(b []byte) *arrayParser { p := &arrayParser{ - b: b, - i: 1, + streamParser: newStreamParser(b, 1), } if len(b) < 2 || b[0] != '{' || b[len(b)-1] != '}' { p.err = fmt.Errorf("bun: can't parse array: %q", b) @@ -135,31 +131,3 @@ func (p *arrayParser) readSubstring() ([]byte, error) { return p.buf, nil } - -func (p *arrayParser) valid() bool { - return p.i < len(p.b) -} - -func (p *arrayParser) readByte() (byte, error) { - if p.valid() { - c := p.b[p.i] - p.i++ - return c, nil - } - return 0, io.EOF -} - -func (p *arrayParser) unreadByte() { - p.i-- -} - -func (p *arrayParser) peek() byte { - if p.valid() { - return p.b[p.i] - } - return 0 -} - -func (p *arrayParser) skipNext() { - p.i++ -} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/dialect.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/dialect.go index 852132b7f..d524f0a1a 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/dialect.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/dialect.go @@ -46,7 +46,8 @@ func New() *Dialect { feature.TableTruncate | feature.TableNotExists | feature.InsertOnConflict | - feature.SelectExists + feature.SelectExists | + feature.GeneratedIdentity return d } @@ -73,7 +74,7 @@ func (d *Dialect) OnTable(table *schema.Table) { func (d *Dialect) onField(field *schema.Field) { field.DiscoveredSQLType = fieldSQLType(field) - if field.AutoIncrement { + if field.AutoIncrement && !field.Identity { switch field.DiscoveredSQLType { case sqltype.SmallInt: field.CreateTableSQLType = pgTypeSmallSerial @@ -88,6 +89,11 @@ func (d *Dialect) onField(field *schema.Field) { field.Append = d.arrayAppender(field.StructField.Type) field.Scan = arrayScanner(field.StructField.Type) } + + if field.DiscoveredSQLType == sqltype.HSTORE { + field.Append = d.hstoreAppender(field.StructField.Type) + field.Scan = hstoreScanner(field.StructField.Type) + } } func (d *Dialect) IdentQuote() byte { diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore.go new file mode 100644 index 000000000..029f7cb6d --- /dev/null +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore.go @@ -0,0 +1,73 @@ +package pgdialect + +import ( + "database/sql" + "fmt" + "reflect" + + "github.com/uptrace/bun/schema" +) + +type HStoreValue struct { + v reflect.Value + + append schema.AppenderFunc + scan schema.ScannerFunc +} + +// HStore accepts a map[string]string and returns a wrapper for working with PostgreSQL +// hstore data type. +// +// For struct fields you can use hstore tag: +// +// Attrs map[string]string `bun:",hstore"` +func HStore(vi interface{}) *HStoreValue { + v := reflect.ValueOf(vi) + if !v.IsValid() { + panic(fmt.Errorf("bun: HStore(nil)")) + } + + typ := v.Type() + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + if typ.Kind() != reflect.Map { + panic(fmt.Errorf("bun: Hstore(unsupported %s)", typ)) + } + + return &HStoreValue{ + v: v, + + append: pgDialect.hstoreAppender(v.Type()), + scan: hstoreScanner(v.Type()), + } +} + +var ( + _ schema.QueryAppender = (*HStoreValue)(nil) + _ sql.Scanner = (*HStoreValue)(nil) +) + +func (h *HStoreValue) AppendQuery(fmter schema.Formatter, b []byte) ([]byte, error) { + if h.append == nil { + panic(fmt.Errorf("bun: HStore(unsupported %s)", h.v.Type())) + } + return h.append(fmter, b, h.v), nil +} + +func (h *HStoreValue) Scan(src interface{}) error { + if h.scan == nil { + return fmt.Errorf("bun: HStore(unsupported %s)", h.v.Type()) + } + if h.v.Kind() != reflect.Ptr { + return fmt.Errorf("bun: HStore(non-pointer %s)", h.v.Type()) + } + return h.scan(h.v.Elem(), src) +} + +func (h *HStoreValue) Value() interface{} { + if h.v.IsValid() { + return h.v.Interface() + } + return nil +} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_parser.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_parser.go new file mode 100644 index 000000000..7a18b50b1 --- /dev/null +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_parser.go @@ -0,0 +1,142 @@ +package pgdialect + +import ( + "bytes" + "fmt" +) + +type hstoreParser struct { + *streamParser + err error +} + +func newHStoreParser(b []byte) *hstoreParser { + p := &hstoreParser{ + streamParser: newStreamParser(b, 0), + } + if len(b) < 6 || b[0] != '"' { + p.err = fmt.Errorf("bun: can't parse hstore: %q", b) + } + return p +} + +func (p *hstoreParser) NextKey() (string, error) { + if p.err != nil { + return "", p.err + } + + err := p.skipByte('"') + if err != nil { + return "", err + } + + key, err := p.readSubstring() + if err != nil { + return "", err + } + + const separator = "=>" + + for i := range separator { + err = p.skipByte(separator[i]) + if err != nil { + return "", err + } + } + + return string(key), nil +} + +func (p *hstoreParser) NextValue() (string, error) { + if p.err != nil { + return "", p.err + } + + c, err := p.readByte() + if err != nil { + return "", err + } + + switch c { + case '"': + value, err := p.readSubstring() + if err != nil { + return "", err + } + + if p.peek() == ',' { + p.skipNext() + } + + if p.peek() == ' ' { + p.skipNext() + } + + return string(value), nil + default: + value := p.readSimple() + if bytes.Equal(value, []byte("NULL")) { + value = nil + } + + if p.peek() == ',' { + p.skipNext() + } + + return string(value), nil + } +} + +func (p *hstoreParser) readSimple() []byte { + p.unreadByte() + + if i := bytes.IndexByte(p.b[p.i:], ','); i >= 0 { + b := p.b[p.i : p.i+i] + p.i += i + return b + } + + b := p.b[p.i:len(p.b)] + p.i = len(p.b) + return b +} + +func (p *hstoreParser) readSubstring() ([]byte, error) { + c, err := p.readByte() + if err != nil { + return nil, err + } + + p.buf = p.buf[:0] + for { + if c == '"' { + break + } + + next, err := p.readByte() + if err != nil { + return nil, err + } + + if c == '\\' { + switch next { + case '\\', '"': + p.buf = append(p.buf, next) + + c, err = p.readByte() + if err != nil { + return nil, err + } + default: + p.buf = append(p.buf, '\\') + c = next + } + continue + } + + p.buf = append(p.buf, c) + c = next + } + + return p.buf, nil +} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_scan.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_scan.go new file mode 100644 index 000000000..b10b06b8d --- /dev/null +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_scan.go @@ -0,0 +1,82 @@ +package pgdialect + +import ( + "fmt" + "io" + "reflect" + + "github.com/uptrace/bun/schema" +) + +func hstoreScanner(typ reflect.Type) schema.ScannerFunc { + kind := typ.Kind() + + switch kind { + case reflect.Ptr: + if fn := hstoreScanner(typ.Elem()); fn != nil { + return schema.PtrScanner(fn) + } + case reflect.Map: + // ok: + default: + return nil + } + + if typ.Key() == stringType && typ.Elem() == stringType { + return scanMapStringStringValue + } + return func(dest reflect.Value, src interface{}) error { + return fmt.Errorf("bun: Hstore(unsupported %s)", dest.Type()) + } +} + +func scanMapStringStringValue(dest reflect.Value, src interface{}) error { + dest = reflect.Indirect(dest) + if !dest.CanSet() { + return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) + } + + m, err := decodeMapStringString(src) + if err != nil { + return err + } + + dest.Set(reflect.ValueOf(m)) + return nil +} + +func decodeMapStringString(src interface{}) (map[string]string, error) { + if src == nil { + return nil, nil + } + + b, err := toBytes(src) + if err != nil { + return nil, err + } + + m := make(map[string]string) + + p := newHStoreParser(b) + for { + key, err := p.NextKey() + if err != nil { + if err == io.EOF { + break + } + return nil, err + } + + value, err := p.NextValue() + if err != nil { + if err == io.EOF { + break + } + return nil, err + } + + m[key] = value + } + + return m, nil +} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/sqltype.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/sqltype.go index bfef89fa1..6c6294d71 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/sqltype.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/sqltype.go @@ -53,11 +53,11 @@ func fieldSQLType(field *schema.Field) string { if v, ok := field.Tag.Option("composite"); ok { return v } - if _, ok := field.Tag.Option("hstore"); ok { - return "hstore" + if field.Tag.HasOption("hstore") { + return sqltype.HSTORE } - if _, ok := field.Tag.Options["array"]; ok { + if field.Tag.HasOption("array") { switch field.IndirectType.Kind() { case reflect.Slice, reflect.Array: sqlType := sqlType(field.IndirectType.Elem()) diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/stream_parser.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/stream_parser.go new file mode 100644 index 000000000..7b9a15f62 --- /dev/null +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/stream_parser.go @@ -0,0 +1,60 @@ +package pgdialect + +import ( + "fmt" + "io" +) + +type streamParser struct { + b []byte + i int + + buf []byte +} + +func newStreamParser(b []byte, start int) *streamParser { + return &streamParser{ + b: b, + i: start, + } +} + +func (p *streamParser) valid() bool { + return p.i < len(p.b) +} + +func (p *streamParser) skipByte(skip byte) error { + c, err := p.readByte() + if err != nil { + return err + } + if c == skip { + return nil + } + p.unreadByte() + return fmt.Errorf("got %q, wanted %q", c, skip) +} + +func (p *streamParser) readByte() (byte, error) { + if p.valid() { + c := p.b[p.i] + p.i++ + return c, nil + } + return 0, io.EOF +} + +func (p *streamParser) unreadByte() { + p.i-- +} + +func (p *streamParser) peek() byte { + if p.valid() { + return p.b[p.i] + } + return 0 +} + +func (p *streamParser) skipNext() { + p.i++ +} diff --git a/vendor/github.com/uptrace/bun/dialect/pgdialect/version.go b/vendor/github.com/uptrace/bun/dialect/pgdialect/version.go index a3adb36aa..8ab18b7a7 100644 --- a/vendor/github.com/uptrace/bun/dialect/pgdialect/version.go +++ b/vendor/github.com/uptrace/bun/dialect/pgdialect/version.go @@ -2,5 +2,5 @@ package pgdialect // Version is the current release version. func Version() string { - return "1.1.3" + return "1.1.7" } diff --git a/vendor/github.com/uptrace/bun/dialect/sqlitedialect/version.go b/vendor/github.com/uptrace/bun/dialect/sqlitedialect/version.go index 76a755a86..8f9def8d0 100644 --- a/vendor/github.com/uptrace/bun/dialect/sqlitedialect/version.go +++ b/vendor/github.com/uptrace/bun/dialect/sqlitedialect/version.go @@ -2,5 +2,5 @@ package sqlitedialect // Version is the current release version. func Version() string { - return "1.1.3" + return "1.1.7" } diff --git a/vendor/github.com/uptrace/bun/dialect/sqltype/sqltype.go b/vendor/github.com/uptrace/bun/dialect/sqltype/sqltype.go index f58b2f1d1..1031fd352 100644 --- a/vendor/github.com/uptrace/bun/dialect/sqltype/sqltype.go +++ b/vendor/github.com/uptrace/bun/dialect/sqltype/sqltype.go @@ -12,4 +12,5 @@ const ( Timestamp = "TIMESTAMP" JSON = "JSON" JSONB = "JSONB" + HSTORE = "HSTORE" ) diff --git a/vendor/github.com/uptrace/bun/migrate/migration.go b/vendor/github.com/uptrace/bun/migrate/migration.go index 05bd6006c..ae649446d 100644 --- a/vendor/github.com/uptrace/bun/migrate/migration.go +++ b/vendor/github.com/uptrace/bun/migrate/migration.go @@ -25,11 +25,11 @@ type Migration struct { Down MigrationFunc `bun:"-"` } -func (m *Migration) String() string { +func (m Migration) String() string { return m.Name } -func (m *Migration) IsApplied() bool { +func (m Migration) IsApplied() bool { return m.ID > 0 } @@ -89,6 +89,22 @@ func NewSQLMigrationFunc(fsys fs.FS, name string) MigrationFunc { idb = conn } + var retErr error + + defer func() { + if tx, ok := idb.(bun.Tx); ok { + retErr = tx.Commit() + return + } + + if conn, ok := idb.(bun.Conn); ok { + retErr = conn.Close() + return + } + + panic("not reached") + }() + for _, q := range queries { _, err = idb.ExecContext(ctx, q) if err != nil { @@ -96,13 +112,7 @@ func NewSQLMigrationFunc(fsys fs.FS, name string) MigrationFunc { } } - if tx, ok := idb.(bun.Tx); ok { - return tx.Commit() - } else if conn, ok := idb.(bun.Conn); ok { - return conn.Close() - } - - panic("not reached") + return retErr } } @@ -222,11 +232,11 @@ type MigrationGroup struct { Migrations MigrationSlice } -func (g *MigrationGroup) IsZero() bool { +func (g MigrationGroup) IsZero() bool { return g.ID == 0 && len(g.Migrations) == 0 } -func (g *MigrationGroup) String() string { +func (g MigrationGroup) String() string { if g.IsZero() { return "nil" } diff --git a/vendor/github.com/uptrace/bun/migrate/migrator.go b/vendor/github.com/uptrace/bun/migrate/migrator.go index e271b7a06..d0efca2fc 100644 --- a/vendor/github.com/uptrace/bun/migrate/migrator.go +++ b/vendor/github.com/uptrace/bun/migrate/migrator.go @@ -26,14 +26,23 @@ func WithLocksTableName(table string) MigratorOption { } } +// WithMarkAppliedOnSuccess sets the migrator to only mark migrations as applied/unapplied +// when their up/down is successful +func WithMarkAppliedOnSuccess(enabled bool) MigratorOption { + return func(m *Migrator) { + m.markAppliedOnSuccess = enabled + } +} + type Migrator struct { db *bun.DB migrations *Migrations ms MigrationSlice - table string - locksTable string + table string + locksTable string + markAppliedOnSuccess bool } func NewMigrator(db *bun.DB, migrations *Migrations, opts ...MigratorOption) *Migrator { @@ -148,9 +157,10 @@ func (m *Migrator) Migrate(ctx context.Context, opts ...MigrationOption) (*Migra migration := &migrations[i] migration.GroupID = group.ID - // Always mark migration as applied so the rollback has a chance to fix the database. - if err := m.MarkApplied(ctx, migration); err != nil { - return group, err + if !m.markAppliedOnSuccess { + if err := m.MarkApplied(ctx, migration); err != nil { + return group, err + } } group.Migrations = migrations[:i+1] @@ -160,6 +170,12 @@ func (m *Migrator) Migrate(ctx context.Context, opts ...MigrationOption) (*Migra return group, err } } + + if m.markAppliedOnSuccess { + if err := m.MarkApplied(ctx, migration); err != nil { + return group, err + } + } } return group, nil @@ -187,14 +203,21 @@ func (m *Migrator) Rollback(ctx context.Context, opts ...MigrationOption) (*Migr for i := len(lastGroup.Migrations) - 1; i >= 0; i-- { migration := &lastGroup.Migrations[i] - // Always mark migration as unapplied to match migrate behavior. - if err := m.MarkUnapplied(ctx, migration); err != nil { - return nil, err + if !m.markAppliedOnSuccess { + if err := m.MarkUnapplied(ctx, migration); err != nil { + return lastGroup, err + } } if !cfg.nop && migration.Down != nil { if err := migration.Down(ctx, m.db); err != nil { - return nil, err + return lastGroup, err + } + } + + if m.markAppliedOnSuccess { + if err := m.MarkUnapplied(ctx, migration); err != nil { + return lastGroup, err } } } diff --git a/vendor/github.com/uptrace/bun/package.json b/vendor/github.com/uptrace/bun/package.json index 8bef15e54..9428ddcd5 100644 --- a/vendor/github.com/uptrace/bun/package.json +++ b/vendor/github.com/uptrace/bun/package.json @@ -1,6 +1,6 @@ { - "name": "uptrace/bun", - "version": "1.1.3", + "name": "gobun", + "version": "1.1.7", "main": "index.js", "repository": "git@github.com:uptrace/bun.git", "author": "Vladimir Mihailenco <vladimir.webdev@gmail.com>", diff --git a/vendor/github.com/uptrace/bun/query_base.go b/vendor/github.com/uptrace/bun/query_base.go index 147a8fbd3..45b77f028 100644 --- a/vendor/github.com/uptrace/bun/query_base.go +++ b/vendor/github.com/uptrace/bun/query_base.go @@ -57,6 +57,9 @@ type IDB interface { NewTruncateTable() *TruncateTableQuery NewAddColumn() *AddColumnQuery NewDropColumn() *DropColumnQuery + + BeginTx(ctx context.Context, opts *sql.TxOptions) (Tx, error) + RunInTx(ctx context.Context, opts *sql.TxOptions, f func(ctx context.Context, tx Tx) error) error } var ( @@ -227,13 +230,14 @@ func (q *baseQuery) whereAllWithDeleted() { q.setErr(err) return } - q.flags = q.flags.Set(allWithDeletedFlag) - q.flags = q.flags.Remove(deletedFlag) + q.flags = q.flags.Set(allWithDeletedFlag).Remove(deletedFlag) } func (q *baseQuery) isSoftDelete() bool { if q.table != nil { - return q.table.SoftDeleteField != nil && !q.flags.Has(allWithDeletedFlag) + return q.table.SoftDeleteField != nil && + !q.flags.Has(allWithDeletedFlag) && + !q.flags.Has(forceDeleteFlag) } return false } @@ -1095,3 +1099,235 @@ func (q cascadeQuery) appendCascade(fmter schema.Formatter, b []byte) []byte { } return b } + +//------------------------------------------------------------------------------ + +type idxHintsQuery struct { + use *indexHints + ignore *indexHints + force *indexHints +} + +type indexHints struct { + names []schema.QueryWithArgs + forJoin []schema.QueryWithArgs + forOrderBy []schema.QueryWithArgs + forGroupBy []schema.QueryWithArgs +} + +func (ih *idxHintsQuery) lazyUse() *indexHints { + if ih.use == nil { + ih.use = new(indexHints) + } + return ih.use +} + +func (ih *idxHintsQuery) lazyIgnore() *indexHints { + if ih.ignore == nil { + ih.ignore = new(indexHints) + } + return ih.ignore +} + +func (ih *idxHintsQuery) lazyForce() *indexHints { + if ih.force == nil { + ih.force = new(indexHints) + } + return ih.force +} + +func (ih *idxHintsQuery) appendIndexes(hints []schema.QueryWithArgs, indexes ...string) []schema.QueryWithArgs { + for _, idx := range indexes { + hints = append(hints, schema.UnsafeIdent(idx)) + } + return hints +} + +func (ih *idxHintsQuery) addUseIndex(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyUse().names = ih.appendIndexes(ih.use.names, indexes...) +} + +func (ih *idxHintsQuery) addUseIndexForJoin(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyUse().forJoin = ih.appendIndexes(ih.use.forJoin, indexes...) +} + +func (ih *idxHintsQuery) addUseIndexForOrderBy(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyUse().forOrderBy = ih.appendIndexes(ih.use.forOrderBy, indexes...) +} + +func (ih *idxHintsQuery) addUseIndexForGroupBy(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyUse().forGroupBy = ih.appendIndexes(ih.use.forGroupBy, indexes...) +} + +func (ih *idxHintsQuery) addIgnoreIndex(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyIgnore().names = ih.appendIndexes(ih.ignore.names, indexes...) +} + +func (ih *idxHintsQuery) addIgnoreIndexForJoin(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyIgnore().forJoin = ih.appendIndexes(ih.ignore.forJoin, indexes...) +} + +func (ih *idxHintsQuery) addIgnoreIndexForOrderBy(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyIgnore().forOrderBy = ih.appendIndexes(ih.ignore.forOrderBy, indexes...) +} + +func (ih *idxHintsQuery) addIgnoreIndexForGroupBy(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyIgnore().forGroupBy = ih.appendIndexes(ih.ignore.forGroupBy, indexes...) +} + +func (ih *idxHintsQuery) addForceIndex(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyForce().names = ih.appendIndexes(ih.force.names, indexes...) +} + +func (ih *idxHintsQuery) addForceIndexForJoin(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyForce().forJoin = ih.appendIndexes(ih.force.forJoin, indexes...) +} + +func (ih *idxHintsQuery) addForceIndexForOrderBy(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyForce().forOrderBy = ih.appendIndexes(ih.force.forOrderBy, indexes...) +} + +func (ih *idxHintsQuery) addForceIndexForGroupBy(indexes ...string) { + if len(indexes) == 0 { + return + } + ih.lazyForce().forGroupBy = ih.appendIndexes(ih.force.forGroupBy, indexes...) +} + +func (ih *idxHintsQuery) appendIndexHints( + fmter schema.Formatter, b []byte, +) ([]byte, error) { + type IdxHint struct { + Name string + Values []schema.QueryWithArgs + } + + var hints []IdxHint + if ih.use != nil { + hints = append(hints, []IdxHint{ + { + Name: "USE INDEX", + Values: ih.use.names, + }, + { + Name: "USE INDEX FOR JOIN", + Values: ih.use.forJoin, + }, + { + Name: "USE INDEX FOR ORDER BY", + Values: ih.use.forOrderBy, + }, + { + Name: "USE INDEX FOR GROUP BY", + Values: ih.use.forGroupBy, + }, + }...) + } + + if ih.ignore != nil { + hints = append(hints, []IdxHint{ + { + Name: "IGNORE INDEX", + Values: ih.ignore.names, + }, + { + Name: "IGNORE INDEX FOR JOIN", + Values: ih.ignore.forJoin, + }, + { + Name: "IGNORE INDEX FOR ORDER BY", + Values: ih.ignore.forOrderBy, + }, + { + Name: "IGNORE INDEX FOR GROUP BY", + Values: ih.ignore.forGroupBy, + }, + }...) + } + + if ih.force != nil { + hints = append(hints, []IdxHint{ + { + Name: "FORCE INDEX", + Values: ih.force.names, + }, + { + Name: "FORCE INDEX FOR JOIN", + Values: ih.force.forJoin, + }, + { + Name: "FORCE INDEX FOR ORDER BY", + Values: ih.force.forOrderBy, + }, + { + Name: "FORCE INDEX FOR GROUP BY", + Values: ih.force.forGroupBy, + }, + }...) + } + + var err error + for _, h := range hints { + b, err = ih.bufIndexHint(h.Name, h.Values, fmter, b) + if err != nil { + return nil, err + } + } + return b, nil +} + +func (ih *idxHintsQuery) bufIndexHint( + name string, + hints []schema.QueryWithArgs, + fmter schema.Formatter, b []byte, +) ([]byte, error) { + var err error + if len(hints) == 0 { + return b, nil + } + b = append(b, fmt.Sprintf(" %s (", name)...) + for i, f := range hints { + if i > 0 { + b = append(b, ", "...) + } + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + b = append(b, ")"...) + return b, nil +} diff --git a/vendor/github.com/uptrace/bun/query_delete.go b/vendor/github.com/uptrace/bun/query_delete.go index c5f3d7103..5899c9ba6 100644 --- a/vendor/github.com/uptrace/bun/query_delete.go +++ b/vendor/github.com/uptrace/bun/query_delete.go @@ -287,12 +287,32 @@ func (q *DeleteQuery) afterDeleteHook(ctx context.Context) error { return nil } +func (q *DeleteQuery) String() string { + buf, err := q.AppendQuery(q.db.Formatter(), nil) + if err != nil { + panic(err) + } + + return string(buf) +} + //------------------------------------------------------------------------------ + +func (q *DeleteQuery) QueryBuilder() QueryBuilder { + return &deleteQueryBuilder{q} +} + +func (q *DeleteQuery) ApplyQueryBuilder(fn func(QueryBuilder) QueryBuilder) *DeleteQuery { + return fn(q.QueryBuilder()).Unwrap().(*DeleteQuery) +} + type deleteQueryBuilder struct { *DeleteQuery } -func (q *deleteQueryBuilder) WhereGroup(sep string, fn func(QueryBuilder) QueryBuilder) QueryBuilder { +func (q *deleteQueryBuilder) WhereGroup( + sep string, fn func(QueryBuilder) QueryBuilder, +) QueryBuilder { q.DeleteQuery = q.DeleteQuery.WhereGroup(sep, func(qs *DeleteQuery) *DeleteQuery { return fn(q).(*deleteQueryBuilder).DeleteQuery }) @@ -327,7 +347,3 @@ func (q *deleteQueryBuilder) WherePK(cols ...string) QueryBuilder { func (q *deleteQueryBuilder) Unwrap() interface{} { return q.DeleteQuery } - -func (q *DeleteQuery) Query() QueryBuilder { - return &deleteQueryBuilder{q} -} diff --git a/vendor/github.com/uptrace/bun/query_insert.go b/vendor/github.com/uptrace/bun/query_insert.go index fdbe0c275..073afea47 100644 --- a/vendor/github.com/uptrace/bun/query_insert.go +++ b/vendor/github.com/uptrace/bun/query_insert.go @@ -641,3 +641,12 @@ func (q *InsertQuery) tryLastInsertID(res sql.Result, dest []interface{}) error return nil } + +func (q *InsertQuery) String() string { + buf, err := q.AppendQuery(q.db.Formatter(), nil) + if err != nil { + panic(err) + } + + return string(buf) +} diff --git a/vendor/github.com/uptrace/bun/query_raw.go b/vendor/github.com/uptrace/bun/query_raw.go new file mode 100644 index 000000000..30ae77508 --- /dev/null +++ b/vendor/github.com/uptrace/bun/query_raw.go @@ -0,0 +1,48 @@ +package bun + +import ( + "context" + + "github.com/uptrace/bun/schema" +) + +type RawQuery struct { + baseQuery + + query string + args []interface{} +} + +func (db *DB) Raw(query string, args ...interface{}) *RawQuery { + return &RawQuery{ + baseQuery: baseQuery{ + db: db, + conn: db.DB, + }, + query: query, + args: args, + } +} + +func (q *RawQuery) Scan(ctx context.Context, dest ...interface{}) error { + if q.err != nil { + return q.err + } + + model, err := q.getModel(dest) + if err != nil { + return err + } + + query := q.db.format(q.query, q.args) + _, err = q.scan(ctx, q, query, model, true) + return err +} + +func (q *RawQuery) AppendQuery(fmter schema.Formatter, b []byte) ([]byte, error) { + return fmter.AppendQuery(b, q.query, q.args...), nil +} + +func (q *RawQuery) Operation() string { + return "SELECT" +} diff --git a/vendor/github.com/uptrace/bun/query_select.go b/vendor/github.com/uptrace/bun/query_select.go index 56ba310e5..b61bcfaf0 100644 --- a/vendor/github.com/uptrace/bun/query_select.go +++ b/vendor/github.com/uptrace/bun/query_select.go @@ -10,6 +10,8 @@ import ( "strings" "sync" + "github.com/uptrace/bun/dialect" + "github.com/uptrace/bun/dialect/feature" "github.com/uptrace/bun/internal" "github.com/uptrace/bun/schema" @@ -22,6 +24,7 @@ type union struct { type SelectQuery struct { whereBaseQuery + idxHintsQuery distinctOn []schema.QueryWithArgs joins []joinQuery @@ -159,6 +162,92 @@ func (q *SelectQuery) WhereAllWithDeleted() *SelectQuery { //------------------------------------------------------------------------------ +func (q *SelectQuery) UseIndex(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addUseIndex(indexes...) + } + return q +} + +func (q *SelectQuery) UseIndexForJoin(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addUseIndexForJoin(indexes...) + } + return q +} + +func (q *SelectQuery) UseIndexForOrderBy(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addUseIndexForOrderBy(indexes...) + } + return q +} + +func (q *SelectQuery) UseIndexForGroupBy(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addUseIndexForGroupBy(indexes...) + } + return q +} + +func (q *SelectQuery) IgnoreIndex(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addIgnoreIndex(indexes...) + } + return q +} + +func (q *SelectQuery) IgnoreIndexForJoin(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addIgnoreIndexForJoin(indexes...) + } + return q +} + +func (q *SelectQuery) IgnoreIndexForOrderBy(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addIgnoreIndexForOrderBy(indexes...) + } + return q +} + +func (q *SelectQuery) IgnoreIndexForGroupBy(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addIgnoreIndexForGroupBy(indexes...) + } + return q +} + +func (q *SelectQuery) ForceIndex(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addForceIndex(indexes...) + } + return q +} + +func (q *SelectQuery) ForceIndexForJoin(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addForceIndexForJoin(indexes...) + } + return q +} + +func (q *SelectQuery) ForceIndexForOrderBy(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addForceIndexForOrderBy(indexes...) + } + return q +} + +func (q *SelectQuery) ForceIndexForGroupBy(indexes ...string) *SelectQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addForceIndexForGroupBy(indexes...) + } + return q +} + +//------------------------------------------------------------------------------ + func (q *SelectQuery) Group(columns ...string) *SelectQuery { for _, column := range columns { q.group = append(q.group, schema.UnsafeIdent(column)) @@ -305,8 +394,31 @@ func (q *SelectQuery) Relation(name string, apply ...func(*SelectQuery) *SelectQ return q } + var apply1, apply2 func(*SelectQuery) *SelectQuery + + if len(join.Relation.Condition) > 0 { + apply1 = func(q *SelectQuery) *SelectQuery { + for _, opt := range join.Relation.Condition { + q.addWhere(schema.SafeQueryWithSep(opt, nil, " AND ")) + } + + return q + } + } + if len(apply) == 1 { - join.apply = apply[0] + apply2 = apply[0] + } + + join.apply = func(q *SelectQuery) *SelectQuery { + if apply1 != nil { + q = apply1(q) + } + if apply2 != nil { + q = apply2(q) + } + + return q } return q @@ -441,6 +553,11 @@ func (q *SelectQuery) appendQuery( } } + b, err = q.appendIndexHints(fmter, b) + if err != nil { + return nil, err + } + b, err = q.appendWhere(fmter, b, true) if err != nil { return nil, err @@ -481,7 +598,7 @@ func (q *SelectQuery) appendQuery( } if fmter.Dialect().Features().Has(feature.OffsetFetch) { - if q.offset != 0 { + if q.limit > 0 && q.offset > 0 { b = append(b, " OFFSET "...) b = strconv.AppendInt(b, int64(q.offset), 10) b = append(b, " ROWS"...) @@ -489,13 +606,23 @@ func (q *SelectQuery) appendQuery( b = append(b, " FETCH NEXT "...) b = strconv.AppendInt(b, int64(q.limit), 10) b = append(b, " ROWS ONLY"...) + } else if q.limit > 0 { + b = append(b, " OFFSET 0 ROWS"...) + + b = append(b, " FETCH NEXT "...) + b = strconv.AppendInt(b, int64(q.limit), 10) + b = append(b, " ROWS ONLY"...) + } else if q.offset > 0 { + b = append(b, " OFFSET "...) + b = strconv.AppendInt(b, int64(q.offset), 10) + b = append(b, " ROWS"...) } } else { - if q.limit != 0 { + if q.limit > 0 { b = append(b, " LIMIT "...) b = strconv.AppendInt(b, int64(q.limit), 10) } - if q.offset != 0 { + if q.offset > 0 { b = append(b, " OFFSET "...) b = strconv.AppendInt(b, int64(q.offset), 10) } @@ -920,12 +1047,32 @@ func (q *SelectQuery) whereExists(ctx context.Context) (bool, error) { return n == 1, nil } +func (q *SelectQuery) String() string { + buf, err := q.AppendQuery(q.db.Formatter(), nil) + if err != nil { + panic(err) + } + + return string(buf) +} + //------------------------------------------------------------------------------ + +func (q *SelectQuery) QueryBuilder() QueryBuilder { + return &selectQueryBuilder{q} +} + +func (q *SelectQuery) ApplyQueryBuilder(fn func(QueryBuilder) QueryBuilder) *SelectQuery { + return fn(q.QueryBuilder()).Unwrap().(*SelectQuery) +} + type selectQueryBuilder struct { *SelectQuery } -func (q *selectQueryBuilder) WhereGroup(sep string, fn func(QueryBuilder) QueryBuilder) QueryBuilder { +func (q *selectQueryBuilder) WhereGroup( + sep string, fn func(QueryBuilder) QueryBuilder, +) QueryBuilder { q.SelectQuery = q.SelectQuery.WhereGroup(sep, func(qs *SelectQuery) *SelectQuery { return fn(q).(*selectQueryBuilder).SelectQuery }) @@ -961,10 +1108,6 @@ func (q *selectQueryBuilder) Unwrap() interface{} { return q.SelectQuery } -func (q *SelectQuery) Query() QueryBuilder { - return &selectQueryBuilder{q} -} - //------------------------------------------------------------------------------ type joinQuery struct { diff --git a/vendor/github.com/uptrace/bun/query_table_create.go b/vendor/github.com/uptrace/bun/query_table_create.go index 4aad10070..c795e8a97 100644 --- a/vendor/github.com/uptrace/bun/query_table_create.go +++ b/vendor/github.com/uptrace/bun/query_table_create.go @@ -105,13 +105,16 @@ func (q *CreateTableQuery) TableSpace(tablespace string) *CreateTableQuery { func (q *CreateTableQuery) WithForeignKeys() *CreateTableQuery { for _, relation := range q.tableModel.Table().Relations { if relation.Type == schema.ManyToManyRelation || - relation.Type == schema.HasManyRelation { + relation.Type == schema.HasManyRelation { continue - } - q = q.ForeignKey("(?) REFERENCES ? (?)", + } + + q = q.ForeignKey("(?) REFERENCES ? (?) ? ?", Safe(appendColumns(nil, "", relation.BaseFields)), relation.JoinTable.SQLName, Safe(appendColumns(nil, "", relation.JoinFields)), + Safe(relation.OnUpdate), + Safe(relation.OnDelete), ) } return q @@ -165,6 +168,11 @@ func (q *CreateTableQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []by b = append(b, " IDENTITY"...) } } + if field.Identity { + if fmter.Dialect().Features().Has(feature.GeneratedIdentity) { + b = append(b, " GENERATED BY DEFAULT AS IDENTITY"...) + } + } if field.SQLDefault != "" { b = append(b, " DEFAULT "...) b = append(b, field.SQLDefault...) diff --git a/vendor/github.com/uptrace/bun/query_update.go b/vendor/github.com/uptrace/bun/query_update.go index dbe06799d..b415ff201 100644 --- a/vendor/github.com/uptrace/bun/query_update.go +++ b/vendor/github.com/uptrace/bun/query_update.go @@ -6,6 +6,8 @@ import ( "errors" "fmt" + "github.com/uptrace/bun/dialect" + "github.com/uptrace/bun/dialect/feature" "github.com/uptrace/bun/internal" "github.com/uptrace/bun/schema" @@ -16,6 +18,7 @@ type UpdateQuery struct { returningQuery customValueQuery setQuery + idxHintsQuery omitZero bool } @@ -204,6 +207,11 @@ func (q *UpdateQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, e return nil, err } + b, err = q.appendIndexHints(fmter, b) + if err != nil { + return nil, err + } + b, err = q.mustAppendSet(fmter, b) if err != nil { return nil, err @@ -273,7 +281,13 @@ func (q *UpdateQuery) appendSetStruct( isTemplate := fmter.IsNop() pos := len(b) for _, f := range fields { - if q.omitZero && f.HasZeroValue(model.strct) { + if f.SkipUpdate() { + continue + } + + app, hasValue := q.modelValues[f.Name] + + if !hasValue && q.omitZero && f.HasZeroValue(model.strct) { continue } @@ -290,8 +304,7 @@ func (q *UpdateQuery) appendSetStruct( continue } - app, ok := q.modelValues[f.Name] - if ok { + if hasValue { b, err = app.AppendQuery(fmter, b) if err != nil { return nil, err @@ -487,12 +500,32 @@ func (q *UpdateQuery) hasTableAlias(fmter schema.Formatter) bool { return fmter.HasFeature(feature.UpdateMultiTable | feature.UpdateTableAlias) } +func (q *UpdateQuery) String() string { + buf, err := q.AppendQuery(q.db.Formatter(), nil) + if err != nil { + panic(err) + } + + return string(buf) +} + //------------------------------------------------------------------------------ + +func (q *UpdateQuery) QueryBuilder() QueryBuilder { + return &updateQueryBuilder{q} +} + +func (q *UpdateQuery) ApplyQueryBuilder(fn func(QueryBuilder) QueryBuilder) *UpdateQuery { + return fn(q.QueryBuilder()).Unwrap().(*UpdateQuery) +} + type updateQueryBuilder struct { *UpdateQuery } -func (q *updateQueryBuilder) WhereGroup(sep string, fn func(QueryBuilder) QueryBuilder) QueryBuilder { +func (q *updateQueryBuilder) WhereGroup( + sep string, fn func(QueryBuilder) QueryBuilder, +) QueryBuilder { q.UpdateQuery = q.UpdateQuery.WhereGroup(sep, func(qs *UpdateQuery) *UpdateQuery { return fn(q).(*updateQueryBuilder).UpdateQuery }) @@ -528,6 +561,25 @@ func (q *updateQueryBuilder) Unwrap() interface{} { return q.UpdateQuery } -func (q *UpdateQuery) Query() QueryBuilder { - return &updateQueryBuilder{q} +//------------------------------------------------------------------------------ + +func (q *UpdateQuery) UseIndex(indexes ...string) *UpdateQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addUseIndex(indexes...) + } + return q +} + +func (q *UpdateQuery) IgnoreIndex(indexes ...string) *UpdateQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addIgnoreIndex(indexes...) + } + return q +} + +func (q *UpdateQuery) ForceIndex(indexes ...string) *UpdateQuery { + if q.db.dialect.Name() == dialect.MySQL { + q.addForceIndex(indexes...) + } + return q } diff --git a/vendor/github.com/uptrace/bun/schema/field.go b/vendor/github.com/uptrace/bun/schema/field.go index ac6359da4..283a3b992 100644 --- a/vendor/github.com/uptrace/bun/schema/field.go +++ b/vendor/github.com/uptrace/bun/schema/field.go @@ -32,6 +32,7 @@ type Field struct { NotNull bool NullZero bool AutoIncrement bool + Identity bool Append AppenderFunc Scan ScannerFunc @@ -120,6 +121,10 @@ func (f *Field) ScanValue(strct reflect.Value, src interface{}) error { return f.ScanWithCheck(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 diff --git a/vendor/github.com/uptrace/bun/schema/relation.go b/vendor/github.com/uptrace/bun/schema/relation.go index 8d1baeb3f..6636e26a6 100644 --- a/vendor/github.com/uptrace/bun/schema/relation.go +++ b/vendor/github.com/uptrace/bun/schema/relation.go @@ -18,6 +18,9 @@ type Relation struct { JoinTable *Table BaseFields []*Field JoinFields []*Field + OnUpdate string + OnDelete string + Condition []string PolymorphicField *Field PolymorphicValue string diff --git a/vendor/github.com/uptrace/bun/schema/scan.go b/vendor/github.com/uptrace/bun/schema/scan.go index 069b14e44..96b31caf3 100644 --- a/vendor/github.com/uptrace/bun/schema/scan.go +++ b/vendor/github.com/uptrace/bun/schema/scan.go @@ -449,6 +449,11 @@ func PtrScanner(fn ScannerFunc) ScannerFunc { if dest.IsNil() { dest.Set(reflect.New(dest.Type().Elem())) } + + if dest.Kind() == reflect.Map { + return fn(dest, src) + } + return fn(dest.Elem(), src) } } diff --git a/vendor/github.com/uptrace/bun/schema/table.go b/vendor/github.com/uptrace/bun/schema/table.go index 1a8393fc7..9791f8ff1 100644 --- a/vendor/github.com/uptrace/bun/schema/table.go +++ b/vendor/github.com/uptrace/bun/schema/table.go @@ -353,6 +353,9 @@ func (t *Table) newField(f reflect.StructField, prefix string, index []int) *Fie field.AutoIncrement = true field.NullZero = true } + if tag.HasOption("identity") { + field.Identity = true + } if v, ok := tag.Options["unique"]; ok { var names []string @@ -374,6 +377,7 @@ func (t *Table) newField(f reflect.StructField, prefix string, index []int) *Fie } if s, ok := tag.Option("default"); ok { field.SQLDefault = s + field.NullZero = true } if s, ok := field.Tag.Option("type"); ok { field.UserSQLType = s @@ -478,6 +482,39 @@ func (t *Table) belongsToRelation(field *Field) *Relation { JoinTable: joinTable, } + if field.Tag.HasOption("join_on") { + rel.Condition = field.Tag.Options["join_on"] + } + + rel.OnUpdate = "ON UPDATE NO ACTION" + if onUpdate, ok := field.Tag.Options["on_update"]; ok { + if len(onUpdate) > 1 { + panic(fmt.Errorf("bun: %s belongs-to %s: on_update option must be a single field", t.TypeName, field.GoName)) + } + + rule := strings.ToUpper(onUpdate[0]) + if !isKnownFKRule(rule) { + internal.Warn.Printf("bun: %s belongs-to %s: unknown on_update rule %s", t.TypeName, field.GoName, rule) + } + + s := fmt.Sprintf("ON UPDATE %s", rule) + rel.OnUpdate = s + } + + rel.OnDelete = "ON DELETE NO ACTION" + if onDelete, ok := field.Tag.Options["on_delete"]; ok { + if len(onDelete) > 1 { + panic(fmt.Errorf("bun: %s belongs-to %s: on_delete option must be a single field", t.TypeName, field.GoName)) + } + + rule := strings.ToUpper(onDelete[0]) + if !isKnownFKRule(rule) { + internal.Warn.Printf("bun: %s belongs-to %s: unknown on_delete rule %s", t.TypeName, field.GoName, rule) + } + s := fmt.Sprintf("ON DELETE %s", rule) + rel.OnDelete = s + } + if join, ok := field.Tag.Options["join"]; ok { baseColumns, joinColumns := parseRelationJoin(join) for i, baseColumn := range baseColumns { @@ -539,6 +576,10 @@ func (t *Table) hasOneRelation(field *Field) *Relation { JoinTable: joinTable, } + if field.Tag.HasOption("join_on") { + rel.Condition = field.Tag.Options["join_on"] + } + if join, ok := field.Tag.Options["join"]; ok { baseColumns, joinColumns := parseRelationJoin(join) for i, baseColumn := range baseColumns { @@ -605,6 +646,11 @@ func (t *Table) hasManyRelation(field *Field) *Relation { Field: field, JoinTable: joinTable, } + + if field.Tag.HasOption("join_on") { + rel.Condition = field.Tag.Options["join_on"] + } + var polymorphicColumn string if join, ok := field.Tag.Options["join"]; ok { @@ -715,6 +761,11 @@ func (t *Table) m2mRelation(field *Field) *Relation { JoinTable: joinTable, M2MTable: m2mTable, } + + if field.Tag.HasOption("join_on") { + rel.Condition = field.Tag.Options["join_on"] + } + var leftColumn, rightColumn string if join, ok := field.Tag.Options["join"]; ok { @@ -853,13 +904,29 @@ func isKnownFieldOption(name string) bool { "unique", "soft_delete", "scanonly", + "skipupdate", "pk", "autoincrement", "rel", "join", + "join_on", + "on_update", + "on_delete", "m2m", - "polymorphic": + "polymorphic", + "identity": + return true + } + return false +} + +func isKnownFKRule(name string) bool { + switch name { + case "CASCADE", + "RESTRICT", + "SET NULL", + "SET DEFAULT": return true } return false diff --git a/vendor/github.com/uptrace/bun/version.go b/vendor/github.com/uptrace/bun/version.go index 082782f5f..8d17c97b3 100644 --- a/vendor/github.com/uptrace/bun/version.go +++ b/vendor/github.com/uptrace/bun/version.go @@ -2,5 +2,5 @@ package bun // Version is the current release version. func Version() string { - return "1.1.3" + return "1.1.7" } |