Update golangci-lint and turn it on in CI

This commit is contained in:
Dmitry Kropachev
2024-06-14 13:07:21 -04:00
committed by Sylwia Szunejko
parent a9ab270196
commit ab80d70106
37 changed files with 225 additions and 151 deletions

View File

@@ -17,7 +17,8 @@ jobs:
steps: steps:
- name: Git Checkout - name: Git Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
fetch-depth: '0'
- name: Install Go 1.17 - name: Install Go 1.17
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
@@ -33,17 +34,13 @@ jobs:
${{ runner.os }}-go- ${{ runner.os }}-go-
- name: Make Directory for GOBIN - name: Make Directory for GOBIN
run: mkdir -p ${GOBIN} run: mkdir -p "${GOBIN}"
- name: Download Dependencies - name: Download Dependencies
run: make get-deps run: git --version && make get-deps && make get-tools
# - name: Lint - name: Lint
# uses: golangci/golangci-lint-action@v3 run: make check
# with:
# version: v1.45.2
- run: go vet ./...
- name: Run Scylla Container - name: Run Scylla Container
run: make run-scylla run: make run-scylla

View File

@@ -1,8 +1,23 @@
run: run:
deadline: 5m deadline: 5m
tests: false tests: true
allow-parallel-runners: true
modules-download-mode: readonly
build-tags: [ all, integration ]
linters-settings: linters-settings:
revive:
rules:
- name: package-comments
disabled: true
goimports:
local-prefixes: github.com/scylladb/gocqlx
gofumpt:
extra-rules: true
govet:
enable-all: true
disable:
- shadow
errcheck: errcheck:
check-blank: true check-blank: true
gocognit: gocognit:
@@ -23,22 +38,43 @@ linters-settings:
line-length: 180 line-length: 180
linters: linters:
enable-all: true disable-all: true
disable: enable:
- funlen - errcheck
- gas - gocritic
- gochecknoglobals - gofumpt
- gochecknoinits - goheader
- gomnd - goimports
- interfacer - gosimple
- maligned - govet
- nakedret - ineffassign
- prealloc - lll
- wsl - misspell
- predeclared
- revive
- staticcheck
- thelper
- tparallel
- typecheck
- unused
- forbidigo
issues: issues:
new: true
new-from-rev: origin/master
exclude-use-default: false exclude-use-default: false
exclude: exclude:
- composite literal uses unkeyed fields - composite literal uses unkeyed fields
- Error return value of `.+\.Close` is not checked - Error return value of `.+\.Close` is not checked
- method Json should be JSON - method Json should be JSON
exclude-rules:
- path: (.*_test.go|migrate/example|gocqlxtest/)
linters:
- fieldalignment
- govet
- errcheck
- path: doc_test.go
linters:
- unused
- revive

View File

@@ -28,6 +28,12 @@ fmt:
check: check:
@$(GOBIN)/golangci-lint run ./... @$(GOBIN)/golangci-lint run ./...
.PHONY: fix
fix:
@$(GOBIN)/golangci-lint run --fix ./...
@fieldalignment -V=full >/dev/null 2>&1 || go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@v0.11.0
@$(GOBIN)/fieldalignment -test=false -fix ./...
GOTEST := go test -cpu $(GOTEST_CPU) -count=1 -cover -race -tags all GOTEST := go test -cpu $(GOTEST_CPU) -count=1 -cover -race -tags all
.PHONY: test .PHONY: test
@@ -51,12 +57,12 @@ run-examples:
run-scylla: run-scylla:
@echo "==> Running test instance of Scylla $(SCYLLA_VERSION)" @echo "==> Running test instance of Scylla $(SCYLLA_VERSION)"
@docker pull scylladb/scylla:$(SCYLLA_VERSION) @docker pull scylladb/scylla:$(SCYLLA_VERSION)
@docker run --name scylla -p 9042:9042 --cpuset-cpus=$(SCYLLA_CPU) --memory 1G --rm -d scylladb/scylla:$(SCYLLA_VERSION) @docker run --name gocqlx-scylla -p 9042:9042 --cpuset-cpus=$(SCYLLA_CPU) --memory 1G --rm -d scylladb/scylla:$(SCYLLA_VERSION)
@until docker exec scylla cqlsh -e "DESCRIBE SCHEMA"; do sleep 2; done @until docker exec gocqlx-scylla cqlsh -e "DESCRIBE SCHEMA"; do sleep 2; done
.PHONY: stop-scylla .PHONY: stop-scylla
stop-scylla: stop-scylla:
@docker stop scylla @docker stop gocqlx-scylla
.PHONY: get-deps .PHONY: get-deps
get-deps: get-deps:
@@ -69,4 +75,4 @@ endef
.PHONY: get-tools .PHONY: get-tools
get-tools: get-tools:
@echo "==> Installing tools at $(GOBIN)..." @echo "==> Installing tools at $(GOBIN)..."
@$(call dl_tgz,golangci-lint,https://github.com/golangci/golangci-lint/releases/download/v1.45.2/golangci-lint-v1.45.2-linux-amd64.tar.gz) @$(call dl_tgz,golangci-lint,https://github.com/golangci/golangci-lint/releases/download/v1.59.1/golangci-lint-1.59.1-linux-amd64.tar.gz)

View File

@@ -4,6 +4,7 @@ import (
"github.com/gocql/gocql" "github.com/gocql/gocql"
) )
// Batch is a wrapper around gocql.Batch
type Batch struct { type Batch struct {
*gocql.Batch *gocql.Batch
} }

View File

@@ -12,6 +12,7 @@ import (
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/scylladb/gocqlx/v2" "github.com/scylladb/gocqlx/v2"
"github.com/scylladb/gocqlx/v2/gocqlxtest" "github.com/scylladb/gocqlx/v2/gocqlxtest"
"github.com/scylladb/gocqlx/v2/qb" "github.com/scylladb/gocqlx/v2/qb"

View File

@@ -13,7 +13,7 @@ import (
"testing" "testing"
"github.com/scylladb/gocqlx/v2" "github.com/scylladb/gocqlx/v2"
. "github.com/scylladb/gocqlx/v2/gocqlxtest" "github.com/scylladb/gocqlx/v2/gocqlxtest"
"github.com/scylladb/gocqlx/v2/qb" "github.com/scylladb/gocqlx/v2/qb"
) )
@@ -46,7 +46,7 @@ var benchPersonCols = []string{"id", "first_name", "last_name", "email", "gender
// BenchmarkBaseGocqlInsert performs standard insert. // BenchmarkBaseGocqlInsert performs standard insert.
func BenchmarkBaseGocqlInsert(b *testing.B) { func BenchmarkBaseGocqlInsert(b *testing.B) {
people := loadFixtures() people := loadFixtures()
session := CreateSession(b) session := gocqlxtest.CreateSession(b)
defer session.Close() defer session.Close()
if err := session.ExecStmt(benchPersonSchema); err != nil { if err := session.ExecStmt(benchPersonSchema); err != nil {
@@ -69,7 +69,7 @@ func BenchmarkBaseGocqlInsert(b *testing.B) {
// BenchmarkGocqlInsert performs insert with struct binding. // BenchmarkGocqlInsert performs insert with struct binding.
func BenchmarkGocqlxInsert(b *testing.B) { func BenchmarkGocqlxInsert(b *testing.B) {
people := loadFixtures() people := loadFixtures()
session := CreateSession(b) session := gocqlxtest.CreateSession(b)
defer session.Close() defer session.Close()
if err := session.ExecStmt(benchPersonSchema); err != nil { if err := session.ExecStmt(benchPersonSchema); err != nil {
@@ -96,7 +96,7 @@ func BenchmarkGocqlxInsert(b *testing.B) {
// BenchmarkBaseGocqlGet performs standard scan. // BenchmarkBaseGocqlGet performs standard scan.
func BenchmarkBaseGocqlGet(b *testing.B) { func BenchmarkBaseGocqlGet(b *testing.B) {
people := loadFixtures() people := loadFixtures()
session := CreateSession(b) session := gocqlxtest.CreateSession(b)
defer session.Close() defer session.Close()
initTable(b, session, people) initTable(b, session, people)
@@ -119,7 +119,7 @@ func BenchmarkBaseGocqlGet(b *testing.B) {
// BenchmarkGocqlxGet performs get. // BenchmarkGocqlxGet performs get.
func BenchmarkGocqlxGet(b *testing.B) { func BenchmarkGocqlxGet(b *testing.B) {
people := loadFixtures() people := loadFixtures()
session := CreateSession(b) session := gocqlxtest.CreateSession(b)
defer session.Close() defer session.Close()
initTable(b, session, people) initTable(b, session, people)
@@ -147,7 +147,7 @@ func BenchmarkGocqlxGet(b *testing.B) {
// pointers. // pointers.
func BenchmarkBaseGocqlSelect(b *testing.B) { func BenchmarkBaseGocqlSelect(b *testing.B) {
people := loadFixtures() people := loadFixtures()
session := CreateSession(b) session := gocqlxtest.CreateSession(b)
defer session.Close() defer session.Close()
initTable(b, session, people) initTable(b, session, people)
@@ -162,7 +162,7 @@ func BenchmarkBaseGocqlSelect(b *testing.B) {
v := make([]*benchPerson, 100) v := make([]*benchPerson, 100)
p := new(benchPerson) p := new(benchPerson)
for iter.Scan(&p.ID, &p.FirstName, &p.LastName, &p.Email, &p.Gender, &p.IPAddress) { for iter.Scan(&p.ID, &p.FirstName, &p.LastName, &p.Email, &p.Gender, &p.IPAddress) {
v = append(v, p) v = append(v, p) // nolint:staticcheck
p = new(benchPerson) p = new(benchPerson)
} }
if err := iter.Close(); err != nil { if err := iter.Close(); err != nil {
@@ -174,7 +174,7 @@ func BenchmarkBaseGocqlSelect(b *testing.B) {
// BenchmarkGocqlSelect performs select to a slice pointers. // BenchmarkGocqlSelect performs select to a slice pointers.
func BenchmarkGocqlxSelect(b *testing.B) { func BenchmarkGocqlxSelect(b *testing.B) {
people := loadFixtures() people := loadFixtures()
session := CreateSession(b) session := gocqlxtest.CreateSession(b)
defer session.Close() defer session.Close()
initTable(b, session, people) initTable(b, session, people)
@@ -212,6 +212,8 @@ func loadFixtures() []*benchPerson {
} }
func initTable(b *testing.B, session gocqlx.Session, people []*benchPerson) { func initTable(b *testing.B, session gocqlx.Session, people []*benchPerson) {
b.Helper()
if err := session.ExecStmt(benchPersonSchema); err != nil { if err := session.ExecStmt(benchPersonSchema); err != nil {
b.Fatal(err) b.Fatal(err)
} }

View File

@@ -74,9 +74,9 @@ func mapScyllaToGoType(s string) string {
typeStr := "struct {\n" typeStr := "struct {\n"
for i, t := range types { for i, t := range types {
typeStr = typeStr + "\t\tField" + strconv.Itoa(i+1) + " " + mapScyllaToGoType(t) + "\n" typeStr += "\t\tField" + strconv.Itoa(i+1) + " " + mapScyllaToGoType(t) + "\n"
} }
typeStr = typeStr + "\t}" typeStr += "\t}"
return typeStr return typeStr
} }
@@ -96,8 +96,8 @@ func typeToString(t interface{}) string {
return t.(gocql.NativeType).String() return t.(gocql.NativeType).String()
case "gocql.CollectionType": case "gocql.CollectionType":
collectionType := t.(gocql.CollectionType).String() collectionType := t.(gocql.CollectionType).String()
collectionType = strings.Replace(collectionType, "(", "<", -1) collectionType = strings.ReplaceAll(collectionType, "(", "<")
collectionType = strings.Replace(collectionType, ")", ">", -1) collectionType = strings.ReplaceAll(collectionType, ")", ">")
return collectionType return collectionType
default: default:
panic(fmt.Sprintf("Did not expect %v type in user defined type", tType)) panic(fmt.Sprintf("Did not expect %v type in user defined type", tType))

View File

@@ -15,6 +15,7 @@ import (
"strings" "strings"
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/scylladb/gocqlx/v2" "github.com/scylladb/gocqlx/v2"
_ "github.com/scylladb/gocqlx/v2/table" _ "github.com/scylladb/gocqlx/v2/table"
) )
@@ -31,10 +32,8 @@ var (
flagIgnoreIndexes = cmd.Bool("ignore-indexes", false, "don't generate types for indexes") flagIgnoreIndexes = cmd.Bool("ignore-indexes", false, "don't generate types for indexes")
) )
var (
//go:embed keyspace.tmpl //go:embed keyspace.tmpl
keyspaceTmpl string var keyspaceTmpl string
)
func main() { func main() {
err := cmd.Parse(os.Args[1:]) err := cmd.Parse(os.Args[1:])
@@ -80,7 +79,6 @@ func renderTemplate(md *gocql.KeyspaceMetadata) ([]byte, error) {
Funcs(template.FuncMap{"mapScyllaToGoType": mapScyllaToGoType}). Funcs(template.FuncMap{"mapScyllaToGoType": mapScyllaToGoType}).
Funcs(template.FuncMap{"typeToString": typeToString}). Funcs(template.FuncMap{"typeToString": typeToString}).
Parse(keyspaceTmpl) Parse(keyspaceTmpl)
if err != nil { if err != nil {
log.Fatalln("unable to parse models template:", err) log.Fatalln("unable to parse models template:", err)
} }
@@ -169,7 +167,7 @@ func existsInSlice(s []string, v string) bool {
// The second element contains the name of the type. // The second element contains the name of the type.
// //
// [["<my_type,", "my_type"] ["my_other_type>", "my_other_type"]] // [["<my_type,", "my_type"] ["my_other_type>", "my_other_type"]]
var userTypes = regexp.MustCompile(`(?:<|\s)(\w+)(?:>|,)`) // match all types contained in set<X>, list<X>, tuple<A, B> etc. var userTypes = regexp.MustCompile(`(?:<|\s)(\w+)[>,]`) // match all types contained in set<X>, list<X>, tuple<A, B> etc.
// usedInTables reports whether the typeName is used in any of columns of the provided tables. // usedInTables reports whether the typeName is used in any of columns of the provided tables.
func usedInTables(typeName string, tables map[string]*gocql.TableMetadata) bool { func usedInTables(typeName string, tables map[string]*gocql.TableMetadata) bool {

View File

@@ -10,6 +10,7 @@ import (
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/scylladb/gocqlx/v2/gocqlxtest" "github.com/scylladb/gocqlx/v2/gocqlxtest"
) )

View File

@@ -12,13 +12,13 @@ import (
"time" "time"
"github.com/scylladb/gocqlx/v2/dbutil" "github.com/scylladb/gocqlx/v2/dbutil"
. "github.com/scylladb/gocqlx/v2/gocqlxtest" "github.com/scylladb/gocqlx/v2/gocqlxtest"
"github.com/scylladb/gocqlx/v2/qb" "github.com/scylladb/gocqlx/v2/qb"
"github.com/scylladb/gocqlx/v2/table" "github.com/scylladb/gocqlx/v2/table"
) )
func TestRewriteTableTTL(t *testing.T) { func TestRewriteTableTTL(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.rewrite_table (testtext text PRIMARY KEY)`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.rewrite_table (testtext text PRIMARY KEY)`); err != nil {
@@ -61,7 +61,7 @@ func TestRewriteTableTTL(t *testing.T) {
} }
func TestRewriteTableClone(t *testing.T) { func TestRewriteTableClone(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.rewrite_table_clone_src (testtext text PRIMARY KEY, testint int)`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.rewrite_table_clone_src (testtext text PRIMARY KEY, testint int)`); err != nil {

View File

@@ -6,6 +6,7 @@ package gocqlx_test
import ( import (
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/scylladb/gocqlx/v2" "github.com/scylladb/gocqlx/v2"
"github.com/scylladb/gocqlx/v2/qb" "github.com/scylladb/gocqlx/v2/qb"
) )

View File

@@ -14,12 +14,13 @@ import (
"time" "time"
"github.com/gocql/gocql" "github.com/gocql/gocql"
"golang.org/x/sync/errgroup"
"gopkg.in/inf.v0"
"github.com/scylladb/gocqlx/v2" "github.com/scylladb/gocqlx/v2"
"github.com/scylladb/gocqlx/v2/gocqlxtest" "github.com/scylladb/gocqlx/v2/gocqlxtest"
"github.com/scylladb/gocqlx/v2/qb" "github.com/scylladb/gocqlx/v2/qb"
"github.com/scylladb/gocqlx/v2/table" "github.com/scylladb/gocqlx/v2/table"
"golang.org/x/sync/errgroup"
"gopkg.in/inf.v0"
) )
// Running examples locally: // Running examples locally:
@@ -43,7 +44,7 @@ func TestExample(t *testing.T) {
datatypesBlob(t, session) datatypesBlob(t, session)
datatypesUserDefinedType(t, session) datatypesUserDefinedType(t, session)
datatypesUserDefinedTypeWrapper(t, session) datatypesUserDefinedTypeWrapper(t, session)
datatypesJson(t, session) datatypesJSON(t, session)
pagingForwardPaging(t, session) pagingForwardPaging(t, session)
pagingEfficientFullTableScan(t, session) pagingEfficientFullTableScan(t, session)
@@ -73,6 +74,8 @@ type PlaylistItem struct {
// queries. It uses "BindStruct" function for parameter binding and "Select" // queries. It uses "BindStruct" function for parameter binding and "Select"
// function for loading data to a slice. // function for loading data to a slice.
func basicCreateAndPopulateKeyspace(t *testing.T, session gocqlx.Session, keyspace string) { func basicCreateAndPopulateKeyspace(t *testing.T, session gocqlx.Session, keyspace string) {
t.Helper()
err := session.ExecStmt(fmt.Sprintf( err := session.ExecStmt(fmt.Sprintf(
`CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`, `CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`,
keyspace, keyspace,
@@ -162,6 +165,8 @@ func basicCreateAndPopulateKeyspace(t *testing.T, session gocqlx.Session, keyspa
// queries with all types. It uses "BindStruct" function for parameter binding and "Select" // queries with all types. It uses "BindStruct" function for parameter binding and "Select"
// function for loading data to a slice. // function for loading data to a slice.
func createAndPopulateKeyspaceAllTypes(t *testing.T, session gocqlx.Session) { func createAndPopulateKeyspaceAllTypes(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)
@@ -178,7 +183,7 @@ func createAndPopulateKeyspaceAllTypes(t *testing.T, session gocqlx.Session) {
DoublE float64 DoublE float64
DuratioN gocql.Duration DuratioN gocql.Duration
FloaT float32 FloaT float32
Id [16]byte ID [16]byte
InT int32 InT int32
IneT string IneT string
ListInt []int32 ListInt []int32
@@ -256,14 +261,16 @@ func createAndPopulateKeyspaceAllTypes(t *testing.T, session gocqlx.Session) {
// Insert song using query builder. // Insert song using query builder.
insertCheckTypes := qb.Insert("examples.check_types"). insertCheckTypes := qb.Insert("examples.check_types").
Columns("asci_i", "big_int", "blo_b", "boolea_n", "dat_e", "decima_l", "doubl_e", "duratio_n", "floa_t", "ine_t", "in_t", "small_int", "tex_t", "tim_e", "timestam_p", "timeuui_d", "tiny_int", "id", "var_char", "var_int", "map_int_text", "list_int", "set_int").Query(session) Columns("asci_i", "big_int", "blo_b", "boolea_n", "dat_e", "decima_l", "doubl_e", "duratio_n", "floa_t",
"ine_t", "in_t", "small_int", "tex_t", "tim_e", "timestam_p", "timeuui_d", "tiny_int", "id", "var_char",
"var_int", "map_int_text", "list_int", "set_int").Query(session)
var byteId [16]byte var byteID [16]byte
id := []byte("756716f7-2e54-4715-9f00-91dcbea6cf50") id := []byte("756716f7-2e54-4715-9f00-91dcbea6cf50")
copy(byteId[:], id) copy(byteID[:], id)
date := time.Date(2021, time.December, 11, 10, 23, 0, 0, time.UTC) date := time.Date(2021, time.December, 11, 10, 23, 0, 0, time.UTC)
var double float64 = 1.2 var double float64 = 1.2 // nolint:revive
var float float32 = 1.3 var float float32 = 1.3
var integer int32 = 123 var integer int32 = 123
listInt := []int32{1, 2, 3} listInt := []int32{1, 2, 3}
@@ -286,7 +293,7 @@ func createAndPopulateKeyspaceAllTypes(t *testing.T, session gocqlx.Session) {
DoublE: double, DoublE: double,
DuratioN: gocql.Duration{Months: 1, Days: 1, Nanoseconds: 86400}, DuratioN: gocql.Duration{Months: 1, Days: 1, Nanoseconds: 86400},
FloaT: float, FloaT: float,
Id: byteId, ID: byteID,
InT: integer, InT: integer,
IneT: "127.0.0.1", IneT: "127.0.0.1",
ListInt: listInt, ListInt: listInt,
@@ -309,7 +316,7 @@ func createAndPopulateKeyspaceAllTypes(t *testing.T, session gocqlx.Session) {
queryCheckTypes := checkTypesTable.SelectQuery(session) queryCheckTypes := checkTypesTable.SelectQuery(session)
queryCheckTypes.BindStruct(&CheckTypesStruct{ queryCheckTypes.BindStruct(&CheckTypesStruct{
Id: byteId, ID: byteID,
}) })
var items []*CheckTypesStruct var items []*CheckTypesStruct
@@ -325,6 +332,8 @@ func createAndPopulateKeyspaceAllTypes(t *testing.T, session gocqlx.Session) {
// This example shows how to load a single value using "Get" function. // This example shows how to load a single value using "Get" function.
// Get can also work with UDTs and types that implement gocql marshalling functions. // Get can also work with UDTs and types that implement gocql marshalling functions.
func basicReadScyllaVersion(t *testing.T, session gocqlx.Session) { func basicReadScyllaVersion(t *testing.T, session gocqlx.Session) {
t.Helper()
var releaseVersion string var releaseVersion string
err := session.Query("SELECT release_version FROM system.local", nil).Get(&releaseVersion) err := session.Query("SELECT release_version FROM system.local", nil).Get(&releaseVersion)
@@ -340,6 +349,8 @@ func basicReadScyllaVersion(t *testing.T, session gocqlx.Session) {
// to handle situations where driver returns more coluns that we are ready to // to handle situations where driver returns more coluns that we are ready to
// consume. // consume.
func datatypesBlob(t *testing.T, session gocqlx.Session) { func datatypesBlob(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)
@@ -392,6 +403,8 @@ type Coordinates struct {
// This example shows how to add User Defined Type marshalling capabilities by // This example shows how to add User Defined Type marshalling capabilities by
// adding a single line - embedding gocqlx.UDT. // adding a single line - embedding gocqlx.UDT.
func datatypesUserDefinedType(t *testing.T, session gocqlx.Session) { func datatypesUserDefinedType(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)
@@ -446,6 +459,8 @@ type coordinates struct {
// types that we cannot modify, like library or transfer objects, without // types that we cannot modify, like library or transfer objects, without
// rewriting them in runtime. // rewriting them in runtime.
func datatypesUserDefinedTypeWrapper(t *testing.T, session gocqlx.Session) { func datatypesUserDefinedTypeWrapper(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)
@@ -501,7 +516,9 @@ func datatypesUserDefinedTypeWrapper(t *testing.T, session gocqlx.Session) {
} }
// This example shows how to use query builder to work with // This example shows how to use query builder to work with
func datatypesJson(t *testing.T, session gocqlx.Session) { func datatypesJSON(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)
@@ -524,17 +541,17 @@ func datatypesJson(t *testing.T, session gocqlx.Session) {
} }
// fromJson lets you provide individual columns as JSON: // fromJson lets you provide individual columns as JSON:
insertFromJson := qb.Insert("examples.querybuilder_json"). insertFromJSON := qb.Insert("examples.querybuilder_json").
Columns("id", "name"). Columns("id", "name").
FuncColumn("specs", qb.Fn("fromJson", "json")). FuncColumn("specs", qb.Fn("fromJson", "json")).
Query(session) Query(session)
insertFromJson.BindMap(qb.M{ insertFromJSON.BindMap(qb.M{
"id": 3, "id": 3,
"name": "Screen", "name": "Screen",
"json": `{ "size": "24-inch" }`, "json": `{ "size": "24-inch" }`,
}) })
if err := insertFromJson.Exec(); err != nil { if err := insertFromJSON.Exec(); err != nil {
t.Fatal("Exec() failed:", err) t.Fatal("Exec() failed:", err)
} }
@@ -559,12 +576,12 @@ func datatypesJson(t *testing.T, session gocqlx.Session) {
row := &struct { row := &struct {
ID int ID int
JsonSpecs string JSONSpecs string
}{} }{}
if err := q.Get(row); err != nil { if err := q.Get(row); err != nil {
t.Fatal("Get() failed:", err) t.Fatal("Get() failed:", err)
} }
t.Logf("Entry #%d's specs as JSON: %s", row.ID, row.JsonSpecs) t.Logf("Entry #%d's specs as JSON: %s", row.ID, row.JSONSpecs)
} }
type Video struct { type Video struct {
@@ -600,6 +617,8 @@ func pagingFillTable(t *testing.T, insert *gocqlx.Queryx) {
// This example shows how to use stateful paging and how "Select" function // This example shows how to use stateful paging and how "Select" function
// can be used to fetch single page only. // can be used to fetch single page only.
func pagingForwardPaging(t *testing.T, session gocqlx.Session) { func pagingForwardPaging(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)
@@ -669,6 +688,8 @@ func pagingForwardPaging(t *testing.T, session gocqlx.Session) {
// //
// [1] https://www.scylladb.com/2017/02/13/efficient-full-table-scans-with-scylla-1-6/. // [1] https://www.scylladb.com/2017/02/13/efficient-full-table-scans-with-scylla-1-6/.
func pagingEfficientFullTableScan(t *testing.T, session gocqlx.Session) { func pagingEfficientFullTableScan(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)
@@ -779,6 +800,8 @@ func pagingEfficientFullTableScan(t *testing.T, session gocqlx.Session) {
// Compare-And-Set (CAS) functions. // Compare-And-Set (CAS) functions.
// See: https://docs.scylladb.com/using-scylla/lwt/ for more details. // See: https://docs.scylladb.com/using-scylla/lwt/ for more details.
func lwtLock(t *testing.T, session gocqlx.Session) { func lwtLock(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)
@@ -878,6 +901,8 @@ func lwtLock(t *testing.T, session gocqlx.Session) {
// This example shows how to reuse the same insert statement with // This example shows how to reuse the same insert statement with
// partially filled parameters without generating tombstones for empty columns. // partially filled parameters without generating tombstones for empty columns.
func unsetEmptyValues(t *testing.T, session gocqlx.Session) { func unsetEmptyValues(t *testing.T, session gocqlx.Session) {
t.Helper()
err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`) err := session.ExecStmt(`CREATE KEYSPACE IF NOT EXISTS examples WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`)
if err != nil { if err != nil {
t.Fatal("create keyspace:", err) t.Fatal("create keyspace:", err)

5
go.sum
View File

@@ -3,13 +3,8 @@ github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCS
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gocql/gocql v0.0.0-20200131111108-92af2e088537 h1:NaMut1fdw76YYX/TPinSAbai4DShF5tPort3bHpET6g=
github.com/gocql/gocql v0.0.0-20200131111108-92af2e088537/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY=
github.com/gocql/gocql v0.0.0-20211015133455-b225f9b53fa1 h1:px9qUCy/RNJNsfCam4m2IxWGxNuimkrioEF0vrrbPsg= github.com/gocql/gocql v0.0.0-20211015133455-b225f9b53fa1 h1:px9qUCy/RNJNsfCam4m2IxWGxNuimkrioEF0vrrbPsg=
github.com/gocql/gocql v0.0.0-20211015133455-b225f9b53fa1/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= github.com/gocql/gocql v0.0.0-20211015133455-b225f9b53fa1/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=

View File

@@ -13,6 +13,7 @@ import (
"time" "time"
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/scylladb/gocqlx/v2" "github.com/scylladb/gocqlx/v2"
) )
@@ -31,8 +32,10 @@ var initOnce sync.Once
// CreateSession creates a new gocqlx session from flags. // CreateSession creates a new gocqlx session from flags.
func CreateSession(tb testing.TB) gocqlx.Session { func CreateSession(tb testing.TB) gocqlx.Session {
tb.Helper()
cluster := CreateCluster() cluster := CreateCluster()
return createSessionFromCluster(cluster, tb) return createSessionFromCluster(tb, cluster)
} }
// CreateCluster creates gocql ClusterConfig from flags. // CreateCluster creates gocql ClusterConfig from flags.
@@ -92,7 +95,8 @@ func CreateKeyspace(cluster *gocql.ClusterConfig, keyspace string) error {
return nil return nil
} }
func createSessionFromCluster(cluster *gocql.ClusterConfig, tb testing.TB) gocqlx.Session { func createSessionFromCluster(tb testing.TB, cluster *gocql.ClusterConfig) gocqlx.Session {
tb.Helper()
if !flag.Parsed() { if !flag.Parsed() {
flag.Parse() flag.Parse()
} }

View File

@@ -19,17 +19,16 @@ var DefaultUnsafe bool
// Iterx is a wrapper around gocql.Iter which adds struct scanning capabilities. // Iterx is a wrapper around gocql.Iter which adds struct scanning capabilities.
type Iterx struct { type Iterx struct {
err error
*gocql.Iter *gocql.Iter
Mapper *reflectx.Mapper Mapper *reflectx.Mapper
unsafe bool
structOnly bool
applied bool
err error
// Cache memory for a rows during iteration in structScan. // Cache memory for a rows during iteration in structScan.
fields [][]int fields [][]int
values []interface{} values []interface{}
unsafe bool
structOnly bool
applied bool
} }
// Unsafe forces the iterator to ignore missing fields. By default when scanning // Unsafe forces the iterator to ignore missing fields. By default when scanning
@@ -206,9 +205,9 @@ func (iter *Iterx) scanAll(dest interface{}) bool {
// isScannable takes the reflect.Type and the actual dest value and returns // isScannable takes the reflect.Type and the actual dest value and returns
// whether or not it's Scannable. t is scannable if: // whether or not it's Scannable. t is scannable if:
// * ptr to t implements gocql.Unmarshaler, gocql.UDTUnmarshaler or UDT // - ptr to t implements gocql.Unmarshaler, gocql.UDTUnmarshaler or UDT
// * it is not a struct // - it is not a struct
// * it has no exported fields // - it has no exported fields
func (iter *Iterx) isScannable(t reflect.Type) bool { func (iter *Iterx) isScannable(t reflect.Type) bool {
ptr := reflect.PtrTo(t) ptr := reflect.PtrTo(t)
switch { switch {

View File

@@ -16,10 +16,11 @@ import (
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
"github.com/scylladb/gocqlx/v2"
. "github.com/scylladb/gocqlx/v2/gocqlxtest"
"github.com/scylladb/gocqlx/v2/qb"
"gopkg.in/inf.v0" "gopkg.in/inf.v0"
"github.com/scylladb/gocqlx/v2"
"github.com/scylladb/gocqlx/v2/gocqlxtest"
"github.com/scylladb/gocqlx/v2/qb"
) )
type FullName struct { type FullName struct {
@@ -48,7 +49,7 @@ type FullNamePtrUDT struct {
} }
func TestIterxStruct(t *testing.T) { func TestIterxStruct(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TYPE gocqlx_test.FullName (first_Name text, last_name text)`); err != nil { if err := session.ExecStmt(`CREATE TYPE gocqlx_test.FullName (first_Name text, last_name text)`); err != nil {
@@ -125,7 +126,10 @@ func TestIterxStruct(t *testing.T) {
Testptrudt: FullNamePtrUDT{FullName: &FullName{FirstName: "John", LastName: "Doe"}}, Testptrudt: FullNamePtrUDT{FullName: &FullName{FirstName: "John", LastName: "Doe"}},
} }
const insertStmt = `INSERT INTO struct_table (testuuid, testtimestamp, testvarchar, testbigint, testblob, testbool, testfloat,testdouble, testint, testdecimal, testlist, testset, testmap, testvarint, testinet, testcustom, testudt, testptrudt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` const insertStmt = `INSERT INTO struct_table (
testuuid, testtimestamp, testvarchar, testbigint, testblob, testbool, testfloat, testdouble,
testint, testdecimal, testlist, testset, testmap, testvarint, testinet, testcustom, testudt, testptrudt
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
if err := session.Query(insertStmt, nil).Bind( if err := session.Query(insertStmt, nil).Bind(
m.Testuuid, m.Testuuid,
@@ -212,7 +216,7 @@ func TestIterxStruct(t *testing.T) {
} }
func TestIterxScannable(t *testing.T) { func TestIterxScannable(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.scannable_table (testfullname text PRIMARY KEY)`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.scannable_table (testfullname text PRIMARY KEY)`); err != nil {
@@ -265,7 +269,7 @@ func TestIterxScannable(t *testing.T) {
} }
func TestIterxStructOnly(t *testing.T) { func TestIterxStructOnly(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.struct_only_table (first_name text, last_name text, PRIMARY KEY (first_name, last_name))`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.struct_only_table (first_name text, last_name text, PRIMARY KEY (first_name, last_name))`); err != nil {
@@ -336,7 +340,7 @@ func TestIterxStructOnly(t *testing.T) {
} }
func TestIterxStructOnlyUDT(t *testing.T) { func TestIterxStructOnlyUDT(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.struct_only_udt_table (first_name text, last_name text, PRIMARY KEY (first_name, last_name))`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.struct_only_udt_table (first_name text, last_name text, PRIMARY KEY (first_name, last_name))`); err != nil {
@@ -412,7 +416,7 @@ func TestIterxStructOnlyUDT(t *testing.T) {
} }
func TestIterxUnsafe(t *testing.T) { func TestIterxUnsafe(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.unsafe_table (testtext text PRIMARY KEY, testtextunbound text)`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.unsafe_table (testtext text PRIMARY KEY, testtextunbound text)`); err != nil {
@@ -499,7 +503,7 @@ func TestIterxUnsafe(t *testing.T) {
} }
func TestIterxNotFound(t *testing.T) { func TestIterxNotFound(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.not_found_table (testtext text PRIMARY KEY)`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.not_found_table (testtext text PRIMARY KEY)`); err != nil {
@@ -547,7 +551,7 @@ func TestIterxNotFound(t *testing.T) {
} }
func TestIterxErrorOnNil(t *testing.T) { func TestIterxErrorOnNil(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.nil_table (testtext text PRIMARY KEY)`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.nil_table (testtext text PRIMARY KEY)`); err != nil {
@@ -582,7 +586,7 @@ func TestIterxErrorOnNil(t *testing.T) {
} }
func TestIterxPaging(t *testing.T) { func TestIterxPaging(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.paging_table (id int PRIMARY KEY, val int)`); err != nil { if err := session.ExecStmt(`CREATE TABLE gocqlx_test.paging_table (id int PRIMARY KEY, val int)`); err != nil {
@@ -625,7 +629,7 @@ func TestIterxPaging(t *testing.T) {
} }
func TestIterxCAS(t *testing.T) { func TestIterxCAS(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
const ( const (

View File

@@ -2,6 +2,7 @@
// Use of this source code is governed by a ALv2-style // Use of this source code is governed by a ALv2-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build all || integration
// +build all integration // +build all integration
package cql package cql
@@ -9,5 +10,6 @@ package cql
import "embed" import "embed"
// Files contains *.cql schema migration files. // Files contains *.cql schema migration files.
//
//go:embed *.cql //go:embed *.cql
var Files embed.FS var Files embed.FS

View File

@@ -2,6 +2,7 @@
// Use of this source code is governed by a ALv2-style // Use of this source code is governed by a ALv2-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build all || integration
// +build all integration // +build all integration
package example package example

View File

@@ -7,7 +7,6 @@ package migrate
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs" "io/fs"
@@ -20,6 +19,7 @@ import (
"time" "time"
"github.com/gocql/gocql" "github.com/gocql/gocql"
"github.com/scylladb/gocqlx/v2" "github.com/scylladb/gocqlx/v2"
"github.com/scylladb/gocqlx/v2/qb" "github.com/scylladb/gocqlx/v2/qb"
) )
@@ -58,11 +58,11 @@ const (
// Info contains information on migration applied on a database. // Info contains information on migration applied on a database.
type Info struct { type Info struct {
StartTime time.Time
EndTime time.Time
Name string Name string
Checksum string Checksum string
Done int Done int
StartTime time.Time
EndTime time.Time
} }
// List provides a listing of applied migrations. // List provides a listing of applied migrations.
@@ -128,8 +128,7 @@ func FromFS(ctx context.Context, session gocqlx.Session, f fs.FS) error {
for i := 0; i < len(dbm); i++ { for i := 0; i < len(dbm); i++ {
if dbm[i].Name != fm[i] { if dbm[i].Name != fm[i] {
fmt.Println(dbm[i].Name, fm[i], i) return fmt.Errorf("inconsistent migrations found, expected %q got %q at %d", fm[i], dbm[i].Name, i)
return errors.New("inconsistent migrations")
} }
c, err := fileChecksum(f, fm[i]) c, err := fileChecksum(f, fm[i])
if err != nil { if err != nil {

View File

@@ -15,8 +15,9 @@ import (
"testing" "testing"
"github.com/psanford/memfs" "github.com/psanford/memfs"
"github.com/scylladb/gocqlx/v2" "github.com/scylladb/gocqlx/v2"
. "github.com/scylladb/gocqlx/v2/gocqlxtest" "github.com/scylladb/gocqlx/v2/gocqlxtest"
"github.com/scylladb/gocqlx/v2/migrate" "github.com/scylladb/gocqlx/v2/migrate"
) )
@@ -45,7 +46,7 @@ func recreateTables(tb testing.TB, session gocqlx.Session) {
} }
func TestMigration(t *testing.T) { func TestMigration(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
recreateTables(t, session) recreateTables(t, session)
@@ -91,7 +92,7 @@ func TestMigration(t *testing.T) {
} }
func TestMigrationNoSemicolon(t *testing.T) { func TestMigrationNoSemicolon(t *testing.T) {
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
recreateTables(t, session) recreateTables(t, session)
@@ -171,11 +172,11 @@ func TestMigrationCallback(t *testing.T) {
migrate.Callback = func(ctx context.Context, session gocqlx.Session, ev migrate.CallbackEvent, name string) error { migrate.Callback = func(ctx context.Context, session gocqlx.Session, ev migrate.CallbackEvent, name string) error {
switch ev { switch ev {
case migrate.BeforeMigration: case migrate.BeforeMigration:
beforeCalled += 1 beforeCalled++
case migrate.AfterMigration: case migrate.AfterMigration:
afterCalled += 1 afterCalled++
case migrate.CallComment: case migrate.CallComment:
inCalled += 1 inCalled++
} }
return nil return nil
} }
@@ -191,6 +192,8 @@ func TestMigrationCallback(t *testing.T) {
} }
assertCallbacks := func(t *testing.T, before, afer, in int) { assertCallbacks := func(t *testing.T, before, afer, in int) {
t.Helper()
if beforeCalled != before { if beforeCalled != before {
t.Fatalf("expected %d before calls got %d", before, beforeCalled) t.Fatalf("expected %d before calls got %d", before, beforeCalled)
} }
@@ -202,7 +205,7 @@ func TestMigrationCallback(t *testing.T) {
} }
} }
session := CreateSession(t) session := gocqlxtest.CreateSession(t)
defer session.Close() defer session.Close()
recreateTables(t, session) recreateTables(t, session)

View File

@@ -18,20 +18,20 @@ import (
// BatchBuilder builds CQL BATCH statements. // BatchBuilder builds CQL BATCH statements.
type BatchBuilder struct { type BatchBuilder struct {
unlogged bool
counter bool
using using
stmts []string stmts []string
names []string names []string
using using
unlogged bool
counter bool
} }
// Batch returns a new BatchBuilder. // Batch returns a new BatchBuilder.
// BatchBuilder encapsulates batch cqls as one ordinary gocql.Query for convenience. // BatchBuilder encapsulates batch cqls as one ordinary gocql.Query for convenience.
// Below are the limitations of encapsulating batch cqls based on gocql.Query instead of gocql.Batch: // Below are the limitations of encapsulating batch cqls based on gocql.Query instead of gocql.Batch:
// * gocql.Batch has some more batch specific check, such as BatchSize(65535). // - gocql.Batch has some more batch specific check, such as BatchSize(65535).
// * gocql.Batch use BatchObserver instead of QueryObserver. // - gocql.Batch use BatchObserver instead of QueryObserver.
// * gocql.Batch has cancelBatch call back. // - gocql.Batch has cancelBatch call back.
// * gocql.Batch prepares the included statements separately, which is more efficient. // - gocql.Batch prepares the included statements separately, which is more efficient.
// In contrast, gocqlx.qb.BatchBuilder, which is based on gocql.Query, prepares the whole batch statements as one ordinary query. // In contrast, gocqlx.qb.BatchBuilder, which is based on gocql.Query, prepares the whole batch statements as one ordinary query.
// //
// Deprecated: Please use gocql.Session.NewBatch() instead. // Deprecated: Please use gocql.Session.NewBatch() instead.

View File

@@ -39,7 +39,8 @@ func TestBatchBuilder(t *testing.T) {
B: Batch(). B: Batch().
AddWithPrefix("a", m). AddWithPrefix("a", m).
AddWithPrefix("b", m), AddWithPrefix("b", m),
S: "BEGIN BATCH INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) ; INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) ; APPLY BATCH ", S: "BEGIN BATCH INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) ; " +
"INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) ; APPLY BATCH ",
N: []string{"a.id", "a.user_uuid", "a.firstname", "b.id", "b.user_uuid", "b.firstname"}, N: []string{"a.id", "a.user_uuid", "a.firstname", "b.id", "b.user_uuid", "b.firstname"},
}, },
// Add UNLOGGED // Add UNLOGGED
@@ -64,7 +65,7 @@ func TestBatchBuilder(t *testing.T) {
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Batch().Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: Batch().Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "BEGIN BATCH USING TIMESTAMP 1115251200000000 APPLY BATCH ", S: "BEGIN BATCH USING TIMESTAMP 1115251200000000 APPLY BATCH ",
}, },
{ {

View File

@@ -26,9 +26,9 @@ const (
// Cmp if a filtering comparator that is used in WHERE and IF clauses. // Cmp if a filtering comparator that is used in WHERE and IF clauses.
type Cmp struct { type Cmp struct {
op op
column string
value value value value
column string
op op
} }
func (c Cmp) writeCql(cql *bytes.Buffer) (names []string) { func (c Cmp) writeCql(cql *bytes.Buffer) (names []string) {

View File

@@ -165,8 +165,6 @@ func TestCmp(t *testing.T) {
S: "like LIKE (?,?)", S: "like LIKE (?,?)",
N: []string{"name[0]", "name[1]"}, N: []string{"name[0]", "name[1]"},
}, },
// Custom bind names on tuples // Custom bind names on tuples
{ {
C: EqTupleNamed("eq", 2, "name"), C: EqTupleNamed("eq", 2, "name"),

View File

@@ -19,9 +19,9 @@ import (
type DeleteBuilder struct { type DeleteBuilder struct {
table string table string
columns columns columns columns
using using
where where where where
_if _if _if _if
using using
exists bool exists bool
} }

View File

@@ -69,7 +69,7 @@ func TestDeleteBuilder(t *testing.T) {
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Delete("cycling.cyclist_name").Where(w).Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: Delete("cycling.cyclist_name").Where(w).Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "DELETE FROM cycling.cyclist_name USING TIMESTAMP 1115251200000000 WHERE id=? ", S: "DELETE FROM cycling.cyclist_name USING TIMESTAMP 1115251200000000 WHERE id=? ",
N: []string{"expr"}, N: []string{"expr"},
}, },

View File

@@ -17,16 +17,16 @@ import (
// initializer specifies an value for a column in an insert operation. // initializer specifies an value for a column in an insert operation.
type initializer struct { type initializer struct {
column string
value value value value
column string
} }
// InsertBuilder builds CQL INSERT statements. // InsertBuilder builds CQL INSERT statements.
type InsertBuilder struct { type InsertBuilder struct {
table string table string
columns []initializer columns []initializer
unique bool
using using using using
unique bool
json bool json bool
} }

View File

@@ -17,7 +17,6 @@ func TestInsertBuilder(t *testing.T) {
N []string N []string
S string S string
}{ }{
// Basic test for insert // Basic test for insert
{ {
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname"), B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname"),
@@ -67,7 +66,7 @@ func TestInsertBuilder(t *testing.T) {
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP 1115251200000000 ", S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP 1115251200000000 ",
N: []string{"id", "user_uuid", "firstname"}, N: []string{"id", "user_uuid", "firstname"},
}, },
@@ -78,7 +77,7 @@ func TestInsertBuilder(t *testing.T) {
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP 1115251200000000 ", S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP 1115251200000000 ",
N: []string{"id", "user_uuid", "firstname"}, N: []string{"id", "user_uuid", "firstname"},
}, },
@@ -89,7 +88,7 @@ func TestInsertBuilder(t *testing.T) {
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP 1115251200000000 ", S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP 1115251200000000 ",
N: []string{"id", "user_uuid", "firstname"}, N: []string{"id", "user_uuid", "firstname"},
}, },

View File

@@ -34,15 +34,15 @@ func (o Order) String() string {
// SelectBuilder builds CQL SELECT statements. // SelectBuilder builds CQL SELECT statements.
type SelectBuilder struct { type SelectBuilder struct {
limit limit
limitPerPartition limit
table string table string
columns columns
distinct columns
using using
where where where where
groupBy columns groupBy columns
orderBy columns orderBy columns
limit limit columns columns
limitPerPartition limit distinct columns
using using
allowFiltering bool allowFiltering bool
bypassCache bool bypassCache bool
json bool json bool
@@ -132,7 +132,7 @@ func (b *SelectBuilder) From(table string) *SelectBuilder {
} }
// Json sets the clause of the query. // Json sets the clause of the query.
func (b *SelectBuilder) Json() *SelectBuilder { func (b *SelectBuilder) Json() *SelectBuilder { // nolint: revive
b.json = true b.json = true
return b return b
} }

View File

@@ -32,10 +32,10 @@ func (a assignment) writeCql(cql *bytes.Buffer) (names []string) {
// UpdateBuilder builds CQL UPDATE statements. // UpdateBuilder builds CQL UPDATE statements.
type UpdateBuilder struct { type UpdateBuilder struct {
table string table string
using using
assignments []assignment assignments []assignment
where where where where
_if _if _if _if
using using
exists bool exists bool
} }

View File

@@ -117,7 +117,7 @@ func TestUpdateBuilder(t *testing.T) {
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "UPDATE cycling.cyclist_name USING TIMESTAMP 1115251200000000 SET id=?,user_uuid=?,firstname=? WHERE id=? ", S: "UPDATE cycling.cyclist_name USING TIMESTAMP 1115251200000000 SET id=?,user_uuid=?,firstname=? WHERE id=? ",
N: []string{"id", "user_uuid", "firstname", "expr"}, N: []string{"id", "user_uuid", "firstname", "expr"},
}, },

View File

@@ -21,12 +21,12 @@ func Timestamp(t time.Time) int64 {
} }
type using struct { type using struct {
ttl int64
ttlName string ttlName string
timestamp int64
timestampName string timestampName string
timeout time.Duration
timeoutName string timeoutName string
ttl int64
timestamp int64
timeout time.Duration
} }
func (u *using) TTL(d time.Duration) *using { func (u *using) TTL(d time.Duration) *using {

View File

@@ -43,7 +43,7 @@ func TestUsing(t *testing.T) {
}, },
// Timestamp // Timestamp
{ {
B: new(using).Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: new(using).Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "USING TIMESTAMP 1115251200000000 ", S: "USING TIMESTAMP 1115251200000000 ",
}, },
// TimestampNamed // TimestampNamed
@@ -65,7 +65,7 @@ func TestUsing(t *testing.T) {
}, },
// TTL Timestamp // TTL Timestamp
{ {
B: new(using).TTL(time.Second).Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: new(using).TTL(time.Second).Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "USING TTL 1 AND TIMESTAMP 1115251200000000 ", S: "USING TTL 1 AND TIMESTAMP 1115251200000000 ",
}, },
// TTL TimestampNamed // TTL TimestampNamed
@@ -82,7 +82,7 @@ func TestUsing(t *testing.T) {
}, },
// TTLNamed Timestamp // TTLNamed Timestamp
{ {
B: new(using).TTLNamed("ttl").Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: new(using).TTLNamed("ttl").Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "USING TTL ? AND TIMESTAMP 1115251200000000 ", S: "USING TTL ? AND TIMESTAMP 1115251200000000 ",
N: []string{"ttl"}, N: []string{"ttl"},
}, },
@@ -99,7 +99,7 @@ func TestUsing(t *testing.T) {
}, },
// TTL Timestamp Timeout // TTL Timestamp Timeout
{ {
B: new(using).TTL(time.Second).Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)).Timeout(time.Second), B: new(using).TTL(time.Second).Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)).Timeout(time.Second),
S: "USING TTL 1 AND TIMESTAMP 1115251200000000 AND TIMEOUT 1s ", S: "USING TTL 1 AND TIMESTAMP 1115251200000000 AND TIMEOUT 1s ",
}, },
// TTL with no duration // TTL with no duration
@@ -129,13 +129,13 @@ func TestUsing(t *testing.T) {
}, },
// Timestamp TimestampNamed // Timestamp TimestampNamed
{ {
B: new(using).Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)).TimestampNamed("ts"), B: new(using).Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)).TimestampNamed("ts"),
S: "USING TIMESTAMP ? ", S: "USING TIMESTAMP ? ",
N: []string{"ts"}, N: []string{"ts"},
}, },
// TimestampNamed Timestamp // TimestampNamed Timestamp
{ {
B: new(using).TimestampNamed("ts").Timestamp(time.Date(2005, 05, 05, 0, 0, 0, 0, time.UTC)), B: new(using).TimestampNamed("ts").Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)),
S: "USING TIMESTAMP 1115251200000000 ", S: "USING TIMESTAMP 1115251200000000 ",
}, },
} }

View File

@@ -90,12 +90,11 @@ func allowedBindRune(b byte) bool {
// Queryx is a wrapper around gocql.Query which adds struct binding capabilities. // Queryx is a wrapper around gocql.Query which adds struct binding capabilities.
type Queryx struct { type Queryx struct {
err error
tr Transformer
Mapper *reflectx.Mapper
*gocql.Query *gocql.Query
Names []string Names []string
Mapper *reflectx.Mapper
tr Transformer
err error
} }
// Query creates a new Queryx from gocql.Query using a default mapper. // Query creates a new Queryx from gocql.Query using a default mapper.
@@ -151,7 +150,7 @@ func (q *Queryx) bindStructArgs(arg0 interface{}, arg1 map[string]interface{}) (
// grab the indirected value of arg // grab the indirected value of arg
v := reflect.ValueOf(arg0) v := reflect.ValueOf(arg0)
for v = reflect.ValueOf(arg0); v.Kind() == reflect.Ptr; { for v.Kind() == reflect.Ptr {
v = v.Elem() v = v.Elem()
} }

View File

@@ -34,6 +34,7 @@ func NewSession(session *gocql.Session) Session {
// the created session to gocqlx.Session. // the created session to gocqlx.Session.
// //
// Example: // Example:
//
// session, err := gocqlx.WrapSession(cluster.CreateSession()) // session, err := gocqlx.WrapSession(cluster.CreateSession())
func WrapSession(session *gocql.Session, err error) (Session, error) { func WrapSession(session *gocql.Session, err error) (Session, error) {
return Session{ return Session{

View File

@@ -9,6 +9,7 @@ import (
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/scylladb/gocqlx/v2/qb" "github.com/scylladb/gocqlx/v2/qb"
) )

2
udt.go
View File

@@ -24,8 +24,8 @@ var (
) )
type udt struct { type udt struct {
value reflect.Value
field map[string]reflect.Value field map[string]reflect.Value
value reflect.Value
unsafe bool unsafe bool
} }