diff --git a/func_expression.go b/func_expression.go index 84c55b0..91fa61a 100644 --- a/func_expression.go +++ b/func_expression.go @@ -168,7 +168,7 @@ func UPPER(stringExpression StringExpression) StringExpression { // in characters (a space by default) from the start and end of string func BTRIM(stringExpression StringExpression, trimChars ...StringExpression) StringExpression { if len(trimChars) > 0 { - return newStringFunc("LTRIM", stringExpression, trimChars[0]) + return newStringFunc("BTRIM", stringExpression, trimChars[0]) } return newStringFunc("BTRIM", stringExpression) } diff --git a/func_expression_test.go b/func_expression_test.go index 9b7f5b1..fa4a0a5 100644 --- a/func_expression_test.go +++ b/func_expression_test.go @@ -155,3 +155,8 @@ func TestFuncLEAST(t *testing.T) { assertClauseSerialize(t, LEAST(table1ColFloat), "LEAST(table1.col_float)") assertClauseSerialize(t, LEAST(Float(11.2222), NULL, String("str")), "LEAST($1, NULL, $2)", float64(11.2222), "str") } + +func TestTO_ASCII(t *testing.T) { + assertClauseSerialize(t, TO_ASCII(String("Karel")), `TO_ASCII($1)`, "Karel") + assertClauseSerialize(t, TO_ASCII(String("Karel")), `TO_ASCII($1)`, "Karel") +} diff --git a/tests/all_types_test.go b/tests/all_types_test.go index 23111fc..b6d9dad 100644 --- a/tests/all_types_test.go +++ b/tests/all_types_test.go @@ -127,7 +127,10 @@ func TestStringOperators(t *testing.T) { LOWER(AllTypes.CharacterVaryingPtr), UPPER(AllTypes.Character), BTRIM(AllTypes.CharacterVarying), + BTRIM(AllTypes.CharacterVarying, String("AA")), + LTRIM(AllTypes.CharacterVarying), LTRIM(AllTypes.CharacterVarying, String("A")), + RTRIM(AllTypes.CharacterVarying), RTRIM(AllTypes.CharacterVarying, String("B")), CHR(Int(65)), //CONCAT(String("string1"), Int(1), Float(11.12)), @@ -143,13 +146,16 @@ func TestStringOperators(t *testing.T) { RIGHT(String("abcde"), Int(2)), LENGTH(String("jose")), LENGTH(String("jose"), String("UTF8")), + LPAD(String("Hi"), Int(5)), LPAD(String("Hi"), Int(5), String("xy")), + RPAD(String("Hi"), Int(5)), RPAD(String("Hi"), Int(5), String("xy")), MD5(AllTypes.CharacterVarying), REPEAT(AllTypes.Text, Int(33)), REPLACE(AllTypes.Character, String("BA"), String("AB")), REVERSE(AllTypes.CharacterVarying), STRPOS(AllTypes.Text, String("A")), + SUBSTR(AllTypes.CharacterPtr, Int(3)), SUBSTR(AllTypes.CharacterPtr, Int(3), Int(2)), TO_HEX(AllTypes.IntegerPtr), ) diff --git a/tests/chinook_db_test.go b/tests/chinook_db_test.go index 525bbac..550db0b 100644 --- a/tests/chinook_db_test.go +++ b/tests/chinook_db_test.go @@ -246,23 +246,21 @@ ORDER BY "Album.AlbumId"; assert.DeepEqual(t, dest[1], album2) } -//func TestQueryWithContext(t *testing.T) { -// -// ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) -// defer cancel() -// -// dest := []model.Album{} -// -// err := Album. -// CROSS_JOIN(Track). -// CROSS_JOIN(InvoiceLine). -// SELECT(Album.AllColumns, Track.AllColumns, InvoiceLine.AllColumns). -// QueryContext(db, ctx, &dest) -// -// spew.Dump(dest) -// -// assert.Error(t, err, "context deadline exceeded") -//} +func TestQueryWithContext(t *testing.T) { + + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + + dest := []model.Album{} + + err := Album. + CROSS_JOIN(Track). + CROSS_JOIN(InvoiceLine). + SELECT(Album.AllColumns, Track.AllColumns, InvoiceLine.AllColumns). + QueryContext(ctx, db, &dest) + + assert.Error(t, err, "context deadline exceeded") +} func TestExecWithContext(t *testing.T) { diff --git a/tests/delete_test.go b/tests/delete_test.go index 6f87161..732a3dd 100644 --- a/tests/delete_test.go +++ b/tests/delete_test.go @@ -1,11 +1,13 @@ package tests import ( + "context" . "github.com/go-jet/jet" "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model" . "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table" "gotest.tools/assert" "testing" + "time" ) func TestDeleteWithWhere(t *testing.T) { @@ -60,3 +62,38 @@ func initForDeleteTest(t *testing.T) { assertExec(t, stmt, 2) } + +func TestDeleteQueryContext(t *testing.T) { + initForDeleteTest(t) + + deleteStmt := Link. + DELETE(). + WHERE(Link.Name.IN(String("Gmail"), String("Outlook"))) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond) + defer cancel() + + time.Sleep(10 * time.Millisecond) + + dest := []model.Link{} + err := deleteStmt.QueryContext(ctx, db, &dest) + + assert.Error(t, err, "context deadline exceeded") +} + +func TestDeleteExecContext(t *testing.T) { + initForDeleteTest(t) + + deleteStmt := Link. + DELETE(). + WHERE(Link.Name.IN(String("Gmail"), String("Outlook"))) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond) + defer cancel() + + time.Sleep(10 * time.Millisecond) + + _, err := deleteStmt.ExecContext(ctx, db) + + assert.Error(t, err, "context deadline exceeded") +} diff --git a/tests/insert_test.go b/tests/insert_test.go index 8c6f17d..81f3a13 100644 --- a/tests/insert_test.go +++ b/tests/insert_test.go @@ -1,11 +1,13 @@ package tests import ( + "context" . "github.com/go-jet/jet" "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model" . "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table" "gotest.tools/assert" "testing" + "time" ) func TestInsertValues(t *testing.T) { @@ -245,3 +247,37 @@ RETURNING link.id AS "link.id", assert.NilError(t, err) assert.Equal(t, len(youtubeLinks), 2) } + +func TestInsertWithQueryContext(t *testing.T) { + cleanUpLinkTable(t) + + stmt := Link.INSERT(). + VALUES(1100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT). + RETURNING(Link.AllColumns) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond) + defer cancel() + + time.Sleep(10 * time.Millisecond) + + dest := []model.Link{} + err := stmt.QueryContext(ctx, db, &dest) + + assert.Error(t, err, "context deadline exceeded") +} + +func TestInsertWithExecContext(t *testing.T) { + cleanUpLinkTable(t) + + stmt := Link.INSERT(). + VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond) + defer cancel() + + time.Sleep(10 * time.Millisecond) + + _, err := stmt.ExecContext(ctx, db) + + assert.Error(t, err, "context deadline exceeded") +} diff --git a/tests/lock_test.go b/tests/lock_test.go new file mode 100644 index 0000000..fdc4dc4 --- /dev/null +++ b/tests/lock_test.go @@ -0,0 +1,73 @@ +package tests + +import ( + "context" + "gotest.tools/assert" + "testing" + "time" + + . "github.com/go-jet/jet" + . "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/table" +) + +func TestLockTable(t *testing.T) { + expectedSQL := ` +LOCK TABLE dvds.address IN` + + var testData = []TableLockMode{ + LOCK_ACCESS_SHARE, + LOCK_ROW_SHARE, + LOCK_ROW_EXCLUSIVE, + LOCK_SHARE_UPDATE_EXCLUSIVE, + LOCK_SHARE, + LOCK_SHARE_ROW_EXCLUSIVE, + LOCK_EXCLUSIVE, + LOCK_ACCESS_EXCLUSIVE, + } + + for _, lockMode := range testData { + query := Address.LOCK().IN(lockMode) + + assertStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE;\n") + + tx, _ := db.Begin() + + _, err := query.Exec(tx) + + assert.NilError(t, err) + + err = tx.Rollback() + + assert.NilError(t, err) + } + + for _, lockMode := range testData { + query := Address.LOCK().IN(lockMode).NOWAIT() + + assertStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE NOWAIT;\n") + + tx, _ := db.Begin() + + _, err := query.Exec(tx) + + assert.NilError(t, err) + + err = tx.Rollback() + + assert.NilError(t, err) + } +} + +func TestLockExecContext(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond) + defer cancel() + + time.Sleep(10 * time.Millisecond) + + tx, _ := db.Begin() + defer tx.Rollback() + + _, err := Address.LOCK().IN(LOCK_ACCESS_SHARE).ExecContext(ctx, tx) + + assert.Error(t, err, "context deadline exceeded") +} diff --git a/tests/main_test.go b/tests/main_test.go index 09106a4..e80b585 100644 --- a/tests/main_test.go +++ b/tests/main_test.go @@ -119,6 +119,7 @@ func assertGeneratedFiles(t *testing.T) { // Enums SQL Builder files enumFiles, err := ioutil.ReadDir("./.gentestdata2/jetdb/dvds/enum") + assert.NilError(t, err) assertFileNameEqual(t, enumFiles, "mpaa_rating.go") assertFileContent(t, "./.gentestdata2/jetdb/dvds/enum/mpaa_rating.go", "\npackage enum", mpaaRatingEnumFile) diff --git a/tests/select_test.go b/tests/select_test.go index bdba6d4..40f7bbb 100644 --- a/tests/select_test.go +++ b/tests/select_test.go @@ -1315,54 +1315,6 @@ LIMIT 20; assert.Equal(t, dest[1].StaffIDNum, "ONE") } -func TestLockTable(t *testing.T) { - expectedSQL := ` -LOCK TABLE dvds.address IN` - - var testData = []TableLockMode{ - LOCK_ACCESS_SHARE, - LOCK_ROW_SHARE, - LOCK_ROW_EXCLUSIVE, - LOCK_SHARE_UPDATE_EXCLUSIVE, - LOCK_SHARE, - LOCK_SHARE_ROW_EXCLUSIVE, - LOCK_EXCLUSIVE, - LOCK_ACCESS_EXCLUSIVE, - } - - for _, lockMode := range testData { - query := Address.LOCK().IN(lockMode) - - assertStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE;\n") - - tx, _ := db.Begin() - - _, err := query.Exec(tx) - - assert.NilError(t, err) - - err = tx.Rollback() - - assert.NilError(t, err) - } - - for _, lockMode := range testData { - query := Address.LOCK().IN(lockMode).NOWAIT() - - assertStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE NOWAIT;\n") - - tx, _ := db.Begin() - - _, err := query.Exec(tx) - - assert.NilError(t, err) - - err = tx.Rollback() - - assert.NilError(t, err) - } -} - func getRowLockTestData() map[SelectLock]string { return map[SelectLock]string{ UPDATE(): "UPDATE", diff --git a/tests/update_test.go b/tests/update_test.go index d8e1f0e..ff48f16 100644 --- a/tests/update_test.go +++ b/tests/update_test.go @@ -1,11 +1,13 @@ package tests import ( + "context" . "github.com/go-jet/jet" "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model" . "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table" "gotest.tools/assert" "testing" + "time" ) func TestUpdateValues(t *testing.T) { @@ -241,6 +243,43 @@ WHERE link.id = 201; assertExecErr(t, stmt, "pq: number of columns does not match number of values") } +func TestUpdateQueryContext(t *testing.T) { + setupLinkTableForUpdateTest(t) + + updateStmt := Link. + UPDATE(Link.Name, Link.URL). + SET("Bong", "http://bong.com"). + WHERE(Link.Name.EQ(String("Bing"))) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond) + defer cancel() + + time.Sleep(10 * time.Millisecond) + + dest := []model.Link{} + err := updateStmt.QueryContext(ctx, db, &dest) + + assert.Error(t, err, "context deadline exceeded") +} + +func TestUpdateExecContext(t *testing.T) { + setupLinkTableForUpdateTest(t) + + updateStmt := Link. + UPDATE(Link.Name, Link.URL). + SET("Bong", "http://bong.com"). + WHERE(Link.Name.EQ(String("Bing"))) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond) + defer cancel() + + time.Sleep(10 * time.Millisecond) + + _, err := updateStmt.ExecContext(ctx, db) + + assert.Error(t, err, "context deadline exceeded") +} + func setupLinkTableForUpdateTest(t *testing.T) { cleanUpLinkTable(t) diff --git a/time_expression.go b/time_expression.go index 6d13eba..779d37f 100644 --- a/time_expression.go +++ b/time_expression.go @@ -59,15 +59,15 @@ type prefixTimeExpression struct { prefixOpExpression } -func newPrefixTimeExpression(operator string, expression Expression) TimeExpression { - timeExpr := prefixTimeExpression{} - timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) - - timeExpr.expressionInterfaceImpl.parent = &timeExpr - timeExpr.timeInterfaceImpl.parent = &timeExpr - - return &timeExpr -} +//func newPrefixTimeExpression(operator string, expression Expression) TimeExpression { +// timeExpr := prefixTimeExpression{} +// timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) +// +// timeExpr.expressionInterfaceImpl.parent = &timeExpr +// timeExpr.timeInterfaceImpl.parent = &timeExpr +// +// return &timeExpr +//} //---------------------------------------------------// diff --git a/timez_expression.go b/timez_expression.go index cfd1f1d..d860703 100644 --- a/timez_expression.go +++ b/timez_expression.go @@ -67,15 +67,15 @@ type prefixTimezExpression struct { prefixOpExpression } -func newPrefixTimezExpression(operator string, expression Expression) TimezExpression { - timeExpr := prefixTimezExpression{} - timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) - - timeExpr.expressionInterfaceImpl.parent = &timeExpr - timeExpr.timezInterfaceImpl.parent = &timeExpr - - return &timeExpr -} +//func newPrefixTimezExpression(operator string, expression Expression) TimezExpression { +// timeExpr := prefixTimezExpression{} +// timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) +// +// timeExpr.expressionInterfaceImpl.parent = &timeExpr +// timeExpr.timezInterfaceImpl.parent = &timeExpr +// +// return &timeExpr +//} //---------------------------------------------------//