diff --git a/core.go b/core.go index 6eb3fc3..fae5eea 100644 --- a/core.go +++ b/core.go @@ -6,8 +6,6 @@ import ( "io" "reflect" "strings" - - "github.com/jmoiron/sqlx" ) const ( @@ -150,15 +148,15 @@ type PrepareContext interface { PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) } -// PreparexContext enhances the Conn interface with context. -type PreparexContext interface { +// PreparexContext[T] enhances the Conn interface with context. +type PreparexContext[T any] interface { // PrepareContext prepares a statement. // The provided context is used for the preparation of the statement, not for // the execution of the statement. - PreparexContext(ctx context.Context, query string) (*sqlx.Stmt, error) + PreparexContext(ctx context.Context, query string) (T, error) // PrepareNamedContext returns an sqlx.NamedStmt - PrepareNamedContext(ctx context.Context, query string) (*sqlx.NamedStmt, error) + PrepareNamedContext(ctx context.Context, query string) (T, error) // Rebind rebind query to adapte SQL Driver Rebind(query string) string @@ -171,8 +169,8 @@ type PrepareBuilder interface { } // PreparexBuilder preparex builder interface for sqlx -type PreparexBuilder interface { - PreparexContext +type PreparexBuilder[T any] interface { + PreparexContext[T] QueryHook(query string) string } diff --git a/generator.go b/generator.go index 99aaf9a..dbbd49b 100644 --- a/generator.go +++ b/generator.go @@ -9,7 +9,6 @@ import ( "github.com/alimy/yesql/naming" "github.com/alimy/yesql/template" - "github.com/jmoiron/sqlx" ) const ( @@ -35,8 +34,8 @@ type simplePrepareBuilder struct { hooks []func(string) string } -type simplePreparexBuilder struct { - p PreparexContext +type simplePreparexBuilder[T any] struct { + p PreparexContext[T] hooks []func(string) string } @@ -55,19 +54,19 @@ func (s *simplePrepareBuilder) QueryHook(query string) string { return query } -func (s *simplePreparexBuilder) PreparexContext(ctx context.Context, query string) (*sqlx.Stmt, error) { +func (s *simplePreparexBuilder[T]) PreparexContext(ctx context.Context, query string) (T, error) { return s.p.PreparexContext(ctx, query) } -func (s *simplePreparexBuilder) PrepareNamedContext(ctx context.Context, query string) (*sqlx.NamedStmt, error) { +func (s *simplePreparexBuilder[T]) PrepareNamedContext(ctx context.Context, query string) (T, error) { return s.p.PrepareNamedContext(ctx, query) } -func (s *simplePreparexBuilder) Rebind(query string) string { +func (s *simplePreparexBuilder[T]) Rebind(query string) string { return s.p.Rebind(query) } -func (s *simplePreparexBuilder) QueryHook(query string) string { +func (s *simplePreparexBuilder[T]) QueryHook(query string) string { for _, h := range s.hooks { query = h(query) } @@ -133,9 +132,9 @@ func NewPrepareBuilder(p PrepareContext, hooks ...func(string) string) PrepareBu return obj } -// NewPreprarexBuilder create a simple preparex builder instance -func NewPreparexBuilder(p PreparexContext, hooks ...func(string) string) PreparexBuilder { - obj := &simplePreparexBuilder{ +// NewPreprarexBuilder[T] create a simple preparex builder instance +func NewPreparexBuilder[T any](p PreparexContext[T], hooks ...func(string) string) PreparexBuilder[T] { + obj := &simplePreparexBuilder[T]{ p: p, } for _, h := range hooks { diff --git a/go.mod b/go.mod index df014bc..09eb9f3 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,6 @@ module github.com/alimy/yesql go 1.18 -require github.com/jmoiron/sqlx v1.3.5 +require ( + github.com/bitbus/sqlx v1.6.0 +) diff --git a/go.sum b/go.sum index fdd4295..4ae7591 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/bitbus/sqlx v1.6.0 h1:ewrBydRkyHZqfOqvHVYpiBlqQtLn93B/loa2EwjpZ74= +github.com/bitbus/sqlx v1.6.0/go.mod h1:MemKLfQ600g6PxUVsIDe48PlY3wOquyW2ApeiXoynFo= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= diff --git a/hooks.go b/hooks.go index 4fbd1f9..60c5c96 100644 --- a/hooks.go +++ b/hooks.go @@ -8,15 +8,15 @@ import ( var ( _ PrepareHook = (*stdPrepareHook)(nil) - _ PrepareHook = (*sqlxPrepareHook)(nil) + _ PrepareHook = (*sqlxPrepareHook[any])(nil) ) type stdPrepareHook struct { prepare PrepareContext } -type sqlxPrepareHook struct { - prepare PreparexContext +type sqlxPrepareHook[T any] struct { + prepare PreparexContext[T] } func (s *stdPrepareHook) Prepare(field reflect.Type, query string) (any, error) { @@ -53,7 +53,7 @@ func (s *stdPrepareHook) PrepareContext(ctx context.Context, field reflect.Type, } } -func (s *sqlxPrepareHook) Prepare(field reflect.Type, query string) (any, error) { +func (s *sqlxPrepareHook[T]) Prepare(field reflect.Type, query string) (any, error) { switch field.String() { case "string": // Unprepared SQL query. @@ -77,7 +77,7 @@ func (s *sqlxPrepareHook) Prepare(field reflect.Type, query string) (any, error) } } -func (s *sqlxPrepareHook) PrepareContext(ctx context.Context, field reflect.Type, query string) (any, error) { +func (s *sqlxPrepareHook[T]) PrepareContext(ctx context.Context, field reflect.Type, query string) (any, error) { switch field.String() { case "string": // Unprepared SQL query. @@ -108,9 +108,9 @@ func NewPrepareHook(p PrepareContext) PrepareHook { } } -// NewSqlxPrepareHook create a prepare hook prepare that implement PreparexContext -func NewSqlxPrepareHook(p PreparexContext) PrepareHook { - return &sqlxPrepareHook{ +// NewSqlxPrepareHook[T] create a prepare hook prepare that implement PreparexContext +func NewSqlxPrepareHook[T any](p PreparexContext[T]) PrepareHook { + return &sqlxPrepareHook[T]{ prepare: p, } } diff --git a/template/sqlx.tmpl b/template/sqlx.tmpl index 7bea0b6..3d28b93 100644 --- a/template/sqlx.tmpl +++ b/template/sqlx.tmpl @@ -16,6 +16,26 @@ const ( {{end -}} ) +// PreparexContext enhances the Conn interface with context. +type PreparexContext interface { + // PrepareContext prepares a statement. + // The provided context is used for the preparation of the statement, not for + // the execution of the statement. + PreparexContext(ctx context.Context, query string) (*sqlx.Stmt, error) + + // PrepareNamedContext returns an sqlx.NamedStmt + PrepareNamedContext(ctx context.Context, query string) (*sqlx.NamedStmt, error) + + // Rebind rebind query to adapte SQL Driver + Rebind(query string) string +} + +// PreparexBuilder preparex builder interface for sqlx +type PreparexBuilder interface { + PreparexContext + QueryHook(query string) string +} + {{if .DefaultQueryMapNotEmpty}}type {{ .DefaultStructName }} struct { {{range $name, $query := .DefaultQueryMap.FilterByStyle "raw" }}{{ naming $name }} {{if eq .PrepareStyle "stmt" }}*sqlx.Stmt{{else if eq .PrepareStyle "named_stmt"}}*sqlx.NamedStmt{{else}}string{{end}} `yesql:"{{ $query.Name }}"` {{end}} @@ -37,7 +57,7 @@ type {{ naming $scope }} struct { {{end -}} {{if .DefaultQueryMapNotEmpty}} -func Build{{ .DefaultStructName }}(p yesql.PreparexBuilder{{if .DefaultQueryMap.IsStmtQueryNotEmpty }}, ctx ...context.Context{{end}}) (obj *{{ .DefaultStructName }}, err error) { +func Build{{ .DefaultStructName }}(p PreparexBuilder{{if .DefaultQueryMap.IsStmtQueryNotEmpty }}, ctx ...context.Context{{end}}) (obj *{{ .DefaultStructName }}, err error) { {{- if .DefaultQueryMap.IsStmtQueryNotEmpty -}} var c context.Context if len(ctx) > 0 && ctx[0] != nil { @@ -60,7 +80,7 @@ func Build{{ .DefaultStructName }}(p yesql.PreparexBuilder{{if .DefaultQueryMap. return }{{end}} {{range $scope, $queryMap := .ScopeQuery }} -func Build{{ naming $scope }}(p yesql.PreparexBuilder{{if $queryMap.IsStmtQueryNotEmpty }}, ctx ...context.Context{{end}}) (obj *{{ naming $scope }}, err error) { +func Build{{ naming $scope }}(p PreparexBuilder{{if $queryMap.IsStmtQueryNotEmpty }}, ctx ...context.Context{{end}}) (obj *{{ naming $scope }}, err error) { {{- if $queryMap.IsStmtQueryNotEmpty -}} var c context.Context if len(ctx) > 0 && ctx[0] != nil { diff --git a/version.go b/version.go index 4f2824d..25eaea9 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package yesql -var Version = "v1.6.0" +var Version = "v1.7.0" diff --git a/yesql.go b/yesql.go index 96651e4..ed7555a 100644 --- a/yesql.go +++ b/yesql.go @@ -26,9 +26,9 @@ func Use(p PrepareContext) { _defaultPrepareScanner = NewPrepareScanner(prepareHook) } -// UseSqlx use default prepare scanner withprepare that implement PreparexContext -func UseSqlx(p PreparexContext) { - prepareHook := NewSqlxPrepareHook(p) +// UseSqlx[T] use default prepare scanner withprepare that implement PreparexContext +func UseSqlx[T any](p PreparexContext[T]) { + prepareHook := NewSqlxPrepareHook[T](p) _defaultPrepareScanner = NewPrepareScanner(prepareHook) } @@ -149,8 +149,8 @@ func MustBuild[T any](p PrepareContext, fn func(PrepareBuilder, ...context.Conte return obj } -// MustBuildx build a struct object than type of T -func MustBuildx[T any](p PreparexContext, fn func(PreparexBuilder, ...context.Context) (T, error), hook ...func(query string) string) T { +// MustBuildx[T] build a struct object than type of T +func MustBuildx[T any](p PreparexContext[T], fn func(PreparexBuilder[T], ...context.Context) (T, error), hook ...func(query string) string) T { b := NewPreparexBuilder(p, hook...) obj, err := fn(b) if err != nil { diff --git a/yesql_test.go b/yesql_test.go index 32e179b..cc10fbb 100644 --- a/yesql_test.go +++ b/yesql_test.go @@ -2,6 +2,8 @@ package yesql import ( "testing" + + "github.com/bitbus/sqlx" ) func TestMustParseFilePanic(t *testing.T) { @@ -77,7 +79,7 @@ func TestScan(t *testing.T) { t.Error("[q2] expected to fail at non-existent query 'does-not-exist' but didn't") } - SetDefaultPrepareHook(NewSqlxPrepareHook(nil)) + SetDefaultPrepareHook(NewSqlxPrepareHook[*sqlx.Stmt](nil)) if err = Scan(&q3, queries); err != nil { t.Errorf("[q3] failed to scan raw query to struct: %s", err) }