From 0dd976601e2aa63ac46d5930db56d98b7b45dfeb Mon Sep 17 00:00:00 2001 From: go-jet Date: Sun, 11 Aug 2019 18:23:02 +0200 Subject: [PATCH] MySQL: Add Where and Limit for Delete statement. --- mysql/delete_statement.go | 25 ++++++++++++++++++++----- mysql/delete_statement_test.go | 9 +++++++++ mysql/table.go | 25 +++++++++++++++---------- tests/mysql/delete_test.go | 19 +++++++++++++++++++ tests/mysql/generator_test.go | 28 ++++++++++++++-------------- tests/mysql/update_test.go | 14 ++++++++++++++ 6 files changed, 91 insertions(+), 29 deletions(-) diff --git a/mysql/delete_statement.go b/mysql/delete_statement.go index 8aa3977..a01f1c3 100644 --- a/mysql/delete_statement.go +++ b/mysql/delete_statement.go @@ -5,29 +5,44 @@ import "github.com/go-jet/jet/internal/jet" type DeleteStatement interface { jet.Statement - WHERE(expression BoolExpression) Statement + WHERE(expression BoolExpression) DeleteStatement + ORDER_BY(orderByClauses ...jet.OrderByClause) DeleteStatement + LIMIT(limit int64) DeleteStatement } type deleteStatementImpl struct { jet.StatementImpl - Delete jet.ClauseStatementBegin - Where jet.ClauseWhere + Delete jet.ClauseStatementBegin + Where jet.ClauseWhere + OrderBy jet.ClauseOrderBy + Limit jet.ClauseLimit } func newDeleteStatement(table Table) DeleteStatement { newDelete := &deleteStatementImpl{} newDelete.StatementImpl = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newDelete, &newDelete.Delete, - &newDelete.Where) + &newDelete.Where, &newDelete.OrderBy, &newDelete.Limit) newDelete.Delete.Name = "DELETE FROM" newDelete.Delete.Tables = append(newDelete.Delete.Tables, table) newDelete.Where.Mandatory = true + newDelete.Limit.Count = -1 return newDelete } -func (d *deleteStatementImpl) WHERE(expression BoolExpression) Statement { +func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement { d.Where.Condition = expression return d } + +func (s *deleteStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) DeleteStatement { + s.OrderBy.List = orderByClauses + return s +} + +func (s *deleteStatementImpl) LIMIT(limit int64) DeleteStatement { + s.Limit.Count = limit + return s +} diff --git a/mysql/delete_statement_test.go b/mysql/delete_statement_test.go index 5d84802..cfe990e 100644 --- a/mysql/delete_statement_test.go +++ b/mysql/delete_statement_test.go @@ -15,3 +15,12 @@ DELETE FROM db.table1 WHERE table1.col1 = ?; `, int64(1)) } + +func TestDeleteWithWhereOrderByLimit(t *testing.T) { + assertStatement(t, table1.DELETE().WHERE(table1Col1.EQ(Int(1))).ORDER_BY(table1Col1).LIMIT(1), ` +DELETE FROM db.table1 +WHERE table1.col1 = ? +ORDER BY table1.col1 +LIMIT ?; +`, int64(1), int64(1)) +} diff --git a/mysql/table.go b/mysql/table.go index 91d6d3a..ada83d6 100644 --- a/mysql/table.go +++ b/mysql/table.go @@ -17,19 +17,24 @@ type readableTable interface { SELECT(projection jet.Projection, projections ...jet.Projection) SelectStatement // Creates a inner join tableName Expression using onCondition. - INNER_JOIN(table ReadableTable, onCondition BoolExpression) Table + INNER_JOIN(table ReadableTable, onCondition BoolExpression) joinSelectUpdateTable // Creates a left join tableName Expression using onCondition. - LEFT_JOIN(table ReadableTable, onCondition BoolExpression) Table + LEFT_JOIN(table ReadableTable, onCondition BoolExpression) joinSelectUpdateTable // Creates a right join tableName Expression using onCondition. - RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) Table + RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) joinSelectUpdateTable // Creates a full join tableName Expression using onCondition. - FULL_JOIN(table ReadableTable, onCondition BoolExpression) Table + FULL_JOIN(table ReadableTable, onCondition BoolExpression) joinSelectUpdateTable // Creates a cross join tableName Expression using onCondition. - CROSS_JOIN(table ReadableTable) Table + CROSS_JOIN(table ReadableTable) joinSelectUpdateTable +} + +type joinSelectUpdateTable interface { + ReadableTable + UPDATE(column jet.Column, columns ...jet.Column) UpdateStatement } type ReadableTable interface { @@ -47,25 +52,25 @@ func (r *readableTableInterfaceImpl) SELECT(projection1 jet.Projection, projecti } // Creates a inner join tableName Expression using onCondition. -func (r *readableTableInterfaceImpl) INNER_JOIN(table ReadableTable, onCondition BoolExpression) Table { +func (r *readableTableInterfaceImpl) INNER_JOIN(table ReadableTable, onCondition BoolExpression) joinSelectUpdateTable { return newJoinTable(r.parent, table, jet.InnerJoin, onCondition) } // Creates a left join tableName Expression using onCondition. -func (r *readableTableInterfaceImpl) LEFT_JOIN(table ReadableTable, onCondition BoolExpression) Table { +func (r *readableTableInterfaceImpl) LEFT_JOIN(table ReadableTable, onCondition BoolExpression) joinSelectUpdateTable { return newJoinTable(r.parent, table, jet.LeftJoin, onCondition) } // Creates a right join tableName Expression using onCondition. -func (r *readableTableInterfaceImpl) RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) Table { +func (r *readableTableInterfaceImpl) RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) joinSelectUpdateTable { return newJoinTable(r.parent, table, jet.RightJoin, onCondition) } -func (r *readableTableInterfaceImpl) FULL_JOIN(table ReadableTable, onCondition BoolExpression) Table { +func (r *readableTableInterfaceImpl) FULL_JOIN(table ReadableTable, onCondition BoolExpression) joinSelectUpdateTable { return newJoinTable(r.parent, table, jet.FullJoin, onCondition) } -func (r *readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) Table { +func (r *readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) joinSelectUpdateTable { return newJoinTable(r.parent, table, jet.CrossJoin, nil) } diff --git a/tests/mysql/delete_test.go b/tests/mysql/delete_test.go index a46777e..c3409a5 100644 --- a/tests/mysql/delete_test.go +++ b/tests/mysql/delete_test.go @@ -26,6 +26,25 @@ WHERE link.name IN ('Gmail', 'Outlook'); testutils.AssertExec(t, deleteStmt, db, 2) } +func TestDeleteWithWhereOrderByLimit(t *testing.T) { + initForDeleteTest(t) + + var expectedSQL = ` +DELETE FROM test_sample.link +WHERE link.name IN ('Gmail', 'Outlook') +ORDER BY link.name +LIMIT 1; +` + deleteStmt := Link. + DELETE(). + WHERE(Link.Name.IN(String("Gmail"), String("Outlook"))). + ORDER_BY(Link.Name). + LIMIT(1) + + testutils.AssertDebugStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook", int64(1)) + testutils.AssertExec(t, deleteStmt, db, 1) +} + func TestDeleteQueryContext(t *testing.T) { initForDeleteTest(t) diff --git a/tests/mysql/generator_test.go b/tests/mysql/generator_test.go index 91c45c0..3d8f173 100644 --- a/tests/mysql/generator_test.go +++ b/tests/mysql/generator_test.go @@ -11,14 +11,14 @@ import ( "testing" ) -const genTestDir2 = "./.gentestdata2/mysql" +const genTestDirRoot = "./.gentestdata3" +const genTestDir3 = "./.gentestdata3/mysql" func TestGenerator(t *testing.T) { - - err := os.RemoveAll(genTestDir2) + err := os.RemoveAll(genTestDir3) assert.NilError(t, err) - err = mysql.Generate(genTestDir2, mysql.DBConnection{ + err = mysql.Generate(genTestDir3, mysql.DBConnection{ Host: dbconfig.MySqLHost, Port: dbconfig.MySQLPort, User: dbconfig.MySQLUser, @@ -30,7 +30,7 @@ func TestGenerator(t *testing.T) { assertGeneratedFiles(t) - err = os.RemoveAll(genTestDir2) + err = os.RemoveAll(genTestDirRoot) assert.NilError(t, err) } @@ -40,11 +40,11 @@ func TestCmdGenerator(t *testing.T) { err := goInstallJet.Run() assert.NilError(t, err) - err = os.RemoveAll(genTestDir2) + err = os.RemoveAll(genTestDir3) assert.NilError(t, err) cmd := exec.Command("jet", "-source=MySQL", "-dbname=dvds", "-host=localhost", "-port=3306", - "-user=jet", "-password=jet", "-path="+genTestDir2) + "-user=jet", "-password=jet", "-path="+genTestDir3) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout @@ -54,37 +54,37 @@ func TestCmdGenerator(t *testing.T) { assertGeneratedFiles(t) - err = os.RemoveAll(genTestDir2) + err = os.RemoveAll(genTestDirRoot) assert.NilError(t, err) } func assertGeneratedFiles(t *testing.T) { // Table SQL Builder files - tableSQLBuilderFiles, err := ioutil.ReadDir("./.gentestdata2/mysql/dvds/table") + tableSQLBuilderFiles, err := ioutil.ReadDir(genTestDir3 + "/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/mysql/dvds/table/actor.go", "\npackage table", actorSQLBuilderFile) + assertFileContent(t, genTestDir3+"/dvds/table/actor.go", "\npackage table", actorSQLBuilderFile) // Enums SQL Builder files - enumFiles, err := ioutil.ReadDir("./.gentestdata2/mysql/dvds/enum") + enumFiles, err := ioutil.ReadDir(genTestDir3 + "/dvds/enum") assert.NilError(t, err) assertFileNameEqual(t, enumFiles, "film_list_rating.go", "film_rating.go", "nicer_but_slower_film_list_rating.go") - assertFileContent(t, "./.gentestdata2/mysql/dvds/enum/film_rating.go", "\npackage enum", mpaaRatingEnumFile) + assertFileContent(t, genTestDir3+"/dvds/enum/film_rating.go", "\npackage enum", mpaaRatingEnumFile) // Model files - modelFiles, err := ioutil.ReadDir("./.gentestdata2/mysql/dvds/model") + modelFiles, err := ioutil.ReadDir(genTestDir3 + "/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", "film_list_rating.go", "film_rating.go", "nicer_but_slower_film_list_rating.go") - assertFileContent(t, "./.gentestdata2/mysql/dvds/model/actor.go", "\npackage model", actorModelFile) + assertFileContent(t, genTestDir3+"/dvds/model/actor.go", "\npackage model", actorModelFile) } func assertFileContent(t *testing.T, filePath string, contentBegin string, expectedContent string) { diff --git a/tests/mysql/update_test.go b/tests/mysql/update_test.go index 8c2ce49..185c8e8 100644 --- a/tests/mysql/update_test.go +++ b/tests/mysql/update_test.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/go-jet/jet/internal/testutils" . "github.com/go-jet/jet/mysql" + "github.com/go-jet/jet/tests/.gentestdata/mysql/dvds/table" "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/model" . "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/table" "gotest.tools/assert" @@ -204,6 +205,19 @@ func TestUpdateExecContext(t *testing.T) { assert.Error(t, err, "context deadline exceeded") } +func TestUpdateWithJoin(t *testing.T) { + query := table.Staff. + INNER_JOIN(table.Address, table.Address.AddressID.EQ(table.Staff.AddressID)). + UPDATE(table.Staff.LastName). + SET(String("New name")). + WHERE(table.Staff.StaffID.EQ(Int(1))) + + //fmt.Println(query.DebugSql()) + + _, err := query.Exec(db) + assert.NilError(t, err) +} + func setupLinkTableForUpdateTest(t *testing.T) { cleanUpLinkTable(t)