diff --git a/boil/debug.go b/boil/debug.go index 354d08ba7..d4b337e83 100644 --- a/boil/debug.go +++ b/boil/debug.go @@ -2,8 +2,11 @@ package boil import ( "context" + "fmt" "io" "os" + "regexp" + "strings" ) // DebugMode is a flag controlling whether generated sql statements and @@ -47,3 +50,38 @@ func DebugWriterFrom(ctx context.Context) io.Writer { } return DebugWriter } + +// PrintQuery prints a modified query string with placeholders replaced by their +// corresponding argument values to writer. +func PrintQuery(writer io.Writer, query string, args ...interface{}) { + substitutedQuery := substituteQueryArgs(query, args...) + fmt.Fprintln(writer, substitutedQuery) +} + +// substituteQueryArgs takes a query string and an array of arguments. +// It returns a modified query string with placeholders replaced by their +// corresponding argument values. +func substituteQueryArgs(query string, args ...interface{}) string { + // find all occurrences of placeholders ($1, $2, etc.) in the query + re := regexp.MustCompile(`\$\d+`) + matches := re.FindAllString(query, -1) + + for i, match := range matches { + var arg string + + switch v := args[i].(type) { + case string: + arg = fmt.Sprintf("'%s'", v) + case []byte: + arg = fmt.Sprintf("'%s'", string(v)) + default: + arg = fmt.Sprintf("%v", v) + } + + // replace the placeholder with the argument value + query = strings.Replace(query, match, arg, 1) + } + + // return the final query with argument values + return query +} diff --git a/boil/debug_test.go b/boil/debug_test.go new file mode 100644 index 000000000..1b0f16ac8 --- /dev/null +++ b/boil/debug_test.go @@ -0,0 +1,43 @@ +package boil + +import ( + "testing" +) + +func TestSubstituteQueryArgs(t *testing.T) { + tests := []struct { + query string + args []interface{} + want string + }{ + { + query: `INSERT INTO "my_table" ("id","name","age","height","is_active","data") VALUES ($1,$2,$3,$4,$5,$6)`, + args: []interface{}{ + 1, "Alice", 25, 1.68, true, []byte(`{"key":"value"}`), + }, + want: `INSERT INTO "my_table" ("id","name","age","height","is_active","data") VALUES (1,'Alice',25,1.68,true,'{"key":"value"}')`, + }, + { + query: `SELECT * FROM "my_table"`, + args: []interface{}{}, + want: `SELECT * FROM "my_table"`, + }, + { + query: `UPDATE "my_table" SET "name"=$1,"age"=$2,"height"=$3,"is_active"=$4,"data"=$5 WHERE "id"=$6`, + args: []interface{}{ + "Bob", 30, 1.78, false, []byte(`{"key":123}`), 2, + }, + want: `UPDATE "my_table" SET "name"='Bob',"age"=30,"height"=1.78,"is_active"=false,"data"='{"key":123}' WHERE "id"=2`, + }, + } + + for _, tt := range tests { + t.Run(tt.query, func(t *testing.T) { + got := substituteQueryArgs(tt.query, tt.args...) + + if got != tt.want { + t.Errorf("substituteQueryArgs() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/drivers/sqlboiler-mssql/driver/override/main/17_upsert.go.tpl b/drivers/sqlboiler-mssql/driver/override/main/17_upsert.go.tpl index 5665d3495..d663aaa7d 100644 --- a/drivers/sqlboiler-mssql/driver/override/main/17_upsert.go.tpl +++ b/drivers/sqlboiler-mssql/driver/override/main/17_upsert.go.tpl @@ -130,14 +130,12 @@ func (o *{{$alias.UpSingular}}) Upsert({{if .NoContext}}exec boil.Executor{{else {{if .NoContext -}} if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, cache.query) - fmt.Fprintln(boil.DebugWriter, vals) + boil.PrintQuery(boil.DebugWriter, cache.query, vals...) } {{else -}} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, cache.query) - fmt.Fprintln(writer, vals) + boil.PrintQuery(writer, cache.query, vals...) } {{end -}} diff --git a/drivers/sqlboiler-mysql/driver/override/main/17_upsert.go.tpl b/drivers/sqlboiler-mysql/driver/override/main/17_upsert.go.tpl index a1e4e95a4..83a5891e2 100644 --- a/drivers/sqlboiler-mysql/driver/override/main/17_upsert.go.tpl +++ b/drivers/sqlboiler-mysql/driver/override/main/17_upsert.go.tpl @@ -138,14 +138,12 @@ func (o *{{$alias.UpSingular}}) Upsert({{if .NoContext}}exec boil.Executor{{else {{if .NoContext -}} if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, cache.query) - fmt.Fprintln(boil.DebugWriter, vals) + boil.PrintQuery(boil.DebugWriter, cache.query, vals...) } {{else -}} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, cache.query) - fmt.Fprintln(writer, vals) + boil.PrintQuery(writer, cache.query, vals...) } {{end -}} @@ -200,14 +198,12 @@ func (o *{{$alias.UpSingular}}) Upsert({{if .NoContext}}exec boil.Executor{{else {{if .NoContext -}} if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, cache.retQuery) - fmt.Fprintln(boil.DebugWriter, nzUniqueCols...) + boil.PrintQuery(boil.DebugWriter, cache.retQuery, nzUniqueCols...) } {{else -}} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, cache.retQuery) - fmt.Fprintln(writer, nzUniqueCols...) + boil.PrintQuery(writer, cache.retQuery, nzUniqueCols...) } {{end -}} diff --git a/drivers/sqlboiler-psql/driver/override/main/17_upsert.go.tpl b/drivers/sqlboiler-psql/driver/override/main/17_upsert.go.tpl index 41c2485f5..98f9dac53 100644 --- a/drivers/sqlboiler-psql/driver/override/main/17_upsert.go.tpl +++ b/drivers/sqlboiler-psql/driver/override/main/17_upsert.go.tpl @@ -130,14 +130,12 @@ func (o *{{$alias.UpSingular}}) Upsert({{if .NoContext}}exec boil.Executor{{else {{if .NoContext -}} if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, cache.query) - fmt.Fprintln(boil.DebugWriter, vals) + boil.PrintQuery(boil.DebugWriter, cache.query, vals...) } {{else -}} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, cache.query) - fmt.Fprintln(writer, vals) + boil.PrintQuery(writer, cache.query, vals...) } {{end -}} diff --git a/drivers/sqlboiler-sqlite3/driver/override/main/17_upsert.go.tpl b/drivers/sqlboiler-sqlite3/driver/override/main/17_upsert.go.tpl index 648a061f5..2e00753ce 100644 --- a/drivers/sqlboiler-sqlite3/driver/override/main/17_upsert.go.tpl +++ b/drivers/sqlboiler-sqlite3/driver/override/main/17_upsert.go.tpl @@ -125,14 +125,12 @@ func (o *{{$alias.UpSingular}}) Upsert({{if .NoContext}}exec boil.Executor{{else {{if .NoContext -}} if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, cache.query) - fmt.Fprintln(boil.DebugWriter, vals) + boil.PrintQuery(boil.DebugWriter, cache.query, vals...) } {{else -}} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, cache.query) - fmt.Fprintln(writer, vals) + boil.PrintQuery(writer, cache.query, vals...) } {{end -}} diff --git a/queries/query.go b/queries/query.go index ea8052ec8..26ecc0e1d 100644 --- a/queries/query.go +++ b/queries/query.go @@ -3,7 +3,6 @@ package queries import ( "context" "database/sql" - "fmt" "regexp" "github.com/volatiletech/sqlboiler/v4/boil" @@ -118,8 +117,7 @@ func RawG(query string, args ...interface{}) *Query { func (q *Query) Exec(exec boil.Executor) (sql.Result, error) { qs, args := BuildQuery(q) if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, qs) - fmt.Fprintln(boil.DebugWriter, args) + boil.PrintQuery(boil.DebugWriter, qs, args...) } return exec.Exec(qs, args...) } @@ -128,8 +126,7 @@ func (q *Query) Exec(exec boil.Executor) (sql.Result, error) { func (q *Query) QueryRow(exec boil.Executor) *sql.Row { qs, args := BuildQuery(q) if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, qs) - fmt.Fprintln(boil.DebugWriter, args) + boil.PrintQuery(boil.DebugWriter, qs, args...) } return exec.QueryRow(qs, args...) } @@ -138,8 +135,7 @@ func (q *Query) QueryRow(exec boil.Executor) *sql.Row { func (q *Query) Query(exec boil.Executor) (*sql.Rows, error) { qs, args := BuildQuery(q) if boil.DebugMode { - fmt.Fprintln(boil.DebugWriter, qs) - fmt.Fprintln(boil.DebugWriter, args) + boil.PrintQuery(boil.DebugWriter, qs, args...) } return exec.Query(qs, args...) } @@ -149,8 +145,7 @@ func (q *Query) ExecContext(ctx context.Context, exec boil.ContextExecutor) (sql qs, args := BuildQuery(q) if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, qs) - fmt.Fprintln(writer, args) + boil.PrintQuery(writer, qs, args...) } return exec.ExecContext(ctx, qs, args...) } @@ -160,8 +155,7 @@ func (q *Query) QueryRowContext(ctx context.Context, exec boil.ContextExecutor) qs, args := BuildQuery(q) if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, qs) - fmt.Fprintln(writer, args) + boil.PrintQuery(writer, qs, args...) } return exec.QueryRowContext(ctx, qs, args...) } @@ -171,8 +165,7 @@ func (q *Query) QueryContext(ctx context.Context, exec boil.ContextExecutor) (*s qs, args := BuildQuery(q) if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, qs) - fmt.Fprintln(writer, args) + boil.PrintQuery(writer, qs, args...) } return exec.QueryContext(ctx, qs, args...) }