goone finds N+1(strictly speaking call SQL in a for loop) query in go
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
)
type Person struct {
Name string
JobID int
}
type Job struct {
JobID int
Name string
}
func main(){
cnn, _ := sql.Open("mysql", "user:password@tcp(host:port)/dbname")
rows, _ := cnn.Query("SELECT name, job_id FROM persons")
defer rows.Close()
for rows.Next() {
var person Person
if err := rows.Scan(&person.Name,&person.JobID); err != nil {
log.Fatal(err)
}
var job Job
// This is N+1 query
if err := cnn.QueryRow("SELECT job_id, name FROM Jobs WHERE job_id = ?",person.JobID).Scan(&job.JobID,&job.Name); err != nil {
log.Fatal(err)
}
fmt.Println(person.Name,job.Name)
}
}
./hoge.go:38:13: this query is called in a loop
go get github.com/masibw/goone/cmd/goone
go vet -vettool=`which goone` ./...
go vet -vettool=(which goone) ./...
- name: install goone
run: go get -u github.com/masibw/goone/cmd/goone
- name: run goone
run: go vet -vettool=`which goone` -goone.configPath="$PWD/goone.yml" ./...
- sql
- sqlx
- gorp
- gorm
You can add types to detect sql query.
You can add any types that you want to detect as sql query. You can also detect the case where an interface is in between by writing below. example project
package:
- pkgName: 'github.com/masibw/go_todo/cmd/go_todo/infrastructure/api/handler'
typeNames:
- typeName: '*todoHandler'
goone searches for goone.yml
in directories up to the root from the file directory which analyzing currently. (not the working directory(command executed))
You can use the -goone.configPath
flag at runtime to indicate config by an absolute path.
If goone.yml exists in the directory where the command was executed
go vet -vettool=`which goone` -goone.configPath="$PWD/goone.yml" ./...
You're welcome to build an Issue or create a PR and be proactive!