mirror of
https://github.com/hanzo-fi/go-libs.git
synced 2026-10-30 20:53:44 +00:00
* refactor: move all packages under pkg/ for v5 Move all 13 top-level Go packages into pkg/ for a cleaner repository structure. All internal import paths updated from github.com/formancehq/go-libs/v5/<pkg> to github.com/formancehq/go-libs/v5/pkg/<pkg>. Also includes cleanup: - Fix .golangci.yml stale v4 CircuitBreaker path - Replace deprecated str.Contains with stdlib slices.Contains - Update TODO(v4) markers to TODO - Delete stale coverage.txt - Fix pgtesting timeout not being propagated to docker pool - Update docs/ARCHITECTURE.md to reflect new structure Co-Authored-By: Claude Opus 4.6 <[email protected]> * chore: remove compatibility aliases, unused params, and stub files - Remove unused type aliases (Authenticator, KeySet) from authnfx - Remove unused `debug` parameter from S3ModuleFromFlags - Delete comment-only stub files in messaging/publish/circuit/ Co-Authored-By: Claude Opus 4.6 <[email protected]> * chore: rename cli.go to flags.go for consistency Standardize naming across all packages: cli.go -> flags.go since these files all serve the same purpose (flag definitions). Co-Authored-By: Claude Opus 4.6 <[email protected]> * chore: rename * chore(deps): update all dependencies Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: resolve package name mismatches in generated mocks Generated mock files had stale package names from before the pkg/ move, causing import cycles and build failures with --build-tags it. Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
98 lines
1.8 KiB
Go
98 lines
1.8 KiB
Go
package explain
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/uptrace/bun"
|
|
)
|
|
|
|
type listener func(data string)
|
|
|
|
//nolint:unused
|
|
type explainHook struct {
|
|
listener listener
|
|
json bool
|
|
}
|
|
|
|
//nolint:unused
|
|
func (h *explainHook) AfterQuery(ctx context.Context, event *bun.QueryEvent) {}
|
|
|
|
//nolint:unused
|
|
func (h *explainHook) BeforeQuery(ctx context.Context, event *bun.QueryEvent) context.Context {
|
|
|
|
lowerQuery := strings.ToLower(event.Query)
|
|
if !strings.HasPrefix(lowerQuery, "select") && !strings.HasPrefix(lowerQuery, "with") {
|
|
return ctx
|
|
}
|
|
|
|
if err := event.DB.RunInTx(context.Background(), &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
|
|
query := "explain "
|
|
if h.json {
|
|
query += "(format json) "
|
|
} else {
|
|
query += "analyze verbose "
|
|
}
|
|
query += event.Query
|
|
rows, err := tx.Query(query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
_ = rows.Close()
|
|
}()
|
|
|
|
data := bytes.NewBufferString("")
|
|
for rows.Next() {
|
|
var line string
|
|
if err := rows.Scan(&line); err != nil {
|
|
return err
|
|
}
|
|
data.WriteString(line)
|
|
data.WriteString("\r\n")
|
|
}
|
|
if rows.Err() != nil {
|
|
return rows.Err()
|
|
}
|
|
h.listener(data.String())
|
|
|
|
return tx.Rollback()
|
|
|
|
}); err != nil {
|
|
// Nothing to do, let the original request fail
|
|
}
|
|
|
|
return ctx
|
|
}
|
|
|
|
func NewExplainHook(opts ...option) *explainHook {
|
|
ret := &explainHook{}
|
|
for _, opt := range append(defaultOptions, opts...) {
|
|
opt(ret)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
type option func(hook *explainHook)
|
|
|
|
var defaultOptions = []option{
|
|
WithListener(func(data string) {
|
|
fmt.Println(data)
|
|
}),
|
|
}
|
|
|
|
var WithListener = func(w listener) option {
|
|
return func(hook *explainHook) {
|
|
hook.listener = w
|
|
}
|
|
}
|
|
|
|
var WithJSONFormat = func() option {
|
|
return func(hook *explainHook) {
|
|
hook.json = true
|
|
}
|
|
}
|