From 31ec532b6dc2bbb0d9b4713c4464c33c3b0633ad Mon Sep 17 00:00:00 2001 From: go-jet Date: Fri, 19 Jul 2019 12:39:10 +0200 Subject: [PATCH 1/7] Additional generator tests. --- cmd/jet/main.go | 3 +- generator/postgres/generator.go | 5 +- tests/init/init.go | 2 +- tests/main_test.go | 191 +++++++++++++++++++++++++++++++- 4 files changed, 195 insertions(+), 6 deletions(-) diff --git a/cmd/jet/main.go b/cmd/jet/main.go index 03eee06..bedbe7d 100644 --- a/cmd/jet/main.go +++ b/cmd/jet/main.go @@ -6,7 +6,6 @@ import ( "github.com/go-jet/jet/generator/postgres" _ "github.com/lib/pq" "os" - "strconv" ) var ( @@ -71,7 +70,7 @@ Usage of jet: genData := postgres.DBConnection{ Host: host, - Port: strconv.Itoa(port), + Port: port, User: user, Password: password, SslMode: sslmode, diff --git a/generator/postgres/generator.go b/generator/postgres/generator.go index c18ab7e..6c5b04b 100644 --- a/generator/postgres/generator.go +++ b/generator/postgres/generator.go @@ -8,12 +8,13 @@ import ( "github.com/go-jet/jet/internal/utils" "path" "path/filepath" + "strconv" ) // DBConnection contains postgres connection details type DBConnection struct { Host string - Port string + Port int User string Password string SslMode string @@ -27,7 +28,7 @@ type DBConnection struct { func Generate(destDir string, dbConn DBConnection) error { connectionString := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s %s", - dbConn.Host, dbConn.Port, dbConn.User, dbConn.Password, dbConn.DBName, dbConn.SslMode, dbConn.Params) + dbConn.Host, strconv.Itoa(dbConn.Port), dbConn.User, dbConn.Password, dbConn.DBName, dbConn.SslMode, dbConn.Params) fmt.Println("Connecting to postgres database: " + connectionString) diff --git a/tests/init/init.go b/tests/init/init.go index 3165516..a8f3110 100644 --- a/tests/init/init.go +++ b/tests/init/init.go @@ -39,7 +39,7 @@ func main() { err = postgres.Generate("./.gentestdata", postgres.DBConnection{ Host: dbconfig.Host, - Port: "5432", + Port: 5432, User: dbconfig.User, Password: dbconfig.Password, DBName: dbconfig.DBName, diff --git a/tests/main_test.go b/tests/main_test.go index 6f5fb42..09106a4 100644 --- a/tests/main_test.go +++ b/tests/main_test.go @@ -1,13 +1,17 @@ package tests import ( + "bytes" "database/sql" + "github.com/go-jet/jet/generator/postgres" "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/model" "github.com/go-jet/jet/tests/dbconfig" _ "github.com/lib/pq" "github.com/pkg/profile" "gotest.tools/assert" + "io/ioutil" "os" + "os/exec" "reflect" "testing" ) @@ -29,7 +33,7 @@ func TestMain(m *testing.M) { os.Exit(ret) } -func TestGenerateModel(t *testing.T) { +func TestGeneratedModel(t *testing.T) { actor := model.Actor{} @@ -58,3 +62,188 @@ func TestGenerateModel(t *testing.T) { assert.Equal(t, reflect.TypeOf(staff.Email).String(), "*string") assert.Equal(t, reflect.TypeOf(staff.Picture).String(), "*[]uint8") } + +const genTestDir2 = "./.gentestdata2" + +func TestCmdGenerator(t *testing.T) { + err := os.RemoveAll(genTestDir2) + assert.NilError(t, err) + + cmd := exec.Command("jet", "-dbname=jetdb", "-host=localhost", "-port=5432", + "-user=jet", "-password=jet", "-schema=dvds", "-path="+genTestDir2) + + err = cmd.Run() + assert.NilError(t, err) + + assertGeneratedFiles(t) + + err = os.RemoveAll(genTestDir2) + assert.NilError(t, err) +} + +func TestGenerator(t *testing.T) { + + err := os.RemoveAll(genTestDir2) + assert.NilError(t, err) + + err = postgres.Generate(genTestDir2, postgres.DBConnection{ + Host: dbconfig.Host, + Port: dbconfig.Port, + User: dbconfig.User, + Password: dbconfig.Password, + SslMode: "disable", + Params: "", + + DBName: dbconfig.DBName, + SchemaName: "dvds", + }) + + assert.NilError(t, err) + + assertGeneratedFiles(t) + + err = os.RemoveAll(genTestDir2) + assert.NilError(t, err) +} + +func assertGeneratedFiles(t *testing.T) { + // Table SQL Builder files + tableSQLBuilderFiles, err := ioutil.ReadDir("./.gentestdata2/jetdb/dvds/table") + assert.NilError(t, err) + + assertFileNameEqual(t, tableSQLBuilderFiles, "actor.go", "address.go", "category.go", "city.go", "country.go", + "customer.go", "film.go", "film_actor.go", "film_category.go", "inventory.go", "language.go", + "payment.go", "rental.go", "staff.go", "store.go") + + assertFileContent(t, "./.gentestdata2/jetdb/dvds/table/actor.go", "\npackage table", actorSQLBuilderFile) + + // Enums SQL Builder files + enumFiles, err := ioutil.ReadDir("./.gentestdata2/jetdb/dvds/enum") + + assertFileNameEqual(t, enumFiles, "mpaa_rating.go") + assertFileContent(t, "./.gentestdata2/jetdb/dvds/enum/mpaa_rating.go", "\npackage enum", mpaaRatingEnumFile) + + // Model files + modelFiles, err := ioutil.ReadDir("./.gentestdata2/jetdb/dvds/model") + assert.NilError(t, err) + + assertFileNameEqual(t, modelFiles, "actor.go", "address.go", "category.go", "city.go", "country.go", + "customer.go", "film.go", "film_actor.go", "film_category.go", "inventory.go", "language.go", + "payment.go", "rental.go", "staff.go", "store.go", "mpaa_rating.go") + + assertFileContent(t, "./.gentestdata2/jetdb/dvds/model/actor.go", "\npackage model", actorModelFile) +} + +func assertFileContent(t *testing.T, filePath string, contentBegin string, expectedContent string) { + enumFileData, err := ioutil.ReadFile(filePath) + + assert.NilError(t, err) + + beginIndex := bytes.Index(enumFileData, []byte(contentBegin)) + + //fmt.Println("-"+string(enumFileData[beginIndex:])+"-") + + assert.DeepEqual(t, string(enumFileData[beginIndex:]), expectedContent) +} + +func assertFileNameEqual(t *testing.T, fileInfos []os.FileInfo, fileNames ...string) { + + fileNamesMap := map[string]bool{} + + for _, fileInfo := range fileInfos { + fileNamesMap[fileInfo.Name()] = true + } + + for _, fileName := range fileNames { + assert.Assert(t, fileNamesMap[fileName], fileName+" does not exist.") + } +} + +var mpaaRatingEnumFile = ` +package enum + +import "github.com/go-jet/jet" + +var MpaaRating = &struct { + G jet.StringExpression + Pg jet.StringExpression + Pg13 jet.StringExpression + R jet.StringExpression + Nc17 jet.StringExpression +}{ + G: jet.NewEnumValue("G"), + Pg: jet.NewEnumValue("PG"), + Pg13: jet.NewEnumValue("PG-13"), + R: jet.NewEnumValue("R"), + Nc17: jet.NewEnumValue("NC-17"), +} +` + +var actorSQLBuilderFile = ` +package table + +import ( + "github.com/go-jet/jet" +) + +var Actor = newActorTable() + +type ActorTable struct { + jet.Table + + //Columns + ActorID jet.ColumnInteger + FirstName jet.ColumnString + LastName jet.ColumnString + LastUpdate jet.ColumnTimestamp + + AllColumns jet.ColumnList + MutableColumns jet.ColumnList +} + +// creates new ActorTable with assigned alias +func (a *ActorTable) AS(alias string) *ActorTable { + aliasTable := newActorTable() + + aliasTable.Table.AS(alias) + + return aliasTable +} + +func newActorTable() *ActorTable { + var ( + ActorIDColumn = jet.IntegerColumn("actor_id") + FirstNameColumn = jet.StringColumn("first_name") + LastNameColumn = jet.StringColumn("last_name") + LastUpdateColumn = jet.TimestampColumn("last_update") + ) + + return &ActorTable{ + Table: jet.NewTable("dvds", "actor", ActorIDColumn, FirstNameColumn, LastNameColumn, LastUpdateColumn), + + //Columns + ActorID: ActorIDColumn, + FirstName: FirstNameColumn, + LastName: LastNameColumn, + LastUpdate: LastUpdateColumn, + + AllColumns: jet.ColumnList{ActorIDColumn, FirstNameColumn, LastNameColumn, LastUpdateColumn}, + MutableColumns: jet.ColumnList{FirstNameColumn, LastNameColumn, LastUpdateColumn}, + } +} +` + +var actorModelFile = ` +package model + +import ( + "time" +) + +type Actor struct { + ActorID int32 ` + "`sql:\"primary_key\"`" + ` + FirstName string + LastName string + LastUpdate time.Time +} +` From d1a8b6e13280d5a2115673113aa488db6e41955a Mon Sep 17 00:00:00 2001 From: go-jet Date: Fri, 19 Jul 2019 14:33:54 +0200 Subject: [PATCH 2/7] Add code coverage support. --- .circleci/config.yml | 15 +++++++++------ clause.go | 5 ----- execution/execution.go | 10 ---------- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c040498..2357279 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,10 +34,7 @@ jobs: go get github.com/davecgh/go-spew/spew go get github.com/jstemmer/go-junit-report - - run: mkdir -p $TEST_RESULTS/unit-tests - - run: mkdir -p $TEST_RESULTS/integration-tests - - - run: go test -v 2>&1 | go-junit-report > $TEST_RESULTS/unit-tests/results.xml + go install github.com/go-jet/jet/cmd/jet - run: name: Waiting for Postgres to be ready @@ -51,13 +48,19 @@ jobs: echo Failed waiting for Postgres && exit 1 - run: - name: Run integration tests + name: Init Postgres database command: | cd tests go run ./init/init.go - go test -v 2>&1 | go-junit-report > $TEST_RESULTS/integration-tests/results.xml cd .. + - run: mkdir -p $TEST_RESULTS + - run: go test -v . ./tests -coverpkg=github.com/go-jet/jet,github.com/go-jet/jet/execution/...,github.com/go-jet/jet/generator/...,github.com/go-jet/jet/internal/... -coverprofile=cover.out 2>&1 | go-junit-report > $TEST_RESULTS/results.xml + + - run: + name: Upload code coverage + command: bash <(curl -s https://codecov.io/bash) + - store_artifacts: # Upload test summary for display in Artifacts: https://circleci.com/docs/2.0/artifacts/ path: /tmp/test-results destination: raw-test-output diff --git a/clause.go b/clause.go index 7603a76..43ce624 100644 --- a/clause.go +++ b/clause.go @@ -199,11 +199,6 @@ func (q *sqlBuilder) insertParametrizedArgument(arg interface{}) { q.writeString(argPlaceholder) } -func (q *sqlBuilder) reset() { - q.buff.Reset() - q.args = []interface{}{} -} - func argToString(value interface{}) string { if isNil(value) { return "NULL" diff --git a/execution/execution.go b/execution/execution.go index 18b5606..86075b2 100644 --- a/execution/execution.go +++ b/execution/execution.go @@ -743,16 +743,6 @@ func (s *scanContext) typeToColumnIndex(typeName, fieldName string) int { return index } -func (s *scanContext) getCellValue(typeName, fieldName string) interface{} { - index := s.typeToColumnIndex(typeName, fieldName) - - if index < 0 { - return nil - } - - return s.rowElem(index) -} - func (s *scanContext) rowElem(index int) interface{} { valuer, ok := s.row[index].(driver.Valuer) From c82c2d0b6b60c1ca9b1e060e8ec13ef8e75f95c4 Mon Sep 17 00:00:00 2001 From: go-jet Date: Fri, 19 Jul 2019 14:44:19 +0200 Subject: [PATCH 3/7] Add code coverage support. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d74d41d..3f033c5 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/go-jet/jet)](https://goreportcard.com/report/github.com/go-jet/jet) [![Documentation](https://godoc.org/github.com/go-jet/jet?status.svg)](http://godoc.org/github.com/go-jet/jet) +[![codecov](https://codecov.io/gh/go-jet/jet/branch/coverage/graph/badge.svg)](https://codecov.io/gh/go-jet/jet) [![CircleCI](https://circleci.com/gh/go-jet/jet/tree/develop.svg?style=svg&circle-token=97f255c6a4a3ab6590ea2e9195eb3ebf9f97b4a7)](https://circleci.com/gh/go-jet/jet/tree/develop) Jet is a framework for writing type-safe SQL queries for PostgreSQL in Go, with ability to easily From a2ee0155ac3449d023eb6b76dc10d2dd46f7d2a0 Mon Sep 17 00:00:00 2001 From: go-jet Date: Fri, 19 Jul 2019 16:19:20 +0200 Subject: [PATCH 4/7] Remove unused code. --- internal/3rdparty/snaker/snaker.go | 83 +------------------------ internal/3rdparty/snaker/snaker_test.go | 81 ------------------------ 2 files changed, 3 insertions(+), 161 deletions(-) diff --git a/internal/3rdparty/snaker/snaker.go b/internal/3rdparty/snaker/snaker.go index bb20fee..aadd928 100644 --- a/internal/3rdparty/snaker/snaker.go +++ b/internal/3rdparty/snaker/snaker.go @@ -8,42 +8,9 @@ import ( "unicode" ) -// CamelToSnake converts a given string to snake case -func CamelToSnake(s string) string { - var result string - var words []string - var lastPos int - rs := []rune(s) - - for i := 0; i < len(rs); i++ { - if i > 0 && unicode.IsUpper(rs[i]) { - if initialism := startsWithInitialism(s[lastPos:]); initialism != "" { - words = append(words, initialism) - - i += len(initialism) - 1 - lastPos = i - continue - } - - words = append(words, s[lastPos:i]) - lastPos = i - } - } - - // append the last word - if s[lastPos:] != "" { - words = append(words, s[lastPos:]) - } - - for k, word := range words { - if k > 0 { - result += "_" - } - - result += strings.ToLower(word) - } - - return result +// SnakeToCamel returns a string converted from snake case to uppercase +func SnakeToCamel(s string) string { + return snakeToCamel(s, true) } func snakeToCamel(s string, upperCase bool) string { @@ -54,28 +21,6 @@ func snakeToCamel(s string, upperCase bool) string { words := strings.Split(s, "_") - //// if there is no underscore, first try commons and then just return - //if len(words) == 1 { - // if exception := snakeToCamelExceptions[words[0]]; len(exception) > 0 { - // return exception - // } - // - // if upperCase { - // if upper := strings.ToUpper(words[0]); commonInitialisms[upper] { - // return upper - // } - // } - // - // w := []rune(s) - // if upperCase { - // w[0] = unicode.ToUpper(w[0]) - // } else { - // w[0] = unicode.ToLower(w[0]) - // } - // - // return string(w) - //} - for i, word := range words { if exception := snakeToCamelExceptions[word]; len(exception) > 0 { result += exception @@ -117,28 +62,6 @@ func camelizeWord(word string, force bool) string { return string(runes) } -// SnakeToCamel returns a string converted from snake case to uppercase -func SnakeToCamel(s string) string { - return snakeToCamel(s, true) -} - -// SnakeToCamelLower returns a string converted from snake case to lowercase -func SnakeToCamelLower(s string) string { - return snakeToCamel(s, false) -} - -// startsWithInitialism returns the initialism if the given string begins with it -func startsWithInitialism(s string) string { - var initialism string - // the longest initialism is 5 char, the shortest 2 - for i := 1; i <= 5; i++ { - if len(s) > i-1 && commonInitialisms[s[:i]] { - initialism = s[:i] - } - } - return initialism -} - // commonInitialisms, taken from // https://github.com/golang/lint/blob/206c0f020eba0f7fbcfbc467a5eb808037df2ed6/lint.go#L731 var commonInitialisms = map[string]bool{ diff --git a/internal/3rdparty/snaker/snaker_test.go b/internal/3rdparty/snaker/snaker_test.go index 545ec5c..f0a2843 100644 --- a/internal/3rdparty/snaker/snaker_test.go +++ b/internal/3rdparty/snaker/snaker_test.go @@ -6,56 +6,6 @@ import ( ) var _ = Describe("Snaker", func() { - Describe("CamelToSnake test", func() { - It("should return an empty string on an empty input", func() { - Expect(CamelToSnake("")).To(Equal("")) - }) - - It("should work with one word", func() { - Expect(CamelToSnake("One")).To(Equal("one")) - }) - - It("should return an uppercase string as separate words", func() { - Expect(CamelToSnake("ONE")).To(Equal("o_n_e")) - }) - - It("should return ID as lowercase", func() { - Expect(CamelToSnake("ID")).To(Equal("id")) - }) - - It("should work with a single lowercase character", func() { - Expect(CamelToSnake("i")).To(Equal("i")) - }) - - It("should work with a single uppcase character", func() { - Expect(CamelToSnake("I")).To(Equal("i")) - }) - - It("should return a long text as expected", func() { - Expect(CamelToSnake("ThisHasToBeConvertedCorrectlyID")).To( - Equal("this_has_to_be_converted_correctly_id")) - }) - - It("should return the text as expected if the initialism is in the middle", func() { - Expect(CamelToSnake("ThisIDIsFine")).To(Equal("this_id_is_fine")) - }) - - It("should work with long initialism", func() { - Expect(CamelToSnake("ThisHTTPSConnection")).To(Equal("this_https_connection")) - }) - - It("should work with multi initialisms", func() { - Expect(CamelToSnake("HelloHTTPSConnectionID")).To(Equal("hello_https_connection_id")) - }) - - It("should work with concat initialisms", func() { - Expect(CamelToSnake("HTTPSID")).To(Equal("https_id")) - }) - - It("should work with initialism where only certain characters are uppercase", func() { - Expect(CamelToSnake("OAuthClient")).To(Equal("oauth_client")) - }) - }) Describe("SnakeToCamel test", func() { It("should return an empty string on an empty input", func() { @@ -87,35 +37,4 @@ var _ = Describe("Snaker", func() { Expect(SnakeToCamel("oauth_client")).To(Equal("OAuthClient")) }) }) - - Describe("SnakeToCamelLower test", func() { - It("should return an empty string on an empty input", func() { - Ω(SnakeToCamelLower("")).To(Equal("")) - }) - - It("should not blow up on trailing _", func() { - Ω(SnakeToCamelLower("potato_")).To(Equal("potato")) - }) - - It("should return a snaked text as camel case", func() { - Ω(SnakeToCamelLower("this_has_to_be_uppercased")).To( - Equal("thisHasToBeUppercased")) - }) - - It("should return a snaked text as camel case, except the word ID", func() { - Ω(SnakeToCamelLower("this_is_an_id")).To(Equal("thisIsAnID")) - }) - - It("should return 'id' not as uppercase", func() { - Ω(SnakeToCamelLower("this_is_an_identifier")).To(Equal("thisIsAnIdentifier")) - }) - - It("should simply work with id", func() { - Ω(SnakeToCamelLower("id")).To(Equal("id")) - }) - - It("should simply work with leading id", func() { - Ω(SnakeToCamelLower("id_me_please")).To(Equal("idMePlease")) - }) - }) }) From e431f3ecb132dc7a6b8820ff5684071558e3508f Mon Sep 17 00:00:00 2001 From: go-jet Date: Fri, 19 Jul 2019 17:19:58 +0200 Subject: [PATCH 5/7] Additional unit tests. --- bool_expression_test.go | 10 +++++++ date_expression_test.go | 45 ++++++++++++++++++++++++++++++ float_expression_test.go | 10 +++++++ internal/utils/utils.go | 4 --- internal/utils/utils_test.go | 1 + string_expression_test.go | 10 +++++++ time_expression_test.go | 24 ++++++++++++---- timestamp_expression_test.go | 52 +++++++++++++++++++++++++++++++++++ timestampz_expression_test.go | 52 +++++++++++++++++++++++++++++++++++ timez_expression_test.go | 51 ++++++++++++++++++++++++++++++++++ utils_test.go | 22 +++++++++++++-- 11 files changed, 269 insertions(+), 12 deletions(-) create mode 100644 date_expression_test.go create mode 100644 timestamp_expression_test.go create mode 100644 timestampz_expression_test.go create mode 100644 timez_expression_test.go diff --git a/bool_expression_test.go b/bool_expression_test.go index dd05e94..70ab9f8 100644 --- a/bool_expression_test.go +++ b/bool_expression_test.go @@ -15,6 +15,16 @@ func TestBoolExpressionNOT_EQ(t *testing.T) { assertClauseSerialize(t, table1ColBool.NOT_EQ(Bool(true)), "(table1.col_bool != $1)", true) } +func TestBoolExpressionIS_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColBool.IS_DISTINCT_FROM(table2ColBool), "(table1.col_bool IS DISTINCT FROM table2.col_bool)") + assertClauseSerialize(t, table1ColBool.IS_DISTINCT_FROM(Bool(false)), "(table1.col_bool IS DISTINCT FROM $1)", false) +} + +func TestBoolExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColBool.IS_NOT_DISTINCT_FROM(table2ColBool), "(table1.col_bool IS NOT DISTINCT FROM table2.col_bool)") + assertClauseSerialize(t, table1ColBool.IS_NOT_DISTINCT_FROM(Bool(false)), "(table1.col_bool IS NOT DISTINCT FROM $1)", false) +} + func TestBoolExpressionIS_TRUE(t *testing.T) { assertClauseSerialize(t, table1ColBool.IS_TRUE(), "table1.col_bool IS TRUE") assertClauseSerialize(t, (Int(2).EQ(table1ColInt)).IS_TRUE(), diff --git a/date_expression_test.go b/date_expression_test.go new file mode 100644 index 0000000..2565c67 --- /dev/null +++ b/date_expression_test.go @@ -0,0 +1,45 @@ +package jet + +import "testing" + +var dateVar = Date(2000, 12, 30) + +func TestDateExpressionEQ(t *testing.T) { + assertClauseSerialize(t, table1ColDate.EQ(table2ColDate), "(table1.col_date = table2.col_date)") + assertClauseSerialize(t, table1ColDate.EQ(dateVar), "(table1.col_date = $1::date)", "2000-12-30") +} + +func TestDateExpressionNOT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColDate.NOT_EQ(table2ColDate), "(table1.col_date != table2.col_date)") + assertClauseSerialize(t, table1ColDate.NOT_EQ(dateVar), "(table1.col_date != $1::date)", "2000-12-30") +} + +func TestDateExpressionIS_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColDate.IS_DISTINCT_FROM(table2ColDate), "(table1.col_date IS DISTINCT FROM table2.col_date)") + assertClauseSerialize(t, table1ColDate.IS_DISTINCT_FROM(dateVar), "(table1.col_date IS DISTINCT FROM $1::date)", "2000-12-30") +} + +func TestDateExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColDate.IS_NOT_DISTINCT_FROM(table2ColDate), "(table1.col_date IS NOT DISTINCT FROM table2.col_date)") + assertClauseSerialize(t, table1ColDate.IS_NOT_DISTINCT_FROM(dateVar), "(table1.col_date IS NOT DISTINCT FROM $1::date)", "2000-12-30") +} + +func TestDateExpressionGT(t *testing.T) { + assertClauseSerialize(t, table1ColDate.GT(table2ColDate), "(table1.col_date > table2.col_date)") + assertClauseSerialize(t, table1ColDate.GT(dateVar), "(table1.col_date > $1::date)", "2000-12-30") +} + +func TestDateExpressionGT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColDate.GT_EQ(table2ColDate), "(table1.col_date >= table2.col_date)") + assertClauseSerialize(t, table1ColDate.GT_EQ(dateVar), "(table1.col_date >= $1::date)", "2000-12-30") +} + +func TestDateExpressionLT(t *testing.T) { + assertClauseSerialize(t, table1ColDate.LT(table2ColDate), "(table1.col_date < table2.col_date)") + assertClauseSerialize(t, table1ColDate.LT(dateVar), "(table1.col_date < $1::date)", "2000-12-30") +} + +func TestDateExpressionLT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColDate.LT_EQ(table2ColDate), "(table1.col_date <= table2.col_date)") + assertClauseSerialize(t, table1ColDate.LT_EQ(dateVar), "(table1.col_date <= $1::date)", "2000-12-30") +} diff --git a/float_expression_test.go b/float_expression_test.go index 1b83868..e9103e9 100644 --- a/float_expression_test.go +++ b/float_expression_test.go @@ -14,6 +14,16 @@ func TestFloatExpressionNOT_EQ(t *testing.T) { assertClauseSerialize(t, table1ColFloat.NOT_EQ(Float(2.11)), "(table1.col_float != $1)", float64(2.11)) } +func TestFloatExpressionIS_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColFloat.IS_DISTINCT_FROM(table2ColFloat), "(table1.col_float IS DISTINCT FROM table2.col_float)") + assertClauseSerialize(t, table1ColFloat.IS_DISTINCT_FROM(Float(2.11)), "(table1.col_float IS DISTINCT FROM $1)", float64(2.11)) +} + +func TestFloatExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColFloat.IS_NOT_DISTINCT_FROM(table2ColFloat), "(table1.col_float IS NOT DISTINCT FROM table2.col_float)") + assertClauseSerialize(t, table1ColFloat.IS_NOT_DISTINCT_FROM(Float(2.11)), "(table1.col_float IS NOT DISTINCT FROM $1)", float64(2.11)) +} + func TestFloatExpressionGT(t *testing.T) { assertClauseSerialize(t, table1ColFloat.GT(table2ColFloat), "(table1.col_float > table2.col_float)") assertClauseSerialize(t, table1ColFloat.GT(Float(2.11)), "(table1.col_float > $1)", float64(2.11)) diff --git a/internal/utils/utils.go b/internal/utils/utils.go index eb2e1b7..85aeec2 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -14,10 +14,6 @@ import ( // ToGoIdentifier converts database to Go identifier. func ToGoIdentifier(databaseIdentifier string) string { - if len(databaseIdentifier) == 0 { - return databaseIdentifier - } - return snaker.SnakeToCamel(replaceInvalidChars(databaseIdentifier)) } diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index 7a3a370..7e96925 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -6,6 +6,7 @@ import ( ) func TestToGoIdentifier(t *testing.T) { + assert.Equal(t, ToGoIdentifier(""), "") assert.Equal(t, ToGoIdentifier("uuid"), "UUID") assert.Equal(t, ToGoIdentifier("col1"), "Col1") assert.Equal(t, ToGoIdentifier("PG-13"), "Pg13") diff --git a/string_expression_test.go b/string_expression_test.go index 8dd7b18..a1209ce 100644 --- a/string_expression_test.go +++ b/string_expression_test.go @@ -17,6 +17,16 @@ func TestStringNOT_EQ(t *testing.T) { assertClauseSerialize(t, table3StrCol.NOT_EQ(String("JOHN")), "(table3.col2 != $1)", "JOHN") } +func TestStringExpressionIS_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table3StrCol.IS_DISTINCT_FROM(table2ColStr), "(table3.col2 IS DISTINCT FROM table2.col_str)") + assertClauseSerialize(t, table3StrCol.IS_DISTINCT_FROM(String("JOHN")), "(table3.col2 IS DISTINCT FROM $1)", "JOHN") +} + +func TestStringExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table3StrCol.IS_NOT_DISTINCT_FROM(table2ColStr), "(table3.col2 IS NOT DISTINCT FROM table2.col_str)") + assertClauseSerialize(t, table3StrCol.IS_NOT_DISTINCT_FROM(String("JOHN")), "(table3.col2 IS NOT DISTINCT FROM $1)", "JOHN") +} + func TestStringGT(t *testing.T) { exp := table3StrCol.GT(table2ColStr) assertClauseSerialize(t, exp, "(table3.col2 > table2.col_str)") diff --git a/time_expression_test.go b/time_expression_test.go index 1a328a5..44d54ad 100644 --- a/time_expression_test.go +++ b/time_expression_test.go @@ -4,34 +4,46 @@ import ( "testing" ) +var timeVar = Time(10, 20, 0, 0) + func TestTimeExpressionEQ(t *testing.T) { assertClauseSerialize(t, table1ColTime.EQ(table2ColTime), "(table1.col_time = table2.col_time)") - assertClauseSerialize(t, table1ColTime.EQ(Time(10, 20, 0, 0)), "(table1.col_time = $1::time without time zone)", "10:20:00.000") + assertClauseSerialize(t, table1ColTime.EQ(timeVar), "(table1.col_time = $1::time without time zone)", "10:20:00.000") } func TestTimeExpressionNOT_EQ(t *testing.T) { assertClauseSerialize(t, table1ColTime.NOT_EQ(table2ColTime), "(table1.col_time != table2.col_time)") - assertClauseSerialize(t, table1ColTime.NOT_EQ(Time(10, 20, 0, 0)), "(table1.col_time != $1::time without time zone)", "10:20:00.000") + assertClauseSerialize(t, table1ColTime.NOT_EQ(timeVar), "(table1.col_time != $1::time without time zone)", "10:20:00.000") +} + +func TestTimeExpressionIS_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColTime.IS_DISTINCT_FROM(table2ColTime), "(table1.col_time IS DISTINCT FROM table2.col_time)") + assertClauseSerialize(t, table1ColTime.IS_DISTINCT_FROM(timeVar), "(table1.col_time IS DISTINCT FROM $1::time without time zone)", "10:20:00.000") +} + +func TestTimeExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColTime.IS_NOT_DISTINCT_FROM(table2ColTime), "(table1.col_time IS NOT DISTINCT FROM table2.col_time)") + assertClauseSerialize(t, table1ColTime.IS_NOT_DISTINCT_FROM(timeVar), "(table1.col_time IS NOT DISTINCT FROM $1::time without time zone)", "10:20:00.000") } func TestTimeExpressionLT(t *testing.T) { assertClauseSerialize(t, table1ColTime.LT(table2ColTime), "(table1.col_time < table2.col_time)") - assertClauseSerialize(t, table1ColTime.LT(Time(10, 20, 0, 0)), "(table1.col_time < $1::time without time zone)", "10:20:00.000") + assertClauseSerialize(t, table1ColTime.LT(timeVar), "(table1.col_time < $1::time without time zone)", "10:20:00.000") } func TestTimeExpressionLT_EQ(t *testing.T) { assertClauseSerialize(t, table1ColTime.LT_EQ(table2ColTime), "(table1.col_time <= table2.col_time)") - assertClauseSerialize(t, table1ColTime.LT_EQ(Time(10, 20, 0, 0)), "(table1.col_time <= $1::time without time zone)", "10:20:00.000") + assertClauseSerialize(t, table1ColTime.LT_EQ(timeVar), "(table1.col_time <= $1::time without time zone)", "10:20:00.000") } func TestTimeExpressionGT(t *testing.T) { assertClauseSerialize(t, table1ColTime.GT(table2ColTime), "(table1.col_time > table2.col_time)") - assertClauseSerialize(t, table1ColTime.GT(Time(10, 20, 0, 0)), "(table1.col_time > $1::time without time zone)", "10:20:00.000") + assertClauseSerialize(t, table1ColTime.GT(timeVar), "(table1.col_time > $1::time without time zone)", "10:20:00.000") } func TestTimeExpressionGT_EQ(t *testing.T) { assertClauseSerialize(t, table1ColTime.GT_EQ(table2ColTime), "(table1.col_time >= table2.col_time)") - assertClauseSerialize(t, table1ColTime.GT_EQ(Time(10, 20, 0, 0)), "(table1.col_time >= $1::time without time zone)", "10:20:00.000") + assertClauseSerialize(t, table1ColTime.GT_EQ(timeVar), "(table1.col_time >= $1::time without time zone)", "10:20:00.000") } func TestTimeExp(t *testing.T) { diff --git a/timestamp_expression_test.go b/timestamp_expression_test.go new file mode 100644 index 0000000..1c44091 --- /dev/null +++ b/timestamp_expression_test.go @@ -0,0 +1,52 @@ +package jet + +import "testing" + +var timestamp = Timestamp(2000, 1, 31, 10, 20, 0, 0) + +func TestTimestampExpressionEQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimestamp.EQ(table2ColTimestamp), "(table1.col_timestamp = table2.col_timestamp)") + assertClauseSerialize(t, table1ColTimestamp.EQ(timestamp), + "(table1.col_timestamp = $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} + +func TestTimestampExpressionNOT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimestamp.NOT_EQ(table2ColTimestamp), "(table1.col_timestamp != table2.col_timestamp)") + assertClauseSerialize(t, table1ColTimestamp.NOT_EQ(timestamp), "(table1.col_timestamp != $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} + +func TestTimestampExpressionIS_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColTimestamp.IS_DISTINCT_FROM(table2ColTimestamp), "(table1.col_timestamp IS DISTINCT FROM table2.col_timestamp)") + assertClauseSerialize(t, table1ColTimestamp.IS_DISTINCT_FROM(timestamp), "(table1.col_timestamp IS DISTINCT FROM $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} + +func TestTimestampExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColTimestamp.IS_NOT_DISTINCT_FROM(table2ColTimestamp), "(table1.col_timestamp IS NOT DISTINCT FROM table2.col_timestamp)") + assertClauseSerialize(t, table1ColTimestamp.IS_NOT_DISTINCT_FROM(timestamp), "(table1.col_timestamp IS NOT DISTINCT FROM $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} + +func TestTimestampExpressionLT(t *testing.T) { + assertClauseSerialize(t, table1ColTimestamp.LT(table2ColTimestamp), "(table1.col_timestamp < table2.col_timestamp)") + assertClauseSerialize(t, table1ColTimestamp.LT(timestamp), "(table1.col_timestamp < $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} + +func TestTimestampExpressionLT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimestamp.LT_EQ(table2ColTimestamp), "(table1.col_timestamp <= table2.col_timestamp)") + assertClauseSerialize(t, table1ColTimestamp.LT_EQ(timestamp), "(table1.col_timestamp <= $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} + +func TestTimestampExpressionGT(t *testing.T) { + assertClauseSerialize(t, table1ColTimestamp.GT(table2ColTimestamp), "(table1.col_timestamp > table2.col_timestamp)") + assertClauseSerialize(t, table1ColTimestamp.GT(timestamp), "(table1.col_timestamp > $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} + +func TestTimestampExpressionGT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimestamp.GT_EQ(table2ColTimestamp), "(table1.col_timestamp >= table2.col_timestamp)") + assertClauseSerialize(t, table1ColTimestamp.GT_EQ(timestamp), "(table1.col_timestamp >= $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} + +func TestTimestampExp(t *testing.T) { + assertClauseSerialize(t, TimestampExp(table1ColFloat), "table1.col_float") + assertClauseSerialize(t, TimestampExp(table1ColFloat).LT(timestamp), + "(table1.col_float < $1::timestamp without time zone)", "2000-01-31 10:20:00.000") +} diff --git a/timestampz_expression_test.go b/timestampz_expression_test.go new file mode 100644 index 0000000..3451b3f --- /dev/null +++ b/timestampz_expression_test.go @@ -0,0 +1,52 @@ +package jet + +import "testing" + +var timestampz = Timestampz(2000, 1, 31, 10, 20, 0, 0, 2) + +func TestTimestampzExpressionEQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimestampz.EQ(table2ColTimestampz), "(table1.col_timestampz = table2.col_timestampz)") + assertClauseSerialize(t, table1ColTimestampz.EQ(timestampz), + "(table1.col_timestampz = $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} + +func TestTimestampzExpressionNOT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimestampz.NOT_EQ(table2ColTimestampz), "(table1.col_timestampz != table2.col_timestampz)") + assertClauseSerialize(t, table1ColTimestampz.NOT_EQ(timestampz), "(table1.col_timestampz != $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} + +func TestTimestampzExpressionIS_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColTimestampz.IS_DISTINCT_FROM(table2ColTimestampz), "(table1.col_timestampz IS DISTINCT FROM table2.col_timestampz)") + assertClauseSerialize(t, table1ColTimestampz.IS_DISTINCT_FROM(timestampz), "(table1.col_timestampz IS DISTINCT FROM $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} + +func TestTimestampzExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColTimestampz.IS_NOT_DISTINCT_FROM(table2ColTimestampz), "(table1.col_timestampz IS NOT DISTINCT FROM table2.col_timestampz)") + assertClauseSerialize(t, table1ColTimestampz.IS_NOT_DISTINCT_FROM(timestampz), "(table1.col_timestampz IS NOT DISTINCT FROM $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} + +func TestTimestampzExpressionLT(t *testing.T) { + assertClauseSerialize(t, table1ColTimestampz.LT(table2ColTimestampz), "(table1.col_timestampz < table2.col_timestampz)") + assertClauseSerialize(t, table1ColTimestampz.LT(timestampz), "(table1.col_timestampz < $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} + +func TestTimestampzExpressionLT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimestampz.LT_EQ(table2ColTimestampz), "(table1.col_timestampz <= table2.col_timestampz)") + assertClauseSerialize(t, table1ColTimestampz.LT_EQ(timestampz), "(table1.col_timestampz <= $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} + +func TestTimestampzExpressionGT(t *testing.T) { + assertClauseSerialize(t, table1ColTimestampz.GT(table2ColTimestampz), "(table1.col_timestampz > table2.col_timestampz)") + assertClauseSerialize(t, table1ColTimestampz.GT(timestampz), "(table1.col_timestampz > $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} + +func TestTimestampzExpressionGT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimestampz.GT_EQ(table2ColTimestampz), "(table1.col_timestampz >= table2.col_timestampz)") + assertClauseSerialize(t, table1ColTimestampz.GT_EQ(timestampz), "(table1.col_timestampz >= $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} + +func TestTimestampzExp(t *testing.T) { + assertClauseSerialize(t, TimestampzExp(table1ColFloat), "table1.col_float") + assertClauseSerialize(t, TimestampzExp(table1ColFloat).LT(timestampz), + "(table1.col_float < $1::timestamp with time zone)", "2000-01-31 10:20:00.000 +002") +} diff --git a/timez_expression_test.go b/timez_expression_test.go new file mode 100644 index 0000000..1d2c641 --- /dev/null +++ b/timez_expression_test.go @@ -0,0 +1,51 @@ +package jet + +import "testing" + +var timezVar = Timez(10, 20, 0, 0, 4) + +func TestTimezExpressionEQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimez.EQ(table2ColTimez), "(table1.col_timez = table2.col_timez)") + assertClauseSerialize(t, table1ColTimez.EQ(timezVar), "(table1.col_timez = $1::time with time zone)", "10:20:00.000 +04") +} + +func TestTimezExpressionNOT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimez.NOT_EQ(table2ColTimez), "(table1.col_timez != table2.col_timez)") + assertClauseSerialize(t, table1ColTimez.NOT_EQ(timezVar), "(table1.col_timez != $1::time with time zone)", "10:20:00.000 +04") +} + +func TestTimezExpressionIS_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColTimez.IS_DISTINCT_FROM(table2ColTimez), "(table1.col_timez IS DISTINCT FROM table2.col_timez)") + assertClauseSerialize(t, table1ColTimez.IS_DISTINCT_FROM(timezVar), "(table1.col_timez IS DISTINCT FROM $1::time with time zone)", "10:20:00.000 +04") +} + +func TestTimezExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { + assertClauseSerialize(t, table1ColTimez.IS_NOT_DISTINCT_FROM(table2ColTimez), "(table1.col_timez IS NOT DISTINCT FROM table2.col_timez)") + assertClauseSerialize(t, table1ColTimez.IS_NOT_DISTINCT_FROM(timezVar), "(table1.col_timez IS NOT DISTINCT FROM $1::time with time zone)", "10:20:00.000 +04") +} + +func TestTimezExpressionLT(t *testing.T) { + assertClauseSerialize(t, table1ColTimez.LT(table2ColTimez), "(table1.col_timez < table2.col_timez)") + assertClauseSerialize(t, table1ColTimez.LT(timezVar), "(table1.col_timez < $1::time with time zone)", "10:20:00.000 +04") +} + +func TestTimezExpressionLT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimez.LT_EQ(table2ColTimez), "(table1.col_timez <= table2.col_timez)") + assertClauseSerialize(t, table1ColTimez.LT_EQ(timezVar), "(table1.col_timez <= $1::time with time zone)", "10:20:00.000 +04") +} + +func TestTimezExpressionGT(t *testing.T) { + assertClauseSerialize(t, table1ColTimez.GT(table2ColTimez), "(table1.col_timez > table2.col_timez)") + assertClauseSerialize(t, table1ColTimez.GT(timezVar), "(table1.col_timez > $1::time with time zone)", "10:20:00.000 +04") +} + +func TestTimezExpressionGT_EQ(t *testing.T) { + assertClauseSerialize(t, table1ColTimez.GT_EQ(table2ColTimez), "(table1.col_timez >= table2.col_timez)") + assertClauseSerialize(t, table1ColTimez.GT_EQ(timezVar), "(table1.col_timez >= $1::time with time zone)", "10:20:00.000 +04") +} + +func TestTimezExp(t *testing.T) { + assertClauseSerialize(t, TimezExp(table1ColFloat), "table1.col_float") + assertClauseSerialize(t, TimezExp(table1ColFloat).LT(Timez(1, 1, 1, 1, 4)), + "(table1.col_float < $1::time with time zone)", string("01:01:01.001 +04")) +} diff --git a/utils_test.go b/utils_test.go index 8429349..2f0ea75 100644 --- a/utils_test.go +++ b/utils_test.go @@ -10,7 +10,11 @@ var table1ColInt = IntegerColumn("col_int") var table1ColFloat = FloatColumn("col_float") var table1Col3 = IntegerColumn("col3") var table1ColTime = TimeColumn("col_time") +var table1ColTimez = TimezColumn("col_timez") +var table1ColTimestamp = TimestampColumn("col_timestamp") +var table1ColTimestampz = TimestampzColumn("col_timestampz") var table1ColBool = BoolColumn("col_bool") +var table1ColDate = DateColumn("col_date") var table1 = NewTable( "db", @@ -20,7 +24,12 @@ var table1 = NewTable( table1ColFloat, table1Col3, table1ColTime, - table1ColBool) + table1ColTimez, + table1ColBool, + table1ColDate, + table1ColTimestamp, + table1ColTimestampz, +) var table2Col3 = IntegerColumn("col3") var table2Col4 = IntegerColumn("col4") @@ -29,6 +38,10 @@ var table2ColFloat = FloatColumn("col_float") var table2ColStr = StringColumn("col_str") var table2ColBool = BoolColumn("col_bool") var table2ColTime = TimeColumn("col_time") +var table2ColTimez = TimezColumn("col_timez") +var table2ColTimestamp = TimestampColumn("col_timestamp") +var table2ColTimestampz = TimestampzColumn("col_timestampz") +var table2ColDate = DateColumn("col_date") var table2 = NewTable( "db", @@ -39,7 +52,12 @@ var table2 = NewTable( table2ColFloat, table2ColStr, table2ColBool, - table2ColTime) + table2ColTime, + table2ColTimez, + table2ColDate, + table2ColTimestamp, + table2ColTimestampz, +) var table3Col1 = IntegerColumn("col1") var table3ColInt = IntegerColumn("col_int") From e74e090b0af8d68fb76748cf913b8dd38c4ab246 Mon Sep 17 00:00:00 2001 From: go-jet Date: Sat, 20 Jul 2019 11:22:01 +0200 Subject: [PATCH 6/7] Additional unit tests. --- clause.go | 2 +- clause_test.go | 33 +++++++++++++++ select_statement_test.go | 88 ++++++++++++++++++++++++++++++++++++++++ tests/insert_test.go | 22 ++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 clause_test.go diff --git a/clause.go b/clause.go index 43ce624..8714992 100644 --- a/clause.go +++ b/clause.go @@ -246,7 +246,7 @@ func argToString(value interface{}) string { case time.Time: return stringQuote(string(utils.FormatTimestamp(bindVal))) default: - return "[Unknown type]" + return "[Unsupported type]" } } diff --git a/clause_test.go b/clause_test.go new file mode 100644 index 0000000..a105cb3 --- /dev/null +++ b/clause_test.go @@ -0,0 +1,33 @@ +package jet + +import ( + "github.com/google/uuid" + "gotest.tools/assert" + "testing" + "time" +) + +func TestArgToString(t *testing.T) { + assert.Equal(t, argToString(true), "TRUE") + assert.Equal(t, argToString(false), "FALSE") + + assert.Equal(t, argToString(int8(-8)), "-8") + assert.Equal(t, argToString(int16(-16)), "-16") + assert.Equal(t, argToString(int(-32)), "-32") + assert.Equal(t, argToString(int32(-32)), "-32") + assert.Equal(t, argToString(int64(-64)), "-64") + assert.Equal(t, argToString(uint8(8)), "8") + assert.Equal(t, argToString(uint16(16)), "16") + assert.Equal(t, argToString(uint(32)), "32") + assert.Equal(t, argToString(uint32(32)), "32") + assert.Equal(t, argToString(uint64(64)), "64") + + assert.Equal(t, argToString("john"), "'john'") + assert.Equal(t, argToString([]byte("john")), "'john'") + assert.Equal(t, argToString(uuid.MustParse("b68dbff4-a87d-11e9-a7f2-98ded00c39c6")), "'b68dbff4-a87d-11e9-a7f2-98ded00c39c6'") + + time, err := time.Parse("Mon Jan 2 15:04:05 -0700 MST 2006", "Mon Jan 2 15:04:05 -0700 MST 2006") + assert.NilError(t, err) + assert.Equal(t, argToString(time), "'2006-01-02 15:04:05-07:00'") + assert.Equal(t, argToString(map[string]bool{}), "[Unsupported type]") +} diff --git a/select_statement_test.go b/select_statement_test.go index 50cfc00..7c432ef 100644 --- a/select_statement_test.go +++ b/select_statement_test.go @@ -122,3 +122,91 @@ FROM db.table1 FOR NO KEY UPDATE SKIP LOCKED; `) } + +func TestSelectSets(t *testing.T) { + select1 := SELECT(table1ColBool).FROM(table1) + select2 := SELECT(table2ColBool).FROM(table2) + + assertStatement(t, select1.UNION(select2), ` +( + ( + SELECT table1.col_bool AS "table1.col_bool" + FROM db.table1 + ) + UNION + ( + SELECT table2.col_bool AS "table2.col_bool" + FROM db.table2 + ) +); +`) + assertStatement(t, select1.UNION_ALL(select2), ` +( + ( + SELECT table1.col_bool AS "table1.col_bool" + FROM db.table1 + ) + UNION ALL + ( + SELECT table2.col_bool AS "table2.col_bool" + FROM db.table2 + ) +); +`) + + assertStatement(t, select1.INTERSECT(select2), ` +( + ( + SELECT table1.col_bool AS "table1.col_bool" + FROM db.table1 + ) + INTERSECT + ( + SELECT table2.col_bool AS "table2.col_bool" + FROM db.table2 + ) +); +`) + + assertStatement(t, select1.INTERSECT_ALL(select2), ` +( + ( + SELECT table1.col_bool AS "table1.col_bool" + FROM db.table1 + ) + INTERSECT ALL + ( + SELECT table2.col_bool AS "table2.col_bool" + FROM db.table2 + ) +); +`) + assertStatement(t, select1.EXCEPT(select2), ` +( + ( + SELECT table1.col_bool AS "table1.col_bool" + FROM db.table1 + ) + EXCEPT + ( + SELECT table2.col_bool AS "table2.col_bool" + FROM db.table2 + ) +); +`) + + assertStatement(t, select1.EXCEPT_ALL(select2), ` +( + ( + SELECT table1.col_bool AS "table1.col_bool" + FROM db.table1 + ) + EXCEPT ALL + ( + SELECT table2.col_bool AS "table2.col_bool" + FROM db.table2 + ) +); +`) + +} diff --git a/tests/insert_test.go b/tests/insert_test.go index b5783c8..8c6f17d 100644 --- a/tests/insert_test.go +++ b/tests/insert_test.go @@ -109,6 +109,28 @@ INSERT INTO test_sample.link (url, name) VALUES assertExec(t, query, 1) } +func TestInsertModelObjectEmptyColumnList(t *testing.T) { + cleanUpLinkTable(t) + var expectedSQL = ` +INSERT INTO test_sample.link VALUES + (1000, 'http://www.duckduckgo.com', 'Duck Duck go', NULL); +` + + linkData := model.Link{ + ID: 1000, + URL: "http://www.duckduckgo.com", + Name: "Duck Duck go", + } + + query := Link. + INSERT(). + MODEL(linkData) + + assertStatementSql(t, query, expectedSQL, int32(1000), "http://www.duckduckgo.com", "Duck Duck go", nil) + + assertExec(t, query, 1) +} + func TestInsertModelsObject(t *testing.T) { expectedSQL := ` INSERT INTO test_sample.link (url, name) VALUES From cecee43ffea8a7f81ba58e62cefe0f654a07e53f Mon Sep 17 00:00:00 2001 From: go-jet Date: Sat, 20 Jul 2019 11:33:14 +0200 Subject: [PATCH 7/7] Update readme. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3f033c5..8aa78d9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/go-jet/jet)](https://goreportcard.com/report/github.com/go-jet/jet) [![Documentation](https://godoc.org/github.com/go-jet/jet?status.svg)](http://godoc.org/github.com/go-jet/jet) -[![codecov](https://codecov.io/gh/go-jet/jet/branch/coverage/graph/badge.svg)](https://codecov.io/gh/go-jet/jet) +[![codecov](https://codecov.io/gh/go-jet/jet/branch/develop/graph/badge.svg)](https://codecov.io/gh/go-jet/jet) [![CircleCI](https://circleci.com/gh/go-jet/jet/tree/develop.svg?style=svg&circle-token=97f255c6a4a3ab6590ea2e9195eb3ebf9f97b4a7)](https://circleci.com/gh/go-jet/jet/tree/develop) Jet is a framework for writing type-safe SQL queries for PostgreSQL in Go, with ability to easily @@ -261,10 +261,11 @@ Let's say this is our desired structure: ```go var dest []struct { model.Actor + Films []struct { model.Film - Language model.Language - Categories []model.Category + Language model.Language + Categories []model.Category } } ```