diff --git a/batchx_test.go b/batchx_test.go deleted file mode 100644 index 052e481..0000000 --- a/batchx_test.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -//go:build all || integration -// +build all integration - -package gocqlx_test - -import ( - "reflect" - "testing" - - gocql "github.com/apache/cassandra-gocql-driver/v2" - "github.com/google/go-cmp/cmp" - - "github.com/scylladb/gocqlx/v3" - "github.com/scylladb/gocqlx/v3/gocqlxtest" - "github.com/scylladb/gocqlx/v3/qb" -) - -func TestBatch(t *testing.T) { - t.Parallel() - - cluster := gocqlxtest.CreateCluster() - if err := gocqlxtest.CreateKeyspace(cluster, "batch_test"); err != nil { - t.Fatal("create keyspace:", err) - } - - session, err := gocqlx.WrapSession(cluster.CreateSession()) - if err != nil { - t.Fatal("create session:", err) - } - t.Cleanup(func() { - session.Close() - }) - - basicCreateAndPopulateKeyspace(t, session, "batch_test") - - song := Song{ - ID: mustParseUUID("60fc234a-8481-4343-93bb-72ecab404863"), - Title: "La Petite Tonkinoise", - Album: "Bye Bye Blackbird", - Artist: "Joséphine Baker", - Tags: []string{"jazz"}, - Data: []byte("music"), - } - playlist := PlaylistItem{ - ID: mustParseUUID("6a6255d9-680f-4cb5-b9a2-27cf4a810344"), - Title: "La Petite Tonkinoise", - Album: "Bye Bye Blackbird", - Artist: "Joséphine Baker", - SongID: mustParseUUID("60fc234a-8481-4343-93bb-72ecab404863"), - } - - t.Run("batch inserts", func(t *testing.T) { - t.Parallel() - - tcases := []struct { - name string - methodSong func(*gocqlx.Batch, *gocqlx.Queryx, Song) error - methodPlaylist func(*gocqlx.Batch, *gocqlx.Queryx, PlaylistItem) error - }{ - { - name: "BindStruct", - methodSong: func(b *gocqlx.Batch, q *gocqlx.Queryx, song Song) error { - return b.BindStruct(q, song) - }, - methodPlaylist: func(b *gocqlx.Batch, q *gocqlx.Queryx, playlist PlaylistItem) error { - return b.BindStruct(q, playlist) - }, - }, - { - name: "BindMap", - methodSong: func(b *gocqlx.Batch, q *gocqlx.Queryx, song Song) error { - return b.BindMap(q, map[string]interface{}{ - "id": song.ID, - "title": song.Title, - "album": song.Album, - "artist": song.Artist, - "tags": song.Tags, - "data": song.Data, - }) - }, - methodPlaylist: func(b *gocqlx.Batch, q *gocqlx.Queryx, playlist PlaylistItem) error { - return b.BindMap(q, map[string]interface{}{ - "id": playlist.ID, - "title": playlist.Title, - "album": playlist.Album, - "artist": playlist.Artist, - "song_id": playlist.SongID, - }) - }, - }, - { - name: "Bind", - methodSong: func(b *gocqlx.Batch, q *gocqlx.Queryx, song Song) error { - return b.Bind(q, song.ID, song.Title, song.Album, song.Artist, song.Tags, song.Data) - }, - methodPlaylist: func(b *gocqlx.Batch, q *gocqlx.Queryx, playlist PlaylistItem) error { - return b.Bind(q, playlist.ID, playlist.Title, playlist.Album, playlist.Artist, playlist.SongID) - }, - }, - { - name: "BindStructMap", - methodSong: func(b *gocqlx.Batch, q *gocqlx.Queryx, song Song) error { - in := map[string]interface{}{ - "title": song.Title, - "album": song.Album, - } - return b.BindStructMap(q, struct { - ID gocql.UUID - Artist string - Tags []string - Data []byte - }{ - ID: song.ID, - Artist: song.Artist, - Tags: song.Tags, - Data: song.Data, - }, in) - }, - methodPlaylist: func(b *gocqlx.Batch, q *gocqlx.Queryx, playlist PlaylistItem) error { - in := map[string]interface{}{ - "title": playlist.Title, - "album": playlist.Album, - } - return b.BindStructMap(q, struct { - ID gocql.UUID - Artist string - SongID gocql.UUID - }{ - ID: playlist.ID, - Artist: playlist.Artist, - SongID: playlist.SongID, - }, - in, - ) - }, - }, - } - for _, tcase := range tcases { - t.Run(tcase.name, func(t *testing.T) { - insertSong := qb.Insert("batch_test.songs"). - Columns("id", "title", "album", "artist", "tags", "data").Query(session) - insertPlaylist := qb.Insert("batch_test.playlists"). - Columns("id", "title", "album", "artist", "song_id").Query(session) - selectSong := qb.Select("batch_test.songs").Where(qb.Eq("id")).Query(session) - selectPlaylist := qb.Select("batch_test.playlists").Where(qb.Eq("id")).Query(session) - deleteSong := qb.Delete("batch_test.songs").Where(qb.Eq("id")).Query(session) - deletePlaylist := qb.Delete("batch_test.playlists").Where(qb.Eq("id")).Query(session) - - b := session.NewBatch(gocql.LoggedBatch) - - if err = tcase.methodSong(b, insertSong, song); err != nil { - t.Fatal("insert song:", err) - } - if err = tcase.methodPlaylist(b, insertPlaylist, playlist); err != nil { - t.Fatal("insert playList:", err) - } - - if err := session.ExecuteBatch(b); err != nil { - t.Fatal("batch execution:", err) - } - - // verify song was inserted - var gotSong Song - if err := selectSong.BindStruct(song).Get(&gotSong); err != nil { - t.Fatal("select song:", err) - } - if diff := cmp.Diff(gotSong, song); diff != "" { - t.Errorf("expected %v song, got %v, diff: %q", song, gotSong, diff) - } - - // verify playlist item was inserted - var gotPlayList PlaylistItem - if err := selectPlaylist.BindStruct(playlist).Get(&gotPlayList); err != nil { - t.Fatal("select playList:", err) - } - if diff := cmp.Diff(gotPlayList, playlist); diff != "" { - t.Errorf("expected %v playList, got %v, diff: %q", playlist, gotPlayList, diff) - } - if err = deletePlaylist.BindStruct(playlist).Exec(); err != nil { - t.Error("delete playlist:", err) - } - if err = deleteSong.BindStruct(song).Exec(); err != nil { - t.Error("delete song:", err) - } - }) - } - }) -} - -func TestBatchAllWrapped(t *testing.T) { - var ( - gocqlType = reflect.TypeOf((*gocql.Batch)(nil)) - gocqlxType = reflect.TypeOf((*gocqlx.Batch)(nil)) - ) - - for i := 0; i < gocqlType.NumMethod(); i++ { - m, ok := gocqlxType.MethodByName(gocqlType.Method(i).Name) - if !ok { - t.Fatalf("Batch missing method %s", gocqlType.Method(i).Name) - } - - for j := 0; j < m.Type.NumOut(); j++ { - if m.Type.Out(j) == gocqlType { - t.Errorf("Batch method %s not wrapped", m.Name) - } - } - } -} diff --git a/benchmark_test.go b/benchmark_test.go deleted file mode 100644 index 66ace8c..0000000 --- a/benchmark_test.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -//go:build all || integration -// +build all integration - -package gocqlx_test - -import ( - "encoding/json" - "os" - "testing" - - "github.com/scylladb/gocqlx/v3" - "github.com/scylladb/gocqlx/v3/gocqlxtest" - "github.com/scylladb/gocqlx/v3/qb" -) - -type benchPerson struct { - ID int `json:"id"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Email []string `json:"email"` - Gender string `json:"gender"` - IPAddress string `json:"ip_address"` -} - -var benchPersonSchema = ` -CREATE TABLE IF NOT EXISTS gocqlx_test.bench_person ( - id int, - first_name text, - last_name text, - email list, - gender text, - ip_address text, - PRIMARY KEY(id) -)` - -var benchPersonCols = []string{"id", "first_name", "last_name", "email", "gender", "ip_address"} - -// -// Insert -// - -// BenchmarkBaseGocqlInsert performs standard insert. -func BenchmarkBaseGocqlInsert(b *testing.B) { - people := loadFixtures() - session := gocqlxtest.CreateSession(b) - defer session.Close() - - if err := session.ExecStmt(benchPersonSchema); err != nil { - b.Fatal(err) - } - - stmt, _ := qb.Insert("gocqlx_test.bench_person").Columns(benchPersonCols...).ToCql() - q := session.Session.Query(stmt) - defer q.Release() - - b.ResetTimer() - for i := 0; i < b.N; i++ { - p := people[i%len(people)] - if err := q.Bind(p.ID, p.FirstName, p.LastName, p.Email, p.Gender, p.IPAddress).Exec(); err != nil { - b.Fatal(err) - } - } -} - -// BenchmarkGocqlInsert performs insert with struct binding. -func BenchmarkGocqlxInsert(b *testing.B) { - people := loadFixtures() - session := gocqlxtest.CreateSession(b) - defer session.Close() - - if err := session.ExecStmt(benchPersonSchema); err != nil { - b.Fatal(err) - } - - stmt, names := qb.Insert("gocqlx_test.bench_person").Columns(benchPersonCols...).ToCql() - q := session.Query(stmt, names) - defer q.Release() - - b.ResetTimer() - for i := 0; i < b.N; i++ { - p := people[i%len(people)] - if err := q.BindStruct(p).Exec(); err != nil { - b.Fatal(err) - } - } -} - -// -// Get -// - -// BenchmarkBaseGocqlGet performs standard scan. -func BenchmarkBaseGocqlGet(b *testing.B) { - people := loadFixtures() - session := gocqlxtest.CreateSession(b) - defer session.Close() - - initTable(b, session, people) - - stmt, _ := qb.Select("gocqlx_test.bench_person").Columns(benchPersonCols...).Where(qb.Eq("id")).Limit(1).ToCql() - q := session.Session.Query(stmt) - defer q.Release() - - var p benchPerson - - b.ResetTimer() - for i := 0; i < b.N; i++ { - q.Bind(people[i%len(people)].ID) - if err := q.Scan(&p.ID, &p.FirstName, &p.LastName, &p.Email, &p.Gender, &p.IPAddress); err != nil { - b.Fatal(err) - } - } -} - -// BenchmarkGocqlxGet performs get. -func BenchmarkGocqlxGet(b *testing.B) { - people := loadFixtures() - session := gocqlxtest.CreateSession(b) - defer session.Close() - - initTable(b, session, people) - - stmt, names := qb.Select("gocqlx_test.bench_person").Columns(benchPersonCols...).Where(qb.Eq("id")).Limit(1).ToCql() - q := session.Query(stmt, names) - defer q.Release() - - var p benchPerson - - b.ResetTimer() - for i := 0; i < b.N; i++ { - q.Bind(people[i%len(people)].ID) - if err := q.Get(&p); err != nil { - b.Fatal(err) - } - } -} - -// -// Select -// - -// BenchmarkBaseGocqlSelect performs standard loop scan with a slice of -// pointers. -func BenchmarkBaseGocqlSelect(b *testing.B) { - people := loadFixtures() - session := gocqlxtest.CreateSession(b) - defer session.Close() - - initTable(b, session, people) - - stmt, _ := qb.Select("gocqlx_test.bench_person").Columns(benchPersonCols...).Limit(100).ToCql() - q := session.Session.Query(stmt) - defer q.Release() - - b.ResetTimer() - for i := 0; i < b.N; i++ { - iter := q.Iter() - v := make([]*benchPerson, 100) - p := new(benchPerson) - for iter.Scan(&p.ID, &p.FirstName, &p.LastName, &p.Email, &p.Gender, &p.IPAddress) { - v = append(v, p) - p = new(benchPerson) - } - if err := iter.Close(); err != nil { - b.Fatal(err) - } - _ = v - } -} - -// BenchmarkGocqlSelect performs select to a slice pointers. -func BenchmarkGocqlxSelect(b *testing.B) { - people := loadFixtures() - session := gocqlxtest.CreateSession(b) - defer session.Close() - - initTable(b, session, people) - - stmt, names := qb.Select("gocqlx_test.bench_person").Columns(benchPersonCols...).Limit(100).ToCql() - q := session.Query(stmt, names) - defer q.Release() - - b.ResetTimer() - for i := 0; i < b.N; i++ { - var v []*benchPerson - if err := q.Select(&v); err != nil { - b.Fatal(err) - } - } -} - -func loadFixtures() []*benchPerson { - f, err := os.Open("testdata/people.json") - if err != nil { - panic(err) - } - defer func() { - if err := f.Close(); err != nil { - panic(err) - } - }() - - var v []*benchPerson - if err := json.NewDecoder(f).Decode(&v); err != nil { - panic(err) - } - - return v -} - -func initTable(b *testing.B, session gocqlx.Session, people []*benchPerson) { - b.Helper() - - if err := session.ExecStmt(benchPersonSchema); err != nil { - b.Fatal(err) - } - - stmt, names := qb.Insert("gocqlx_test.bench_person").Columns(benchPersonCols...).ToCql() - q := session.Query(stmt, names) - - for _, p := range people { - if err := q.BindStruct(p).Exec(); err != nil { - b.Fatal(err) - } - } -} diff --git a/example_test.go b/example_test.go deleted file mode 100644 index 26a9fd6..0000000 --- a/example_test.go +++ /dev/null @@ -1,978 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -//go:build all || integration -// +build all integration - -package gocqlx_test - -import ( - "fmt" - "math" - "testing" - "time" - - gocql "github.com/apache/cassandra-gocql-driver/v2" - "golang.org/x/sync/errgroup" - "gopkg.in/inf.v0" - - "github.com/scylladb/gocqlx/v3" - "github.com/scylladb/gocqlx/v3/gocqlxtest" - "github.com/scylladb/gocqlx/v3/qb" - "github.com/scylladb/gocqlx/v3/table" -) - -// Running examples locally: -// make run-scylla -// make run-examples -func TestExample(t *testing.T) { - cluster := gocqlxtest.CreateCluster() - - session, err := gocqlx.WrapSession(cluster.CreateSession()) - if err != nil { - t.Fatal("create session:", err) - } - defer session.Close() - - _ = session.ExecStmt(`DROP KEYSPACE examples`) - - basicCreateAndPopulateKeyspace(t, session, "examples") - createAndPopulateKeyspaceAllTypes(t, session) - basicReadScyllaVersion(t, session) - - datatypesBlob(t, session) - datatypesUserDefinedType(t, session) - datatypesUserDefinedTypeWrapper(t, session) - datatypesJSON(t, session) - - pagingForwardPaging(t, session) - pagingEfficientFullTableScan(t, session) - - lwtLock(t, session) - unsetEmptyValues(t, session) -} - -type Song struct { - ID gocql.UUID - Title string - Album string - Artist string - Tags []string - Data []byte -} - -type PlaylistItem struct { - ID gocql.UUID - Title string - Album string - Artist string - SongID gocql.UUID -} - -// This example shows how to use query builders and table models to build -// queries. It uses "BindStruct" function for parameter binding and "Select" -// function for loading data to a slice. -func basicCreateAndPopulateKeyspace(t *testing.T, session gocqlx.Session, keyspace string) { - t.Helper() - - err := session.ExecStmt(fmt.Sprintf( - `CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}`, - keyspace, - )) - if err != nil { - t.Fatal("create keyspace:", err) - } - - err = session.ExecStmt(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.songs ( - id uuid PRIMARY KEY, - title text, - album text, - artist text, - tags set, - data blob)`, keyspace)) - if err != nil { - t.Fatal("create table:", err) - } - - err = session.ExecStmt(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.playlists ( - id uuid, - title text, - album text, - artist text, - song_id uuid, - PRIMARY KEY (id, title, album, artist))`, keyspace)) - if err != nil { - t.Fatal("create table:", err) - } - - playlistMetadata := table.Metadata{ - Name: fmt.Sprintf("%s.playlists", keyspace), - Columns: []string{"id", "title", "album", "artist", "song_id"}, - PartKey: []string{"id"}, - SortKey: []string{"title", "album", "artist", "song_id"}, - } - playlistTable := table.New(playlistMetadata) - - // Insert song using query builder. - insertSong := qb.Insert(fmt.Sprintf("%s.songs", keyspace)). - Columns("id", "title", "album", "artist", "tags", "data").Query(session) - - insertSong.BindStruct(Song{ - ID: mustParseUUID("756716f7-2e54-4715-9f00-91dcbea6cf50"), - Title: "La Petite Tonkinoise", - Album: "Bye Bye Blackbird", - Artist: "Joséphine Baker", - Tags: []string{"jazz", "2013"}, - Data: []byte("music"), - }) - if err := insertSong.ExecRelease(); err != nil { - t.Fatal("ExecRelease() failed:", err) - } - - // Insert playlist using table model. - insertPlaylist := playlistTable.InsertQuery(session) - - insertPlaylist.BindStruct(PlaylistItem{ - ID: mustParseUUID("2cc9ccb7-6221-4ccb-8387-f22b6a1b354d"), - Title: "La Petite Tonkinoise", - Album: "Bye Bye Blackbird", - Artist: "Joséphine Baker", - SongID: mustParseUUID("756716f7-2e54-4715-9f00-91dcbea6cf50"), - }) - if err := insertPlaylist.ExecRelease(); err != nil { - t.Fatal("ExecRelease() failed:", err) - } - - // Query and displays data. - queryPlaylist := playlistTable.SelectQuery(session) - - queryPlaylist.BindStruct(&PlaylistItem{ - ID: mustParseUUID("2cc9ccb7-6221-4ccb-8387-f22b6a1b354d"), - }) - - var items []*PlaylistItem - if err := queryPlaylist.Select(&items); err != nil { - t.Fatal("Select() failed:", err) - } - - for _, i := range items { - t.Logf("%+v", *i) - } -} - -// This example shows how to use query builders and table models to build -// queries with all types. It uses "BindStruct" function for parameter binding and "Select" -// function for loading data to a slice. -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - // generated with schemagen - type CheckTypesStruct struct { - AsciI string - BigInt int64 - BloB []byte - BooleaN bool - DatE time.Time - DecimaL inf.Dec - DoublE float64 - DuratioN gocql.Duration - FloaT float32 - ID [16]byte - InT int32 - IneT string - ListInt []int32 - MapIntText map[int32]string - SetInt []int32 - SmallInt int16 - TexT string - TimE time.Duration - TimestamP time.Time - TimeuuiD [16]byte - TinyInt int8 - VarChar string - VarInt int64 - } - - err = session.ExecStmt(`CREATE TABLE IF NOT EXISTS examples.check_types ( - asci_i ascii, - big_int bigint, - blo_b blob, - boolea_n boolean, - dat_e date, - decima_l decimal, - doubl_e double, - duratio_n duration, - floa_t float, - ine_t inet, - in_t int, - small_int smallint, - tex_t text, - tim_e time, - timestam_p timestamp, - timeuui_d timeuuid, - tiny_int tinyint, - id uuid PRIMARY KEY, - var_char varchar, - var_int varint, - map_int_text map, - list_int list, - set_int set)`) - if err != nil { - t.Fatal("create table:", err) - } - - // generated with schemagen - checkTypesTable := table.New(table.Metadata{ - Name: "examples.check_types", - Columns: []string{ - "asci_i", - "big_int", - "blo_b", - "boolea_n", - "dat_e", - "decima_l", - "doubl_e", - "duratio_n", - "floa_t", - "id", - "in_t", - "ine_t", - "list_int", - "map_int_text", - "set_int", - "small_int", - "tex_t", - "tim_e", - "timestam_p", - "timeuui_d", - "tiny_int", - "var_char", - "var_int", - }, - PartKey: []string{"id"}, - SortKey: []string{}, - }) - - // Insert song using query builder. - 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) - - var byteID [16]byte - id := []byte("756716f7-2e54-4715-9f00-91dcbea6cf50") - copy(byteID[:], id) - - date := time.Date(2021, time.December, 11, 10, 23, 0, 0, time.UTC) - var double float64 = 1.2 //nolint:staticcheck // type needs to be enforces - var float float32 = 1.3 - var integer int32 = 123 - listInt := []int32{1, 2, 3} - mapIntStr := map[int32]string{ - 1: "a", - 2: "b", - } - setInt := []int32{2, 4, 6} - var smallInt int16 = 12 - var tinyInt int8 = 14 - var varInt int64 = 20 - - insertCheckTypes.BindStruct(CheckTypesStruct{ - AsciI: "test qscci", - BigInt: 9223372036854775806, // MAXINT64 - 1, - BloB: []byte("this is blob test"), - BooleaN: false, - DatE: date, - DecimaL: *inf.NewDec(1, 1), - DoublE: double, - DuratioN: gocql.Duration{Months: 1, Days: 1, Nanoseconds: 86400}, - FloaT: float, - ID: byteID, - InT: integer, - IneT: "127.0.0.1", - ListInt: listInt, - MapIntText: mapIntStr, - SetInt: setInt, - SmallInt: smallInt, - TexT: "text example", - TimE: 86400000000, - TimestamP: date, - TimeuuiD: gocql.TimeUUID(), - TinyInt: tinyInt, - VarChar: "test varchar", - VarInt: varInt, - }) - if err := insertCheckTypes.ExecRelease(); err != nil { - t.Fatal("ExecRelease() failed:", err) - } - - // Query and displays data. - queryCheckTypes := checkTypesTable.SelectQuery(session) - - queryCheckTypes.BindStruct(&CheckTypesStruct{ - ID: byteID, - }) - - var items []*CheckTypesStruct - if err := queryCheckTypes.Select(&items); err != nil { - t.Fatal("Select() failed:", err) - } - - for _, i := range items { - t.Logf("%+v", *i) - } -} - -// 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. -func basicReadScyllaVersion(t *testing.T, session gocqlx.Session) { - t.Helper() - - var releaseVersion string - - err := session.Query("SELECT release_version FROM system.local", nil).Get(&releaseVersion) - if err != nil { - t.Fatal("Get() failed:", err) - } - - t.Logf("Scylla version is: %s", releaseVersion) -} - -// This examples shows how to bind data from a map using "BindMap" function, -// override field name mapping using the "db" tags, with the default mechanism of -// handling situations where driver returns more coluns that we are ready to -// consume. -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - err = session.ExecStmt(`CREATE TABLE IF NOT EXISTS examples.blobs(k int PRIMARY KEY, b blob, m map)`) - if err != nil { - t.Fatal("create table:", err) - } - - // One way to get a byte buffer is to allocate it and fill it yourself: - var buf [16]byte - for i := range buf { - buf[i] = 0xff - } - - insert := qb.Insert("examples.blobs").Columns("k", "b", "m").Query(session) - insert.BindMap(qb.M{ - "k": 1, - "b": buf[:], - "m": map[string][]byte{"test": buf[:]}, - }) - - if err := insert.ExecRelease(); err != nil { - t.Fatal("ExecRelease() failed:", err) - } - - row := &struct { - Buffer []byte `db:"b"` - Mapping map[string][]byte `db:"m"` - }{} - q := qb.Select("examples.blobs").Where(qb.EqLit("k", "1")).Query(session) - - // By default missing UDT fields are treated as null instead of failing - if err := q.Iter().Get(row); err != nil { - t.Fatal("Get() failed:", err) - } - - t.Logf("%+v", row.Buffer) - t.Logf("%+v", row.Mapping) -} - -type Coordinates struct { - gocqlx.UDT - X int - Y int -} - -// This example shows how to add User Defined Type marshalling capabilities by -// adding a single line - embedding gocqlx.UDT. -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - err = session.ExecStmt(`CREATE TYPE IF NOT EXISTS examples.coordinates(x int, y int)`) - if err != nil { - t.Fatal("create type:", err) - } - - err = session.ExecStmt(`CREATE TABLE IF NOT EXISTS examples.udts(k int PRIMARY KEY, c coordinates)`) - if err != nil { - t.Fatal("create table:", err) - } - - coordinates1 := Coordinates{X: 12, Y: 34} - coordinates2 := Coordinates{X: 56, Y: 78} - - insert := qb.Insert("examples.udts").Columns("k", "c").Query(session) - insert.BindMap(qb.M{ - "k": 1, - "c": coordinates1, - }) - if err := insert.Exec(); err != nil { - t.Fatal("Exec() failed:", err) - } - insert.BindMap(qb.M{ - "k": 2, - "c": coordinates2, - }) - if err := insert.Exec(); err != nil { - t.Fatal("Exec() failed:", err) - } - - var coordinates []Coordinates - q := qb.Select("examples.udts").Columns("c").Query(session) - if err := q.Select(&coordinates); err != nil { - t.Fatal("Select() failed:", err) - } - - for _, c := range coordinates { - t.Logf("%+v", c) - } -} - -type coordinates struct { - X int - Y int -} - -// This example shows how to add User Defined Type marshalling capabilities to -// types that we cannot modify, like library or transfer objects, without -// rewriting them in runtime. -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - err = session.ExecStmt(`CREATE TYPE IF NOT EXISTS examples.coordinates(x int, y int)`) - if err != nil { - t.Fatal("create type:", err) - } - - err = session.ExecStmt(`CREATE TABLE IF NOT EXISTS examples.udts_wrapper(k int PRIMARY KEY, c coordinates)`) - if err != nil { - t.Fatal("create table:", err) - } - - // Embed coordinates within CoordinatesUDT - c1 := &coordinates{X: 12, Y: 34} - c2 := &coordinates{X: 56, Y: 78} - - type CoordinatesUDT struct { - gocqlx.UDT - *coordinates - } - - coordinates1 := CoordinatesUDT{coordinates: c1} - coordinates2 := CoordinatesUDT{coordinates: c2} - - insert := qb.Insert("examples.udts_wrapper").Columns("k", "c").Query(session) - insert.BindMap(qb.M{ - "k": 1, - "c": coordinates1, - }) - if err := insert.Exec(); err != nil { - t.Fatal("Exec() failed:", err) - } - insert.BindMap(qb.M{ - "k": 2, - "c": coordinates2, - }) - if err := insert.Exec(); err != nil { - t.Fatal("Exec() failed:", err) - } - - var coordinates []Coordinates - q := qb.Select("examples.udts_wrapper").Columns("c").Query(session) - if err := q.Select(&coordinates); err != nil { - t.Fatal("Select() failed:", err) - } - - for _, c := range coordinates { - t.Logf("%+v", c) - } -} - -// This example shows how to use query builder to work with -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - err = session.ExecStmt(`CREATE TABLE IF NOT EXISTS examples.querybuilder_json(id int PRIMARY KEY, name text, specs map)`) - if err != nil { - t.Fatal("create table:", err) - } - - insert := qb.Insert("examples.querybuilder_json").Json().Query(session) - - insert.Bind(`{ "id": 1, "name": "Mouse", "specs": { "color": "silver" } }`) - if err := insert.Exec(); err != nil { - t.Fatal("Exec() failed:", err) - } - insert.Bind(`{ "id": 2, "name": "Keyboard", "specs": { "layout": "qwerty" } }`) - if err := insert.Exec(); err != nil { - t.Fatal("Exec() failed:", err) - } - - // fromJson lets you provide individual columns as JSON: - insertFromJSON := qb.Insert("examples.querybuilder_json"). - Columns("id", "name"). - FuncColumn("specs", qb.Fn("fromJson", "json")). - Query(session) - - insertFromJSON.BindMap(qb.M{ - "id": 3, - "name": "Screen", - "json": `{ "size": "24-inch" }`, - }) - if err := insertFromJSON.Exec(); err != nil { - t.Fatal("Exec() failed:", err) - } - - // Reading the whole row as a JSON object: - q := qb.Select("examples.querybuilder_json"). - Json(). - Where(qb.EqLit("id", "1")). - Query(session) - - var jsonString string - - if err := q.Get(&jsonString); err != nil { - t.Fatal("Get() failed:", err) - } - t.Logf("Entry #1 as JSON: %s", jsonString) - - // Extracting a particular column as JSON: - q = qb.Select("examples.querybuilder_json"). - Columns("id", "toJson(specs) AS json_specs"). - Where(qb.EqLit("id", "2")). - Query(session) - - row := &struct { - ID int - JSONSpecs string - }{} - if err := q.Get(row); err != nil { - t.Fatal("Get() failed:", err) - } - t.Logf("Entry #%d's specs as JSON: %s", row.ID, row.JSONSpecs) -} - -type Video struct { - UserID int - UserName string - Added time.Time - VideoID int - Title string -} - -func pagingFillTable(t *testing.T, insert *gocqlx.Queryx) { - t.Helper() - - // 3 users - for i := 0; i < 3; i++ { - // 49 videos each - for j := 0; j < 49; j++ { - insert.BindStruct(Video{ - UserID: i, - UserName: fmt.Sprint("user ", i), - Added: time.Unix(int64(j)*100, 0), - VideoID: i*100 + j, - Title: fmt.Sprint("video ", i*100+j), - }) - - if err := insert.Exec(); err != nil { - t.Fatal("Exec() failed:", err) - } - } - } -} - -// This example shows how to use stateful paging and how "Select" function -// can be used to fetch single page only. -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - err = session.ExecStmt(`CREATE TABLE IF NOT EXISTS examples.paging_forward_paging( - user_id int, - user_name text, - added timestamp, - video_id int, - title text, - PRIMARY KEY (user_id, added, video_id) - ) WITH CLUSTERING ORDER BY (added DESC, video_id ASC)`) - if err != nil { - t.Fatal("create table:", err) - } - - videoMetadata := table.Metadata{ - Name: "examples.paging_forward_paging", - Columns: []string{"user_id", "user_name", "added", "video_id", "title"}, - PartKey: []string{"user_id"}, - SortKey: []string{"added", "video_id"}, - } - videoTable := table.New(videoMetadata) - - pagingFillTable(t, videoTable.InsertQuery(session)) - - // Query and displays data. Iterate over videos of user "1" 10 entries per request. - - const itemsPerPage = 10 - - getUserVideos := func(userID int, page []byte) (userVideos []Video, nextPage []byte, err error) { - q := videoTable.SelectQuery(session).Bind(userID) - defer q.Release() - q.PageState(page) - q.PageSize(itemsPerPage) - - iter := q.Iter() - return userVideos, iter.PageState(), iter.Select(&userVideos) - } - - var ( - userVideos []Video - nextPage []byte - ) - - for i := 1; ; i++ { - userVideos, nextPage, err = getUserVideos(1, nextPage) - if err != nil { - t.Fatalf("load page %d: %s", i, err) - } - - t.Logf("Page %d:", i) - for _, v := range userVideos { - t.Logf("%+v", v) - } - if len(nextPage) == 0 { - break - } - } -} - -// This example shows how to efficiently process all rows in a table using -// the "token" function. It implements idea from blog post [1]: -// As a bonus we use "CompileNamedQueryString" to get named parameters out of -// CQL query placeholders like in Python or Java driver. -// -// [1] https://www.scylladb.com/2017/02/13/efficient-full-table-scans-with-scylla-1-6/. -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - err = session.ExecStmt(`CREATE TABLE IF NOT EXISTS examples.paging_efficient_full_table_scan( - user_id int, - user_name text, - added timestamp, - video_id int, - title text, - PRIMARY KEY (user_id, added, video_id) - ) WITH CLUSTERING ORDER BY (added DESC, video_id ASC)`) - if err != nil { - t.Fatal("create table:", err) - } - - videoMetadata := table.Metadata{ - Name: "examples.paging_efficient_full_table_scan", - Columns: []string{"user_id", "user_name", "added", "video_id", "title"}, - PartKey: []string{"user_id"}, - SortKey: []string{"added", "video_id"}, - } - videoTable := table.New(videoMetadata) - - pagingFillTable(t, videoTable.InsertQuery(session)) - - // Calculate optimal number of workers for the cluster: - var ( - nodesInCluster = 1 - coresInNode = 1 - smudgeFactor = 3 - ) - workers := nodesInCluster * coresInNode * smudgeFactor - - t.Logf("Workers %d", workers) - - type tokenRange struct { - Start int64 - End int64 - } - buf := make(chan tokenRange) - - // sequencer pushes token ranges to buf - sequencer := func() error { - span := int64(math.MaxInt64 / (50 * workers)) - - tr := tokenRange{math.MinInt64, math.MinInt64 + span} - for tr.End > tr.Start { - buf <- tr - tr.Start = tr.End - tr.End += span - } - - tr.End = math.MaxInt64 - buf <- tr - close(buf) - - return nil - } - - // worker queries a token ranges generated by sequencer - worker := func() error { - const cql = `SELECT * FROM examples.paging_efficient_full_table_scan WHERE - token(user_id) >= :start AND - token(user_id) < :end` - - stmt, names, err := gocqlx.CompileNamedQueryString(cql) - if err != nil { - return err - } - q := session.Query(stmt, names) - defer q.Release() - - var v Video - for { - tr, ok := <-buf - if !ok { - break - } - - iter := q.BindStruct(tr).Iter() - for iter.StructScan(&v) { - t.Logf("%+v:", v) - } - if err := iter.Close(); err != nil { - return err - } - } - - return nil - } - - // Query and displays data. - - var wg errgroup.Group - wg.Go(sequencer) - for i := 0; i < workers; i++ { - wg.Go(worker) - } - - if err := wg.Wait(); err != nil { - t.Fatal(err) - } -} - -// This example shows how to use Lightweight Transactions (LWT) aka. -// Compare-And-Set (CAS) functions. -// See: https://docs.scylladb.com/using-scylla/lwt/ for more details. -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - type Lock struct { - Name string - Owner string - TTL int64 - } - - err = session.ExecStmt(`CREATE TABLE examples.lock (name text PRIMARY KEY, owner text)`) - if err != nil { - t.Fatal("create table:", err) - } - - extend := func(lock Lock) bool { - q := qb.Update("examples.lock"). - Set("owner"). - Where(qb.Eq("name")). - If(qb.Eq("owner")). - TTLNamed("ttl"). - Query(session). - SerialConsistency(gocql.Serial). - BindStruct(lock) - - applied, err := q.ExecCASRelease() - if err != nil { - t.Fatal("ExecCASRelease() failed:", err) - } - return applied - } - - acquire := func(lock Lock) (applied bool) { - var prev Lock - - defer func() { - t.Logf("Acquire %+v applied %v owner %+v)", lock, applied, prev) - }() - - q := qb.Insert("examples.lock"). - Columns("name", "owner"). - TTLNamed("ttl"). - Unique(). - Query(session). - SerialConsistency(gocql.Serial). - BindStruct(lock) - - applied, err = q.GetCASRelease(&prev) - if err != nil { - t.Fatal("GetCASRelease() failed:", err) - } - if applied { - return true - } - if prev.Owner == lock.Owner { - return extend(lock) - } - return false - } - - const ( - resource = "acme" - ttl = time.Second - ) - - l1 := Lock{ - Name: resource, - Owner: "1", - TTL: qb.TTL(ttl), - } - - l2 := Lock{ - Name: resource, - Owner: "2", - TTL: qb.TTL(ttl), - } - - if !acquire(l1) { - t.Fatal("l1 failed to acquire lock") - } - if acquire(l2) { - t.Fatal("unexpectedly l2 acquired lock") - } - if !acquire(l1) { - t.Fatal("l1 failed to extend lock") - } - time.Sleep(time.Second) - if !acquire(l2) { - t.Fatal("l2 failed to acquire lock") - } - if acquire(l1) { - t.Fatal("unexpectedly l1 acquired lock") - } -} - -// This example shows how to reuse the same insert statement with -// partially filled parameters without generating tombstones for empty columns. -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}`) - if err != nil { - t.Fatal("create keyspace:", err) - } - - type Operation struct { - ID string - ClientID string - Type string - PaymentID string - Fee *inf.Dec - } - err = session.ExecStmt(`CREATE TABLE IF NOT EXISTS examples.operations ( - id text PRIMARY KEY, - client_id text, - type text, - payment_id text, - fee decimal)`) - if err != nil { - t.Fatal("create table:", err) - } - - insertOperation := qb.Insert("examples.operations"). - Columns("id", "client_id", "type", "payment_id", "fee") - - // Insert operation with empty paymentID. - insertQuery := insertOperation.Query(session). - WithBindTransformer(gocqlx.UnsetEmptyTransformer). - BindStruct(Operation{ - ID: "1", - ClientID: "42", - Type: "Transfer", - Fee: inf.NewDec(1, 1), - }) - if err := insertQuery.ExecRelease(); err != nil { - t.Fatal("ExecRelease() failed:", err) - } - - // Set default transformer to avoid setting it for each query. - gocqlx.DefaultBindTransformer = gocqlx.UnsetEmptyTransformer - defer func() { - gocqlx.DefaultBindTransformer = nil - }() - - // Insert operation with empty fee. - insertQuery = insertOperation.Query(session). - BindStruct(Operation{ - ID: "2", - ClientID: "42", - Type: "Input", - PaymentID: "1", - }) - if err := insertQuery.ExecRelease(); err != nil { - t.Fatal("ExecRelease() failed:", err) - } - - // Query and displays data. - var ops []*Operation - if err := qb.Select("examples.operations").Query(session).Select(&ops); err != nil { - t.Fatal("Select() failed:", err) - } - - for _, op := range ops { - t.Logf("%+v", *op) - } -} - -func mustParseUUID(s string) gocql.UUID { - u, err := gocql.ParseUUID(s) - if err != nil { - panic(err) - } - return u -} diff --git a/iterx_test.go b/iterx_test.go deleted file mode 100644 index b57afaa..0000000 --- a/iterx_test.go +++ /dev/null @@ -1,1015 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -//go:build all || integration -// +build all integration - -package gocqlx_test - -import ( - "math/big" - "reflect" - "strings" - "testing" - "time" - - gocql "github.com/apache/cassandra-gocql-driver/v2" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "gopkg.in/inf.v0" - - "github.com/scylladb/gocqlx/v3" - "github.com/scylladb/gocqlx/v3/gocqlxtest" - "github.com/scylladb/gocqlx/v3/qb" -) - -type FullName struct { - FirstName string - LastName string -} - -func (n FullName) MarshalCQL(info gocql.TypeInfo) ([]byte, error) { - return []byte(n.FirstName + " " + n.LastName), nil -} - -func (n *FullName) UnmarshalCQL(info gocql.TypeInfo, data []byte) error { - t := strings.SplitN(string(data), " ", 2) - n.FirstName, n.LastName = t[0], t[1] - return nil -} - -type FullNameUDT struct { - gocqlx.UDT - FullName -} - -type FullNamePtrUDT struct { - gocqlx.UDT - *FullName -} - -func diff(t *testing.T, expected, got interface{}) { - t.Helper() - - if d := cmp.Diff(expected, got, diffOpts); d != "" { - t.Errorf("got %+v expected %+v, diff: %s", got, expected, d) - } -} - -var diffOpts = cmpopts.IgnoreUnexported(big.Int{}, inf.Dec{}) - -func TestIterxUDT(t *testing.T) { - session := gocqlxtest.CreateSession(t) - t.Cleanup(func() { - session.Close() - }) - - if err := session.ExecStmt(`CREATE TYPE gocqlx_test.UDTTest_Full (first text, second text)`); err != nil { - t.Fatal("create type:", err) - } - - if err := session.ExecStmt(`CREATE TABLE gocqlx_test.udt_table ( - testuuid timeuuid PRIMARY KEY, - testudt gocqlx_test.UDTTest_Full - )`); err != nil { - t.Fatal("create table:", err) - } - - type Full struct { - First string - Second string - } - - type Part struct { - First string - } - - type Extra struct { - First string - Second string - Third string - } - - type FullUDT struct { - gocqlx.UDT - Full - } - - type PartUDT struct { - gocqlx.UDT - Part - } - - type ExtraUDT struct { - gocqlx.UDT - Extra - } - - type FullUDTPtr struct { - gocqlx.UDT - *Full - } - - type PartUDTPtr struct { - gocqlx.UDT - *Part - } - - type ExtraUDTPtr struct { - gocqlx.UDT - *Extra - } - - full := FullUDT{ - Full: Full{ - First: "John", - Second: "Doe", - }, - } - - makeStruct := func(testuuid gocql.UUID, insert interface{}) interface{} { - b := reflect.New(reflect.StructOf([]reflect.StructField{ - { - Name: "TestUUID", - Type: reflect.TypeOf(gocql.UUID{}), - }, - { - Name: "TestUDT", - Type: reflect.TypeOf(insert), - }, - })).Interface() - reflect.ValueOf(b).Elem().FieldByName("TestUUID").Set(reflect.ValueOf(testuuid)) - reflect.ValueOf(b).Elem().FieldByName("TestUDT").Set(reflect.ValueOf(insert)) - return b - } - - tcases := []struct { - name string - insert interface{} - expected interface{} - expectedOnDB FullUDT - }{ - { - name: "exact-match", - insert: full, - expectedOnDB: full, - expected: full, - }, - { - name: "exact-match-ptr", - insert: FullUDTPtr{ - Full: &Full{ - First: "John", - Second: "Doe", - }, - }, - expectedOnDB: full, - expected: FullUDTPtr{ - Full: &Full{ - First: "John", - Second: "Doe", - }, - }, - }, - { - name: "extra-field", - insert: ExtraUDT{ - Extra: Extra{ - First: "John", - Second: "Doe", - Third: "Smith", - }, - }, - expectedOnDB: full, - expected: ExtraUDT{ - Extra: Extra{ - First: "John", - Second: "Doe", - Third: "", // Since the UDT has only 2 fields, the third field should be empty - }, - }, - }, - { - name: "extra-field-ptr", - insert: ExtraUDTPtr{ - Extra: &Extra{ - First: "John", - Second: "Doe", - Third: "Smith", - }, - }, - expectedOnDB: full, - expected: ExtraUDTPtr{ - Extra: &Extra{ - First: "John", - Second: "Doe", - Third: "", // Since the UDT has only 2 fields, the third field should be empty - }, - }, - }, - { - name: "absent-field", - insert: PartUDT{ - Part: Part{ - First: "John", - }, - }, - expectedOnDB: FullUDT{ - Full: Full{ - First: "John", - Second: "", - }, - }, - expected: PartUDT{ - Part: Part{ - First: "John", - }, - }, - }, - { - name: "absent-field-ptr", - insert: PartUDTPtr{ - Part: &Part{ - First: "John", - }, - }, - expectedOnDB: FullUDT{ - Full: Full{ - First: "John", - Second: "", - }, - }, - expected: PartUDTPtr{ - Part: &Part{ - First: "John", - }, - }, - }, - } - - const insertStmt = `INSERT INTO udt_table (testuuid, testudt) VALUES (?, ?)` - const deleteStmt = `DELETE FROM udt_table WHERE testuuid = ?` - - for _, tc := range tcases { - t.Run(tc.name, func(t *testing.T) { - testuuid := gocql.TimeUUID() - - if reflect.TypeOf(tc.insert) != reflect.TypeOf(tc.expected) { - t.Fatalf("insert and expectedOnDB must have the same type") - } - - t.Cleanup(func() { - _ = session.Query(deleteStmt, nil).Bind(testuuid).ExecRelease() - }) - - t.Run("insert-bind", func(t *testing.T) { - if err := session.Query(insertStmt, nil).Bind( - testuuid, - tc.insert, - ).ExecRelease(); err != nil { - t.Fatal(err.Error()) - } - - // Make sure the UDT was inserted correctly - v := FullUDT{} - if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Get(&v); err != nil { - t.Fatal(err.Error()) - } - diff(t, tc.expectedOnDB, v) - }) - - t.Run("scan", func(t *testing.T) { - v := reflect.New(reflect.TypeOf(tc.expected)).Interface() - if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Scan(v); err != nil { - t.Fatal(err.Error()) - } - diff(t, tc.expected, reflect.ValueOf(v).Elem().Interface()) - }) - - t.Run("get", func(t *testing.T) { - v := reflect.New(reflect.TypeOf(tc.expected)).Interface() - if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Get(v); err != nil { - t.Fatal(err.Error()) - } - diff(t, tc.expected, reflect.ValueOf(v).Elem().Interface()) - }) - - t.Run("delete", func(t *testing.T) { - if err := session.Query(deleteStmt, nil).Bind( - testuuid, - ).ExecRelease(); err != nil { - t.Fatal(err.Error()) - } - }) - - t.Run("insert-bind-struct", func(t *testing.T) { - b := makeStruct(testuuid, tc.insert) - if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).BindStruct(b).ExecRelease(); err != nil { - t.Fatal(err.Error()) - } - - // Make sure the UDT was inserted correctly - v := reflect.New(reflect.TypeOf(tc.expectedOnDB)).Interface() - if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Get(v); err != nil { - t.Fatal(err.Error()) - } - diff(t, &tc.expectedOnDB, v) - }) - - t.Run("insert-bind-struct-map", func(t *testing.T) { - t.Run("empty-map", func(t *testing.T) { - b := makeStruct(testuuid, tc.insert) - if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}). - BindStructMap(b, nil).ExecRelease(); err != nil { - t.Fatal(err.Error()) - } - - // Make sure the UDT was inserted correctly - v := reflect.New(reflect.TypeOf(tc.expectedOnDB)).Interface() - if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Get(v); err != nil { - t.Fatal(err.Error()) - } - diff(t, &tc.expectedOnDB, v) - }) - - t.Run("empty-struct", func(t *testing.T) { - if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}). - BindStructMap(struct{}{}, map[string]interface{}{ - "test_uuid": testuuid, - "test_udt": tc.insert, - }).ExecRelease(); err != nil { - t.Fatal(err.Error()) - } - - // Make sure the UDT was inserted correctly - v := reflect.New(reflect.TypeOf(tc.expectedOnDB)).Interface() - if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Get(v); err != nil { - t.Fatal(err.Error()) - } - diff(t, &tc.expectedOnDB, v) - }) - }) - - t.Run("insert-bind-map", func(t *testing.T) { - if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}). - BindMap(map[string]interface{}{ - "test_uuid": testuuid, - "test_udt": tc.insert, - }).ExecRelease(); err != nil { - t.Fatal(err.Error()) - } - - // Make sure the UDT was inserted correctly - v := reflect.New(reflect.TypeOf(tc.expectedOnDB)).Interface() - if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Get(v); err != nil { - t.Fatal(err.Error()) - } - diff(t, &tc.expectedOnDB, v) - }) - }) - } -} - -func TestIterxStruct(t *testing.T) { - session := gocqlxtest.CreateSession(t) - defer session.Close() - - if err := session.ExecStmt(`CREATE TYPE gocqlx_test.FullName (first_Name text, last_name text)`); err != nil { - t.Fatal("create type:", err) - } - - if err := session.ExecStmt(`CREATE TABLE gocqlx_test.struct_table ( - testuuid timeuuid PRIMARY KEY, - testtimestamp timestamp, - testvarchar varchar, - testbigint bigint, - testblob blob, - testbool boolean, - testfloat float, - testdouble double, - testint int, - testdecimal decimal, - testlist list, - testset set, - testmap map, - testvarint varint, - testinet inet, - testcustom text, - testudt gocqlx_test.FullName, - testptrudt gocqlx_test.FullName - )`); err != nil { - t.Fatal("create table:", err) - } - - type StructTable struct { - Testuuid gocql.UUID - Testvarchar string - Testbigint int64 - Testtimestamp time.Time - Testblob []byte - Testbool bool - Testfloat float32 - Testdouble float64 - Testint int - Testdecimal *inf.Dec - Testlist []string - Testset []int - Testmap map[string]string - Testvarint *big.Int - Testinet string - Testcustom FullName - Testudt FullNameUDT - Testptrudt FullNamePtrUDT - } - - bigInt := new(big.Int) - if _, ok := bigInt.SetString("830169365738487321165427203929228", 10); !ok { - t.Fatal("failed setting bigint by string") - } - - m := StructTable{ - Testuuid: gocql.TimeUUID(), - Testvarchar: "Test VarChar", - Testbigint: time.Now().Unix(), - Testtimestamp: time.Now().Truncate(time.Millisecond).UTC(), - Testblob: []byte("test blob"), - Testbool: true, - Testfloat: float32(4.564), - Testdouble: float64(4.815162342), - Testint: 2343, - Testdecimal: inf.NewDec(100, 0), - Testlist: []string{"quux", "foo", "bar", "baz", "quux"}, - Testset: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, - Testmap: map[string]string{"field1": "val1", "field2": "val2", "field3": "val3"}, - Testvarint: bigInt, - Testinet: "213.212.2.19", - Testcustom: FullName{FirstName: "John", LastName: "Doe"}, - Testudt: FullNameUDT{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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` - - if err := session.Query(insertStmt, nil).Bind( - m.Testuuid, - m.Testtimestamp, - m.Testvarchar, - m.Testbigint, - m.Testblob, - m.Testbool, - m.Testfloat, - m.Testdouble, - m.Testint, - m.Testdecimal, - m.Testlist, - m.Testset, - m.Testmap, - m.Testvarint, - m.Testinet, - m.Testcustom, - m.Testudt, - m.Testptrudt).ExecRelease(); err != nil { - t.Fatal("insert:", err) - } - - const stmt = `SELECT * FROM struct_table` - - t.Run("get", func(t *testing.T) { - var v StructTable - if err := session.Query(stmt, nil).Get(&v); err != nil { - t.Fatal("Get() failed:", err) - } - if diff := cmp.Diff(m, v, diffOpts); diff != "" { - t.Fatalf("Get()=%+v expected %+v, diff: %s", v, m, diff) - } - }) - - t.Run("select", func(t *testing.T) { - var v []StructTable - if err := session.Query(stmt, nil).Select(&v); err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(m, v[0], diffOpts); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], m, diff) - } - }) - - t.Run("select ptr", func(t *testing.T) { - var v []*StructTable - if err := session.Query(stmt, nil).Select(&v); err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(&m, v[0], diffOpts); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], &m, diff) - } - }) - - t.Run("struct scan", func(t *testing.T) { - var ( - v StructTable - n int - ) - - iter := session.Query(stmt, nil).Iter() - for iter.StructScan(&v) { - n++ - } - if err := iter.Close(); err != nil { - t.Fatal("StructScan() failed:", err) - } - if n != 1 { - t.Fatalf("StructScan() expected 1 row got %d", n) - } - if diff := cmp.Diff(m, v, diffOpts); diff != "" { - t.Fatalf("StructScan()=%+v expected %+v, diff: %s", v, m, diff) - } - }) -} - -func TestIterxScannable(t *testing.T) { - session := gocqlxtest.CreateSession(t) - defer session.Close() - - if err := session.ExecStmt(`CREATE TABLE gocqlx_test.scannable_table (testfullname text PRIMARY KEY)`); err != nil { - t.Fatal("create table:", err) - } - - m := FullName{"John", "Doe"} - - if err := session.Query(`INSERT INTO scannable_table (testfullname) values (?)`, nil).Bind(m).Exec(); err != nil { - t.Fatal("insert:", err) - } - - const stmt = `SELECT testfullname FROM scannable_table` - - t.Run("get", func(t *testing.T) { - var v FullName - if err := session.Query(stmt, nil).Get(&v); err != nil { - t.Fatal("Get() failed:", err) - } - if diff := cmp.Diff(m, v); diff != "" { - t.Fatalf("Get()=%+v expected %+v, diff: %s", v, m, diff) - } - }) - - t.Run("select", func(t *testing.T) { - var v []FullName - if err := session.Query(stmt, nil).Select(&v); err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(m, v[0]); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], m, diff) - } - }) - - t.Run("select ptr", func(t *testing.T) { - var v []*FullName - if err := session.Query(stmt, nil).Select(&v); err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(&m, v[0]); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], &m, diff) - } - }) -} - -func TestIterxStructOnly(t *testing.T) { - session := gocqlxtest.CreateSession(t) - 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 { - t.Fatal("create table:", err) - } - - m := FullName{"John", "Doe"} - - if err := session.Query(`INSERT INTO struct_only_table (first_name, last_name) values (?, ?)`, nil).Bind(m.FirstName, m.LastName).Exec(); err != nil { - t.Fatal("insert:", err) - } - - const stmt = `SELECT first_name, last_name FROM struct_only_table` - - t.Run("get", func(t *testing.T) { - var v FullName - if err := session.Query(stmt, nil).Iter().StructOnly().Get(&v); err != nil { - t.Fatal("Get() failed:", err) - } - if diff := cmp.Diff(m, v); diff != "" { - t.Fatalf("Get()=%+v expected %+v, diff: %s", v, m, diff) - } - }) - - t.Run("select", func(t *testing.T) { - var v []FullName - if err := session.Query(stmt, nil).Iter().StructOnly().Select(&v); err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(m, v[0]); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], m, diff) - } - }) - - t.Run("select ptr", func(t *testing.T) { - var v []*FullName - if err := session.Query(stmt, nil).Iter().StructOnly().Select(&v); err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(&m, v[0]); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], &m, diff) - } - }) - - const golden = "expected 1 column in result" - - t.Run("get error", func(t *testing.T) { - var v FullName - err := session.Query(stmt, nil).Get(&v) - if err == nil || !strings.HasPrefix(err.Error(), golden) { - t.Fatalf("Get() error=%q expected %s", err, golden) - } - }) - - t.Run("select error", func(t *testing.T) { - var v []FullName - err := session.Query(stmt, nil).Select(&v) - if err == nil || !strings.HasPrefix(err.Error(), golden) { - t.Fatalf("Select() error=%q expected %s", err, golden) - } - }) -} - -func TestIterxStructOnlyUDT(t *testing.T) { - session := gocqlxtest.CreateSession(t) - 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 { - t.Fatal("create table:", err) - } - - m := FullNameUDT{ - FullName: FullName{ - FirstName: "John", - LastName: "Doe", - }, - } - - if err := session.Query(`INSERT INTO struct_only_udt_table (first_name, last_name) values (?, ?)`, nil).Bind(m.FirstName, m.LastName).Exec(); err != nil { - t.Fatal("insert:", err) - } - - const stmt = `SELECT first_name, last_name FROM struct_only_udt_table` - - t.Run("get", func(t *testing.T) { - var v FullNameUDT - if err := session.Query(stmt, nil).Iter().StructOnly().Get(&v); err != nil { - t.Fatal("Get() failed:", err) - } - if diff := cmp.Diff(m, v); diff != "" { - t.Fatalf("Get()=%+v expected %+v, diff: %s", v, m, diff) - } - }) - - t.Run("select", func(t *testing.T) { - var v []FullNameUDT - if err := session.Query(stmt, nil).Iter().StructOnly().Select(&v); err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(m, v[0]); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], m, diff) - } - }) - - t.Run("select ptr", func(t *testing.T) { - var v []*FullNameUDT - if err := session.Query(stmt, nil).Iter().StructOnly().Select(&v); err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(&m, v[0]); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], &m, diff) - } - }) - - const golden = "expected 1 column in result" - - t.Run("get error", func(t *testing.T) { - var v FullNameUDT - err := session.Query(stmt, nil).Get(&v) - if err == nil || !strings.HasPrefix(err.Error(), golden) { - t.Fatalf("Get() error=%q expected %s", err, golden) - } - }) - - t.Run("select error", func(t *testing.T) { - var v []FullNameUDT - err := session.Query(stmt, nil).Select(&v) - if err == nil || !strings.HasPrefix(err.Error(), golden) { - t.Fatalf("Select() error=%q expected %s", err, golden) - } - }) -} - -func TestIterxStrict(t *testing.T) { - session := gocqlxtest.CreateSession(t) - defer session.Close() - - if err := session.ExecStmt(`CREATE TABLE gocqlx_test.strict_table (testtext text PRIMARY KEY, testtextunbound text)`); err != nil { - t.Fatal("create table:", err) - } - if err := session.Query(`INSERT INTO strict_table (testtext, testtextunbound) values (?, ?)`, nil).Bind("test", "test").Exec(); err != nil { - t.Fatal("insert:", err) - } - - type StrictTable struct { - Testtext string - } - - m := StrictTable{ - Testtext: "test", - } - - const ( - stmt = `SELECT * FROM strict_table` - golden = "missing destination name \"testtextunbound\" in gocqlx_test.StrictTable" - ) - - t.Run("get strict", func(t *testing.T) { - var v StrictTable - err := session.Query(stmt, nil).Strict().Get(&v) - if err == nil || !strings.HasPrefix(err.Error(), golden) { - t.Fatalf("Get() error=%q expected %s", err, golden) - } - }) - - t.Run("select strict", func(t *testing.T) { - var v []StrictTable - err := session.Query(stmt, nil).Strict().Select(&v) - if err == nil || !strings.HasPrefix(err.Error(), golden) { - t.Fatalf("Select() error=%q expected %s", err, golden) - } - if cap(v) > 0 { - t.Fatalf("Select() effect alloc cap=%d expected 0", cap(v)) - } - }) - - t.Run("get", func(t *testing.T) { - var v StrictTable - err := session.Query(stmt, nil).Get(&v) - if err != nil { - t.Fatal("Get() failed:", err) - } - if diff := cmp.Diff(m, v); diff != "" { - t.Fatalf("Get()=%+v expected %+v, diff: %s", v, m, diff) - } - }) - - t.Run("select", func(t *testing.T) { - var v []StrictTable - err := session.Query(stmt, nil).Select(&v) - if err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(m, v[0]); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], m, diff) - } - }) - - t.Run("select default", func(t *testing.T) { - var v []StrictTable - err := session.Query(stmt, nil).Iter().Select(&v) - if err != nil { - t.Fatal("Select() failed:", err) - } - if len(v) != 1 { - t.Fatalf("Select()=%+v expected 1 row got %d", v, len(v)) - } - if diff := cmp.Diff(m, v[0]); diff != "" { - t.Fatalf("Select()[0]=%+v expected %+v, diff: %s", v[0], m, diff) - } - }) -} - -func TestIterxNotFound(t *testing.T) { - session := gocqlxtest.CreateSession(t) - defer session.Close() - - if err := session.ExecStmt(`CREATE TABLE gocqlx_test.not_found_table (testtext text PRIMARY KEY)`); err != nil { - t.Fatal("create table:", err) - } - - type NotFoundTable struct { - Testtext string - } - - t.Run("get cql error", func(t *testing.T) { - var v NotFoundTable - err := session.Query(`SELECT * FROM not_found_table WRONG`, nil).RetryPolicy(nil).Get(&v) - if err == nil || !strings.Contains(err.Error(), "WRONG") { - t.Fatalf("Get() error=%q", err) - } - }) - - t.Run("get", func(t *testing.T) { - var v NotFoundTable - err := session.Query(`SELECT * FROM not_found_table`, nil).Get(&v) - if err != gocql.ErrNotFound { - t.Fatalf("Get() error=%q expected %s", err, gocql.ErrNotFound) - } - }) - - t.Run("select cql error", func(t *testing.T) { - var v []NotFoundTable - err := session.Query(`SELECT * FROM not_found_table WRONG`, nil).RetryPolicy(nil).Select(&v) - if err == nil || !strings.Contains(err.Error(), "WRONG") { - t.Fatalf("Get() error=%q", err) - } - }) - - t.Run("select", func(t *testing.T) { - var v []NotFoundTable - err := session.Query(`SELECT * FROM not_found_table`, nil).Select(&v) - if err != nil { - t.Fatalf("Select() error=%q expected %s", err, gocql.ErrNotFound) - } - if cap(v) > 0 { - t.Fatalf("Select() effect alloc cap=%d expected 0", cap(v)) - } - }) -} - -func TestIterxErrorOnNil(t *testing.T) { - session := gocqlxtest.CreateSession(t) - defer session.Close() - - if err := session.ExecStmt(`CREATE TABLE gocqlx_test.nil_table (testtext text PRIMARY KEY)`); err != nil { - t.Fatal("create table:", err) - } - - const ( - stmt = "SELECT * FROM not_found_table WRONG" - golden = "expected a pointer but got " - ) - - t.Run("get", func(t *testing.T) { - err := session.Query(stmt, nil).Get(nil) - if err == nil || err.Error() != golden { - t.Fatalf("Get() error=%q expected %q", err, golden) - } - }) - t.Run("select", func(t *testing.T) { - err := session.Query(stmt, nil).Select(nil) - if err == nil || err.Error() != golden { - t.Fatalf("Select() error=%q expected %q", err, golden) - } - }) - t.Run("struct scan", func(t *testing.T) { - iter := session.Query(stmt, nil).Iter() - iter.StructScan(nil) - err := iter.Close() - if err == nil || err.Error() != golden { - t.Fatalf("StructScan() error=%q expected %q", err, golden) - } - }) -} - -func TestIterxPaging(t *testing.T) { - session := gocqlxtest.CreateSession(t) - defer session.Close() - - if err := session.ExecStmt(`CREATE TABLE gocqlx_test.paging_table (id int PRIMARY KEY, val int)`); err != nil { - t.Fatal("create table:", err) - } - if err := session.ExecStmt(`CREATE INDEX id_val_index ON gocqlx_test.paging_table (val)`); err != nil { - t.Fatal("create index:", err) - } - - q := session.Query(qb.Insert("gocqlx_test.paging_table").Columns("id", "val").ToCql()) - for i := 0; i < 5000; i++ { - if err := q.Bind(i, i).Exec(); err != nil { - t.Fatal(err) - } - } - - type Paging struct { - ID int - Val int - } - - stmt, names := qb.Select("gocqlx_test.paging_table"). - Where(qb.Lt("val")). - AllowFiltering(). - Columns("id", "val").ToCql() - iter := session.Query(stmt, names).Bind(100).PageSize(10).Iter() - defer func() { - _ = iter.Close() - }() - - var cnt int - for { - p := &Paging{} - if !iter.StructScan(p) { - break - } - cnt++ - } - if cnt != 100 { - t.Fatal("expected 100", "got", cnt) - } -} - -func TestIterxCAS(t *testing.T) { - session := gocqlxtest.CreateSession(t) - defer session.Close() - - const ( - id = 0 - baseSalary = 1000 - minSalary = 2000 - ) - - john := struct { - ID int - Salary int - }{ID: id, Salary: baseSalary} - - if err := session.ExecStmt(`CREATE TABLE gocqlx_test.cas_table (id int PRIMARY KEY, salary int)`); err != nil { - t.Fatal("create table:", err) - } - - insert := session.Query(qb.Insert("cas_table").Columns("id", "salary").Unique().ToCql()) - - applied, err := insert.BindStruct(john).ExecCAS() - if err != nil { - t.Fatal("ExecCAS() failed:", err) - } - if !applied { - t.Error("ExecCAS() expected first insert success") - } - - applied, err = insert.BindStruct(john).ExecCAS() - if err != nil { - t.Fatal("ExecCAS() failed:", err) - } - if applied { - t.Error("ExecCAS() Expected second insert to not be applied") - } - - update := session.Query(qb.Update("cas_table"). - SetNamed("salary", "min_salary"). - Where(qb.Eq("id")). - If(qb.LtNamed("salary", "min_salary")). - ToCql(), - ) - - applied, err = update.BindStructMap(john, qb.M{"min_salary": minSalary}).GetCAS(&john) - if err != nil { - t.Fatal("GetCAS() failed:", err) - } - if !applied { - t.Error("GetCAS() expected update to be applied") - } - if john.Salary != baseSalary { - t.Error("GetCAS()=%=v expected to have pre-image", john) - } - - applied, err = update.BindStructMap(john, qb.M{"min_salary": minSalary * 2}).GetCAS(&john) - if err != nil { - t.Fatal(err) - } - if !applied { - t.Error("GetCAS() expected update to be applied") - } - if john.Salary != minSalary { - t.Error("GetCAS()=%=v expected to have pre-image", john) - } -} diff --git a/qb/batch_bench_test.go b/qb/batch_bench_test.go deleted file mode 100644 index 7a07a92..0000000 --- a/qb/batch_bench_test.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import "testing" - -func BenchmarkBatchBuilder(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Batch().Add(mockBuilder{"INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) ", []string{"id", "user_uuid", "firstname"}}).ToCql() - } -} diff --git a/qb/batch_test.go b/qb/batch_test.go deleted file mode 100644 index 94bff26..0000000 --- a/qb/batch_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import ( - "testing" - "time" - - "github.com/google/go-cmp/cmp" -) - -type mockBuilder struct { - stmt string - names []string -} - -func (b mockBuilder) ToCql() (stmt string, names []string) { - return b.stmt, b.names -} - -func TestBatchBuilder(t *testing.T) { - m := mockBuilder{"INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) ", []string{"id", "user_uuid", "firstname"}} - - table := []struct { - B *BatchBuilder - N []string - S string - }{ - // Basic test for Batch - { - B: Batch().Add(m), - S: "BEGIN BATCH INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) ; APPLY BATCH ", - N: []string{"id", "user_uuid", "firstname"}, - }, - // Add statement - { - B: Batch(). - AddWithPrefix("a", 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 ", - N: []string{"a.id", "a.user_uuid", "a.firstname", "b.id", "b.user_uuid", "b.firstname"}, - }, - // Add UNLOGGED - { - B: Batch().UnLogged(), - S: "BEGIN UNLOGGED BATCH APPLY BATCH ", - }, - // Add COUNTER - { - B: Batch().Counter(), - S: "BEGIN COUNTER BATCH APPLY BATCH ", - }, - // Add TTL - { - B: Batch().TTL(time.Second), - S: "BEGIN BATCH USING TTL 1 APPLY BATCH ", - }, - { - B: Batch().TTLNamed("ttl"), - S: "BEGIN BATCH USING TTL ? APPLY BATCH ", - N: []string{"ttl"}, - }, - // Add TIMESTAMP - { - B: Batch().Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)), - S: "BEGIN BATCH USING TIMESTAMP 1115251200000000 APPLY BATCH ", - }, - { - B: Batch().TimestampNamed("ts"), - S: "BEGIN BATCH USING TIMESTAMP ? APPLY BATCH ", - N: []string{"ts"}, - }, - // Add TIMEOUT - { - B: Batch().Timeout(time.Second), - S: "BEGIN BATCH USING TIMEOUT 1s APPLY BATCH ", - }, - { - B: Batch().TimeoutNamed("to"), - S: "BEGIN BATCH USING TIMEOUT ? APPLY BATCH ", - N: []string{"to"}, - }, - } - - for _, test := range table { - stmt, names := test.B.ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff) - } - } -} diff --git a/qb/cmp_bench_test.go b/qb/cmp_bench_test.go deleted file mode 100644 index bb8abc4..0000000 --- a/qb/cmp_bench_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import ( - "bytes" - "testing" -) - -func BenchmarkCmp(b *testing.B) { - buf := bytes.Buffer{} - b.ResetTimer() - for i := 0; i < b.N; i++ { - buf.Reset() - c := cmps{ - Eq("id"), - Lt("user_uuid"), - LtOrEq("firstname"), - Gt("stars"), - } - c.writeCql(&buf) - } -} diff --git a/qb/delete_bench_test.go b/qb/delete_bench_test.go deleted file mode 100644 index 222c138..0000000 --- a/qb/delete_bench_test.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import "testing" - -func BenchmarkDeleteBuilder(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Delete("cycling.cyclist_name").Columns("id", "user_uuid", "firstname", "stars").Where(Eq("id")).ToCql() - } -} diff --git a/qb/delete_test.go b/qb/delete_test.go deleted file mode 100644 index b524b71..0000000 --- a/qb/delete_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import ( - "testing" - "time" - - "github.com/google/go-cmp/cmp" -) - -func TestDeleteBuilder(t *testing.T) { - w := EqNamed("id", "expr") - - table := []struct { - B *DeleteBuilder - N []string - S string - }{ - // Basic test for delete - { - B: Delete("cycling.cyclist_name").Where(w), - S: "DELETE FROM cycling.cyclist_name WHERE id=? ", - N: []string{"expr"}, - }, - // Change table name - { - B: Delete("cycling.cyclist_name").Where(w).From("Foobar"), - S: "DELETE FROM Foobar WHERE id=? ", - N: []string{"expr"}, - }, - // Add column - { - B: Delete("cycling.cyclist_name").Where(w).Columns("stars"), - S: "DELETE stars FROM cycling.cyclist_name WHERE id=? ", - N: []string{"expr"}, - }, - // Add WHERE - { - B: Delete("cycling.cyclist_name").Where(w, Gt("firstname")), - S: "DELETE FROM cycling.cyclist_name WHERE id=? AND firstname>? ", - N: []string{"expr", "firstname"}, - }, - // Add a tuple column - { - B: Delete("cycling.cyclist_name").Where(EqTuple("id", 2)).Columns("stars"), - S: "DELETE stars FROM cycling.cyclist_name WHERE id=(?,?) ", - N: []string{"id[0]", "id[1]"}, - }, - // Add WHERE for tuple column - { - B: Delete("cycling.cyclist_name").Where(w, GtTuple("firstname", 2)), - S: "DELETE FROM cycling.cyclist_name WHERE id=? AND firstname>(?,?) ", - N: []string{"expr", "firstname[0]", "firstname[1]"}, - }, - // Add WHERE for all tuple columns - { - B: Delete("cycling.cyclist_name").Where(EqTuple("id", 2), GtTuple("firstname", 2)), - S: "DELETE FROM cycling.cyclist_name WHERE id=(?,?) AND firstname>(?,?) ", - N: []string{"id[0]", "id[1]", "firstname[0]", "firstname[1]"}, - }, - // Add IF - { - B: Delete("cycling.cyclist_name").Where(w).If(Gt("firstname")), - S: "DELETE FROM cycling.cyclist_name WHERE id=? IF firstname>? ", - N: []string{"expr", "firstname"}, - }, - // Add TIMESTAMP - { - 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=? ", - N: []string{"expr"}, - }, - { - B: Delete("cycling.cyclist_name").Where(w).TimestampNamed("ts"), - S: "DELETE FROM cycling.cyclist_name USING TIMESTAMP ? WHERE id=? ", - N: []string{"ts", "expr"}, - }, - // Add TIMEOUT - { - B: Delete("cycling.cyclist_name").Where(w).Timeout(time.Second), - S: "DELETE FROM cycling.cyclist_name USING TIMEOUT 1s WHERE id=? ", - N: []string{"expr"}, - }, - { - B: Delete("cycling.cyclist_name").Where(w).TimeoutNamed("to"), - S: "DELETE FROM cycling.cyclist_name USING TIMEOUT ? WHERE id=? ", - N: []string{"to", "expr"}, - }, - // Add IF EXISTS - { - B: Delete("cycling.cyclist_name").Where(w).Existing(), - S: "DELETE FROM cycling.cyclist_name WHERE id=? IF EXISTS ", - N: []string{"expr"}, - }, - } - - for _, test := range table { - stmt, names := test.B.ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } -} diff --git a/qb/insert_bench_test.go b/qb/insert_bench_test.go deleted file mode 100644 index 51578b8..0000000 --- a/qb/insert_bench_test.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import "testing" - -func BenchmarkInsertBuilder(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname", "stars").ToCql() - } -} diff --git a/qb/insert_test.go b/qb/insert_test.go deleted file mode 100644 index 9193c96..0000000 --- a/qb/insert_test.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import ( - "testing" - "time" - - "github.com/google/go-cmp/cmp" -) - -func TestInsertBuilder(t *testing.T) { - table := []struct { - B *InsertBuilder - N []string - S string - }{ - // Basic test for insert - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) ", - N: []string{"id", "user_uuid", "firstname"}, - }, - // Basic test for insert JSON - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Json(), - S: "INSERT INTO cycling.cyclist_name JSON ?", - N: nil, - }, - // Change table name - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Into("Foobar"), - S: "INSERT INTO Foobar (id,user_uuid,firstname) VALUES (?,?,?) ", - N: []string{"id", "user_uuid", "firstname"}, - }, - // Add columns - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Columns("stars"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname,stars) VALUES (?,?,?,?) ", - N: []string{"id", "user_uuid", "firstname", "stars"}, - }, - // Add a named column - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").NamedColumn("stars", "stars_name"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname,stars) VALUES (?,?,?,?) ", - N: []string{"id", "user_uuid", "firstname", "stars_name"}, - }, - // Add a literal column - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").LitColumn("stars", "stars_lit"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname,stars) VALUES (?,?,?,stars_lit) ", - N: []string{"id", "user_uuid", "firstname"}, - }, - // Add TTL - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TTL(time.Second), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TTL 1 ", - N: []string{"id", "user_uuid", "firstname"}, - }, - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TTLNamed("ttl"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TTL ? ", - N: []string{"id", "user_uuid", "firstname", "ttl"}, - }, - // Add TIMESTAMP - { - 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 ", - N: []string{"id", "user_uuid", "firstname"}, - }, - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TimestampNamed("ts"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP ? ", - N: []string{"id", "user_uuid", "firstname", "ts"}, - }, - // Add TIMESTAMP - { - 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 ", - N: []string{"id", "user_uuid", "firstname"}, - }, - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TimestampNamed("ts"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP ? ", - N: []string{"id", "user_uuid", "firstname", "ts"}, - }, - // Add TIMESTAMP - { - 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 ", - N: []string{"id", "user_uuid", "firstname"}, - }, - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TimestampNamed("ts"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP ? ", - N: []string{"id", "user_uuid", "firstname", "ts"}, - }, - // Add TIMEOUT - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timeout(time.Second), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMEOUT 1s ", - N: []string{"id", "user_uuid", "firstname"}, - }, - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TimeoutNamed("to"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMEOUT ? ", - N: []string{"id", "user_uuid", "firstname", "to"}, - }, - // Add TupleColumn - { - B: Insert("cycling.cyclist_name").TupleColumn("id", 2), - S: "INSERT INTO cycling.cyclist_name (id) VALUES ((?,?)) ", - N: []string{"id[0]", "id[1]"}, - }, - { - B: Insert("cycling.cyclist_name").TupleColumn("id", 2).Columns("user_uuid"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid) VALUES ((?,?),?) ", - N: []string{"id[0]", "id[1]", "user_uuid"}, - }, - // Add IF NOT EXISTS - { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Unique(), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) IF NOT EXISTS ", - N: []string{"id", "user_uuid", "firstname"}, - }, - // Add FuncColumn - { - B: Insert("cycling.cyclist_name").FuncColumn("id", Now()), - S: "INSERT INTO cycling.cyclist_name (id) VALUES (now()) ", - N: nil, - }, - { - B: Insert("cycling.cyclist_name").FuncColumn("id", Now()).Columns("user_uuid"), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid) VALUES (now(),?) ", - N: []string{"user_uuid"}, - }, - } - - for _, test := range table { - stmt, names := test.B.ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff) - } - } -} diff --git a/qb/select_bench_test.go b/qb/select_bench_test.go deleted file mode 100644 index 03451c7..0000000 --- a/qb/select_bench_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import "testing" - -func BenchmarkSelectBuilder(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Select("cycling.cyclist_name"). - Columns("id", "user_uuid", "firstname", "surname", "stars"). - Where(Eq("id")). - ToCql() - } -} - -func BenchmarkSelectBuildAssign(b *testing.B) { - b.ResetTimer() - cols := []string{ - "id", "user_uuid", "firstname", - "surname", "stars", - } - for i := 0; i < b.N; i++ { - Select("cycling.cyclist_name"). - Columns(cols...). - Where(Eq("id")). - ToCql() - } -} diff --git a/qb/select_test.go b/qb/select_test.go deleted file mode 100644 index 80df9ca..0000000 --- a/qb/select_test.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import ( - "testing" - "time" - - "github.com/google/go-cmp/cmp" -) - -func TestSelectBuilder(t *testing.T) { - w := EqNamed("id", "expr") - - table := []struct { - B *SelectBuilder - N []string - S string - }{ - // Basic test for select * - { - B: Select("cycling.cyclist_name"), - S: "SELECT * FROM cycling.cyclist_name ", - }, - // Basic test for select columns - { - B: Select("cycling.cyclist_name").Columns("id", "user_uuid", "firstname"), - S: "SELECT id,user_uuid,firstname FROM cycling.cyclist_name ", - }, - // Add a SELECT AS column - { - B: Select("cycling.cyclist_name").Columns("id", "user_uuid", As("firstname", "name")), - S: "SELECT id,user_uuid,firstname AS name FROM cycling.cyclist_name ", - }, - // Basic test for select columns as JSON - { - B: Select("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Json(), - S: "SELECT JSON id,user_uuid,firstname FROM cycling.cyclist_name ", - }, - // Add a SELECT AS column as JSON - { - B: Select("cycling.cyclist_name").Columns("id", "user_uuid", As("firstname", "name")).Json(), - S: "SELECT JSON id,user_uuid,firstname AS name FROM cycling.cyclist_name ", - }, - // Add a SELECT AS column 2 - { - B: Select("cycling.cyclist_name"). - Columns(As("firstname", "name"), "id", As("user_uuid", "user")), - S: "SELECT firstname AS name,id,user_uuid AS user FROM cycling.cyclist_name ", - }, - // Basic test for select distinct - { - B: Select("cycling.cyclist_name").Distinct("id"), - S: "SELECT DISTINCT id FROM cycling.cyclist_name ", - }, - // Change table name - { - B: Select("cycling.cyclist_name").From("Foobar"), - S: "SELECT * FROM Foobar ", - }, - // Add WHERE - { - B: Select("cycling.cyclist_name").Where(w, Gt("firstname")), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? AND firstname>? ", - N: []string{"expr", "firstname"}, - }, - // Add WHERE with tuple - { - B: Select("cycling.cyclist_name").Where(EqTuple("id", 2), Gt("firstname")), - S: "SELECT * FROM cycling.cyclist_name WHERE id=(?,?) AND firstname>? ", - N: []string{"id[0]", "id[1]", "firstname"}, - }, - // Add WHERE with only tuples - { - B: Select("cycling.cyclist_name").Where(EqTuple("id", 2), GtTuple("firstname", 2)), - S: "SELECT * FROM cycling.cyclist_name WHERE id=(?,?) AND firstname>(?,?) ", - N: []string{"id[0]", "id[1]", "firstname[0]", "firstname[1]"}, - }, - // Add TIMEOUT - { - B: Select("cycling.cyclist_name").Where(w, Gt("firstname")).Timeout(time.Second), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? AND firstname>? USING TIMEOUT 1s ", - N: []string{"expr", "firstname"}, - }, - { - B: Select("cycling.cyclist_name").Where(w, Gt("firstname")).TimeoutNamed("to"), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? AND firstname>? USING TIMEOUT ? ", - N: []string{"expr", "firstname", "to"}, - }, - // Add GROUP BY - { - B: Select("cycling.cyclist_name").Columns("MAX(stars) as max_stars").GroupBy("id"), - S: "SELECT id,MAX(stars) as max_stars FROM cycling.cyclist_name GROUP BY id ", - }, - // Add GROUP BY - { - B: Select("cycling.cyclist_name").GroupBy("id"), - S: "SELECT id FROM cycling.cyclist_name GROUP BY id ", - }, - // Add GROUP BY two columns - { - B: Select("cycling.cyclist_name").GroupBy("id", "user_uuid"), - S: "SELECT id,user_uuid FROM cycling.cyclist_name GROUP BY id,user_uuid ", - }, - // Add ORDER BY - { - B: Select("cycling.cyclist_name").Where(w).OrderBy("firstname", ASC), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? ORDER BY firstname ASC ", - N: []string{"expr"}, - }, - // Add ORDER BY - { - B: Select("cycling.cyclist_name").Where(w).OrderBy("firstname", DESC), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? ORDER BY firstname DESC ", - N: []string{"expr"}, - }, - // Add ORDER BY two columns - { - B: Select("cycling.cyclist_name").Where(w).OrderBy("firstname", ASC).OrderBy("lastname", DESC), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? ORDER BY firstname ASC,lastname DESC ", - N: []string{"expr"}, - }, - // Add LIMIT - { - B: Select("cycling.cyclist_name").Where(w).Limit(10), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? LIMIT 10 ", - N: []string{"expr"}, - }, - // Add named LIMIT - { - B: Select("cycling.cyclist_name").Where(w).LimitNamed("limit"), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? LIMIT ? ", - N: []string{"expr", "limit"}, - }, - // Add PER PARTITION LIMIT - { - B: Select("cycling.cyclist_name").Where(w).LimitPerPartition(10), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? PER PARTITION LIMIT 10 ", - N: []string{"expr"}, - }, - // Add named PER PARTITION LIMIT - { - B: Select("cycling.cyclist_name").Where(w).LimitPerPartitionNamed("partition_limit"), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? PER PARTITION LIMIT ? ", - N: []string{"expr", "partition_limit"}, - }, - // Add PER PARTITION LIMIT and LIMIT - { - B: Select("cycling.cyclist_name").Where(w).LimitPerPartition(2).Limit(10), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? PER PARTITION LIMIT 2 LIMIT 10 ", - N: []string{"expr"}, - }, - // Add named PER PARTITION LIMIT and LIMIT - { - B: Select("cycling.cyclist_name").Where(w).LimitPerPartitionNamed("partition_limit").LimitNamed("limit"), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? PER PARTITION LIMIT ? LIMIT ? ", - N: []string{"expr", "partition_limit", "limit"}, - }, - // Add ALLOW FILTERING - { - B: Select("cycling.cyclist_name").Where(w).AllowFiltering(), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? ALLOW FILTERING ", - N: []string{"expr"}, - }, - // Add ALLOW FILTERING and BYPASS CACHE - { - B: Select("cycling.cyclist_name").Where(w).AllowFiltering().BypassCache(), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? ALLOW FILTERING BYPASS CACHE ", - N: []string{"expr"}, - }, - // Add BYPASS CACHE - { - B: Select("cycling.cyclist_name").Where(w).BypassCache(), - S: "SELECT * FROM cycling.cyclist_name WHERE id=? BYPASS CACHE ", - N: []string{"expr"}, - }, - // Add COUNT all - { - B: Select("cycling.cyclist_name").CountAll().Where(Gt("stars")), - S: "SELECT count(*) FROM cycling.cyclist_name WHERE stars>? ", - N: []string{"stars"}, - }, - // Add COUNT with GROUP BY - { - B: Select("cycling.cyclist_name").Count("stars").GroupBy("id"), - S: "SELECT id,count(stars) FROM cycling.cyclist_name GROUP BY id ", - }, - // Add Min - { - B: Select("cycling.cyclist_name").Min("stars"), - S: "SELECT min(stars) FROM cycling.cyclist_name ", - }, - // Add Sum - { - B: Select("cycling.cyclist_name").Sum("*"), - S: "SELECT sum(*) FROM cycling.cyclist_name ", - }, - // Add Avg - { - B: Select("cycling.cyclist_name").Avg("stars"), - S: "SELECT avg(stars) FROM cycling.cyclist_name ", - }, - // Add Max - { - B: Select("cycling.cyclist_name").Max("stars"), - S: "SELECT max(stars) FROM cycling.cyclist_name ", - }, - } - - for _, test := range table { - stmt, names := test.B.ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff) - } - } -} diff --git a/qb/token_test.go b/qb/token_test.go deleted file mode 100644 index 4ac6c53..0000000 --- a/qb/token_test.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import ( - "bytes" - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestToken(t *testing.T) { - table := []struct { - C Cmp - S string - N []string - }{ - // Basic comparators - { - C: Token("a", "b").Eq(), - S: "token(a,b)=token(?,?)", - N: []string{"a", "b"}, - }, - { - C: Token("a", "b").Lt(), - S: "token(a,b)token(?,?)", - N: []string{"a", "b"}, - }, - { - C: Token("a", "b").GtOrEq(), - S: "token(a,b)>=token(?,?)", - N: []string{"a", "b"}, - }, - - // Custom bind names - { - C: Token("a", "b").EqNamed("c", "d"), - S: "token(a,b)=token(?,?)", - N: []string{"c", "d"}, - }, - { - C: Token("a", "b").LtNamed("c", "d"), - S: "token(a,b)token(?,?)", - N: []string{"c", "d"}, - }, - { - C: Token("a", "b").GtOrEqNamed("c", "d"), - S: "token(a,b)>=token(?,?)", - N: []string{"c", "d"}, - }, - { - C: Token("a", "b").EqValue(), - S: "token(a,b)=?", - N: []string{"token"}, - }, - { - C: Token("a", "b").EqValueNamed("c"), - S: "token(a,b)=?", - N: []string{"c"}, - }, - { - C: Token("a", "b").LtValue(), - S: "token(a,b)?", - N: []string{"token"}, - }, - { - C: Token("a", "b").GtValueNamed("c"), - S: "token(a,b)>?", - N: []string{"c"}, - }, - { - C: Token("a", "b").GtOrEqValue(), - S: "token(a,b)>=?", - N: []string{"token"}, - }, - { - C: Token("a", "b").GtOrEqValueNamed("c"), - S: "token(a,b)>=?", - N: []string{"c"}, - }, - } - - buf := bytes.Buffer{} - for _, test := range table { - buf.Reset() - name := test.C.writeCql(&buf) - if diff := cmp.Diff(test.S, buf.String()); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, name); diff != "" { - t.Error(diff) - } - } -} diff --git a/qb/update_bench_test.go b/qb/update_bench_test.go deleted file mode 100644 index 5d44447..0000000 --- a/qb/update_bench_test.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import "testing" - -func BenchmarkUpdateBuilder(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname", "stars").Where(Eq("id")).ToCql() - } -} diff --git a/qb/update_test.go b/qb/update_test.go deleted file mode 100644 index 4afa761..0000000 --- a/qb/update_test.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import ( - "testing" - "time" - - "github.com/google/go-cmp/cmp" -) - -func TestUpdateBuilder(t *testing.T) { - w := EqNamed("id", "expr") - - table := []struct { - B *UpdateBuilder - N []string - S string - }{ - // Basic test for update - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w), - S: "UPDATE cycling.cyclist_name SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"id", "user_uuid", "firstname", "expr"}, - }, - // Change table name - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Table("Foobar"), - S: "UPDATE Foobar SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"id", "user_uuid", "firstname", "expr"}, - }, - // Add SET - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Set("stars"), - S: "UPDATE cycling.cyclist_name SET id=?,user_uuid=?,firstname=?,stars=? WHERE id=? ", - N: []string{"id", "user_uuid", "firstname", "stars", "expr"}, - }, - // Add SET literal - { - B: Update("cycling.cyclist_name").SetLit("user_uuid", "literal_uuid").Where(w).Set("stars"), - S: "UPDATE cycling.cyclist_name SET user_uuid=literal_uuid,stars=? WHERE id=? ", - N: []string{"stars", "expr"}, - }, - - // Add SET tuple - { - B: Update("cycling.cyclist_name").SetTuple("id", 2).Set("user_uuid", "firstname").Where(EqTuple("id", 2)), - S: "UPDATE cycling.cyclist_name SET id=(?,?),user_uuid=?,firstname=? WHERE id=(?,?) ", - N: []string{"id[0]", "id[1]", "user_uuid", "firstname", "id[0]", "id[1]"}, - }, - // Add SET SetFunc - { - B: Update("cycling.cyclist_name").SetFunc("user_uuid", Fn("someFunc", "param_0", "param_1")).Where(w).Set("stars"), - S: "UPDATE cycling.cyclist_name SET user_uuid=someFunc(?,?),stars=? WHERE id=? ", - N: []string{"param_0", "param_1", "stars", "expr"}, - }, - // Add SET Add - { - B: Update("cycling.cyclist_name").Add("total").Where(w), - S: "UPDATE cycling.cyclist_name SET total=total+? WHERE id=? ", - N: []string{"total", "expr"}, - }, - // Add SET AddNamed - { - B: Update("cycling.cyclist_name").AddNamed("total", "inc").Where(w), - S: "UPDATE cycling.cyclist_name SET total=total+? WHERE id=? ", - N: []string{"inc", "expr"}, - }, - // Add SET AddLit - { - B: Update("cycling.cyclist_name").AddLit("total", "1").Where(w), - S: "UPDATE cycling.cyclist_name SET total=total+1 WHERE id=? ", - N: []string{"expr"}, - }, - // Add SET Remove - { - B: Update("cycling.cyclist_name").Remove("total").Where(w), - S: "UPDATE cycling.cyclist_name SET total=total-? WHERE id=? ", - N: []string{"total", "expr"}, - }, - // Add SET RemoveNamed - { - B: Update("cycling.cyclist_name").RemoveNamed("total", "dec").Where(w), - S: "UPDATE cycling.cyclist_name SET total=total-? WHERE id=? ", - N: []string{"dec", "expr"}, - }, - // Add SET RemoveLit - { - B: Update("cycling.cyclist_name").RemoveLit("total", "1").Where(w), - S: "UPDATE cycling.cyclist_name SET total=total-1 WHERE id=? ", - N: []string{"expr"}, - }, - // Add WHERE - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w, Gt("firstname")), - S: "UPDATE cycling.cyclist_name SET id=?,user_uuid=?,firstname=? WHERE id=? AND firstname>? ", - N: []string{"id", "user_uuid", "firstname", "expr", "firstname"}, - }, - // Add IF - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).If(Gt("firstname")), - S: "UPDATE cycling.cyclist_name SET id=?,user_uuid=?,firstname=? WHERE id=? IF firstname>? ", - N: []string{"id", "user_uuid", "firstname", "expr", "firstname"}, - }, - // Add TTL - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).TTL(time.Second), - S: "UPDATE cycling.cyclist_name USING TTL 1 SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"id", "user_uuid", "firstname", "expr"}, - }, - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).TTLNamed("ttl"), - S: "UPDATE cycling.cyclist_name USING TTL ? SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"ttl", "id", "user_uuid", "firstname", "expr"}, - }, - // Add TIMESTAMP - { - 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=? ", - N: []string{"id", "user_uuid", "firstname", "expr"}, - }, - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).TimestampNamed("ts"), - S: "UPDATE cycling.cyclist_name USING TIMESTAMP ? SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"ts", "id", "user_uuid", "firstname", "expr"}, - }, - // Add TIMEOUT - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Timeout(time.Second), - S: "UPDATE cycling.cyclist_name USING TIMEOUT 1s SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"id", "user_uuid", "firstname", "expr"}, - }, - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).TimeoutNamed("to"), - S: "UPDATE cycling.cyclist_name USING TIMEOUT ? SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"to", "id", "user_uuid", "firstname", "expr"}, - }, - // Add IF EXISTS - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Existing(), - S: "UPDATE cycling.cyclist_name SET id=?,user_uuid=?,firstname=? WHERE id=? IF EXISTS ", - N: []string{"id", "user_uuid", "firstname", "expr"}, - }, - // Add SET column - { - B: Update("cycling.cyclist_name").SetNamed("firstname", "name"), - S: "UPDATE cycling.cyclist_name SET firstname=? ", - N: []string{"name"}, - }, - // Add AddFunc - { - B: Update("cycling.cyclist_name").AddFunc("timestamp", Now()), - S: "UPDATE cycling.cyclist_name SET timestamp=timestamp+now() ", - N: nil, - }, - // Add RemoveFunc - { - B: Update("cycling.cyclist_name").RemoveFunc("timestamp", Now()), - S: "UPDATE cycling.cyclist_name SET timestamp=timestamp-now() ", - N: nil, - }, - // Add ALLOW FILTERING - { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).AllowFiltering(), - S: "UPDATE cycling.cyclist_name SET id=?,user_uuid=?,firstname=? WHERE id=? ALLOW FILTERING ", - N: []string{"id", "user_uuid", "firstname", "expr"}, - }, - } - - for _, test := range table { - stmt, names := test.B.ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff) - } - } -} diff --git a/qb/using_test.go b/qb/using_test.go deleted file mode 100644 index 69c2665..0000000 --- a/qb/using_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package qb - -import ( - "bytes" - "testing" - "time" - - "github.com/google/go-cmp/cmp" -) - -func TestTTL(t *testing.T) { - if TTL(time.Second*86400) != 86400 { - t.Fatal("wrong ttl") - } -} - -func TestTimestamp(t *testing.T) { - if Timestamp(time.Unix(0, 0).Add(time.Microsecond*123456789)) != 123456789 { - t.Fatal("wrong timestamp") - } -} - -func TestUsing(t *testing.T) { - table := []struct { - B *using - N []string - S string - }{ - // TTL - { - B: new(using).TTL(time.Second), - S: "USING TTL 1 ", - }, - // TTLNamed - { - B: new(using).TTLNamed("ttl"), - S: "USING TTL ? ", - N: []string{"ttl"}, - }, - // Timestamp - { - B: new(using).Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)), - S: "USING TIMESTAMP 1115251200000000 ", - }, - // TimestampNamed - { - B: new(using).TimestampNamed("ts"), - S: "USING TIMESTAMP ? ", - N: []string{"ts"}, - }, - // Timeout - { - B: new(using).Timeout(time.Second), - S: "USING TIMEOUT 1s ", - }, - // Timeout faction - { - B: new(using).Timeout(time.Second + 100*time.Millisecond), - S: "USING TIMEOUT 1s100ms ", - }, - // TimeoutNamed - { - B: new(using).TimeoutNamed("to"), - S: "USING TIMEOUT ? ", - N: []string{"to"}, - }, - // TTL Timestamp - { - 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 ", - }, - // TTL TimestampNamed - { - B: new(using).TTL(time.Second).TimestampNamed("ts"), - S: "USING TTL 1 AND TIMESTAMP ? ", - N: []string{"ts"}, - }, - // TTLNamed TimestampNamed - { - B: new(using).TTLNamed("ttl").TimestampNamed("ts"), - S: "USING TTL ? AND TIMESTAMP ? ", - N: []string{"ttl", "ts"}, - }, - // TTLNamed Timestamp - { - B: new(using).TTLNamed("ttl").Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)), - S: "USING TTL ? AND TIMESTAMP 1115251200000000 ", - N: []string{"ttl"}, - }, - // TTL Timeout - { - B: new(using).TTL(time.Second).Timeout(time.Second), - S: "USING TTL 1 AND TIMEOUT 1s ", - }, - // TTL TimeoutNamed - { - B: new(using).TTL(time.Second).TimeoutNamed("to"), - S: "USING TTL 1 AND TIMEOUT ? ", - N: []string{"to"}, - }, - // TTL Timestamp Timeout - { - 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 ", - }, - // TTL with no duration - { - B: new(using).TTL(0 * time.Second), - S: "USING TTL 0 ", - }, - { - B: new(using).TTL(-1 * time.Second), - S: "USING TTL 0 ", - }, - { - // TODO patch this maybe in the future - B: new(using).TTL(-2 * time.Second), - S: "USING TTL -2 ", - }, - // TTL TTLNamed - { - B: new(using).TTL(time.Second).TTLNamed("ttl"), - S: "USING TTL ? ", - N: []string{"ttl"}, - }, - // TTLNamed TTL - { - B: new(using).TTLNamed("ttl").TTL(time.Second), - S: "USING TTL 1 ", - }, - // Timestamp TimestampNamed - { - B: new(using).Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)).TimestampNamed("ts"), - S: "USING TIMESTAMP ? ", - N: []string{"ts"}, - }, - // TimestampNamed Timestamp - { - B: new(using).TimestampNamed("ts").Timestamp(time.Date(2005, 5, 5, 0, 0, 0, 0, time.UTC)), - S: "USING TIMESTAMP 1115251200000000 ", - }, - } - - for _, test := range table { - buf := bytes.NewBuffer(nil) - names := test.B.writeCql(buf) - stmt := buf.String() - - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff) - } - } -} diff --git a/qb/utils_test.go b/qb/utils_test.go deleted file mode 100644 index d11afb7..0000000 --- a/qb/utils_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package qb - -import ( - "testing" - "time" -) - -func TestFormatDuration(t *testing.T) { - tests := []struct { - name string - input time.Duration - expected string - }{ - { - name: "Zero duration", - input: 0, - expected: "", - }, - { - input: 500 * time.Millisecond, - expected: "500ms", - }, - { - input: 10 * time.Second, - expected: "10s", - }, - { - input: 3 * time.Minute, - expected: "3m", - }, - { - input: (2 * time.Minute) + (30 * time.Second), - expected: "2m30s", - }, - { - input: (15 * time.Second) + (250 * time.Millisecond), - expected: "15s250ms", - }, - { - input: (1 * time.Minute) + (45 * time.Second) + (123 * time.Millisecond), - expected: "1m45s123ms", - }, - { - input: (5 * time.Minute) + (1 * time.Second) + (999 * time.Millisecond), - expected: "5m1s999ms", - }, - { - input: (2 * time.Second) + (1500 * time.Millisecond), // 3 seconds, 500ms - expected: "3s500ms", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - actual := formatDuration(tt.input) - if actual != tt.expected { - t.Errorf("got %q, want %q", actual, tt.expected) - } - }) - } -} diff --git a/queryx_test.go b/queryx_test.go deleted file mode 100644 index 476e346..0000000 --- a/queryx_test.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package gocqlx - -import ( - "reflect" - "testing" - - gocql "github.com/apache/cassandra-gocql-driver/v2" - "github.com/google/go-cmp/cmp" -) - -func TestCompileQuery(t *testing.T) { - table := []struct { - Q, R string - V []string - }{ - // Basic test for named parameters, invalid char ',' terminating - { - Q: `INSERT INTO foo (a,b,c,d) VALUES (:name, :age, :first, :last)`, - R: `INSERT INTO foo (a,b,c,d) VALUES (?, ?, ?, ?)`, - V: []string{"name", "age", "first", "last"}, - }, - // This query tests a named parameter ending the string as well as numbers - { - Q: `SELECT * FROM a WHERE first_name=:name1 AND last_name=:name2`, - R: `SELECT * FROM a WHERE first_name=? AND last_name=?`, - V: []string{"name1", "name2"}, - }, - { - Q: `SELECT "::foo" FROM a WHERE first_name=:name1 AND last_name=:name2`, - R: `SELECT ":foo" FROM a WHERE first_name=? AND last_name=?`, - V: []string{"name1", "name2"}, - }, - { - Q: `SELECT 'a::b::c' || first_name, '::::ABC::_::' FROM person WHERE first_name=:first_name AND last_name=:last_name`, - R: `SELECT 'a:b:c' || first_name, '::ABC:_:' FROM person WHERE first_name=? AND last_name=?`, - V: []string{"first_name", "last_name"}, - }, - /* This unicode awareness test sadly fails, because of our byte-wise worldview. - * We could certainly iterate by Rune instead, though it's a great deal slower, - * it's probably the RightWay(tm) - { - Q: `INSERT INTO foo (a,b,c,d) VALUES (:あ, :b, :キコ, :名前)`, - R: `INSERT INTO foo (a,b,c,d) VALUES (?, ?, ?, ?)`, - }, - */ - } - - for _, test := range table { - qr, names, err := CompileNamedQuery([]byte(test.Q)) - if err != nil { - t.Error(err) - } - if qr != test.R { - t.Error("expected", test.R, "got", qr) - } - if diff := cmp.Diff(names, test.V); diff != "" { - t.Error("names mismatch", diff) - } - } -} - -func TestQueryxBindStruct(t *testing.T) { - v := &struct { - Name string - Age int - First string - Last string - }{ - Name: "name", - Age: 30, - First: "first", - Last: "last", - } - - t.Run("simple", func(t *testing.T) { - names := []string{"name", "age", "first", "last"} - args, err := Query(nil, names).bindStructArgs(v, nil) - if err != nil { - t.Fatal(err) - } - - if diff := cmp.Diff(args, []interface{}{"name", 30, "first", "last"}); diff != "" { - t.Error("args mismatch", diff) - } - }) - - t.Run("with transformer", func(t *testing.T) { - tr := func(name string, val interface{}) interface{} { - if name == "age" { - return 42 - } - return val - } - - names := []string{"name", "age", "first", "last"} - args, err := Query(nil, names).WithBindTransformer(tr).bindStructArgs(v, nil) - if err != nil { - t.Fatal(err) - } - - if diff := cmp.Diff(args, []interface{}{"name", 42, "first", "last"}); diff != "" { - t.Error("args mismatch", diff) - } - }) - - t.Run("error", func(t *testing.T) { - names := []string{"name", "age", "first", "not_found"} - _, err := Query(nil, names).bindStructArgs(v, nil) - if err == nil { - t.Fatal("unexpected error") - } - }) - - t.Run("fallback", func(t *testing.T) { - names := []string{"name", "age", "first", "not_found"} - m := map[string]interface{}{ - "not_found": "last", - } - args, err := Query(nil, names).bindStructArgs(v, m) - if err != nil { - t.Fatal(err) - } - - if diff := cmp.Diff(args, []interface{}{"name", 30, "first", "last"}); diff != "" { - t.Error("args mismatch", diff) - } - }) - - t.Run("fallback with transformer", func(t *testing.T) { - tr := func(name string, val interface{}) interface{} { - if name == "not_found" { - return "map_found" - } - return val - } - - names := []string{"name", "age", "first", "not_found"} - m := map[string]interface{}{ - "not_found": "last", - } - args, err := Query(nil, names).WithBindTransformer(tr).bindStructArgs(v, m) - if err != nil { - t.Fatal(err) - } - - if diff := cmp.Diff(args, []interface{}{"name", 30, "first", "map_found"}); diff != "" { - t.Error("args mismatch", diff) - } - }) - - t.Run("fallback error", func(t *testing.T) { - names := []string{"name", "age", "first", "not_found", "really_not_found"} - m := map[string]interface{}{ - "not_found": "last", - } - _, err := Query(nil, names).bindStructArgs(v, m) - if err == nil { - t.Fatal("unexpected error") - } - }) -} - -func TestQueryxBindMap(t *testing.T) { - v := map[string]interface{}{ - "name": "name", - "age": 30, - "first": "first", - "last": "last", - } - - t.Run("simple", func(t *testing.T) { - names := []string{"name", "age", "first", "last"} - args, err := Query(nil, names).bindMapArgs(v) - if err != nil { - t.Fatal(err) - } - - if diff := cmp.Diff(args, []interface{}{"name", 30, "first", "last"}); diff != "" { - t.Error("args mismatch", diff) - } - }) - - t.Run("with transformer", func(t *testing.T) { - tr := func(name string, val interface{}) interface{} { - if name == "age" { - return 42 - } - return val - } - - names := []string{"name", "age", "first", "last"} - args, err := Query(nil, names).WithBindTransformer(tr).bindMapArgs(v) - if err != nil { - t.Fatal(err) - } - - if diff := cmp.Diff(args, []interface{}{"name", 42, "first", "last"}); diff != "" { - t.Error("args mismatch", diff) - } - }) - - t.Run("error", func(t *testing.T) { - names := []string{"name", "first", "not_found"} - _, err := Query(nil, names).bindMapArgs(v) - if err == nil { - t.Fatal("unexpected error") - } - }) -} - -func TestQueryxAllWrapped(t *testing.T) { - var ( - gocqlQueryPtr = reflect.TypeOf((*gocql.Query)(nil)) - queryxPtr = reflect.TypeOf((*Queryx)(nil)) - ) - - for i := 0; i < gocqlQueryPtr.NumMethod(); i++ { - m, ok := queryxPtr.MethodByName(gocqlQueryPtr.Method(i).Name) - if !ok { - t.Fatalf("Queryx missing method %s", gocqlQueryPtr.Method(i).Name) - } - - for j := 0; j < m.Type.NumOut(); j++ { - if m.Type.Out(j) == gocqlQueryPtr { - t.Errorf("Queryx method %s not wrapped", m.Name) - } - } - } -} diff --git a/table/table_test.go b/table/table_test.go deleted file mode 100644 index 8911f92..0000000 --- a/table/table_test.go +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (C) 2017 ScyllaDB -// Use of this source code is governed by a ALv2-style -// license that can be found in the LICENSE file. - -package table - -import ( - "sync" - "testing" - - "github.com/google/go-cmp/cmp" - - "github.com/scylladb/gocqlx/v3/qb" -) - -func TestTableGet(t *testing.T) { - table := []struct { - M Metadata - C []string - N []string - S string - }{ - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - SortKey: []string{"b"}, - }, - N: []string{"a", "b"}, - S: "SELECT * FROM table WHERE a=? AND b=? ", - }, - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - }, - N: []string{"a"}, - S: "SELECT * FROM table WHERE a=? ", - }, - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - }, - C: []string{"d"}, - N: []string{"a"}, - S: "SELECT d FROM table WHERE a=? ", - }, - } - - for _, test := range table { - stmt, names := New(test.M).Get(test.C...) - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } - - // run GetBuilder on the same data set - for _, test := range table { - stmt, names := New(test.M).GetBuilder(test.C...).ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } -} - -func TestTableSelect(t *testing.T) { - table := []struct { - M Metadata - C []string - N []string - S string - }{ - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - SortKey: []string{"b"}, - }, - N: []string{"a"}, - S: "SELECT * FROM table WHERE a=? ", - }, - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - SortKey: []string{"b"}, - }, - C: []string{"d"}, - N: []string{"a"}, - S: "SELECT d FROM table WHERE a=? ", - }, - } - - for _, test := range table { - stmt, names := New(test.M).Select(test.C...) - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } - - // run SelectBuilder on the same data set - for _, test := range table { - stmt, names := New(test.M).SelectBuilder(test.C...).ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } -} - -func TestTableInsert(t *testing.T) { - table := []struct { - M Metadata - N []string - S string - }{ - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - SortKey: []string{"b"}, - }, - N: []string{"a", "b", "c", "d"}, - S: "INSERT INTO table (a,b,c,d) VALUES (?,?,?,?) ", - }, - } - - for _, test := range table { - stmt, names := New(test.M).Insert() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } -} - -func TestTableUpdate(t *testing.T) { - table := []struct { - M Metadata - C []string - N []string - S string - }{ - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - SortKey: []string{"b"}, - }, - C: []string{"d"}, - N: []string{"d", "a", "b"}, - S: "UPDATE table SET d=? WHERE a=? AND b=? ", - }, - } - - for _, test := range table { - stmt, names := New(test.M).Update(test.C...) - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } - - // run UpdateBuilder on the same data set - for _, test := range table { - stmt, names := New(test.M).UpdateBuilder(test.C...).ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } -} - -func TestTableDelete(t *testing.T) { - table := []struct { - M Metadata - C []string - N []string - S string - }{ - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - SortKey: []string{"b"}, - }, - N: []string{"a", "b"}, - S: "DELETE FROM table WHERE a=? AND b=? ", - }, - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - }, - N: []string{"a"}, - S: "DELETE FROM table WHERE a=? ", - }, - { - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - }, - C: []string{"d"}, - N: []string{"a"}, - S: "DELETE d FROM table WHERE a=? ", - }, - } - - for _, test := range table { - stmt, names := New(test.M).Delete(test.C...) - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } - - // run DeleteBuilder on the same data set - for _, test := range table { - stmt, names := New(test.M).DeleteBuilder(test.C...).ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - } -} - -func TestTableConcurrentUsage(t *testing.T) { - table := []struct { - Name string - M Metadata - C []string - N []string - S string - }{ - { - Name: "Full select", - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - SortKey: []string{"b"}, - }, - N: []string{"a", "b"}, - S: "SELECT * FROM table WHERE a=? AND b=? ", - }, - { - Name: "Sub select", - M: Metadata{ - Name: "table", - Columns: []string{"a", "b", "c", "d"}, - PartKey: []string{"a"}, - SortKey: []string{"b"}, - }, - C: []string{"d"}, - N: []string{"a", "b"}, - S: "SELECT d FROM table WHERE a=? AND b=? ", - }, - } - - parallelCount := 3 - // run SelectBuilder on the data set in parallel - for _, test := range table { - var wg sync.WaitGroup - testTable := New(test.M) - wg.Add(parallelCount) - for i := 0; i < parallelCount; i++ { - go func() { - defer wg.Done() - stmt, names := testTable.SelectBuilder(test.C...). - Where(qb.Eq("b")).ToCql() - if diff := cmp.Diff(test.S, stmt); diff != "" { - t.Error(diff) - } - if diff := cmp.Diff(test.N, names); diff != "" { - t.Error(diff, names) - } - }() - } - wg.Wait() - } -}