MySQL refactor.

This commit is contained in:
go-jet 2019-08-11 12:13:59 +02:00
parent 8519ccbdd0
commit 4fbf576370
36 changed files with 1080 additions and 270 deletions

33
mysql/delete_statement.go Normal file
View file

@ -0,0 +1,33 @@
package mysql
import "github.com/go-jet/jet/internal/jet"
type DeleteStatement interface {
jet.Statement
WHERE(expression BoolExpression) Statement
}
type deleteStatementImpl struct {
jet.StatementImpl
Delete jet.ClauseStatementBegin
Where jet.ClauseWhere
}
func newDeleteStatement(table Table) DeleteStatement {
newDelete := &deleteStatementImpl{}
newDelete.StatementImpl = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newDelete, &newDelete.Delete,
&newDelete.Where)
newDelete.Delete.Name = "DELETE FROM"
newDelete.Delete.Tables = append(newDelete.Delete.Tables, table)
newDelete.Where.Mandatory = true
return newDelete
}
func (d *deleteStatementImpl) WHERE(expression BoolExpression) Statement {
d.Where.Condition = expression
return d
}

View file

@ -0,0 +1,17 @@
package mysql
import (
"testing"
)
func TestDeleteUnconditionally(t *testing.T) {
assertStatementErr(t, table1.DELETE(), `jet: WHERE clause not set`)
assertStatementErr(t, table1.DELETE().WHERE(nil), `jet: WHERE clause not set`)
}
func TestDeleteWithWhere(t *testing.T) {
assertStatement(t, table1.DELETE().WHERE(table1Col1.EQ(Int(1))), `
DELETE FROM db.table1
WHERE table1.col1 = ?;
`, int64(1))
}

View file

@ -15,8 +15,6 @@ func NewDialect() jet.Dialect {
serializeOverrides["/"] = mysql_DIVISION
serializeOverrides["#"] = mysql_BIT_XOR
serializeOverrides[jet.StringConcatOperator] = mysql_CONCAT_operator
serializeOverrides[jet.Except] = mysql_EXCEPT
serializeOverrides[jet.Intersect] = mysql_INTERSECT
mySQLDialectParams := jet.DialectParams{
Name: "MySQL",
@ -27,24 +25,11 @@ func NewDialect() jet.Dialect {
ArgumentPlaceholder: func(int) string {
return "?"
},
SupportsReturning: false,
}
return jet.NewDialect(mySQLDialectParams)
}
func mysql_EXCEPT(expressions ...jet.Expression) jet.SerializeFunc {
return func(statement jet.StatementType, out *jet.SqlBuilder, options ...jet.SerializeOption) error {
panic("jet: MySQL does not support EXCEPT operator.")
}
}
func mysql_INTERSECT(expressions ...jet.Expression) jet.SerializeFunc {
return func(statement jet.StatementType, out *jet.SqlBuilder, options ...jet.SerializeOption) error {
panic("jet: MySQL does not support INTERSECT operator.")
}
}
func mysql_BIT_XOR(expressions ...jet.Expression) jet.SerializeFunc {
return func(statement jet.StatementType, out *jet.SqlBuilder, options ...jet.SerializeOption) error {
if len(expressions) != 2 {

View file

@ -32,3 +32,5 @@ var TimestampExp = jet.TimestampExp
var Raw = jet.Raw
var NewEnumValue = jet.NewEnumValue
type Statement jet.Statement

View file

@ -27,8 +27,6 @@ var TRUNCATE = func(floatExpression jet.FloatExpression, precision jet.IntegerEx
return jet.NewFloatFunc("TRUNCATE", floatExpression, precision)
}
//var MINUSi = jet.MINUSi
//var MINUSf = jet.MINUSf
var BIT_NOT = jet.BIT_NOT
// ----------------- Aggregate functions -------------------//

64
mysql/insert_statement.go Normal file
View file

@ -0,0 +1,64 @@
package mysql
import "github.com/go-jet/jet/internal/jet"
// InsertStatement is interface for SQL INSERT statements
type InsertStatement interface {
jet.Statement
// Insert row of values
VALUES(value interface{}, values ...interface{}) InsertStatement
// Insert row of values, where value for each column is extracted from filed of structure data.
// If data is not struct or there is no field for every column selected, this method will panic.
MODEL(data interface{}) InsertStatement
MODELS(data interface{}) InsertStatement
QUERY(selectStatement SelectStatement) InsertStatement
}
func newInsertStatement(table Table, columns []jet.IColumn) InsertStatement {
newInsert := &insertStatementImpl{}
newInsert.StatementImpl = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newInsert,
&newInsert.Insert, &newInsert.Values, &newInsert.Select)
newInsert.Insert.Table = table
newInsert.Insert.Columns = columns
return newInsert
}
type insertStatementImpl struct {
jet.StatementImpl
Insert jet.ClauseInsert
Values jet.ClauseValues
Select jet.ClauseQuery
}
func (i *insertStatementImpl) VALUES(value interface{}, values ...interface{}) InsertStatement {
i.Values.Rows = append(i.Values.Rows, jet.UnwindRowFromValues(value, values))
return i
}
func (i *insertStatementImpl) MODEL(data interface{}) InsertStatement {
i.Values.Rows = append(i.Values.Rows, jet.UnwindRowFromModel(i.getColumns(), data))
return i
}
func (i *insertStatementImpl) MODELS(data interface{}) InsertStatement {
i.Values.Rows = append(i.Values.Rows, jet.UnwindRowsFromModels(i.getColumns(), data)...)
return i
}
func (i *insertStatementImpl) QUERY(selectStatement SelectStatement) InsertStatement {
i.Select.Query = selectStatement
return i
}
func (i *insertStatementImpl) getColumns() []jet.IColumn {
if len(i.Insert.Columns) > 0 {
return i.Insert.Columns
}
return i.Insert.Table.Columns()
}

View file

@ -0,0 +1,134 @@
package mysql
import (
"gotest.tools/assert"
"testing"
"time"
)
//TODO:
//func TestInvalidInsert(t *testing.T) {
// assertStatementErr(t, table1.INSERT(table1Col1), "jet: no row values or query specified")
// assertStatementErr(t, table1.INSERT(nil).VALUES(1), "jet: nil column in columns list")
//}
func TestInsertNilValue(t *testing.T) {
assertStatement(t, table1.INSERT(table1Col1).VALUES(nil), `
INSERT INTO db.table1 (col1) VALUES
(?);
`, nil)
}
func TestInsertSingleValue(t *testing.T) {
assertStatement(t, table1.INSERT(table1Col1).VALUES(1), `
INSERT INTO db.table1 (col1) VALUES
(?);
`, int(1))
}
func TestInsertWithColumnList(t *testing.T) {
columnList := ColumnList(table3ColInt, table3StrCol)
assertStatement(t, table3.INSERT(columnList).VALUES(1, 3), `
INSERT INTO db.table3 (col_int, col2) VALUES
(?, ?);
`, 1, 3)
}
func TestInsertDate(t *testing.T) {
date := time.Date(1999, 1, 2, 3, 4, 5, 0, time.UTC)
assertStatement(t, table1.INSERT(table1ColTimestamp).VALUES(date), `
INSERT INTO db.table1 (col_timestamp) VALUES
(?);
`, date)
}
func TestInsertMultipleValues(t *testing.T) {
assertStatement(t, table1.INSERT(table1Col1, table1ColFloat, table1Col3).VALUES(1, 2, 3), `
INSERT INTO db.table1 (col1, col_float, col3) VALUES
(?, ?, ?);
`, 1, 2, 3)
}
func TestInsertMultipleRows(t *testing.T) {
stmt := table1.INSERT(table1Col1, table1ColFloat).
VALUES(1, 2).
VALUES(11, 22).
VALUES(111, 222)
assertStatement(t, stmt, `
INSERT INTO db.table1 (col1, col_float) VALUES
(?, ?),
(?, ?),
(?, ?);
`, 1, 2, 11, 22, 111, 222)
}
func TestInsertValuesFromModel(t *testing.T) {
type Table1Model struct {
Col1 *int
ColFloat float64
}
one := 1
toInsert := Table1Model{
Col1: &one,
ColFloat: 1.11,
}
stmt := table1.INSERT(table1Col1, table1ColFloat).
MODEL(toInsert).
MODEL(&toInsert)
expectedSQL := `
INSERT INTO db.table1 (col1, col_float) VALUES
(?, ?),
(?, ?);
`
assertStatement(t, stmt, expectedSQL, int(1), float64(1.11), int(1), float64(1.11))
}
func TestInsertValuesFromModelColumnMismatch(t *testing.T) {
defer func() {
r := recover()
assert.Equal(t, r, "missing struct field for column : col1")
}()
type Table1Model struct {
Col1Prim int
Col2 string
}
newData := Table1Model{
Col1Prim: 1,
Col2: "one",
}
table1.
INSERT(table1Col1, table1ColFloat).
MODEL(newData)
}
func TestInsertFromNonStructModel(t *testing.T) {
defer func() {
r := recover()
assert.Equal(t, r, "argument mismatch: expected struct, got []int")
}()
table2.INSERT(table2ColInt).MODEL([]int{})
}
func TestInsertDefaultValue(t *testing.T) {
stmt := table1.INSERT(table1Col1, table1ColFloat).
VALUES(DEFAULT, "two")
var expectedSQL = `
INSERT INTO db.table1 (col1, col_float) VALUES
(DEFAULT, ?);
`
assertStatement(t, stmt, expectedSQL, "two")
}

View file

@ -5,6 +5,10 @@ import (
"time"
)
var STAR = jet.STAR
var NULL = jet.NULL
var DEFAULT = jet.DEFAULT
var Bool = jet.Bool
var Int = jet.Int
var Float = jet.Float

118
mysql/select_statement.go Normal file
View file

@ -0,0 +1,118 @@
package mysql
import "github.com/go-jet/jet/internal/jet"
type SelectLock = jet.SelectLock
var (
UPDATE = jet.NewSelectLock("UPDATE")
SHARE = jet.NewSelectLock("SHARE")
)
type SelectStatement interface {
jet.Statement
jet.HasProjections
jet.IExpression
DISTINCT() SelectStatement
FROM(table ReadableTable) SelectStatement
WHERE(expression BoolExpression) SelectStatement
GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement
HAVING(boolExpression BoolExpression) SelectStatement
ORDER_BY(orderByClauses ...jet.OrderByClause) SelectStatement
LIMIT(limit int64) SelectStatement
OFFSET(offset int64) SelectStatement
FOR(lock SelectLock) SelectStatement
UNION(rhs SelectStatement) SetStatement
UNION_ALL(rhs SelectStatement) SetStatement
AsTable(alias string) SelectTable
}
//SELECT creates new SelectStatement with list of projections
func SELECT(projection jet.Projection, projections ...jet.Projection) SelectStatement {
return newSelectStatement(nil, append([]jet.Projection{projection}, projections...))
}
func newSelectStatement(table ReadableTable, projections []jet.Projection) SelectStatement {
newSelect := &selectStatementImpl{}
newSelect.ExpressionStatementImpl.StatementImpl = jet.NewStatementImpl(Dialect, jet.SelectStatementType, newSelect, &newSelect.Select,
&newSelect.From, &newSelect.Where, &newSelect.GroupBy, &newSelect.Having, &newSelect.OrderBy,
&newSelect.Limit, &newSelect.Offset, &newSelect.For)
newSelect.ExpressionStatementImpl.ExpressionInterfaceImpl.Parent = newSelect
newSelect.Select.Projections = projections
newSelect.From.Table = table
newSelect.Limit.Count = -1
newSelect.Offset.Count = -1
newSelect.setOperatorsImpl.parent = newSelect
return newSelect
}
type selectStatementImpl struct {
jet.ExpressionStatementImpl
setOperatorsImpl
Select jet.ClauseSelect
From jet.ClauseFrom
Where jet.ClauseWhere
GroupBy jet.ClauseGroupBy
Having jet.ClauseHaving
OrderBy jet.ClauseOrderBy
Limit jet.ClauseLimit
Offset jet.ClauseOffset
For jet.ClauseFor
}
func (s *selectStatementImpl) DISTINCT() SelectStatement {
s.Select.Distinct = true
return s
}
func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
s.From.Table = table
return s
}
func (s *selectStatementImpl) WHERE(condition BoolExpression) SelectStatement {
s.Where.Condition = condition
return s
}
func (s *selectStatementImpl) GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement {
s.GroupBy.List = groupByClauses
return s
}
func (s *selectStatementImpl) HAVING(boolExpression BoolExpression) SelectStatement {
s.Having.Condition = boolExpression
return s
}
func (s *selectStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) SelectStatement {
s.OrderBy.List = orderByClauses
return s
}
func (s *selectStatementImpl) LIMIT(limit int64) SelectStatement {
s.Limit.Count = limit
return s
}
func (s *selectStatementImpl) OFFSET(offset int64) SelectStatement {
s.Offset.Count = offset
return s
}
func (s *selectStatementImpl) FOR(lock SelectLock) SelectStatement {
s.For.Lock = lock
return s
}
func (s *selectStatementImpl) AsTable(alias string) SelectTable {
return newSelectTable(s, alias)
}

View file

@ -0,0 +1,126 @@
package mysql
import (
"github.com/go-jet/jet/internal/testutils"
"testing"
)
func TestInvalidSelect(t *testing.T) {
assertStatementErr(t, SELECT(nil), "jet: Projection is nil")
}
func TestSelectColumnList(t *testing.T) {
columnList := ColumnList(table2ColInt, table2ColFloat, table3ColInt)
assertStatement(t, SELECT(columnList).FROM(table2), `
SELECT table2.col_int AS "table2.col_int",
table2.col_float AS "table2.col_float",
table3.col_int AS "table3.col_int"
FROM db.table2;
`)
}
func TestSelectLiterals(t *testing.T) {
assertStatement(t, SELECT(Int(1), Float(2.2), Bool(false)).FROM(table1), `
SELECT ?,
?,
?
FROM db.table1;
`, int64(1), 2.2, false)
}
func TestSelectDistinct(t *testing.T) {
assertStatement(t, SELECT(table1ColBool).DISTINCT().FROM(table1), `
SELECT DISTINCT table1.col_bool AS "table1.col_bool"
FROM db.table1;
`)
}
func TestSelectFrom(t *testing.T) {
assertStatement(t, SELECT(table1ColInt, table2ColFloat).FROM(table1), `
SELECT table1.col_int AS "table1.col_int",
table2.col_float AS "table2.col_float"
FROM db.table1;
`)
assertStatement(t, SELECT(table1ColInt, table2ColFloat).FROM(table1.INNER_JOIN(table2, table1ColInt.EQ(table2ColInt))), `
SELECT table1.col_int AS "table1.col_int",
table2.col_float AS "table2.col_float"
FROM db.table1
INNER JOIN db.table2 ON (table1.col_int = table2.col_int);
`)
assertStatement(t, table1.INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)).SELECT(table1ColInt, table2ColFloat), `
SELECT table1.col_int AS "table1.col_int",
table2.col_float AS "table2.col_float"
FROM db.table1
INNER JOIN db.table2 ON (table1.col_int = table2.col_int);
`)
}
func TestSelectWhere(t *testing.T) {
assertStatement(t, SELECT(table1ColInt).FROM(table1).WHERE(Bool(true)), `
SELECT table1.col_int AS "table1.col_int"
FROM db.table1
WHERE ?;
`, true)
assertStatement(t, SELECT(table1ColInt).FROM(table1).WHERE(table1ColInt.GT_EQ(Int(10))), `
SELECT table1.col_int AS "table1.col_int"
FROM db.table1
WHERE table1.col_int >= ?;
`, int64(10))
}
func TestSelectGroupBy(t *testing.T) {
assertStatement(t, SELECT(table2ColInt).FROM(table2).GROUP_BY(table2ColFloat), `
SELECT table2.col_int AS "table2.col_int"
FROM db.table2
GROUP BY table2.col_float;
`)
}
func TestSelectHaving(t *testing.T) {
assertStatement(t, SELECT(table3ColInt).FROM(table3).HAVING(table1ColBool.EQ(Bool(true))), `
SELECT table3.col_int AS "table3.col_int"
FROM db.table3
HAVING table1.col_bool = ?;
`, true)
}
func TestSelectOrderBy(t *testing.T) {
assertStatement(t, SELECT(table2ColFloat).FROM(table2).ORDER_BY(table2ColInt.DESC()), `
SELECT table2.col_float AS "table2.col_float"
FROM db.table2
ORDER BY table2.col_int DESC;
`)
assertStatement(t, SELECT(table2ColFloat).FROM(table2).ORDER_BY(table2ColInt.DESC(), table2ColInt.ASC()), `
SELECT table2.col_float AS "table2.col_float"
FROM db.table2
ORDER BY table2.col_int DESC, table2.col_int ASC;
`)
}
func TestSelectLimitOffset(t *testing.T) {
assertStatement(t, SELECT(table2ColInt).FROM(table2).LIMIT(10), `
SELECT table2.col_int AS "table2.col_int"
FROM db.table2
LIMIT ?;
`, int64(10))
assertStatement(t, SELECT(table2ColInt).FROM(table2).LIMIT(10).OFFSET(2), `
SELECT table2.col_int AS "table2.col_int"
FROM db.table2
LIMIT ?
OFFSET ?;
`, int64(10), int64(2))
}
func TestSelectLock(t *testing.T) {
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(UPDATE()), `
SELECT table1.col_bool AS "table1.col_bool"
FROM db.table1
FOR UPDATE;
`)
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(SHARE().NOWAIT()), `
SELECT table1.col_bool AS "table1.col_bool"
FROM db.table1
FOR SHARE NOWAIT;
`)
}

23
mysql/select_table.go Normal file
View file

@ -0,0 +1,23 @@
package mysql
import "github.com/go-jet/jet/internal/jet"
type SelectTable interface {
ReadableTable
jet.SelectTable
}
type selectTableImpl struct {
jet.SelectTableImpl2
readableTableInterfaceImpl
}
func newSelectTable(selectStmt jet.StatementWithProjections, alias string) SelectTable {
subQuery := &selectTableImpl{
SelectTableImpl2: jet.NewSelectTable(selectStmt, alias),
}
subQuery.readableTableInterfaceImpl.parent = subQuery
return subQuery
}

104
mysql/set_statement.go Normal file
View file

@ -0,0 +1,104 @@
package mysql
import "github.com/go-jet/jet/internal/jet"
// UNION effectively appends the result of sub-queries(select statements) into single query.
// It eliminates duplicate rows from its result.
func UNION(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) SetStatement {
return newSetStatementImpl(Union, false, toSelectList(lhs, rhs, selects...))
}
// UNION_ALL effectively appends the result of sub-queries(select statements) into single query.
// It does not eliminates duplicate rows from its result.
func UNION_ALL(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) SetStatement {
return newSetStatementImpl(Union, true, toSelectList(lhs, rhs, selects...))
}
type SetStatement interface {
SetOperators
ORDER_BY(orderByClauses ...jet.OrderByClause) SetStatement
LIMIT(limit int64) SetStatement
OFFSET(offset int64) SetStatement
AsTable(alias string) SelectTable
}
type SetStatementFinal interface {
}
type SetOperators interface {
jet.Statement
jet.HasProjections
jet.IExpression
UNION(rhs SelectStatement) SetStatement
UNION_ALL(rhs SelectStatement) SetStatement
}
type setOperatorsImpl struct {
parent SetOperators
}
func (s *setOperatorsImpl) UNION(rhs SelectStatement) SetStatement {
return UNION(s.parent, rhs)
}
func (s *setOperatorsImpl) UNION_ALL(rhs SelectStatement) SetStatement {
return UNION_ALL(s.parent, rhs)
}
type setStatementImpl struct {
jet.ExpressionStatementImpl
setOperatorsImpl
setOperator jet.ClauseSetStmtOperator
}
func newSetStatementImpl(operator string, all bool, selects []jet.StatementWithProjections) SetStatement {
newSetStatement := &setStatementImpl{}
newSetStatement.ExpressionStatementImpl.StatementImpl = jet.NewStatementImpl(Dialect, jet.SetStatementType, newSetStatement,
&newSetStatement.setOperator)
newSetStatement.ExpressionStatementImpl.ExpressionInterfaceImpl.Parent = newSetStatement
newSetStatement.setOperator.Operator = operator
newSetStatement.setOperator.All = all
newSetStatement.setOperator.Selects = selects
newSetStatement.setOperator.Limit.Count = -1
newSetStatement.setOperator.Offset.Count = -1
newSetStatement.setOperatorsImpl.parent = newSetStatement
newSetStatement.Clauses = []jet.Clause{&newSetStatement.setOperator}
return newSetStatement
}
func (s *setStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) SetStatement {
s.setOperator.OrderBy.List = orderByClauses
return s
}
func (s *setStatementImpl) LIMIT(limit int64) SetStatement {
s.setOperator.Limit.Count = limit
return s
}
func (s *setStatementImpl) OFFSET(offset int64) SetStatement {
s.setOperator.Offset.Count = offset
return s
}
func (s *setStatementImpl) AsTable(alias string) SelectTable {
return newSelectTable(s, alias)
}
const (
Union = "UNION"
)
func toSelectList(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) []jet.StatementWithProjections {
return append([]jet.StatementWithProjections{lhs, rhs}, selects...)
}

View file

@ -0,0 +1,33 @@
package mysql
import (
"testing"
)
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
);
`)
}

View file

@ -1,23 +0,0 @@
package mysql
import "github.com/go-jet/jet/internal/jet"
// ----------------- FUNCTIONS ----------------------//
var SELECT = jet.SELECT
type SelectLock jet.SelectLock
var (
UPDATE = jet.NewSelectLock("UPDATE")
SHARE = jet.NewSelectLock("SHARE")
)
var UNION = jet.UNION
var UNION_ALL = jet.UNION_ALL
//-----------------literals----------------------//
var STAR = jet.STAR
var NULL = jet.NULL
var DEFAULT = jet.DEFAULT

View file

@ -2,8 +2,126 @@ package mysql
import "github.com/go-jet/jet/internal/jet"
type Table jet.Table
//type Table jet.Table
//
//func NewTable(schemaName, name string, columns ...jet.Column) Table {
// return jet.NewTable(Dialect, schemaName, name, columns...)
//}
type Table interface {
jet.SerializerTable
readableTable
INSERT(columns ...jet.IColumn) InsertStatement
UPDATE(column jet.IColumn, columns ...jet.IColumn) UpdateStatement
DELETE() DeleteStatement
//LOCK() LockStatement
AS(alias string)
}
type readableTable interface {
// Generates a select query on the current tableName.
SELECT(projection jet.Projection, projections ...jet.Projection) SelectStatement
// Creates a inner join tableName Expression using onCondition.
INNER_JOIN(table ReadableTable, onCondition BoolExpression) Table
// Creates a left join tableName Expression using onCondition.
LEFT_JOIN(table ReadableTable, onCondition BoolExpression) Table
// Creates a right join tableName Expression using onCondition.
RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) Table
// Creates a full join tableName Expression using onCondition.
FULL_JOIN(table ReadableTable, onCondition BoolExpression) Table
// Creates a cross join tableName Expression using onCondition.
CROSS_JOIN(table ReadableTable) Table
}
type ReadableTable interface {
jet.SerializerTable
readableTable
}
type readableTableInterfaceImpl struct {
parent ReadableTable
}
// Generates a select query on the current tableName.
func (r *readableTableInterfaceImpl) SELECT(projection1 jet.Projection, projections ...jet.Projection) SelectStatement {
return newSelectStatement(r.parent, append([]jet.Projection{projection1}, projections...))
}
// Creates a inner join tableName Expression using onCondition.
func (r *readableTableInterfaceImpl) INNER_JOIN(table ReadableTable, onCondition BoolExpression) Table {
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 {
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 {
return newJoinTable(r.parent, table, jet.RightJoin, onCondition)
}
func (r *readableTableInterfaceImpl) FULL_JOIN(table ReadableTable, onCondition BoolExpression) Table {
return newJoinTable(r.parent, table, jet.FullJoin, onCondition)
}
func (r *readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) Table {
return newJoinTable(r.parent, table, jet.CrossJoin, nil)
}
func NewTable(schemaName, name string, columns ...jet.Column) Table {
return jet.NewTable(Dialect, schemaName, name, columns...)
t := &tableImpl{
TableImpl2: jet.NewTable2(Dialect, schemaName, name, columns...),
}
t.readableTableInterfaceImpl.parent = t
t.parent = t
return t
}
type tableImpl struct {
jet.TableImpl2
readableTableInterfaceImpl
parent Table
}
func (w *tableImpl) INSERT(columns ...jet.IColumn) InsertStatement {
return newInsertStatement(w.parent, jet.UnwidColumnList(columns))
}
func (w *tableImpl) UPDATE(column jet.IColumn, columns ...jet.IColumn) UpdateStatement {
return newUpdateStatement(w.parent, jet.UnwindColumns(column, columns...))
}
func (w *tableImpl) DELETE() DeleteStatement {
return newDeleteStatement(w.parent)
}
//func (w *tableInterfaceImpl) LOCK() LockStatement {
// return LOCK(w.parent)
//}
type joinTable2 struct {
tableImpl
jet.JoinTableImpl
}
func newJoinTable(lhs jet.Serializer, rhs jet.Serializer, joinType jet.JoinType, onCondition BoolExpression) Table {
newJoinTable := &joinTable2{
JoinTableImpl: jet.NewJoinTableImpl(lhs, rhs, joinType, onCondition),
}
newJoinTable.readableTableInterfaceImpl.parent = newJoinTable
newJoinTable.parent = newJoinTable
return newJoinTable
}

48
mysql/update_statement.go Normal file
View file

@ -0,0 +1,48 @@
package mysql
import "github.com/go-jet/jet/internal/jet"
// UpdateStatement is interface of SQL UPDATE statement
type UpdateStatement interface {
jet.Statement
SET(value interface{}, values ...interface{}) UpdateStatement
MODEL(data interface{}) UpdateStatement
WHERE(expression BoolExpression) UpdateStatement
}
type updateStatementImpl struct {
jet.StatementImpl
Update jet.ClauseUpdate
Set jet.ClauseSet
Where jet.ClauseWhere
}
func newUpdateStatement(table Table, columns []jet.IColumn) UpdateStatement {
update := &updateStatementImpl{}
update.StatementImpl = jet.NewStatementImpl(Dialect, jet.UpdateStatementType, update, &update.Update,
&update.Set, &update.Where)
update.Update.Table = table
update.Set.Columns = columns
update.Where.Mandatory = true
return update
}
func (u *updateStatementImpl) SET(value interface{}, values ...interface{}) UpdateStatement {
u.Set.Values = jet.UnwindRowFromValues(value, values)
return u
}
func (u *updateStatementImpl) MODEL(data interface{}) UpdateStatement {
u.Set.Values = jet.UnwindRowFromModel(u.Set.Columns, data)
return u
}
func (u *updateStatementImpl) WHERE(expression BoolExpression) UpdateStatement {
u.Where.Condition = expression
return u
}

View file

@ -0,0 +1,63 @@
package mysql
import (
"fmt"
"testing"
)
func TestUpdateWithOneValue(t *testing.T) {
expectedSQL := `
UPDATE db.table1
SET col_int = ?
WHERE table1.col_int >= ?;
`
stmt := table1.UPDATE(table1ColInt).
SET(1).
WHERE(table1ColInt.GT_EQ(Int(33)))
fmt.Println(stmt.Sql())
assertStatement(t, stmt, expectedSQL, 1, int64(33))
}
func TestUpdateWithValues(t *testing.T) {
expectedSQL := `
UPDATE db.table1
SET col_int = ?,
col_float = ?
WHERE table1.col_int >= ?;
`
stmt := table1.UPDATE(table1ColInt, table1ColFloat).
SET(1, 22.2).
WHERE(table1ColInt.GT_EQ(Int(33)))
fmt.Println(stmt.Sql())
assertStatement(t, stmt, expectedSQL, 1, 22.2, int64(33))
}
func TestUpdateOneColumnWithSelect(t *testing.T) {
expectedSQL := `
UPDATE db.table1
SET col_float = (
SELECT table1.col_float AS "table1.col_float"
FROM db.table1
)
WHERE table1.col1 = ?;
`
stmt := table1.
UPDATE(table1ColFloat).
SET(
table1.SELECT(table1ColFloat),
).
WHERE(table1Col1.EQ(Int(2)))
//fmt.Println(stmt.Sql())
assertStatement(t, stmt, expectedSQL, int64(2))
}
func TestInvalidInputs(t *testing.T) {
assertStatementErr(t, table1.UPDATE(table1ColInt).SET(1), "jet: WHERE clause not set")
assertStatementErr(t, table1.UPDATE(nil).SET(1), "jet: nil column in columns list")
}