From 29ee9812ccffd40470a8a4771348b1570c291a07 Mon Sep 17 00:00:00 2001 From: x5iu Date: Mon, 15 Dec 2025 22:23:13 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9B=20Add=20validation=20for=20mut?= =?UTF-8?q?ually=20exclusive=20CONSTBIND=20and=20BIND=20options?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When both CONSTBIND and BIND options are specified for a method, the code generator now reports an error early instead of producing incorrect code. This helps users identify configuration mistakes before runtime. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- gen/sqlx.go | 12 ++++++++++++ gen/sqlx_test.go | 14 ++++++++++++++ gen/testdata/sqlx/test.go | 7 +++++++ 3 files changed, 33 insertions(+) diff --git a/gen/sqlx.go b/gen/sqlx.go index d6c39a6..8c00487 100644 --- a/gen/sqlx.go +++ b/gen/sqlx.go @@ -59,6 +59,11 @@ type sqlxContext struct { } func (ctx *sqlxContext) Build(w io.Writer) error { + const ( + constbindOption = "CONSTBIND" + bindOption = "BIND" + ) + var fixedMethods []*Method = nil for i, method := range ctx.Methods { if l := len(method.Out); l == 0 || !checkErrorType(method.Out[l-1]) { @@ -66,6 +71,13 @@ func (ctx *sqlxContext) Build(w io.Writer) error { quote(method.Ident)) } + // Check for conflicting CONSTBIND and BIND options + opts := method.SqlxOptions() + if hasOption(opts, constbindOption) && hasOption(opts, bindOption) { + return fmt.Errorf("method %s: CONSTBIND and BIND options are mutually exclusive, please use only one of them", + quote(method.Ident)) + } + if method.SingleScan() != "" { if len(method.Out) != 1 { return fmt.Errorf("%s method expects only error returned value when `scan(expr)` option has been specified", diff --git a/gen/sqlx_test.go b/gen/sqlx_test.go index 9ea483b..53c4171 100644 --- a/gen/sqlx_test.go +++ b/gen/sqlx_test.go @@ -205,4 +205,18 @@ func TestBuildSqlx(t *testing.T) { return } }) + t.Run("fail_constbind_bind_conflict", func(t *testing.T) { + builder, ok := newBuilder(t) + if !ok { + return + } + if err := runTest(genFile, builder); err == nil { + t.Errorf("build: expects errors, got nil") + return + } else if !strings.Contains(err.Error(), + "CONSTBIND and BIND options are mutually exclusive") { + t.Errorf("build: expects ConstBindBindConflict error, got => %s", err) + return + } + }) } diff --git a/gen/testdata/sqlx/test.go b/gen/testdata/sqlx/test.go index 201524a..5462b0b 100644 --- a/gen/testdata/sqlx/test.go +++ b/gen/testdata/sqlx/test.go @@ -100,3 +100,10 @@ type User struct { Name string Age int } + +//go:generate defc [mode] [output] [features...] TestBuildSqlx/fail_constbind_bind_conflict +type FailConstBindBindConflict interface { + // GetUser query constbind bind + // SELECT * FROM user WHERE username = ${user.Name} AND age > ${user.Age}; + GetUser(ctx context.Context, user *User) (*User, error) +} From 696da5cad3b549d861a9eae72e69b0bbd602f85d Mon Sep 17 00:00:00 2001 From: Xiu <120178620+x5iu@users.noreply.github.com> Date: Mon, 15 Dec 2025 22:57:19 +0800 Subject: [PATCH 2/2] Update version.go --- runtime/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/version.go b/runtime/version.go index dd687ff..5ad8eaa 100644 --- a/runtime/version.go +++ b/runtime/version.go @@ -1,3 +1,3 @@ package defc -const Version = "v1.44.1" +const Version = "v1.44.2"