Skip to content

Commit 9ff8f59

Browse files
MirrexOneldez
andauthored
Add unqueryvet linter (#6060)
Co-authored-by: Fernandez Ludovic <[email protected]>
1 parent 8a0d1a2 commit 9ff8f59

File tree

11 files changed

+168
-0
lines changed

11 files changed

+168
-0
lines changed

.golangci.next.reference.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ linters:
120120
- tparallel
121121
- unconvert
122122
- unparam
123+
- unqueryvet
123124
- unused
124125
- usestdlibvars
125126
- usetesting
@@ -233,6 +234,7 @@ linters:
233234
- tparallel
234235
- unconvert
235236
- unparam
237+
- unqueryvet
236238
- unused
237239
- usestdlibvars
238240
- usetesting
@@ -3888,6 +3890,21 @@ linters:
38883890
# Default: false
38893891
check-exported: true
38903892

3893+
unqueryvet:
3894+
# Enable SQL builder checking.
3895+
# Default: true
3896+
check-sql-builders: false
3897+
# Regex patterns for acceptable SELECT * usage.
3898+
# Default:
3899+
# - "SELECT \\* FROM information_schema\\..*"
3900+
# - "SELECT \\* FROM pg_catalog\\..*"
3901+
# - "SELECT COUNT\\(\\*\\)"
3902+
# - "SELECT MAX\\(\\*\\)"
3903+
# - "SELECT MIN\\(\\*\\)"
3904+
allowed-patterns:
3905+
- "SELECT \\* FROM temp_.*"
3906+
- "SELECT \\* FROM.*-- migration"
3907+
38913908
unused:
38923909
# Mark all struct fields that have been written to as used.
38933910
# Default: true

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ require (
1515
github.com/Antonboom/testifylint v1.6.4
1616
github.com/BurntSushi/toml v1.5.0
1717
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24
18+
github.com/MirrexOne/unqueryvet v1.2.1
1819
github.com/OpenPeeDeeP/depguard/v2 v2.2.1
1920
github.com/alecthomas/chroma/v2 v2.20.0
2021
github.com/alecthomas/go-check-sumtype v0.3.1

go.sum

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jsonschema/golangci.next.jsonschema.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4005,6 +4005,24 @@
40054005
}
40064006
}
40074007
},
4008+
"unqueryvetSettings": {
4009+
"type": "object",
4010+
"additionalProperties": false,
4011+
"properties": {
4012+
"check-sql-builders": {
4013+
"description": "Enable SQL builder checking.",
4014+
"type": "boolean",
4015+
"default": true
4016+
},
4017+
"allowed-patterns": {
4018+
"description": "Regex patterns for acceptable SELECT * usage.",
4019+
"type": "array",
4020+
"items": {
4021+
"type": "string"
4022+
}
4023+
}
4024+
}
4025+
},
40084026
"unusedSettings": {
40094027
"type": "object",
40104028
"additionalProperties": false,
@@ -4801,6 +4819,9 @@
48014819
"unparam": {
48024820
"$ref": "#/definitions/settings/definitions/unparamSettings"
48034821
},
4822+
"unqueryvet": {
4823+
"$ref": "#/definitions/settings/definitions/unqueryvetSettings"
4824+
},
48044825
"unused": {
48054826
"$ref": "#/definitions/settings/definitions/unusedSettings"
48064827
},

pkg/config/linters_settings.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ var defaultLintersSettings = LintersSettings{
162162
SkipRegexp: `(export|internal)_test\.go`,
163163
AllowPackages: []string{"main"},
164164
},
165+
Unqueryvet: UnqueryvetSettings{
166+
CheckSQLBuilders: true,
167+
},
165168
Unused: UnusedSettings{
166169
FieldWritesAreUses: true,
167170
PostStatementsAreReads: false,
@@ -250,6 +253,7 @@ type LintersSettings struct {
250253
Gomodguard GoModGuardSettings `mapstructure:"gomodguard"`
251254
Gosec GoSecSettings `mapstructure:"gosec"`
252255
Gosmopolitan GosmopolitanSettings `mapstructure:"gosmopolitan"`
256+
Unqueryvet UnqueryvetSettings `mapstructure:"unqueryvet"`
253257
Govet GovetSettings `mapstructure:"govet"`
254258
Grouper GrouperSettings `mapstructure:"grouper"`
255259
Iface IfaceSettings `mapstructure:"iface"`
@@ -1005,6 +1009,11 @@ type UnparamSettings struct {
10051009
CheckExported bool `mapstructure:"check-exported"`
10061010
}
10071011

1012+
type UnqueryvetSettings struct {
1013+
CheckSQLBuilders bool `mapstructure:"check-sql-builders"`
1014+
AllowedPatterns []string `mapstructure:"allowed-patterns"`
1015+
}
1016+
10081017
type UnusedSettings struct {
10091018
FieldWritesAreUses bool `mapstructure:"field-writes-are-uses"`
10101019
PostStatementsAreReads bool `mapstructure:"post-statements-are-reads"`
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//golangcitest:args -Eunqueryvet
2+
package testdata
3+
4+
import (
5+
"database/sql"
6+
"fmt"
7+
"strconv"
8+
)
9+
10+
func _() {
11+
query := "SELECT * FROM users" // want "avoid SELECT \\* - explicitly specify needed columns for better performance, maintainability and stability"
12+
13+
var db *sql.DB
14+
rows, _ := db.Query("SELECT * FROM orders WHERE status = ?", "active") // want "avoid SELECT \\* - explicitly specify needed columns for better performance, maintainability and stability"
15+
_ = rows
16+
17+
count := "SELECT COUNT(*) FROM users"
18+
_ = count
19+
20+
goodQuery := "SELECT id, name, email FROM users"
21+
_ = goodQuery
22+
23+
fmt.Println(query)
24+
25+
_ = strconv.Itoa(42)
26+
}
27+
28+
type SQLBuilder interface {
29+
Select(columns ...string) SQLBuilder
30+
From(table string) SQLBuilder
31+
Where(condition string) SQLBuilder
32+
Query() string
33+
}
34+
35+
func _(builder SQLBuilder) {
36+
query := builder.Select("*").From("products") // want "avoid SELECT \\* in SQL builder - explicitly specify columns to prevent unnecessary data transfer and schema change issues"
37+
_ = query
38+
}
39+
40+
func _(builder SQLBuilder) {
41+
query := builder.Select("id", "name", "price").From("products")
42+
_ = query
43+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//golangcitest:args -Eunqueryvet
2+
//golangcitest:config_path testdata/unqueryvet_custom.yml
3+
package testdata
4+
5+
import (
6+
"database/sql"
7+
"fmt"
8+
"strconv"
9+
)
10+
11+
func _() {
12+
query := "SELECT * FROM users" // want "avoid SELECT \\* - explicitly specify needed columns for better performance, maintainability and stability"
13+
14+
var db *sql.DB
15+
rows, _ := db.Query("SELECT * FROM orders WHERE status = ?", "active") // want "avoid SELECT \\* - explicitly specify needed columns for better performance, maintainability and stability"
16+
_ = rows
17+
18+
count := "SELECT COUNT(*) FROM users"
19+
_ = count
20+
21+
goodQuery := "SELECT id, name, email FROM users"
22+
_ = goodQuery
23+
24+
fmt.Println(query)
25+
26+
_ = strconv.Itoa(42)
27+
}
28+
29+
// Custom allowed patterns test - SELECT * from temp tables should be allowed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: "2"
2+
3+
linters:
4+
settings:
5+
unqueryvet:
6+
check-sql-builders: false
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package unqueryvet
2+
3+
import (
4+
"github.com/MirrexOne/unqueryvet"
5+
pkgconfig "github.com/MirrexOne/unqueryvet/pkg/config"
6+
7+
"github.com/golangci/golangci-lint/v2/pkg/config"
8+
"github.com/golangci/golangci-lint/v2/pkg/goanalysis"
9+
)
10+
11+
func New(settings *config.UnqueryvetSettings) *goanalysis.Linter {
12+
cfg := pkgconfig.DefaultSettings()
13+
14+
if settings != nil {
15+
cfg.CheckSQLBuilders = settings.CheckSQLBuilders
16+
if len(settings.AllowedPatterns) > 0 {
17+
cfg.AllowedPatterns = settings.AllowedPatterns
18+
}
19+
}
20+
21+
return goanalysis.
22+
NewLinterFromAnalyzer(unqueryvet.NewWithConfig(&cfg)).
23+
WithLoadMode(goanalysis.LoadModeSyntax)
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package unqueryvet
2+
3+
import (
4+
"testing"
5+
6+
"github.com/golangci/golangci-lint/v2/test/testshared/integration"
7+
)
8+
9+
func TestFromTestdata(t *testing.T) {
10+
integration.RunTestdata(t)
11+
}

0 commit comments

Comments
 (0)