From dcafbc90dc685e20a870c7604a444bff7a5f4267 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= <florinpatan@gmail.com>
Date: Mon, 15 Apr 2024 15:14:46 +0300
Subject: [PATCH] Introduce CircleCI (#922)

* Introduce CircleCI

With this PR, we introduce the CircleCI as a CI pipeline.

The old configuration, TravisCI, is removed.

A Makefile is also created to allow easier interaction with the different commands available.

* Fix all linting issues

* Fix goimports version
---
 .circleci/config.yml     | 140 +++++++++++++++++++++++++++++++++++++++
 .travis.yml              |  26 --------
 Makefile                 |  30 +++++++++
 README.md                |   2 +-
 doc.go                   |   1 -
 named.go                 |   2 +-
 named_context.go         |   1 +
 named_context_test.go    |   5 +-
 named_test.go            |   4 +-
 reflectx/reflect.go      |   1 -
 reflectx/reflect_test.go |  17 +++--
 sqlx.go                  |  21 +++---
 sqlx_context.go          |   1 +
 sqlx_context_test.go     |  27 ++++----
 sqlx_test.go             |  33 +++++----
 types/doc.go             |   4 ++
 types/types.go           |   3 +-
 types/types_test.go      |   2 +-
 18 files changed, 236 insertions(+), 84 deletions(-)
 create mode 100644 .circleci/config.yml
 delete mode 100644 .travis.yml
 create mode 100644 Makefile
 create mode 100644 types/doc.go

diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 00000000..91bd4f4a
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,140 @@
+version: 2.1
+
+"-": &go-versions
+  [ "1.18.10", "1.19.13", "1.20.14", "1.21.9", "1.22.2" ]
+
+executors:
+  go_executor:
+    parameters:
+      version:
+        type: string
+    docker:
+      - image: cimg/go:<< parameters.version >>
+
+jobs:
+  test:
+    parameters:
+      go_version:
+        type: string
+    executor:
+      name: go_executor
+      version: << parameters.go_version >>
+    steps:
+      - checkout
+      - restore_cache:
+          keys:
+            - go-mod-v4-{{ checksum "go.sum" }}
+      - run:
+          name: Install Dependencies
+          command: go mod download
+      - save_cache:
+          key: go-mod-v4-{{ checksum "go.sum" }}
+          paths:
+            - "/go/pkg/mod"
+      - run:
+          name: Run tests
+          command: |
+            mkdir -p /tmp/test-reports
+            gotestsum --junitfile /tmp/test-reports/unit-tests.xml
+      - store_test_results:
+          path: /tmp/test-reports
+  test-race:
+    parameters:
+      go_version:
+        type: string
+    executor:
+      name: go_executor
+      version: << parameters.go_version >>
+    steps:
+      - checkout
+      - restore_cache:
+          keys:
+            - go-mod-v4-{{ checksum "go.sum" }}
+      - run:
+          name: Install Dependencies
+          command: go mod download
+      - save_cache:
+          key: go-mod-v4-{{ checksum "go.sum" }}
+          paths:
+            - "/go/pkg/mod"
+      - run:
+          name: Run tests with race detector
+          command: make test-race
+  lint:
+    parameters:
+      go_version:
+        type: string
+    executor:
+      name: go_executor
+      version: << parameters.go_version >>
+    steps:
+      - checkout
+      - restore_cache:
+          keys:
+            - go-mod-v4-{{ checksum "go.sum" }}
+      - run:
+          name: Install Dependencies
+          command: go mod download
+      - run:
+          name: Install tooling
+          command: |
+            make tooling
+      - save_cache:
+          key: go-mod-v4-{{ checksum "go.sum" }}
+          paths:
+            - "/go/pkg/mod"
+      - run:
+          name: Linting
+          command: make lint
+      - run:
+          name: Running vulncheck
+          command: make vuln-check
+  fmt:
+    parameters:
+      go_version:
+        type: string
+    executor:
+      name: go_executor
+      version: << parameters.go_version >>
+    steps:
+      - checkout
+      - restore_cache:
+          keys:
+            - go-mod-v4-{{ checksum "go.sum" }}
+      - run:
+          name: Install Dependencies
+          command: go mod download
+      - run:
+          name: Install tooling
+          command: |
+            make tooling
+      - save_cache:
+          key: go-mod-v4-{{ checksum "go.sum" }}
+          paths:
+            - "/go/pkg/mod"
+      - run:
+          name: Running formatting
+          command: |
+            make fmt
+            make has-changes
+
+workflows:
+  version: 2
+  build-and-test:
+    jobs:
+      - test:
+          matrix:
+            parameters:
+              go_version: *go-versions
+      - test-race:
+          matrix:
+            parameters:
+              go_version: *go-versions
+      - lint:
+          matrix:
+            parameters:
+              go_version: *go-versions
+      - fmt:
+          matrix:
+            parameters:
+              go_version: *go-versions
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 1cfa28cb..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-# vim: ft=yaml sw=2 ts=2
-
-language: go
-
-# enable database services
-services:
-  - mysql
-  - postgresql
-
-# create test database
-before_install:
-  - mysql -e 'CREATE DATABASE IF NOT EXISTS sqlxtest;'
-  - psql -c 'create database sqlxtest;' -U postgres
-  - go get github.com/mattn/goveralls
-  - export SQLX_MYSQL_DSN="travis:@/sqlxtest?parseTime=true"
-  - export SQLX_POSTGRES_DSN="postgres://postgres:@localhost/sqlxtest?sslmode=disable"
-  - export SQLX_SQLITE_DSN="$HOME/sqlxtest.db"
-
-# go versions to test
-go:
-  - "1.15.x"
-  - "1.16.x"
-
-# run tests w/ coverage
-script:
-  - travis_retry $GOPATH/bin/goveralls -service=travis-ci
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..448b9ddd
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+.ONESHELL:
+SHELL = /bin/sh
+.SHELLFLAGS = -ec
+
+BASE_PACKAGE := github.com/jmoiron/sqlx
+
+tooling:
+	go install honnef.co/go/tools/cmd/staticcheck@v0.4.7
+	go install golang.org/x/vuln/cmd/govulncheck@v1.0.4
+	go install golang.org/x/tools/cmd/goimports@v0.20.0
+
+has-changes:
+	git diff --exit-code --quiet HEAD --
+
+lint:
+	go vet ./...
+	staticcheck -checks=all ./...
+
+fmt:
+	go list -f '{{.Dir}}' ./... | xargs -I {} goimports -local $(BASE_PACKAGE) -w {}
+
+vuln-check:
+	govulncheck ./...
+
+test-race:
+	go test -v -race -count=1 ./...
+
+update-dependencies:
+	go get -u -t -v ./...
+	go mod tidy
diff --git a/README.md b/README.md
index 0d715929..5bfd231a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # sqlx
 
-[![Build Status](https://travis-ci.org/jmoiron/sqlx.svg?branch=master)](https://travis-ci.org/jmoiron/sqlx) [![Coverage Status](https://coveralls.io/repos/github/jmoiron/sqlx/badge.svg?branch=master)](https://coveralls.io/github/jmoiron/sqlx?branch=master) [![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/jmoiron/sqlx) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/jmoiron/sqlx/master/LICENSE)
+[![CircleCI](https://dl.circleci.com/status-badge/img/gh/jmoiron/sqlx/tree/master.svg?style=shield)](https://dl.circleci.com/status-badge/redirect/gh/jmoiron/sqlx/tree/master) [![Coverage Status](https://coveralls.io/repos/github/jmoiron/sqlx/badge.svg?branch=master)](https://coveralls.io/github/jmoiron/sqlx?branch=master) [![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/jmoiron/sqlx) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/jmoiron/sqlx/master/LICENSE)
 
 sqlx is a library which provides a set of extensions on go's standard
 `database/sql` library.  The sqlx versions of `sql.DB`, `sql.TX`, `sql.Stmt`,
diff --git a/doc.go b/doc.go
index e2b4e60b..b8010417 100644
--- a/doc.go
+++ b/doc.go
@@ -8,5 +8,4 @@
 // Additions include scanning into structs, named query support, rebinding
 // queries for different drivers, convenient shorthands for common error handling
 // and more.
-//
 package sqlx
diff --git a/named.go b/named.go
index 728aa04d..6ac44777 100644
--- a/named.go
+++ b/named.go
@@ -174,7 +174,7 @@ func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{
 	arglist := make([]interface{}, 0, len(names))
 
 	// grab the indirected value of arg
-	v := reflect.ValueOf(arg)
+	var v reflect.Value
 	for v = reflect.ValueOf(arg); v.Kind() == reflect.Ptr; {
 		v = v.Elem()
 	}
diff --git a/named_context.go b/named_context.go
index 07ad2165..9ad23f4e 100644
--- a/named_context.go
+++ b/named_context.go
@@ -1,3 +1,4 @@
+//go:build go1.8
 // +build go1.8
 
 package sqlx
diff --git a/named_context_test.go b/named_context_test.go
index fd1d851b..03f933d9 100644
--- a/named_context_test.go
+++ b/named_context_test.go
@@ -1,3 +1,4 @@
+//go:build go1.8
 // +build go1.8
 
 package sqlx
@@ -18,12 +19,12 @@ func TestNamedContextQueries(t *testing.T) {
 		ctx := context.Background()
 
 		// Check that invalid preparations fail
-		ns, err = db.PrepareNamedContext(ctx, "SELECT * FROM person WHERE first_name=:first:name")
+		_, err = db.PrepareNamedContext(ctx, "SELECT * FROM person WHERE first_name=:first:name")
 		if err == nil {
 			t.Error("Expected an error with invalid prepared statement.")
 		}
 
-		ns, err = db.PrepareNamedContext(ctx, "invalid sql")
+		_, err = db.PrepareNamedContext(ctx, "invalid sql")
 		if err == nil {
 			t.Error("Expected an error with invalid prepared statement.")
 		}
diff --git a/named_test.go b/named_test.go
index 8481b35b..0ee5b85f 100644
--- a/named_test.go
+++ b/named_test.go
@@ -139,12 +139,12 @@ func TestNamedQueries(t *testing.T) {
 		var err error
 
 		// Check that invalid preparations fail
-		ns, err = db.PrepareNamed("SELECT * FROM person WHERE first_name=:first:name")
+		_, err = db.PrepareNamed("SELECT * FROM person WHERE first_name=:first:name")
 		if err == nil {
 			t.Error("Expected an error with invalid prepared statement.")
 		}
 
-		ns, err = db.PrepareNamed("invalid sql")
+		_, err = db.PrepareNamed("invalid sql")
 		if err == nil {
 			t.Error("Expected an error with invalid prepared statement.")
 		}
diff --git a/reflectx/reflect.go b/reflectx/reflect.go
index 0b109942..8ec6a138 100644
--- a/reflectx/reflect.go
+++ b/reflectx/reflect.go
@@ -3,7 +3,6 @@
 // allows for Go-compatible named attribute access, including accessing embedded
 // struct attributes and the ability to use  functions and struct tags to
 // customize field names.
-//
 package reflectx
 
 import (
diff --git a/reflectx/reflect_test.go b/reflectx/reflect_test.go
index e73af5b1..d0d9be23 100644
--- a/reflectx/reflect_test.go
+++ b/reflectx/reflect_test.go
@@ -354,7 +354,7 @@ func TestFieldsEmbedded(t *testing.T) {
 
 	fi = fields.GetByPath("person.name")
 	if fi == nil {
-		t.Errorf("Expecting person.name to exist")
+		t.Fatal("Expecting person.name to exist")
 	}
 	if fi.Path != "person.name" {
 		t.Errorf("Expecting %s, got %s", "person.name", fi.Path)
@@ -365,7 +365,7 @@ func TestFieldsEmbedded(t *testing.T) {
 
 	fi = fields.GetByTraversal([]int{1, 0})
 	if fi == nil {
-		t.Errorf("Expecting traveral to exist")
+		t.Fatal("Expecting traversal to exist")
 	}
 	if fi.Path != "name" {
 		t.Errorf("Expecting %s, got %s", "name", fi.Path)
@@ -373,7 +373,7 @@ func TestFieldsEmbedded(t *testing.T) {
 
 	fi = fields.GetByTraversal([]int{2})
 	if fi == nil {
-		t.Errorf("Expecting traversal to exist")
+		t.Fatal("Expecting traversal to exist")
 	}
 	if _, ok := fi.Options["required"]; !ok {
 		t.Errorf("Expecting required option to be set")
@@ -642,7 +642,6 @@ func TestMapperMethodsByName(t *testing.T) {
 		A0 *B `db:"A0"`
 		B  `db:"A1"`
 		A2 int
-		a3 int
 	}
 
 	val := &A{
@@ -847,22 +846,22 @@ func TestMustBe(t *testing.T) {
 			valueErr, ok := r.(*reflect.ValueError)
 			if !ok {
 				t.Errorf("unexpected Method: %s", valueErr.Method)
-				t.Error("expected panic with *reflect.ValueError")
-				return
+				t.Fatal("expected panic with *reflect.ValueError")
 			}
 			if valueErr.Method != "github.com/jmoiron/sqlx/reflectx.TestMustBe" {
+				t.Fatalf("unexpected Method: %s", valueErr.Method)
 			}
 			if valueErr.Kind != reflect.String {
-				t.Errorf("unexpected Kind: %s", valueErr.Kind)
+				t.Fatalf("unexpected Kind: %s", valueErr.Kind)
 			}
 		} else {
-			t.Error("expected panic")
+			t.Fatal("expected panic")
 		}
 	}()
 
 	typ = reflect.TypeOf("string")
 	mustBe(typ, reflect.Struct)
-	t.Error("got here, didn't expect to")
+	t.Fatal("got here, didn't expect to")
 }
 
 type E1 struct {
diff --git a/sqlx.go b/sqlx.go
index f7b28768..8259a4fe 100644
--- a/sqlx.go
+++ b/sqlx.go
@@ -5,7 +5,6 @@ import (
 	"database/sql/driver"
 	"errors"
 	"fmt"
-
 	"io/ioutil"
 	"path/filepath"
 	"reflect"
@@ -51,9 +50,9 @@ func mapper() *reflectx.Mapper {
 
 // isScannable takes the reflect.Type and the actual dest value and returns
 // whether or not it's Scannable.  Something is scannable if:
-//   * it is not a struct
-//   * it implements sql.Scanner
-//   * it has no exported fields
+//   - it is not a struct
+//   - it implements sql.Scanner
+//   - it has no exported fields
 func isScannable(t reflect.Type) bool {
 	if reflect.PtrTo(t).Implements(_scannerInterface) {
 		return true
@@ -160,6 +159,8 @@ func mapperFor(i interface{}) *reflectx.Mapper {
 }
 
 var _scannerInterface = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
+
+//lint:ignore U1000 ignoring this for now
 var _valuerInterface = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
 
 // Row is a reimplementation of sql.Row in order to gain access to the underlying
@@ -248,6 +249,8 @@ type DB struct {
 
 // NewDb returns a new sqlx DB wrapper for a pre-existing *sql.DB.  The
 // driverName of the original database is required for named query support.
+//
+//lint:ignore ST1003 changing this would break the package interface.
 func NewDb(db *sql.DB, driverName string) *DB {
 	return &DB{DB: db, driverName: driverName, Mapper: mapper()}
 }
@@ -884,9 +887,9 @@ func structOnlyError(t reflect.Type) error {
 // then each row must only have one column which can scan into that type.  This
 // allows you to do something like:
 //
-//    rows, _ := db.Query("select id from people;")
-//    var ids []int
-//    scanAll(rows, &ids, false)
+//	rows, _ := db.Query("select id from people;")
+//	var ids []int
+//	scanAll(rows, &ids, false)
 //
 // and ids will be a list of the id results.  I realize that this is a desirable
 // interface to expose to users, but for now it will only be exposed via changes
@@ -935,9 +938,9 @@ func scanAll(rows rowsi, dest interface{}, structOnly bool) error {
 		var values []interface{}
 		var m *reflectx.Mapper
 
-		switch rows.(type) {
+		switch rows := rows.(type) {
 		case *Rows:
-			m = rows.(*Rows).Mapper
+			m = rows.Mapper
 		default:
 			m = mapper()
 		}
diff --git a/sqlx_context.go b/sqlx_context.go
index 7aa4dd01..32621d56 100644
--- a/sqlx_context.go
+++ b/sqlx_context.go
@@ -1,3 +1,4 @@
+//go:build go1.8
 // +build go1.8
 
 package sqlx
diff --git a/sqlx_context_test.go b/sqlx_context_test.go
index e49ab8b7..91c5cba1 100644
--- a/sqlx_context_test.go
+++ b/sqlx_context_test.go
@@ -1,15 +1,15 @@
+//go:build go1.8
 // +build go1.8
 
 // The following environment variables, if set, will be used:
 //
-//	* SQLX_SQLITE_DSN
-//	* SQLX_POSTGRES_DSN
-//	* SQLX_MYSQL_DSN
+//   - SQLX_SQLITE_DSN
+//   - SQLX_POSTGRES_DSN
+//   - SQLX_MYSQL_DSN
 //
 // Set any of these variables to 'skip' to skip them.  Note that for MySQL,
 // the string '?parseTime=True' will be appended to the DSN if it's not there
 // already.
-//
 package sqlx
 
 import (
@@ -23,9 +23,10 @@ import (
 	"time"
 
 	_ "github.com/go-sql-driver/mysql"
-	"github.com/jmoiron/sqlx/reflectx"
 	_ "github.com/lib/pq"
 	_ "github.com/mattn/go-sqlite3"
+
+	"github.com/jmoiron/sqlx/reflectx"
 )
 
 func MultiExecContext(ctx context.Context, e ExecerContext, query string) {
@@ -92,7 +93,7 @@ func TestMissingNamesContextContext(t *testing.T) {
 			FirstName string `db:"first_name"`
 			LastName  string `db:"last_name"`
 			Email     string
-			//AddedAt time.Time `db:"added_at"`
+			// AddedAt time.Time `db:"added_at"`
 		}
 
 		// test Select first
@@ -485,7 +486,7 @@ func TestNamedQueryContext(t *testing.T) {
 		// these are tests for #73;  they verify that named queries work if you've
 		// changed the db mapper.  This code checks both NamedQuery "ad-hoc" style
 		// queries and NamedStmt queries, which use different code paths internally.
-		old := *db.Mapper
+		old := (*db).Mapper
 
 		type JSONPerson struct {
 			FirstName sql.NullString `json:"FIRST"`
@@ -570,7 +571,7 @@ func TestNamedQueryContext(t *testing.T) {
 
 		check(t, rows)
 
-		db.Mapper = &old
+		db.Mapper = old
 
 		// Test nested structs
 		type Place struct {
@@ -831,7 +832,7 @@ func TestUsageContext(t *testing.T) {
 		if err != nil {
 			t.Error(err)
 		}
-		//fmt.Printf("%#v\n%#v\n%#v\n", placesptr[0], placesptr[1], placesptr[2])
+		// fmt.Printf("%#v\n%#v\n%#v\n", placesptr[0], placesptr[1], placesptr[2])
 
 		// if you have null fields and use SELECT *, you must use sql.Null* in your struct
 		// this test also verifies that you can use either a []Struct{} or a []*Struct{}
@@ -1274,9 +1275,9 @@ func TestInContext(t *testing.T) {
 	}
 	RunWithSchemaContext(context.Background(), defaultSchema, t, func(ctx context.Context, db *DB, t *testing.T) {
 		loadDefaultFixtureContext(ctx, db, t)
-		//tx.MustExecContext(ctx, tx.Rebind("INSERT INTO place (country, city, telcode) VALUES (?, ?, ?)"), "United States", "New York", "1")
-		//tx.MustExecContext(ctx, tx.Rebind("INSERT INTO place (country, telcode) VALUES (?, ?)"), "Hong Kong", "852")
-		//tx.MustExecContext(ctx, tx.Rebind("INSERT INTO place (country, telcode) VALUES (?, ?)"), "Singapore", "65")
+		// tx.MustExecContext(ctx, tx.Rebind("INSERT INTO place (country, city, telcode) VALUES (?, ?, ?)"), "United States", "New York", "1")
+		// tx.MustExecContext(ctx, tx.Rebind("INSERT INTO place (country, telcode) VALUES (?, ?)"), "Hong Kong", "852")
+		// tx.MustExecContext(ctx, tx.Rebind("INSERT INTO place (country, telcode) VALUES (?, ?)"), "Singapore", "65")
 		telcodes := []int{852, 65}
 		q := "SELECT * FROM place WHERE telcode IN(?) ORDER BY telcode"
 		query, args, err := In(q, telcodes)
@@ -1355,7 +1356,7 @@ func TestConn(t *testing.T) {
 
 	RunWithSchemaContext(context.Background(), schema, t, func(ctx context.Context, db *DB, t *testing.T) {
 		conn, err := db.Connx(ctx)
-		defer conn.Close()
+		defer conn.Close() //lint:ignore SA5001 it's OK to ignore this here.
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/sqlx_test.go b/sqlx_test.go
index 1d4aa20d..9fac2cd4 100644
--- a/sqlx_test.go
+++ b/sqlx_test.go
@@ -1,13 +1,12 @@
 // The following environment variables, if set, will be used:
 //
-//	* SQLX_SQLITE_DSN
-//	* SQLX_POSTGRES_DSN
-//	* SQLX_MYSQL_DSN
+//   - SQLX_SQLITE_DSN
+//   - SQLX_POSTGRES_DSN
+//   - SQLX_MYSQL_DSN
 //
 // Set any of these variables to 'skip' to skip them.  Note that for MySQL,
 // the string '?parseTime=True' will be appended to the DSN if it's not there
 // already.
-//
 package sqlx
 
 import (
@@ -23,9 +22,10 @@ import (
 	"time"
 
 	_ "github.com/go-sql-driver/mysql"
-	"github.com/jmoiron/sqlx/reflectx"
 	_ "github.com/lib/pq"
 	_ "github.com/mattn/go-sqlite3"
+
+	"github.com/jmoiron/sqlx/reflectx"
 )
 
 /* compile time checks that Db, Tx, Stmt (qStmt) implement expected interfaces */
@@ -41,7 +41,6 @@ var TestMysql = true
 var sldb *DB
 var pgdb *DB
 var mysqldb *DB
-var active = []*DB{}
 
 func init() {
 	ConnectAll()
@@ -269,7 +268,7 @@ func TestMissingNames(t *testing.T) {
 			FirstName string `db:"first_name"`
 			LastName  string `db:"last_name"`
 			Email     string
-			//AddedAt time.Time `db:"added_at"`
+			// AddedAt time.Time `db:"added_at"`
 		}
 
 		// test Select first
@@ -659,7 +658,7 @@ func TestNamedQuery(t *testing.T) {
 		// these are tests for #73;  they verify that named queries work if you've
 		// changed the db mapper.  This code checks both NamedQuery "ad-hoc" style
 		// queries and NamedStmt queries, which use different code paths internally.
-		old := *db.Mapper
+		old := (*db).Mapper
 
 		type JSONPerson struct {
 			FirstName sql.NullString `json:"FIRST"`
@@ -744,7 +743,7 @@ func TestNamedQuery(t *testing.T) {
 
 		check(t, rows)
 
-		db.Mapper = &old
+		db.Mapper = old
 
 		// Test nested structs
 		type Place struct {
@@ -1016,7 +1015,7 @@ func TestUsage(t *testing.T) {
 		if err != nil {
 			t.Error(err)
 		}
-		//fmt.Printf("%#v\n%#v\n%#v\n", placesptr[0], placesptr[1], placesptr[2])
+		// fmt.Printf("%#v\n%#v\n%#v\n", placesptr[0], placesptr[1], placesptr[2])
 
 		// if you have null fields and use SELECT *, you must use sql.Null* in your struct
 		// this test also verifies that you can use either a []Struct{} or a []*Struct{}
@@ -1578,9 +1577,9 @@ func TestIn(t *testing.T) {
 	}
 	RunWithSchema(defaultSchema, t, func(db *DB, t *testing.T, now string) {
 		loadDefaultFixture(db, t)
-		//tx.MustExec(tx.Rebind("INSERT INTO place (country, city, telcode) VALUES (?, ?, ?)"), "United States", "New York", "1")
-		//tx.MustExec(tx.Rebind("INSERT INTO place (country, telcode) VALUES (?, ?)"), "Hong Kong", "852")
-		//tx.MustExec(tx.Rebind("INSERT INTO place (country, telcode) VALUES (?, ?)"), "Singapore", "65")
+		// tx.MustExec(tx.Rebind("INSERT INTO place (country, city, telcode) VALUES (?, ?, ?)"), "United States", "New York", "1")
+		// tx.MustExec(tx.Rebind("INSERT INTO place (country, telcode) VALUES (?, ?)"), "Hong Kong", "852")
+		// tx.MustExec(tx.Rebind("INSERT INTO place (country, telcode) VALUES (?, ?)"), "Singapore", "65")
 		telcodes := []int{852, 65}
 		q := "SELECT * FROM place WHERE telcode IN(?) ORDER BY telcode"
 		query, args, err := In(q, telcodes)
@@ -1864,11 +1863,11 @@ func TestIn130Regression(t *testing.T) {
 		}
 		t.Log(args)
 		for _, a := range args {
-			switch a.(type) {
+			switch a := a.(type) {
 			case string:
 				t.Log("ok: string", a)
 			case *string:
-				t.Error("ng: string pointer", a, *a.(*string))
+				t.Error("ng: string pointer", a, *a)
 			}
 		}
 	})
@@ -1883,11 +1882,11 @@ func TestIn130Regression(t *testing.T) {
 		}
 		t.Log(args)
 		for _, a := range args {
-			switch a.(type) {
+			switch a := a.(type) {
 			case string:
 				t.Log("ok: string", a)
 			case *string:
-				t.Error("ng: string pointer", a, *a.(*string))
+				t.Error("ng: string pointer", a, *a)
 			}
 		}
 	})
diff --git a/types/doc.go b/types/doc.go
new file mode 100644
index 00000000..a3cca5c7
--- /dev/null
+++ b/types/doc.go
@@ -0,0 +1,4 @@
+// Package types provides some useful types which implement the `sql.Scanner`
+// and `driver.Valuer` interfaces, suitable for use as scan and value targets with
+// database/sql.
+package types
diff --git a/types/types.go b/types/types.go
index 808f5834..fe4c634b 100644
--- a/types/types.go
+++ b/types/types.go
@@ -6,7 +6,6 @@ import (
 	"database/sql/driver"
 	"encoding/json"
 	"errors"
-
 	"io/ioutil"
 )
 
@@ -36,6 +35,7 @@ func (g *GzippedText) Scan(src interface{}) error {
 	case []byte:
 		source = src
 	default:
+		//lint:ignore ST1005 changing this could break consumers of this package
 		return errors.New("Incompatible type for GzippedText")
 	}
 	reader, err := gzip.NewReader(bytes.NewReader(source))
@@ -102,6 +102,7 @@ func (j *JSONText) Scan(src interface{}) error {
 	case nil:
 		*j = emptyJSON
 	default:
+		//lint:ignore ST1005 changing this could break consumers of this package
 		return errors.New("Incompatible type for JSONText")
 	}
 	*j = append((*j)[0:0], source...)
diff --git a/types/types_test.go b/types/types_test.go
index 29813d1e..721d35e4 100644
--- a/types/types_test.go
+++ b/types/types_test.go
@@ -35,7 +35,7 @@ func TestJSONText(t *testing.T) {
 	}
 
 	j = JSONText(`{"foo": 1, invalid, false}`)
-	v, err = j.Value()
+	_, err = j.Value()
 	if err == nil {
 		t.Errorf("Was expecting invalid json to fail!")
 	}