Skip to content

Commit

Permalink
feat: support sqlx (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmzane authored May 26, 2023
1 parent a22690e commit 3593ea5
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 8 deletions.
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ The following packages are supported out of the box:
* [`gopkg.in/yaml.v3`][4]
* [`github.com/BurntSushi/toml`][5]
* [`github.com/mitchellh/mapstructure`][6]
* [`github.com/jmoiron/sqlx`][7]

In addition, any [custom package](#custom-packages) can be added to the list.

Expand All @@ -62,7 +63,7 @@ If you'd rather prefer to use `musttag` standalone, you can install it via `brew
brew install tmzane/tap/musttag
```

...or download a prebuilt binary from the [Releases][8] page.
...or download a prebuilt binary from the [Releases][9] page.

Then run it either directly or as a `go vet` tool:

Expand All @@ -74,24 +75,24 @@ go vet -vettool=$(which musttag) ./...

To enable reporting a custom function, you need to add its description to `.golangci.yml`.

The following is an example of adding support for the `sqlx.Get` function from [`github.com/jmoiron/sqlx`][7]:
The following is an example of adding support for the `hclsimple.DecodeFile` function from [`github.com/hashicorp/hcl`][8]:

```yaml
linters-settings:
musttag:
functions:
# The full name of the function, including the package.
- name: github.com/jmoiron/sqlx.Get
- name: github.com/hashicorp/hcl/v2/hclsimple.DecodeFile
# The struct tag whose presence should be ensured.
tag: db
tag: hcl
# The position of the argument to check.
arg-pos: 1
arg-pos: 2
```

The same can be done via the `-fn=name:tag:arg-pos` flag when using `musttag` standalone:

```shell
musttag -fn="github.com/jmoiron/sqlx.Get:db:1" ./...
musttag -fn="github.com/hashicorp/hcl/v2/hclsimple.DecodeFile:hcl:2" ./...
```

[1]: https://github.com/uber-go/guide/blob/master/style.md#use-field-tags-in-marshaled-structs
Expand All @@ -101,4 +102,5 @@ musttag -fn="github.com/jmoiron/sqlx.Get:db:1" ./...
[5]: https://github.com/BurntSushi/toml
[6]: https://github.com/mitchellh/mapstructure
[7]: https://github.com/jmoiron/sqlx
[8]: https://github.com/tmzane/musttag/releases
[8]: https://github.com/hashicorp/hcl
[9]: https://github.com/tmzane/musttag/releases
27 changes: 27 additions & 0 deletions builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,31 @@ var builtins = []Func{
{Name: "github.com/mitchellh/mapstructure.DecodeMetadata", Tag: "mapstructure", ArgPos: 1},
{Name: "github.com/mitchellh/mapstructure.WeakDecode", Tag: "mapstructure", ArgPos: 1},
{Name: "github.com/mitchellh/mapstructure.WeakDecodeMetadata", Tag: "mapstructure", ArgPos: 1},

// https://github.com/jmoiron/sqlx
{Name: "github.com/jmoiron/sqlx.Get", Tag: "db", ArgPos: 1},
{Name: "github.com/jmoiron/sqlx.GetContext", Tag: "db", ArgPos: 2},
{Name: "github.com/jmoiron/sqlx.Select", Tag: "db", ArgPos: 1},
{Name: "github.com/jmoiron/sqlx.SelectContext", Tag: "db", ArgPos: 2},
{Name: "github.com/jmoiron/sqlx.StructScan", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.Conn).GetContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.Conn).SelectContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.DB).Get", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.DB).GetContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.DB).Select", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.DB).SelectContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.NamedStmt).Get", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.NamedStmt).GetContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.NamedStmt).Select", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.NamedStmt).SelectContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.Row).StructScan", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.Rows).StructScan", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.Stmt).Get", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.Stmt).GetContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.Stmt).Select", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.Stmt).SelectContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.Tx).Get", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.Tx).GetContext", Tag: "db", ArgPos: 1},
{Name: "(*github.com/jmoiron/sqlx.Tx).Select", Tag: "db", ArgPos: 0},
{Name: "(*github.com/jmoiron/sqlx.Tx).SelectContext", Tag: "db", ArgPos: 1},
}
38 changes: 38 additions & 0 deletions musttag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,44 @@ func DecodeMetadata(_, _ any, _ *Metadata) error { return nil }
func WeakDecode(_, _ any) error { return nil }
func WeakDecodeMetadata(_, _ any, _ *Metadata) error { return nil }`,

"github.com/jmoiron/sqlx/sqlx.go": `package sqlx
import "context"
type Queryer interface{}
type QueryerContext interface{}
type rowsi interface{}
func Get(Queryer, any, string, ...any) error { return nil }
func GetContext(context.Context, QueryerContext, any, string, ...any) error { return nil }
func Select(Queryer, any, string, ...any) error { return nil }
func SelectContext(context.Context, QueryerContext, any, string, ...any) error { return nil }
func StructScan(rowsi, any) error { return nil }
type Conn struct{}
func (*Conn) GetContext(context.Context, any, string, ...any) error { return nil }
func (*Conn) SelectContext(context.Context, any, string, ...any) error { return nil }
type DB struct{}
func (*DB) Get(any, string, ...any) error { return nil }
func (*DB) GetContext(context.Context, any, string, ...any) error { return nil }
func (*DB) Select(any, string, ...any) error { return nil }
func (*DB) SelectContext(context.Context, any, string, ...any) error { return nil }
type NamedStmt struct{}
func (n *NamedStmt) Get(any, any) error { return nil }
func (n *NamedStmt) GetContext(context.Context, any, any) error { return nil }
func (n *NamedStmt) Select(any, any) error { return nil }
func (n *NamedStmt) SelectContext(context.Context, any, any) error { return nil }
type Row struct{}
func (*Row) StructScan(any) error { return nil }
type Rows struct{}
func (*Rows) StructScan(any) error { return nil }
type Stmt struct{}
func (*Stmt) Get(any, ...any) error { return nil }
func (*Stmt) GetContext(context.Context, any, ...any) error { return nil }
func (*Stmt) Select(any, ...any) error { return nil }
func (*Stmt) SelectContext(context.Context, any, ...any) error { return nil }
type Tx struct{}
func (*Tx) Get(any, string, ...any) error { return nil }
func (*Tx) GetContext(context.Context, any, string, ...any) error { return nil }
func (*Tx) Select(any, string, ...any) error { return nil }
func (*Tx) SelectContext(context.Context, any, string, ...any) error { return nil }`,

"example.com/custom/custom.go": `package custom
func Marshal(_ any) ([]byte, error) { return nil, nil }
func Unmarshal(_ []byte, _ any) error { return nil }`,
Expand Down
58 changes: 57 additions & 1 deletion testdata/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
// these packages are generated before the tests are run.
"example.com/custom"
"github.com/BurntSushi/toml"
"github.com/jmoiron/sqlx"
"github.com/mitchellh/mapstructure"
"gopkg.in/yaml.v3"
)
Expand Down Expand Up @@ -43,11 +44,37 @@ type User struct { /* want
"`User` should be annotated with the `mapstructure` tag as it is passed to `mapstructure.WeakDecode` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `mapstructure` tag as it is passed to `mapstructure.WeakDecodeMetadata` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Get` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.GetContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Select` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.SelectContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.StructScan` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Conn.GetContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Conn.SelectContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.DB.Get` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.DB.GetContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.DB.Select` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.DB.SelectContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.NamedStmt.Get` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.NamedStmt.GetContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.NamedStmt.Select` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.NamedStmt.SelectContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Row.StructScan` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Rows.StructScan` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Stmt.Get` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Stmt.GetContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Stmt.Select` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Stmt.SelectContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Tx.Get` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Tx.GetContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Tx.Select` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `db` tag as it is passed to `sqlx.Tx.SelectContext` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `custom` tag as it is passed to `custom.Marshal` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
"`User` should be annotated with the `custom` tag as it is passed to `custom.Unmarshal` at testdata(/|\\\\)src(/|\\\\)builtins(/|\\\\)builtins.go"
*/
Name string
Email string `json:"email" xml:"email" yaml:"email" toml:"email" mapstructure:"email" custom:"email"`
Email string `json:"email" xml:"email" yaml:"email" toml:"email" mapstructure:"email" db:"email" custom:"email"`
}

func testJSON() {
Expand Down Expand Up @@ -96,6 +123,35 @@ func testMapstructure() {
mapstructure.WeakDecodeMetadata(nil, &user, nil)
}

func testSQLX() {
var user User
sqlx.Get(nil, &user, "")
sqlx.GetContext(nil, nil, &user, "")
sqlx.Select(nil, &user, "")
sqlx.SelectContext(nil, nil, &user, "")
sqlx.StructScan(nil, &user)
new(sqlx.Conn).GetContext(nil, &user, "")
new(sqlx.Conn).SelectContext(nil, &user, "")
new(sqlx.DB).Get(&user, "")
new(sqlx.DB).GetContext(nil, &user, "")
new(sqlx.DB).Select(&user, "")
new(sqlx.DB).SelectContext(nil, &user, "")
new(sqlx.NamedStmt).Get(&user, nil)
new(sqlx.NamedStmt).GetContext(nil, &user, nil)
new(sqlx.NamedStmt).Select(&user, nil)
new(sqlx.NamedStmt).SelectContext(nil, &user, nil)
new(sqlx.Row).StructScan(&user)
new(sqlx.Rows).StructScan(&user)
new(sqlx.Stmt).Get(&user)
new(sqlx.Stmt).GetContext(nil, &user)
new(sqlx.Stmt).Select(&user)
new(sqlx.Stmt).SelectContext(nil, &user)
new(sqlx.Tx).Get(&user, "")
new(sqlx.Tx).GetContext(nil, &user, "")
new(sqlx.Tx).Select(&user, "")
new(sqlx.Tx).SelectContext(nil, &user, "")
}

func testCustom() {
var user User
custom.Marshal(user)
Expand Down

0 comments on commit 3593ea5

Please sign in to comment.