Additional documentation.
This commit is contained in:
parent
d253a35161
commit
b10270b502
48 changed files with 892 additions and 699 deletions
|
|
@ -1,10 +1,11 @@
|
||||||
# Jet
|
# Jet
|
||||||
|
|
||||||
|
[](http://godoc.org/github.com/go-jet/jet)
|
||||||
[](https://circleci.com/gh/go-jet/jet/tree/develop)
|
[](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
|
Jet is a framework for writing type-safe SQL queries for PostgreSQL in Go, with ability to easily
|
||||||
convert database query result to desired arbitrary structure.
|
convert database query result to desired arbitrary structure.
|
||||||
_Support for additional databases will be added in future jet releases._
|
_*Support for additional databases will be added in future jet releases._
|
||||||
|
|
||||||
|
|
||||||
## Contents
|
## Contents
|
||||||
|
|
|
||||||
2
alias.go
2
alias.go
|
|
@ -12,7 +12,7 @@ func newAlias(expression Expression, aliasName string) projection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *alias) from(subQuery ExpressionTable) projection {
|
func (a *alias) from(subQuery SelectTable) projection {
|
||||||
column := newColumn(a.alias, "", nil)
|
column := newColumn(a.alias, "", nil)
|
||||||
column.parent = &column
|
column.parent = &column
|
||||||
column.subQuery = subQuery
|
column.subQuery = subQuery
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
//BoolExpression interface
|
||||||
type BoolExpression interface {
|
type BoolExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
|
|
@ -150,6 +151,9 @@ func newBoolExpressionWrap(expression Expression) BoolExpression {
|
||||||
return &boolExpressionWrap
|
return &boolExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BoolExp is bool expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as bool expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func BoolExp(expression Expression) BoolExpression {
|
func BoolExp(expression Expression) BoolExpression {
|
||||||
return newBoolExpressionWrap(expression)
|
return newBoolExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
2
cast.go
2
cast.go
|
|
@ -36,6 +36,8 @@ type castImpl struct {
|
||||||
castType string
|
castType string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CAST wraps expression for casting.
|
||||||
|
// For instance: CAST(table.column).AS_BOOL()
|
||||||
func CAST(expression Expression) cast {
|
func CAST(expression Expression) cast {
|
||||||
return &castImpl{
|
return &castImpl{
|
||||||
Expression: expression,
|
Expression: expression,
|
||||||
|
|
|
||||||
23
clause.go
23
clause.go
|
|
@ -40,12 +40,12 @@ type sqlBuilder struct {
|
||||||
type statementType string
|
type statementType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
select_statement statementType = "SELECT"
|
selectStatement statementType = "SELECT"
|
||||||
insert_statement statementType = "INSERT"
|
insertStatement statementType = "INSERT"
|
||||||
update_statement statementType = "UPDATE"
|
updateStatement statementType = "UPDATE"
|
||||||
delete_statement statementType = "DELETE"
|
deleteStatement statementType = "DELETE"
|
||||||
set_statement statementType = "SET"
|
setStatement statementType = "SET"
|
||||||
lock_statement statementType = "LOCK"
|
lockStatement statementType = "LOCK"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultIdent = 5
|
const defaultIdent = 5
|
||||||
|
|
@ -102,7 +102,7 @@ func (q *sqlBuilder) writeGroupBy(statement statementType, groupBy []groupByClau
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *sqlBuilder) writeOrderBy(statement statementType, orderBy []OrderByClause) error {
|
func (q *sqlBuilder) writeOrderBy(statement statementType, orderBy []orderByClause) error {
|
||||||
q.newLine()
|
q.newLine()
|
||||||
q.writeString("ORDER BY")
|
q.writeString("ORDER BY")
|
||||||
|
|
||||||
|
|
@ -189,10 +189,10 @@ func (q *sqlBuilder) finalize() (string, []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *sqlBuilder) insertConstantArgument(arg interface{}) {
|
func (q *sqlBuilder) insertConstantArgument(arg interface{}) {
|
||||||
q.writeString(ArgToString(arg))
|
q.writeString(argToString(arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *sqlBuilder) insertPreparedArgument(arg interface{}) {
|
func (q *sqlBuilder) insertParametrizedArgument(arg interface{}) {
|
||||||
q.args = append(q.args, arg)
|
q.args = append(q.args, arg)
|
||||||
argPlaceholder := "$" + strconv.Itoa(len(q.args))
|
argPlaceholder := "$" + strconv.Itoa(len(q.args))
|
||||||
|
|
||||||
|
|
@ -204,7 +204,7 @@ func (q *sqlBuilder) reset() {
|
||||||
q.args = []interface{}{}
|
q.args = []interface{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ArgToString(value interface{}) string {
|
func argToString(value interface{}) string {
|
||||||
if isNil(value) {
|
if isNil(value) {
|
||||||
return "NULL"
|
return "NULL"
|
||||||
}
|
}
|
||||||
|
|
@ -213,9 +213,8 @@ func ArgToString(value interface{}) string {
|
||||||
case bool:
|
case bool:
|
||||||
if bindVal {
|
if bindVal {
|
||||||
return "TRUE"
|
return "TRUE"
|
||||||
} else {
|
|
||||||
return "FALSE"
|
|
||||||
}
|
}
|
||||||
|
return "FALSE"
|
||||||
case int8:
|
case int8:
|
||||||
return strconv.FormatInt(int64(bindVal), 10)
|
return strconv.FormatInt(int64(bindVal), 10)
|
||||||
case int:
|
case int:
|
||||||
|
|
|
||||||
18
column.go
18
column.go
|
|
@ -7,10 +7,11 @@ type column interface {
|
||||||
TableName() string
|
TableName() string
|
||||||
|
|
||||||
setTableName(table string)
|
setTableName(table string)
|
||||||
setSubQuery(subQuery ExpressionTable)
|
setSubQuery(subQuery SelectTable)
|
||||||
defaultAlias() string
|
defaultAlias() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Column is common column interface for all types of columns.
|
||||||
type Column interface {
|
type Column interface {
|
||||||
Expression
|
Expression
|
||||||
column
|
column
|
||||||
|
|
@ -23,7 +24,7 @@ type columnImpl struct {
|
||||||
name string
|
name string
|
||||||
tableName string
|
tableName string
|
||||||
|
|
||||||
subQuery ExpressionTable
|
subQuery SelectTable
|
||||||
}
|
}
|
||||||
|
|
||||||
func newColumn(name string, tableName string, parent Column) columnImpl {
|
func newColumn(name string, tableName string, parent Column) columnImpl {
|
||||||
|
|
@ -49,7 +50,7 @@ func (c *columnImpl) setTableName(table string) {
|
||||||
c.tableName = table
|
c.tableName = table
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *columnImpl) setSubQuery(subQuery ExpressionTable) {
|
func (c *columnImpl) setSubQuery(subQuery SelectTable) {
|
||||||
c.subQuery = subQuery
|
c.subQuery = subQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +63,7 @@ func (c *columnImpl) defaultAlias() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *columnImpl) serializeForOrderBy(statement statementType, out *sqlBuilder) error {
|
func (c *columnImpl) serializeForOrderBy(statement statementType, out *sqlBuilder) error {
|
||||||
if statement == set_statement {
|
if statement == setStatement {
|
||||||
// set Statement (UNION, EXCEPT ...) can reference only select projections in order by clause
|
// set Statement (UNION, EXCEPT ...) can reference only select projections in order by clause
|
||||||
out.writeString(`"` + c.defaultAlias() + `"`) //always quote
|
out.writeString(`"` + c.defaultAlias() + `"`) //always quote
|
||||||
|
|
||||||
|
|
@ -104,13 +105,13 @@ func (c columnImpl) serialize(statement statementType, out *sqlBuilder, options
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
// Redefined type to support list of columns as projection
|
// ColumnList is redefined type to support list of columns as single projection
|
||||||
type ColumnList []Column
|
type ColumnList []Column
|
||||||
|
|
||||||
// projection interface implementation
|
// projection interface implementation
|
||||||
func (cl ColumnList) isProjectionType() {}
|
func (cl ColumnList) isProjectionType() {}
|
||||||
|
|
||||||
func (cl ColumnList) from(subQuery ExpressionTable) projection {
|
func (cl ColumnList) from(subQuery SelectTable) projection {
|
||||||
newProjectionList := ProjectionList{}
|
newProjectionList := ProjectionList{}
|
||||||
|
|
||||||
for _, column := range cl {
|
for _, column := range cl {
|
||||||
|
|
@ -134,8 +135,11 @@ func (cl ColumnList) serializeForProjection(statement statementType, out *sqlBui
|
||||||
|
|
||||||
// dummy column interface implementation
|
// dummy column interface implementation
|
||||||
|
|
||||||
|
// Name is placeholder for ColumnList to implement Column interface
|
||||||
func (cl ColumnList) Name() string { return "" }
|
func (cl ColumnList) Name() string { return "" }
|
||||||
|
|
||||||
|
// TableName is placeholder for ColumnList to implement Column interface
|
||||||
func (cl ColumnList) TableName() string { return "" }
|
func (cl ColumnList) TableName() string { return "" }
|
||||||
func (cl ColumnList) setTableName(name string) {}
|
func (cl ColumnList) setTableName(name string) {}
|
||||||
func (cl ColumnList) setSubQuery(subQuery ExpressionTable) {}
|
func (cl ColumnList) setSubQuery(subQuery SelectTable) {}
|
||||||
func (cl ColumnList) defaultAlias() string { return "" }
|
func (cl ColumnList) defaultAlias() string { return "" }
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// ColumnBool is interface for SQL boolean columns.
|
||||||
type ColumnBool interface {
|
type ColumnBool interface {
|
||||||
BoolExpression
|
BoolExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnBool
|
From(subQuery SelectTable) ColumnBool
|
||||||
}
|
}
|
||||||
|
|
||||||
type boolColumnImpl struct {
|
type boolColumnImpl struct {
|
||||||
|
|
@ -13,7 +14,7 @@ type boolColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *boolColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *boolColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newBoolColumn := BoolColumn(i.name)
|
newBoolColumn := BoolColumn(i.name)
|
||||||
newBoolColumn.setTableName(i.tableName)
|
newBoolColumn.setTableName(i.tableName)
|
||||||
newBoolColumn.setSubQuery(subQuery)
|
newBoolColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -21,12 +22,13 @@ func (i *boolColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newBoolColumn
|
return newBoolColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *boolColumnImpl) From(subQuery ExpressionTable) ColumnBool {
|
func (i *boolColumnImpl) From(subQuery SelectTable) ColumnBool {
|
||||||
newBoolColumn := i.from(subQuery).(ColumnBool)
|
newBoolColumn := i.from(subQuery).(ColumnBool)
|
||||||
|
|
||||||
return newBoolColumn
|
return newBoolColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BoolColumn creates named bool column.
|
||||||
func BoolColumn(name string) ColumnBool {
|
func BoolColumn(name string) ColumnBool {
|
||||||
boolColumn := &boolColumnImpl{}
|
boolColumn := &boolColumnImpl{}
|
||||||
boolColumn.columnImpl = newColumn(name, "", boolColumn)
|
boolColumn.columnImpl = newColumn(name, "", boolColumn)
|
||||||
|
|
@ -37,11 +39,12 @@ func BoolColumn(name string) ColumnBool {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnFloat is interface for SQL real, numeric, decimal or double precision column.
|
||||||
type ColumnFloat interface {
|
type ColumnFloat interface {
|
||||||
FloatExpression
|
FloatExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnFloat
|
From(subQuery SelectTable) ColumnFloat
|
||||||
}
|
}
|
||||||
|
|
||||||
type floatColumnImpl struct {
|
type floatColumnImpl struct {
|
||||||
|
|
@ -49,7 +52,7 @@ type floatColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *floatColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *floatColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newFloatColumn := FloatColumn(i.name)
|
newFloatColumn := FloatColumn(i.name)
|
||||||
newFloatColumn.setTableName(i.tableName)
|
newFloatColumn.setTableName(i.tableName)
|
||||||
newFloatColumn.setSubQuery(subQuery)
|
newFloatColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -57,12 +60,13 @@ func (i *floatColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newFloatColumn
|
return newFloatColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *floatColumnImpl) From(subQuery ExpressionTable) ColumnFloat {
|
func (i *floatColumnImpl) From(subQuery SelectTable) ColumnFloat {
|
||||||
newFloatColumn := i.from(subQuery).(ColumnFloat)
|
newFloatColumn := i.from(subQuery).(ColumnFloat)
|
||||||
|
|
||||||
return newFloatColumn
|
return newFloatColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FloatColumn creates named float column.
|
||||||
func FloatColumn(name string) ColumnFloat {
|
func FloatColumn(name string) ColumnFloat {
|
||||||
floatColumn := &floatColumnImpl{}
|
floatColumn := &floatColumnImpl{}
|
||||||
floatColumn.floatInterfaceImpl.parent = floatColumn
|
floatColumn.floatInterfaceImpl.parent = floatColumn
|
||||||
|
|
@ -73,11 +77,12 @@ func FloatColumn(name string) ColumnFloat {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnInteger is interface for SQL smallint, integer, bigint columns.
|
||||||
type ColumnInteger interface {
|
type ColumnInteger interface {
|
||||||
IntegerExpression
|
IntegerExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnInteger
|
From(subQuery SelectTable) ColumnInteger
|
||||||
}
|
}
|
||||||
|
|
||||||
type integerColumnImpl struct {
|
type integerColumnImpl struct {
|
||||||
|
|
@ -86,7 +91,7 @@ type integerColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *integerColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *integerColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newIntColumn := IntegerColumn(i.name)
|
newIntColumn := IntegerColumn(i.name)
|
||||||
newIntColumn.setTableName(i.tableName)
|
newIntColumn.setTableName(i.tableName)
|
||||||
newIntColumn.setSubQuery(subQuery)
|
newIntColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -94,10 +99,11 @@ func (i *integerColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newIntColumn
|
return newIntColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *integerColumnImpl) From(subQuery ExpressionTable) ColumnInteger {
|
func (i *integerColumnImpl) From(subQuery SelectTable) ColumnInteger {
|
||||||
return i.from(subQuery).(ColumnInteger)
|
return i.from(subQuery).(ColumnInteger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IntegerColumn creates named integer column.
|
||||||
func IntegerColumn(name string) ColumnInteger {
|
func IntegerColumn(name string) ColumnInteger {
|
||||||
integerColumn := &integerColumnImpl{}
|
integerColumn := &integerColumnImpl{}
|
||||||
integerColumn.integerInterfaceImpl.parent = integerColumn
|
integerColumn.integerInterfaceImpl.parent = integerColumn
|
||||||
|
|
@ -108,11 +114,13 @@ func IntegerColumn(name string) ColumnInteger {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnString is interface for SQL text, character, character varying
|
||||||
|
// bytea, uuid columns and enums types.
|
||||||
type ColumnString interface {
|
type ColumnString interface {
|
||||||
StringExpression
|
StringExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnString
|
From(subQuery SelectTable) ColumnString
|
||||||
}
|
}
|
||||||
|
|
||||||
type stringColumnImpl struct {
|
type stringColumnImpl struct {
|
||||||
|
|
@ -121,7 +129,7 @@ type stringColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *stringColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *stringColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newStrColumn := StringColumn(i.name)
|
newStrColumn := StringColumn(i.name)
|
||||||
newStrColumn.setTableName(i.tableName)
|
newStrColumn.setTableName(i.tableName)
|
||||||
newStrColumn.setSubQuery(subQuery)
|
newStrColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -129,10 +137,11 @@ func (i *stringColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newStrColumn
|
return newStrColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *stringColumnImpl) From(subQuery ExpressionTable) ColumnString {
|
func (i *stringColumnImpl) From(subQuery SelectTable) ColumnString {
|
||||||
return i.from(subQuery).(ColumnString)
|
return i.from(subQuery).(ColumnString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StringColumn creates named string column.
|
||||||
func StringColumn(name string) ColumnString {
|
func StringColumn(name string) ColumnString {
|
||||||
stringColumn := &stringColumnImpl{}
|
stringColumn := &stringColumnImpl{}
|
||||||
stringColumn.stringInterfaceImpl.parent = stringColumn
|
stringColumn.stringInterfaceImpl.parent = stringColumn
|
||||||
|
|
@ -143,11 +152,12 @@ func StringColumn(name string) ColumnString {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnTime is interface for SQL time column.
|
||||||
type ColumnTime interface {
|
type ColumnTime interface {
|
||||||
TimeExpression
|
TimeExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnTime
|
From(subQuery SelectTable) ColumnTime
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeColumnImpl struct {
|
type timeColumnImpl struct {
|
||||||
|
|
@ -155,7 +165,7 @@ type timeColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *timeColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *timeColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newTimeColumn := TimeColumn(i.name)
|
newTimeColumn := TimeColumn(i.name)
|
||||||
newTimeColumn.setTableName(i.tableName)
|
newTimeColumn.setTableName(i.tableName)
|
||||||
newTimeColumn.setSubQuery(subQuery)
|
newTimeColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -163,10 +173,11 @@ func (i *timeColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newTimeColumn
|
return newTimeColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *timeColumnImpl) From(subQuery ExpressionTable) ColumnTime {
|
func (i *timeColumnImpl) From(subQuery SelectTable) ColumnTime {
|
||||||
return i.from(subQuery).(ColumnTime)
|
return i.from(subQuery).(ColumnTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimeColumn creates named time column
|
||||||
func TimeColumn(name string) ColumnTime {
|
func TimeColumn(name string) ColumnTime {
|
||||||
timeColumn := &timeColumnImpl{}
|
timeColumn := &timeColumnImpl{}
|
||||||
timeColumn.timeInterfaceImpl.parent = timeColumn
|
timeColumn.timeInterfaceImpl.parent = timeColumn
|
||||||
|
|
@ -176,11 +187,12 @@ func TimeColumn(name string) ColumnTime {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnTimez is interface of SQL time with time zone columns.
|
||||||
type ColumnTimez interface {
|
type ColumnTimez interface {
|
||||||
TimezExpression
|
TimezExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnTimez
|
From(subQuery SelectTable) ColumnTimez
|
||||||
}
|
}
|
||||||
|
|
||||||
type timezColumnImpl struct {
|
type timezColumnImpl struct {
|
||||||
|
|
@ -189,7 +201,7 @@ type timezColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *timezColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *timezColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newTimezColumn := TimezColumn(i.name)
|
newTimezColumn := TimezColumn(i.name)
|
||||||
newTimezColumn.setTableName(i.tableName)
|
newTimezColumn.setTableName(i.tableName)
|
||||||
newTimezColumn.setSubQuery(subQuery)
|
newTimezColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -197,10 +209,11 @@ func (i *timezColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newTimezColumn
|
return newTimezColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *timezColumnImpl) From(subQuery ExpressionTable) ColumnTimez {
|
func (i *timezColumnImpl) From(subQuery SelectTable) ColumnTimez {
|
||||||
return i.from(subQuery).(ColumnTimez)
|
return i.from(subQuery).(ColumnTimez)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimezColumn creates named time with time zone column.
|
||||||
func TimezColumn(name string) ColumnTimez {
|
func TimezColumn(name string) ColumnTimez {
|
||||||
timezColumn := &timezColumnImpl{}
|
timezColumn := &timezColumnImpl{}
|
||||||
timezColumn.timezInterfaceImpl.parent = timezColumn
|
timezColumn.timezInterfaceImpl.parent = timezColumn
|
||||||
|
|
@ -211,11 +224,12 @@ func TimezColumn(name string) ColumnTimez {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnTimestamp is interface of SQL timestamp columns.
|
||||||
type ColumnTimestamp interface {
|
type ColumnTimestamp interface {
|
||||||
TimestampExpression
|
TimestampExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnTimestamp
|
From(subQuery SelectTable) ColumnTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
type timestampColumnImpl struct {
|
type timestampColumnImpl struct {
|
||||||
|
|
@ -224,7 +238,7 @@ type timestampColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *timestampColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *timestampColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newTimestampColumn := TimestampColumn(i.name)
|
newTimestampColumn := TimestampColumn(i.name)
|
||||||
newTimestampColumn.setTableName(i.tableName)
|
newTimestampColumn.setTableName(i.tableName)
|
||||||
newTimestampColumn.setSubQuery(subQuery)
|
newTimestampColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -232,10 +246,11 @@ func (i *timestampColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newTimestampColumn
|
return newTimestampColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *timestampColumnImpl) From(subQuery ExpressionTable) ColumnTimestamp {
|
func (i *timestampColumnImpl) From(subQuery SelectTable) ColumnTimestamp {
|
||||||
return i.from(subQuery).(ColumnTimestamp)
|
return i.from(subQuery).(ColumnTimestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimestampColumn creates named timestamp column
|
||||||
func TimestampColumn(name string) ColumnTimestamp {
|
func TimestampColumn(name string) ColumnTimestamp {
|
||||||
timestampColumn := ×tampColumnImpl{}
|
timestampColumn := ×tampColumnImpl{}
|
||||||
timestampColumn.timestampInterfaceImpl.parent = timestampColumn
|
timestampColumn.timestampInterfaceImpl.parent = timestampColumn
|
||||||
|
|
@ -246,11 +261,12 @@ func TimestampColumn(name string) ColumnTimestamp {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnTimestampz is interface of SQL timestamp with timezone columns.
|
||||||
type ColumnTimestampz interface {
|
type ColumnTimestampz interface {
|
||||||
TimestampzExpression
|
TimestampzExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnTimestampz
|
From(subQuery SelectTable) ColumnTimestampz
|
||||||
}
|
}
|
||||||
|
|
||||||
type timestampzColumnImpl struct {
|
type timestampzColumnImpl struct {
|
||||||
|
|
@ -259,7 +275,7 @@ type timestampzColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *timestampzColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *timestampzColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newTimestampzColumn := TimestampzColumn(i.name)
|
newTimestampzColumn := TimestampzColumn(i.name)
|
||||||
newTimestampzColumn.setTableName(i.tableName)
|
newTimestampzColumn.setTableName(i.tableName)
|
||||||
newTimestampzColumn.setSubQuery(subQuery)
|
newTimestampzColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -267,10 +283,11 @@ func (i *timestampzColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newTimestampzColumn
|
return newTimestampzColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *timestampzColumnImpl) From(subQuery ExpressionTable) ColumnTimestampz {
|
func (i *timestampzColumnImpl) From(subQuery SelectTable) ColumnTimestampz {
|
||||||
return i.from(subQuery).(ColumnTimestampz)
|
return i.from(subQuery).(ColumnTimestampz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimestampzColumn creates named timestamp with time zone column.
|
||||||
func TimestampzColumn(name string) ColumnTimestampz {
|
func TimestampzColumn(name string) ColumnTimestampz {
|
||||||
timestampzColumn := ×tampzColumnImpl{}
|
timestampzColumn := ×tampzColumnImpl{}
|
||||||
timestampzColumn.timestampzInterfaceImpl.parent = timestampzColumn
|
timestampzColumn.timestampzInterfaceImpl.parent = timestampzColumn
|
||||||
|
|
@ -281,11 +298,12 @@ func TimestampzColumn(name string) ColumnTimestampz {
|
||||||
|
|
||||||
//------------------------------------------------------//
|
//------------------------------------------------------//
|
||||||
|
|
||||||
|
// ColumnDate is interface of SQL date columns.
|
||||||
type ColumnDate interface {
|
type ColumnDate interface {
|
||||||
DateExpression
|
DateExpression
|
||||||
column
|
column
|
||||||
|
|
||||||
From(subQuery ExpressionTable) ColumnDate
|
From(subQuery SelectTable) ColumnDate
|
||||||
}
|
}
|
||||||
|
|
||||||
type dateColumnImpl struct {
|
type dateColumnImpl struct {
|
||||||
|
|
@ -294,7 +312,7 @@ type dateColumnImpl struct {
|
||||||
columnImpl
|
columnImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dateColumnImpl) from(subQuery ExpressionTable) projection {
|
func (i *dateColumnImpl) from(subQuery SelectTable) projection {
|
||||||
newDateColumn := DateColumn(i.name)
|
newDateColumn := DateColumn(i.name)
|
||||||
newDateColumn.setTableName(i.tableName)
|
newDateColumn.setTableName(i.tableName)
|
||||||
newDateColumn.setSubQuery(subQuery)
|
newDateColumn.setSubQuery(subQuery)
|
||||||
|
|
@ -302,10 +320,11 @@ func (i *dateColumnImpl) from(subQuery ExpressionTable) projection {
|
||||||
return newDateColumn
|
return newDateColumn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dateColumnImpl) From(subQuery ExpressionTable) ColumnDate {
|
func (i *dateColumnImpl) From(subQuery SelectTable) ColumnDate {
|
||||||
return i.from(subQuery).(ColumnDate)
|
return i.from(subQuery).(ColumnDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DateColumn creates named date column.
|
||||||
func DateColumn(name string) ColumnDate {
|
func DateColumn(name string) ColumnDate {
|
||||||
dateColumn := &dateColumnImpl{}
|
dateColumn := &dateColumnImpl{}
|
||||||
dateColumn.dateInterfaceImpl.parent = dateColumn
|
dateColumn.dateInterfaceImpl.parent = dateColumn
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// DateExpression is interface for all SQL date expressions.
|
||||||
type DateExpression interface {
|
type DateExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
|
|
@ -63,6 +64,9 @@ func newDateExpressionWrap(expression Expression) DateExpression {
|
||||||
return &dateExpressionWrap
|
return &dateExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DateExp is date expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as date expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func DateExp(expression Expression) DateExpression {
|
func DateExp(expression Expression) DateExpression {
|
||||||
return newDateExpressionWrap(expression)
|
return newDateExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/go-jet/jet/execution"
|
"github.com/go-jet/jet/execution"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DeleteStatement is interface for SQL DELETE statement
|
||||||
type DeleteStatement interface {
|
type DeleteStatement interface {
|
||||||
Statement
|
Statement
|
||||||
|
|
||||||
|
|
@ -48,7 +49,7 @@ func (d *deleteStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
return errors.New("jet: nil tableName")
|
return errors.New("jet: nil tableName")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.table.serialize(delete_statement, out); err != nil {
|
if err := d.table.serialize(deleteStatement, out); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,11 +57,11 @@ func (d *deleteStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
return errors.New("jet: deleting without a WHERE clause")
|
return errors.New("jet: deleting without a WHERE clause")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := out.writeWhere(delete_statement, d.where); err != nil {
|
if err := out.writeWhere(deleteStatement, d.where); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := out.writeReturning(delete_statement, d.returning); err != nil {
|
if err := out.writeReturning(deleteStatement, d.returning); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,7 +90,7 @@ func (d *deleteStatementImpl) Query(db execution.DB, destination interface{}) er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (d *deleteStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return queryContext(d, db, context, destination)
|
return queryContext(context, d, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (d *deleteStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
|
|
|
||||||
2
doc.go
2
doc.go
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Package Jet is a framework for writing type-safe SQL queries for PostgreSQL in Go, with ability
|
Package jet is a framework for writing type-safe SQL queries for PostgreSQL in Go, with ability
|
||||||
to easily convert database query result to desired arbitrary structure.
|
to easily convert database query result to desired arbitrary structure.
|
||||||
*/
|
*/
|
||||||
package jet
|
package jet
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ type enumValue struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEnumValue creates new named enum value
|
||||||
func NewEnumValue(name string) StringExpression {
|
func NewEnumValue(name string) StringExpression {
|
||||||
enumValue := &enumValue{name: name}
|
enumValue := &enumValue{name: name}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,13 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common expression interface
|
// Expression is common interface for all expressions.
|
||||||
|
// Can be Bool, Int, Float, String, Date, Time, Timez, Timestamp or Timestampz expressions.
|
||||||
type Expression interface {
|
type Expression interface {
|
||||||
clause
|
clause
|
||||||
projection
|
projection
|
||||||
groupByClause
|
groupByClause
|
||||||
OrderByClause
|
orderByClause
|
||||||
|
|
||||||
// Test expression whether it is a NULL value.
|
// Test expression whether it is a NULL value.
|
||||||
IS_NULL() BoolExpression
|
IS_NULL() BoolExpression
|
||||||
|
|
@ -25,16 +26,16 @@ type Expression interface {
|
||||||
AS(alias string) projection
|
AS(alias string) projection
|
||||||
|
|
||||||
// Expression will be used to sort query result in ascending order
|
// Expression will be used to sort query result in ascending order
|
||||||
ASC() OrderByClause
|
ASC() orderByClause
|
||||||
// Expression will be used to sort query result in ascending order
|
// Expression will be used to sort query result in ascending order
|
||||||
DESC() OrderByClause
|
DESC() orderByClause
|
||||||
}
|
}
|
||||||
|
|
||||||
type expressionInterfaceImpl struct {
|
type expressionInterfaceImpl struct {
|
||||||
parent Expression
|
parent Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *expressionInterfaceImpl) from(subQuery ExpressionTable) projection {
|
func (e *expressionInterfaceImpl) from(subQuery SelectTable) projection {
|
||||||
return e.parent
|
return e.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,11 +59,11 @@ func (e *expressionInterfaceImpl) AS(alias string) projection {
|
||||||
return newAlias(e.parent, alias)
|
return newAlias(e.parent, alias)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *expressionInterfaceImpl) ASC() OrderByClause {
|
func (e *expressionInterfaceImpl) ASC() orderByClause {
|
||||||
return newOrderByClause(e.parent, true)
|
return newOrderByClause(e.parent, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *expressionInterfaceImpl) DESC() OrderByClause {
|
func (e *expressionInterfaceImpl) DESC() orderByClause {
|
||||||
return newOrderByClause(e.parent, false)
|
return newOrderByClause(e.parent, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,13 +146,13 @@ func newPrefixExpression(expression Expression, operator string) prefixOpExpress
|
||||||
|
|
||||||
func (p *prefixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
|
func (p *prefixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return errors.New("jet: Prefix Expression is nil.")
|
return errors.New("jet: Prefix Expression is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
out.writeString(p.operator + " ")
|
out.writeString(p.operator + " ")
|
||||||
|
|
||||||
if p.expression == nil {
|
if p.expression == nil {
|
||||||
return errors.New("jet: nil prefix Expression.")
|
return errors.New("jet: nil prefix Expression")
|
||||||
}
|
}
|
||||||
if err := p.expression.serialize(statement, out); err != nil {
|
if err := p.expression.serialize(statement, out); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -177,11 +178,11 @@ func newPostfixOpExpression(expression Expression, operator string) postfixOpExp
|
||||||
|
|
||||||
func (p *postfixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
|
func (p *postfixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return errors.New("jet: Postifx operator Expression is nil.")
|
return errors.New("jet: Postifx operator Expression is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.expression == nil {
|
if p.expression == nil {
|
||||||
return errors.New("jet: nil prefix Expression.")
|
return errors.New("jet: nil prefix Expression")
|
||||||
}
|
}
|
||||||
if err := p.expression.serialize(statement, out); err != nil {
|
if err := p.expression.serialize(statement, out); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
package jet
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
type ExpressionTable interface {
|
|
||||||
ReadableTable
|
|
||||||
|
|
||||||
Alias() string
|
|
||||||
|
|
||||||
AllColumns() ProjectionList
|
|
||||||
}
|
|
||||||
|
|
||||||
type expressionTableImpl struct {
|
|
||||||
readableTableInterfaceImpl
|
|
||||||
expression Expression
|
|
||||||
alias string
|
|
||||||
|
|
||||||
projections []projection
|
|
||||||
}
|
|
||||||
|
|
||||||
func newExpressionTable(expression Expression, alias string, projections []projection) ExpressionTable {
|
|
||||||
expTable := &expressionTableImpl{expression: expression, alias: alias}
|
|
||||||
|
|
||||||
expTable.readableTableInterfaceImpl.parent = expTable
|
|
||||||
|
|
||||||
for _, projection := range projections {
|
|
||||||
newProjection := projection.from(expTable)
|
|
||||||
|
|
||||||
expTable.projections = append(expTable.projections, newProjection)
|
|
||||||
}
|
|
||||||
|
|
||||||
return expTable
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *expressionTableImpl) Alias() string {
|
|
||||||
return e.alias
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *expressionTableImpl) columns() []column {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *expressionTableImpl) AllColumns() ProjectionList {
|
|
||||||
return e.projections
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *expressionTableImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
|
|
||||||
if e == nil {
|
|
||||||
return errors.New("jet: Expression table is nil. ")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := e.expression.serialize(statement, out)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
out.writeString("AS")
|
|
||||||
out.writeIdentifier(e.alias)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
//FloatExpression is interface for SQL float columns
|
||||||
type FloatExpression interface {
|
type FloatExpression interface {
|
||||||
Expression
|
Expression
|
||||||
numericExpression
|
numericExpression
|
||||||
|
|
@ -115,6 +116,9 @@ func newFloatExpressionWrap(expression Expression) FloatExpression {
|
||||||
return &floatExpressionWrap
|
return &floatExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FloatExp is date expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as float expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func FloatExp(expression Expression) FloatExpression {
|
func FloatExp(expression Expression) FloatExpression {
|
||||||
return newFloatExpressionWrap(expression)
|
return newFloatExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,466 @@ package jet
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
|
// ROW is construct one table row from list of expressions.
|
||||||
|
func ROW(expressions ...Expression) Expression {
|
||||||
|
return newFunc("ROW", expressions, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------ Mathematical functions ---------------//
|
||||||
|
|
||||||
|
// ABSf calculates absolute value from float expression
|
||||||
|
func ABSf(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("ABS", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSi calculates absolute value from int expression
|
||||||
|
func ABSi(integerExpression IntegerExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("ABS", integerExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SQRT calculates square root of numeric expression
|
||||||
|
func SQRT(numericExpression NumericExpression) FloatExpression {
|
||||||
|
return newFloatFunc("SQRT", numericExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CBRT calculates cube root of numeric expression
|
||||||
|
func CBRT(numericExpression NumericExpression) FloatExpression {
|
||||||
|
return newFloatFunc("CBRT", numericExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CEIL calculates ceil of float expression
|
||||||
|
func CEIL(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("CEIL", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FLOOR calculates floor of float expression
|
||||||
|
func FLOOR(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("FLOOR", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROUND calculates round of a float expressions with optional precision
|
||||||
|
func ROUND(floatExpression FloatExpression, precision ...IntegerExpression) FloatExpression {
|
||||||
|
if len(precision) > 0 {
|
||||||
|
return newFloatFunc("ROUND", floatExpression, precision[0])
|
||||||
|
}
|
||||||
|
return newFloatFunc("ROUND", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIGN returns sign of float expression
|
||||||
|
func SIGN(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("SIGN", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TRUNC calculates trunc of float expression with optional precision
|
||||||
|
func TRUNC(floatExpression FloatExpression, precision ...IntegerExpression) FloatExpression {
|
||||||
|
if len(precision) > 0 {
|
||||||
|
return newFloatFunc("TRUNC", floatExpression, precision[0])
|
||||||
|
}
|
||||||
|
return newFloatFunc("TRUNC", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LN calculates natural algorithm of float expression
|
||||||
|
func LN(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("LN", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG calculates logarithm of float expression
|
||||||
|
func LOG(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("LOG", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------- Aggregate functions -------------------//
|
||||||
|
|
||||||
|
// AVG is aggregate function used to calculate avg value from numeric expression
|
||||||
|
func AVG(numericExpression NumericExpression) FloatExpression {
|
||||||
|
return newFloatFunc("AVG", numericExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BIT_AND is aggregate function used to calculates the bitwise AND of all non-null input values, or null if none.
|
||||||
|
func BIT_AND(integerExpression IntegerExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("BIT_AND", integerExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BIT_OR is aggregate function used to calculates the bitwise OR of all non-null input values, or null if none.
|
||||||
|
func BIT_OR(integerExpression IntegerExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("BIT_OR", integerExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BOOL_AND is aggregate function. Returns true if all input values are true, otherwise false
|
||||||
|
func BOOL_AND(boolExpression BoolExpression) BoolExpression {
|
||||||
|
return newBoolFunc("BOOL_AND", boolExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BOOL_OR is aggregate function. Returns true if at least one input value is true, otherwise false
|
||||||
|
func BOOL_OR(boolExpression BoolExpression) BoolExpression {
|
||||||
|
return newBoolFunc("BOOL_OR", boolExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// COUNT is aggregate function. Returns number of input rows for which the value of expression is not null.
|
||||||
|
func COUNT(expression Expression) IntegerExpression {
|
||||||
|
return newIntegerFunc("COUNT", expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EVERY is aggregate function. Returns true if all input values are true, otherwise false
|
||||||
|
func EVERY(boolExpression BoolExpression) BoolExpression {
|
||||||
|
return newBoolFunc("EVERY", boolExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MAXf is aggregate function. Returns maximum value of float expression across all input values
|
||||||
|
func MAXf(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("MAX", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MAXi is aggregate function. Returns maximum value of int expression across all input values
|
||||||
|
func MAXi(integerExpression IntegerExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("MAX", integerExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MINf is aggregate function. Returns minimum value of float expression across all input values
|
||||||
|
func MINf(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("MIN", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MINi is aggregate function. Returns minimum value of int expression across all input values
|
||||||
|
func MINi(integerExpression IntegerExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("MIN", integerExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUMf is aggregate function. Returns sum of expression across all float expressions
|
||||||
|
func SUMf(floatExpression FloatExpression) FloatExpression {
|
||||||
|
return newFloatFunc("SUM", floatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUMi is aggregate function. Returns sum of expression across all integer expression.
|
||||||
|
func SUMi(integerExpression IntegerExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("SUM", integerExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------ String functions ------------------//
|
||||||
|
|
||||||
|
// BIT_LENGTH returns number of bits in string expression
|
||||||
|
func BIT_LENGTH(stringExpression StringExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("BIT_LENGTH", stringExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHAR_LENGTH returns number of characters in string expression
|
||||||
|
func CHAR_LENGTH(stringExpression StringExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("CHAR_LENGTH", stringExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OCTET_LENGTH returns number of bytes in string expression
|
||||||
|
func OCTET_LENGTH(stringExpression StringExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("OCTET_LENGTH", stringExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOWER returns string expression in lower case
|
||||||
|
func LOWER(stringExpression StringExpression) StringExpression {
|
||||||
|
return newStringFunc("LOWER", stringExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPPER returns string expression in upper case
|
||||||
|
func UPPER(stringExpression StringExpression) StringExpression {
|
||||||
|
return newStringFunc("UPPER", stringExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BTRIM removes the longest string consisting only of characters
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LTRIM removes the longest string containing only characters
|
||||||
|
// from characters (a space by default) from the start of string
|
||||||
|
func LTRIM(str StringExpression, trimChars ...StringExpression) StringExpression {
|
||||||
|
if len(trimChars) > 0 {
|
||||||
|
return newStringFunc("LTRIM", str, trimChars[0])
|
||||||
|
}
|
||||||
|
return newStringFunc("LTRIM", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RTRIM removes the longest string containing only characters
|
||||||
|
// from characters (a space by default) from the end of string
|
||||||
|
func RTRIM(str StringExpression, trimChars ...StringExpression) StringExpression {
|
||||||
|
if len(trimChars) > 0 {
|
||||||
|
return newStringFunc("RTRIM", str, trimChars[0])
|
||||||
|
}
|
||||||
|
return newStringFunc("RTRIM", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHR returns character with the given code.
|
||||||
|
func CHR(integerExpression IntegerExpression) StringExpression {
|
||||||
|
return newStringFunc("CHR", integerExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//func CONCAT(expressions ...Expression) StringExpression {
|
||||||
|
// return newStringFunc("CONCAT", expressions...)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func CONCAT_WS(expressions ...Expression) StringExpression {
|
||||||
|
// return newStringFunc("CONCAT_WS", expressions...)
|
||||||
|
//}
|
||||||
|
|
||||||
|
// CONVERT converts string to dest_encoding. The original encoding is
|
||||||
|
// specified by src_encoding. The string must be valid in this encoding.
|
||||||
|
func CONVERT(str StringExpression, srcEncoding StringExpression, destEncoding StringExpression) StringExpression {
|
||||||
|
return newStringFunc("CONVERT", str, srcEncoding, destEncoding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONVERT_FROM converts string to the database encoding. The original
|
||||||
|
// encoding is specified by src_encoding. The string must be valid in this encoding.
|
||||||
|
func CONVERT_FROM(str StringExpression, srcEncoding StringExpression) StringExpression {
|
||||||
|
return newStringFunc("CONVERT_FROM", str, srcEncoding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONVERT_TO converts string to dest_encoding.
|
||||||
|
func CONVERT_TO(str StringExpression, toEncoding StringExpression) StringExpression {
|
||||||
|
return newStringFunc("CONVERT_TO", str, toEncoding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENCODE encodes binary data into a textual representation.
|
||||||
|
// Supported formats are: base64, hex, escape. escape converts zero bytes and
|
||||||
|
// high-bit-set bytes to octal sequences (\nnn) and doubles backslashes.
|
||||||
|
func ENCODE(data StringExpression, format StringExpression) StringExpression {
|
||||||
|
return newStringFunc("ENCODE", data, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECODE decodes binary data from textual representation in string.
|
||||||
|
// Options for format are same as in encode.
|
||||||
|
func DECODE(data StringExpression, format StringExpression) StringExpression {
|
||||||
|
return newStringFunc("DECODE", data, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
//func FORMAT(formatStr StringExpression, formatArgs ...expressions) StringExpression {
|
||||||
|
// args := []expressions{formatStr}
|
||||||
|
// args = append(args, formatArgs...)
|
||||||
|
// return newStringFunc("FORMAT", args...)
|
||||||
|
//}
|
||||||
|
|
||||||
|
// INITCAP converts the first letter of each word to upper case
|
||||||
|
// and the rest to lower case. Words are sequences of alphanumeric
|
||||||
|
// characters separated by non-alphanumeric characters.
|
||||||
|
func INITCAP(str StringExpression) StringExpression {
|
||||||
|
return newStringFunc("INITCAP", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LEFT returns first n characters in the string.
|
||||||
|
// When n is negative, return all but last |n| characters.
|
||||||
|
func LEFT(str StringExpression, n IntegerExpression) StringExpression {
|
||||||
|
return newStringFunc("LEFT", str, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RIGHT returns last n characters in the string.
|
||||||
|
// When n is negative, return all but first |n| characters.
|
||||||
|
func RIGHT(str StringExpression, n IntegerExpression) StringExpression {
|
||||||
|
return newStringFunc("RIGHT", str, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LENGTH returns number of characters in string with a given encoding
|
||||||
|
func LENGTH(str StringExpression, encoding ...StringExpression) StringExpression {
|
||||||
|
if len(encoding) > 0 {
|
||||||
|
return newStringFunc("LENGTH", str, encoding[0])
|
||||||
|
}
|
||||||
|
return newStringFunc("LENGTH", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LPAD fills up the string to length length by prepending the characters
|
||||||
|
// fill (a space by default). If the string is already longer than length
|
||||||
|
// then it is truncated (on the right).
|
||||||
|
func LPAD(str StringExpression, length IntegerExpression, text ...StringExpression) StringExpression {
|
||||||
|
if len(text) > 0 {
|
||||||
|
return newStringFunc("LPAD", str, length, text[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return newStringFunc("LPAD", str, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPAD fills up the string to length length by appending the characters
|
||||||
|
// fill (a space by default). If the string is already longer than length then it is truncated.
|
||||||
|
func RPAD(str StringExpression, length IntegerExpression, text ...StringExpression) StringExpression {
|
||||||
|
if len(text) > 0 {
|
||||||
|
return newStringFunc("RPAD", str, length, text[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return newStringFunc("RPAD", str, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MD5 calculates the MD5 hash of string, returning the result in hexadecimal
|
||||||
|
func MD5(stringExpression StringExpression) StringExpression {
|
||||||
|
return newStringFunc("MD5", stringExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// REPEAT repeats string the specified number of times
|
||||||
|
func REPEAT(str StringExpression, n IntegerExpression) StringExpression {
|
||||||
|
return newStringFunc("REPEAT", str, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// REPLACE replaces all occurrences in string of substring from with substring to
|
||||||
|
func REPLACE(text, from, to StringExpression) StringExpression {
|
||||||
|
return newStringFunc("REPLACE", text, from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
// REVERSE returns reversed string.
|
||||||
|
func REVERSE(stringExpression StringExpression) StringExpression {
|
||||||
|
return newStringFunc("REVERSE", stringExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// STRPOS returns location of specified substring (same as position(substring in string),
|
||||||
|
// but note the reversed argument order)
|
||||||
|
func STRPOS(str, substring StringExpression) IntegerExpression {
|
||||||
|
return newIntegerFunc("STRPOS", str, substring)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUBSTR extracts substring
|
||||||
|
func SUBSTR(str StringExpression, from IntegerExpression, count ...IntegerExpression) StringExpression {
|
||||||
|
if len(count) > 0 {
|
||||||
|
return newStringFunc("SUBSTR", str, from, count[0])
|
||||||
|
}
|
||||||
|
return newStringFunc("SUBSTR", str, from)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO_ASCII convert string to ASCII from another encoding
|
||||||
|
func TO_ASCII(str StringExpression, encoding ...StringExpression) StringExpression {
|
||||||
|
if len(encoding) > 0 {
|
||||||
|
return newStringFunc("TO_ASCII", str, encoding[0])
|
||||||
|
}
|
||||||
|
return newStringFunc("TO_ASCII", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO_HEX converts number to its equivalent hexadecimal representation
|
||||||
|
func TO_HEX(number IntegerExpression) StringExpression {
|
||||||
|
return newStringFunc("TO_HEX", number)
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------Data Type Formatting Functions ----------------------//
|
||||||
|
|
||||||
|
// TO_CHAR converts expression to string with format
|
||||||
|
func TO_CHAR(expression Expression, format StringExpression) StringExpression {
|
||||||
|
return newStringFunc("TO_CHAR", expression, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO_DATE converts string to date using format
|
||||||
|
func TO_DATE(dateStr, format StringExpression) DateExpression {
|
||||||
|
return newDateFunc("TO_DATE", dateStr, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO_NUMBER converst string to numeric using format
|
||||||
|
func TO_NUMBER(floatStr, format StringExpression) FloatExpression {
|
||||||
|
return newFloatFunc("TO_NUMBER", floatStr, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO_TIMESTAMP converst string to time stamp with time zone using format
|
||||||
|
func TO_TIMESTAMP(timestampzStr, format StringExpression) TimestampzExpression {
|
||||||
|
return newTimestampzFunc("TO_TIMESTAMP", timestampzStr, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------- Date/Time Functions and Operators ---------------//
|
||||||
|
|
||||||
|
// CURRENT_DATE returns current date
|
||||||
|
func CURRENT_DATE() DateExpression {
|
||||||
|
dateFunc := newDateFunc("CURRENT_DATE")
|
||||||
|
dateFunc.noBrackets = true
|
||||||
|
return dateFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// CURRENT_TIME returns current time with time zone
|
||||||
|
func CURRENT_TIME(precision ...int) TimezExpression {
|
||||||
|
var timezFunc *timezFunc
|
||||||
|
|
||||||
|
if len(precision) > 0 {
|
||||||
|
timezFunc = newTimezFunc("CURRENT_TIME", constLiteral(precision[0]))
|
||||||
|
} else {
|
||||||
|
timezFunc = newTimezFunc("CURRENT_TIME")
|
||||||
|
}
|
||||||
|
|
||||||
|
timezFunc.noBrackets = true
|
||||||
|
|
||||||
|
return timezFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// CURRENT_TIMESTAMP returns current timestamp with time zone
|
||||||
|
func CURRENT_TIMESTAMP(precision ...int) TimestampzExpression {
|
||||||
|
var timestampzFunc *timestampzFunc
|
||||||
|
|
||||||
|
if len(precision) > 0 {
|
||||||
|
timestampzFunc = newTimestampzFunc("CURRENT_TIMESTAMP", constLiteral(precision[0]))
|
||||||
|
} else {
|
||||||
|
timestampzFunc = newTimestampzFunc("CURRENT_TIMESTAMP")
|
||||||
|
}
|
||||||
|
|
||||||
|
timestampzFunc.noBrackets = true
|
||||||
|
|
||||||
|
return timestampzFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOCALTIME returns local time of day using optional precision
|
||||||
|
func LOCALTIME(precision ...int) TimeExpression {
|
||||||
|
var timeFunc *timeFunc
|
||||||
|
|
||||||
|
if len(precision) > 0 {
|
||||||
|
timeFunc = newTimeFunc("LOCALTIME", constLiteral(precision[0]))
|
||||||
|
} else {
|
||||||
|
timeFunc = newTimeFunc("LOCALTIME")
|
||||||
|
}
|
||||||
|
|
||||||
|
timeFunc.noBrackets = true
|
||||||
|
|
||||||
|
return timeFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOCALTIMESTAMP returns current date and time using optional precision
|
||||||
|
func LOCALTIMESTAMP(precision ...int) TimestampExpression {
|
||||||
|
var timestampFunc *timestampFunc
|
||||||
|
|
||||||
|
if len(precision) > 0 {
|
||||||
|
timestampFunc = newTimestampFunc("LOCALTIMESTAMP", constLiteral(precision[0]))
|
||||||
|
} else {
|
||||||
|
timestampFunc = newTimestampFunc("LOCALTIMESTAMP")
|
||||||
|
}
|
||||||
|
|
||||||
|
timestampFunc.noBrackets = true
|
||||||
|
|
||||||
|
return timestampFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOW returns current date and time
|
||||||
|
func NOW() TimestampzExpression {
|
||||||
|
return newTimestampzFunc("NOW")
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------- Conditional Expressions Functions -------------//
|
||||||
|
|
||||||
|
// COALESCE function returns the first of its arguments that is not null.
|
||||||
|
func COALESCE(value Expression, values ...Expression) Expression {
|
||||||
|
var allValues = []Expression{value}
|
||||||
|
allValues = append(allValues, values...)
|
||||||
|
return newFunc("COALESCE", allValues, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NULLIF function returns a null value if value1 equals value2; otherwise it returns value1.
|
||||||
|
func NULLIF(value1, value2 Expression) Expression {
|
||||||
|
return newFunc("NULLIF", []Expression{value1, value2}, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GREATEST selects the largest value from a list of expressions
|
||||||
|
func GREATEST(value Expression, values ...Expression) Expression {
|
||||||
|
var allValues = []Expression{value}
|
||||||
|
allValues = append(allValues, values...)
|
||||||
|
return newFunc("GREATEST", allValues, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LEAST selects the smallest value from a list of expressions
|
||||||
|
func LEAST(value Expression, values ...Expression) Expression {
|
||||||
|
var allValues = []Expression{value}
|
||||||
|
allValues = append(allValues, values...)
|
||||||
|
return newFunc("LEAST", allValues, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------//
|
||||||
|
|
||||||
type funcExpressionImpl struct {
|
type funcExpressionImpl struct {
|
||||||
expressionInterfaceImpl
|
expressionInterfaceImpl
|
||||||
|
|
||||||
|
|
@ -175,375 +635,3 @@ func newTimestampzFunc(name string, expressions ...Expression) *timestampzFunc {
|
||||||
|
|
||||||
return timestampzFunc
|
return timestampzFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func ROW(expressions ...Expression) Expression {
|
|
||||||
return newFunc("ROW", expressions, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ Mathematical functions ---------------//
|
|
||||||
|
|
||||||
func ABSf(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("ABS", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ABSi(integerExpression IntegerExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("ABS", integerExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SQRT(numericExpression NumericExpression) FloatExpression {
|
|
||||||
return newFloatFunc("SQRT", numericExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CBRT(numericExpression NumericExpression) FloatExpression {
|
|
||||||
return newFloatFunc("CBRT", numericExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CEIL(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("CEIL", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FLOOR(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("FLOOR", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ROUND(floatExpression FloatExpression, intExpression ...IntegerExpression) FloatExpression {
|
|
||||||
if len(intExpression) > 0 {
|
|
||||||
return newFloatFunc("ROUND", floatExpression, intExpression[0])
|
|
||||||
}
|
|
||||||
return newFloatFunc("ROUND", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SIGN(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("SIGN", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TRUNC(floatExpression FloatExpression, intExpression ...IntegerExpression) FloatExpression {
|
|
||||||
if len(intExpression) > 0 {
|
|
||||||
return newFloatFunc("TRUNC", floatExpression, intExpression[0])
|
|
||||||
}
|
|
||||||
return newFloatFunc("TRUNC", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LN(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("LN", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LOG(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("LOG", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------- Aggregate functions -------------------//
|
|
||||||
|
|
||||||
func AVG(numericExpression NumericExpression) FloatExpression {
|
|
||||||
return newFloatFunc("AVG", numericExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BIT_AND(integerExpression IntegerExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("BIT_AND", integerExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BIT_OR(integerExpression IntegerExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("BIT_OR", integerExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BOOL_AND(boolExpression BoolExpression) BoolExpression {
|
|
||||||
return newBoolFunc("BOOL_AND", boolExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BOOL_OR(boolExpression BoolExpression) BoolExpression {
|
|
||||||
return newBoolFunc("BOOL_OR", boolExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func COUNT(expression Expression) IntegerExpression {
|
|
||||||
return newIntegerFunc("COUNT", expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func EVERY(boolExpression BoolExpression) BoolExpression {
|
|
||||||
return newBoolFunc("EVERY", boolExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MAXf(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("MAX", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MAXi(integerExpression IntegerExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("MAX", integerExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MINf(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("MIN", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MINi(integerExpression IntegerExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("MIN", integerExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SUMf(floatExpression FloatExpression) FloatExpression {
|
|
||||||
return newFloatFunc("SUM", floatExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SUMi(integerExpression IntegerExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("SUM", integerExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------ String functions ------------------//
|
|
||||||
|
|
||||||
func BIT_LENGTH(stringExpression StringExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("BIT_LENGTH", stringExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CHAR_LENGTH(stringExpression StringExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("CHAR_LENGTH", stringExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func OCTET_LENGTH(stringExpression StringExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("OCTET_LENGTH", stringExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LOWER(stringExpression StringExpression) StringExpression {
|
|
||||||
return newStringFunc("LOWER", stringExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UPPER(stringExpression StringExpression) StringExpression {
|
|
||||||
return newStringFunc("UPPER", stringExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BTRIM(stringExpression StringExpression) StringExpression {
|
|
||||||
return newStringFunc("BTRIM", stringExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LTRIM(str StringExpression, trimChars ...StringExpression) StringExpression {
|
|
||||||
if len(trimChars) > 0 {
|
|
||||||
return newStringFunc("LTRIM", str, trimChars[0])
|
|
||||||
}
|
|
||||||
return newStringFunc("LTRIM", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RTRIM(str StringExpression, trimChars ...StringExpression) StringExpression {
|
|
||||||
if len(trimChars) > 0 {
|
|
||||||
return newStringFunc("RTRIM", str, trimChars[0])
|
|
||||||
}
|
|
||||||
return newStringFunc("RTRIM", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CHR(integerExpression IntegerExpression) StringExpression {
|
|
||||||
return newStringFunc("CHR", integerExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//func CONCAT(expressions ...Expression) StringExpression {
|
|
||||||
// return newStringFunc("CONCAT", expressions...)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func CONCAT_WS(expressions ...Expression) StringExpression {
|
|
||||||
// return newStringFunc("CONCAT_WS", expressions...)
|
|
||||||
//}
|
|
||||||
|
|
||||||
func CONVERT(str StringExpression, fromEncoding StringExpression, toEncoding StringExpression) StringExpression {
|
|
||||||
return newStringFunc("CONVERT", str, fromEncoding, toEncoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CONVERT_FROM(str StringExpression, fromEncoding StringExpression) StringExpression {
|
|
||||||
return newStringFunc("CONVERT_FROM", str, fromEncoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CONVERT_TO(str StringExpression, toEncoding StringExpression) StringExpression {
|
|
||||||
return newStringFunc("CONVERT_TO", str, toEncoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ENCODE(data StringExpression, format StringExpression) StringExpression {
|
|
||||||
return newStringFunc("ENCODE", data, format)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DECODE(data StringExpression, format StringExpression) StringExpression {
|
|
||||||
return newStringFunc("DECODE", data, format)
|
|
||||||
}
|
|
||||||
|
|
||||||
//func FORMAT(formatStr StringExpression, formatArgs ...expressions) StringExpression {
|
|
||||||
// args := []expressions{formatStr}
|
|
||||||
// args = append(args, formatArgs...)
|
|
||||||
// return newStringFunc("FORMAT", args...)
|
|
||||||
//}
|
|
||||||
|
|
||||||
func INITCAP(str StringExpression) StringExpression {
|
|
||||||
return newStringFunc("INITCAP", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LEFT(str StringExpression, n IntegerExpression) StringExpression {
|
|
||||||
return newStringFunc("LEFT", str, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RIGHT(str StringExpression, n IntegerExpression) StringExpression {
|
|
||||||
return newStringFunc("RIGHT", str, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LENGTH(str StringExpression, encoding ...StringExpression) StringExpression {
|
|
||||||
if len(encoding) > 0 {
|
|
||||||
return newStringFunc("LENGTH", str, encoding[0])
|
|
||||||
}
|
|
||||||
return newStringFunc("LENGTH", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LPAD(str StringExpression, length IntegerExpression, text ...StringExpression) StringExpression {
|
|
||||||
if len(text) > 0 {
|
|
||||||
return newStringFunc("LPAD", str, length, text[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
return newStringFunc("LPAD", str, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RPAD(str StringExpression, length IntegerExpression, text ...StringExpression) StringExpression {
|
|
||||||
if len(text) > 0 {
|
|
||||||
return newStringFunc("RPAD", str, length, text[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
return newStringFunc("RPAD", str, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MD5(stringExpression StringExpression) StringExpression {
|
|
||||||
return newStringFunc("MD5", stringExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func REPEAT(str StringExpression, n IntegerExpression) StringExpression {
|
|
||||||
return newStringFunc("REPEAT", str, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func REPLACE(text, from, to StringExpression) StringExpression {
|
|
||||||
return newStringFunc("REPLACE", text, from, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
func REVERSE(stringExpression StringExpression) StringExpression {
|
|
||||||
return newStringFunc("REVERSE", stringExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
func STRPOS(str, substring StringExpression) IntegerExpression {
|
|
||||||
return newIntegerFunc("STRPOS", str, substring)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SUBSTR(str StringExpression, from IntegerExpression, count ...IntegerExpression) StringExpression {
|
|
||||||
if len(count) > 0 {
|
|
||||||
return newStringFunc("SUBSTR", str, from, count[0])
|
|
||||||
}
|
|
||||||
return newStringFunc("SUBSTR", str, from)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TO_ASCII(str StringExpression, encoding ...StringExpression) StringExpression {
|
|
||||||
if len(encoding) > 0 {
|
|
||||||
return newStringFunc("TO_ASCII", str, encoding[0])
|
|
||||||
}
|
|
||||||
return newStringFunc("TO_ASCII", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TO_HEX(number IntegerExpression) StringExpression {
|
|
||||||
return newStringFunc("TO_HEX", number)
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------Data Type Formatting Functions ----------------------//
|
|
||||||
|
|
||||||
func TO_CHAR(expression Expression, text StringExpression) StringExpression {
|
|
||||||
return newStringFunc("TO_CHAR", expression, text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TO_DATE(dateStr, format StringExpression) DateExpression {
|
|
||||||
return newDateFunc("TO_DATE", dateStr, format)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TO_NUMBER(floatStr, format StringExpression) FloatExpression {
|
|
||||||
return newFloatFunc("TO_NUMBER", floatStr, format)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TO_TIMESTAMP(timestampzStr, format StringExpression) TimestampzExpression {
|
|
||||||
return newTimestampzFunc("TO_TIMESTAMP", timestampzStr, format)
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------- Date/Time Functions and Operators ---------------//
|
|
||||||
|
|
||||||
func CURRENT_DATE() DateExpression {
|
|
||||||
dateFunc := newDateFunc("CURRENT_DATE")
|
|
||||||
dateFunc.noBrackets = true
|
|
||||||
return dateFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func CURRENT_TIME(precision ...int) TimezExpression {
|
|
||||||
var timezFunc *timezFunc
|
|
||||||
|
|
||||||
if len(precision) > 0 {
|
|
||||||
timezFunc = newTimezFunc("CURRENT_TIME", constLiteral(precision[0]))
|
|
||||||
} else {
|
|
||||||
timezFunc = newTimezFunc("CURRENT_TIME")
|
|
||||||
}
|
|
||||||
|
|
||||||
timezFunc.noBrackets = true
|
|
||||||
|
|
||||||
return timezFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func CURRENT_TIMESTAMP(precision ...int) TimestampzExpression {
|
|
||||||
var timestampzFunc *timestampzFunc
|
|
||||||
|
|
||||||
if len(precision) > 0 {
|
|
||||||
timestampzFunc = newTimestampzFunc("CURRENT_TIMESTAMP", constLiteral(precision[0]))
|
|
||||||
} else {
|
|
||||||
timestampzFunc = newTimestampzFunc("CURRENT_TIMESTAMP")
|
|
||||||
}
|
|
||||||
|
|
||||||
timestampzFunc.noBrackets = true
|
|
||||||
|
|
||||||
return timestampzFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func LOCALTIME(precision ...int) TimeExpression {
|
|
||||||
var timeFunc *timeFunc
|
|
||||||
|
|
||||||
if len(precision) > 0 {
|
|
||||||
timeFunc = newTimeFunc("LOCALTIME", constLiteral(precision[0]))
|
|
||||||
} else {
|
|
||||||
timeFunc = newTimeFunc("LOCALTIME")
|
|
||||||
}
|
|
||||||
|
|
||||||
timeFunc.noBrackets = true
|
|
||||||
|
|
||||||
return timeFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func LOCALTIMESTAMP(precision ...int) TimestampExpression {
|
|
||||||
var timestampFunc *timestampFunc
|
|
||||||
|
|
||||||
if len(precision) > 0 {
|
|
||||||
timestampFunc = newTimestampFunc("LOCALTIMESTAMP", constLiteral(precision[0]))
|
|
||||||
} else {
|
|
||||||
timestampFunc = newTimestampFunc("LOCALTIMESTAMP")
|
|
||||||
}
|
|
||||||
|
|
||||||
timestampFunc.noBrackets = true
|
|
||||||
|
|
||||||
return timestampFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func NOW() TimestampzExpression {
|
|
||||||
return newTimestampzFunc("NOW")
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- Conditional Expressions Functions -------------//
|
|
||||||
|
|
||||||
func COALESCE(value Expression, values ...Expression) Expression {
|
|
||||||
var allValues = []Expression{value}
|
|
||||||
allValues = append(allValues, values...)
|
|
||||||
return newFunc("COALESCE", allValues, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NULLIF(value1, value2 Expression) Expression {
|
|
||||||
return newFunc("NULLIF", []Expression{value1, value2}, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GREATEST(value Expression, values ...Expression) Expression {
|
|
||||||
var allValues = []Expression{value}
|
|
||||||
allValues = append(allValues, values...)
|
|
||||||
return newFunc("GREATEST", allValues, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LEAST(value Expression, values ...Expression) Expression {
|
|
||||||
var allValues = []Expression{value}
|
|
||||||
allValues = append(allValues, values...)
|
|
||||||
return newFunc("LEAST", allValues, nil)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gotest.tools/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -156,14 +155,3 @@ func TestFuncLEAST(t *testing.T) {
|
||||||
assertClauseSerialize(t, LEAST(table1ColFloat), "LEAST(table1.col_float)")
|
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")
|
assertClauseSerialize(t, LEAST(Float(11.2222), NULL, String("str")), "LEAST($1, NULL, $2)", float64(11.2222), "str")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInterval(t *testing.T) {
|
|
||||||
query := INTERVAL(`6 years 5 months 4 days 3 hours 2 minutes 1 second`)
|
|
||||||
|
|
||||||
queryData := &sqlBuilder{}
|
|
||||||
|
|
||||||
err := query.serialize(select_statement, queryData)
|
|
||||||
|
|
||||||
assert.NilError(t, err)
|
|
||||||
assert.Equal(t, queryData.buff.String(), `INTERVAL $1`)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/go-jet/jet/execution"
|
"github.com/go-jet/jet/execution"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// InsertStatement is interface for SQL INSERT statements
|
||||||
type InsertStatement interface {
|
type InsertStatement interface {
|
||||||
Statement
|
Statement
|
||||||
|
|
||||||
|
|
@ -85,7 +86,7 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
return "", nil, errors.New("jet: table is nil")
|
return "", nil, errors.New("jet: table is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = i.table.serialize(insert_statement, queryData)
|
err = i.table.serialize(insertStatement, queryData)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -114,8 +115,8 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
if len(i.rows) > 0 {
|
if len(i.rows) > 0 {
|
||||||
queryData.writeString("VALUES")
|
queryData.writeString("VALUES")
|
||||||
|
|
||||||
for row_i, row := range i.rows {
|
for rowIndex, row := range i.rows {
|
||||||
if row_i > 0 {
|
if rowIndex > 0 {
|
||||||
queryData.writeString(",")
|
queryData.writeString(",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,7 +124,7 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
queryData.newLine()
|
queryData.newLine()
|
||||||
queryData.writeString("(")
|
queryData.writeString("(")
|
||||||
|
|
||||||
err = serializeClauseList(insert_statement, row, queryData)
|
err = serializeClauseList(insertStatement, row, queryData)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
|
|
@ -135,14 +136,14 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if i.query != nil {
|
if i.query != nil {
|
||||||
err = i.query.serialize(insert_statement, queryData)
|
err = i.query.serialize(insertStatement, queryData)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = queryData.writeReturning(insert_statement, i.returning); err != nil {
|
if err = queryData.writeReturning(insertStatement, i.returning); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,7 +157,7 @@ func (i *insertStatementImpl) Query(db execution.DB, destination interface{}) er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insertStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (i *insertStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return queryContext(i, db, context, destination)
|
return queryContext(context, i, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insertStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (i *insertStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
|
|
|
||||||
|
|
@ -81,13 +81,13 @@ func TestInsertValuesFromModel(t *testing.T) {
|
||||||
MODEL(toInsert).
|
MODEL(toInsert).
|
||||||
MODEL(&toInsert)
|
MODEL(&toInsert)
|
||||||
|
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
INSERT INTO db.table1 (col1, col_float) VALUES
|
INSERT INTO db.table1 (col1, col_float) VALUES
|
||||||
($1, $2),
|
($1, $2),
|
||||||
($3, $4);
|
($3, $4);
|
||||||
`
|
`
|
||||||
|
|
||||||
assertStatement(t, stmt, expectedSql, int(1), float64(1.11), int(1), float64(1.11))
|
assertStatement(t, stmt, expectedSQL, int(1), float64(1.11), int(1), float64(1.11))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertValuesFromModelColumnMismatch(t *testing.T) {
|
func TestInsertValuesFromModelColumnMismatch(t *testing.T) {
|
||||||
|
|
@ -125,23 +125,23 @@ func TestInsertQuery(t *testing.T) {
|
||||||
stmt := table1.INSERT(table1Col1).
|
stmt := table1.INSERT(table1Col1).
|
||||||
QUERY(table1.SELECT(table1Col1))
|
QUERY(table1.SELECT(table1Col1))
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
INSERT INTO db.table1 (col1) (
|
INSERT INTO db.table1 (col1) (
|
||||||
SELECT table1.col1 AS "table1.col1"
|
SELECT table1.col1 AS "table1.col1"
|
||||||
FROM db.table1
|
FROM db.table1
|
||||||
);
|
);
|
||||||
`
|
`
|
||||||
assertStatement(t, stmt, expectedSql)
|
assertStatement(t, stmt, expectedSQL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertDefaultValue(t *testing.T) {
|
func TestInsertDefaultValue(t *testing.T) {
|
||||||
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
||||||
VALUES(DEFAULT, "two")
|
VALUES(DEFAULT, "two")
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
INSERT INTO db.table1 (col1, col_float) VALUES
|
INSERT INTO db.table1 (col1, col_float) VALUES
|
||||||
(DEFAULT, $1);
|
(DEFAULT, $1);
|
||||||
`
|
`
|
||||||
|
|
||||||
assertStatement(t, stmt, expectedSql, "two")
|
assertStatement(t, stmt, expectedSQL, "two")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// IntegerExpression interface
|
||||||
type IntegerExpression interface {
|
type IntegerExpression interface {
|
||||||
Expression
|
Expression
|
||||||
numericExpression
|
numericExpression
|
||||||
|
|
@ -180,6 +181,9 @@ func newIntExpressionWrap(expression Expression) IntegerExpression {
|
||||||
return &intExpressionWrap
|
return &intExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IntExp is int expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as int expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func IntExp(expression Expression) IntegerExpression {
|
func IntExp(expression Expression) IntegerExpression {
|
||||||
return newIntExpressionWrap(expression)
|
return newIntExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// DEFAULT is jet equivalent of SQL DEFAULT
|
||||||
DEFAULT keywordClause = "DEFAULT"
|
DEFAULT keywordClause = "DEFAULT"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// NULL is jet equivalent of SQL NULL
|
||||||
NULL = newNullLiteral()
|
NULL = newNullLiteral()
|
||||||
|
// STAR is jet equivalent of SQL *
|
||||||
STAR = newStarLiteral()
|
STAR = newStarLiteral()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func (l literalExpression) serialize(statement statementType, out *sqlBuilder, o
|
||||||
if l.constant {
|
if l.constant {
|
||||||
out.insertConstantArgument(l.value)
|
out.insertConstantArgument(l.value)
|
||||||
} else {
|
} else {
|
||||||
out.insertPreparedArgument(l.value)
|
out.insertParametrizedArgument(l.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -38,6 +38,7 @@ type integerLiteralExpression struct {
|
||||||
integerInterfaceImpl
|
integerInterfaceImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Int is constructor for integer expressions literals.
|
||||||
func Int(value int64) IntegerExpression {
|
func Int(value int64) IntegerExpression {
|
||||||
numLiteral := &integerLiteralExpression{}
|
numLiteral := &integerLiteralExpression{}
|
||||||
|
|
||||||
|
|
@ -55,6 +56,7 @@ type boolLiteralExpression struct {
|
||||||
literalExpression
|
literalExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool creates new bool literal expression
|
||||||
func Bool(value bool) BoolExpression {
|
func Bool(value bool) BoolExpression {
|
||||||
boolLiteralExpression := boolLiteralExpression{}
|
boolLiteralExpression := boolLiteralExpression{}
|
||||||
|
|
||||||
|
|
@ -70,6 +72,7 @@ type floatLiteral struct {
|
||||||
literalExpression
|
literalExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Float creates new float literal expression
|
||||||
func Float(value float64) FloatExpression {
|
func Float(value float64) FloatExpression {
|
||||||
floatLiteral := floatLiteral{}
|
floatLiteral := floatLiteral{}
|
||||||
floatLiteral.literalExpression = *literal(value)
|
floatLiteral.literalExpression = *literal(value)
|
||||||
|
|
@ -85,6 +88,7 @@ type stringLiteral struct {
|
||||||
literalExpression
|
literalExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String creates new string literal expression
|
||||||
func String(value string) StringExpression {
|
func String(value string) StringExpression {
|
||||||
stringLiteral := stringLiteral{}
|
stringLiteral := stringLiteral{}
|
||||||
stringLiteral.literalExpression = *literal(value)
|
stringLiteral.literalExpression = *literal(value)
|
||||||
|
|
@ -100,6 +104,7 @@ type timeLiteral struct {
|
||||||
literalExpression
|
literalExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Time creates new time literal expression
|
||||||
func Time(hour, minute, second, milliseconds int) TimeExpression {
|
func Time(hour, minute, second, milliseconds int) TimeExpression {
|
||||||
timeLiteral := &timeLiteral{}
|
timeLiteral := &timeLiteral{}
|
||||||
timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d", hour, minute, second, milliseconds)
|
timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d", hour, minute, second, milliseconds)
|
||||||
|
|
@ -116,6 +121,7 @@ type timezLiteral struct {
|
||||||
literalExpression
|
literalExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timez creates new time with time zone literal expression
|
||||||
func Timez(hour, minute, second, milliseconds, timezone int) TimezExpression {
|
func Timez(hour, minute, second, milliseconds, timezone int) TimezExpression {
|
||||||
timezLiteral := &timezLiteral{}
|
timezLiteral := &timezLiteral{}
|
||||||
timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d %+03d", hour, minute, second, milliseconds, timezone)
|
timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d %+03d", hour, minute, second, milliseconds, timezone)
|
||||||
|
|
@ -132,6 +138,7 @@ type timestampLiteral struct {
|
||||||
literalExpression
|
literalExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timestamp creates new timestamp literal expression
|
||||||
func Timestamp(year, month, day, hour, minute, second, milliseconds int) TimestampExpression {
|
func Timestamp(year, month, day, hour, minute, second, milliseconds int) TimestampExpression {
|
||||||
timestampLiteral := ×tampLiteral{}
|
timestampLiteral := ×tampLiteral{}
|
||||||
timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, milliseconds)
|
timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, milliseconds)
|
||||||
|
|
@ -148,6 +155,7 @@ type timestampzLiteral struct {
|
||||||
literalExpression
|
literalExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timestampz creates new timestamp with time zone literal expression
|
||||||
func Timestampz(year, month, day, hour, minute, second, milliseconds, timezone int) TimestampzExpression {
|
func Timestampz(year, month, day, hour, minute, second, milliseconds, timezone int) TimestampzExpression {
|
||||||
timestampzLiteral := ×tampzLiteral{}
|
timestampzLiteral := ×tampzLiteral{}
|
||||||
timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d %+04d",
|
timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d %+04d",
|
||||||
|
|
@ -166,6 +174,7 @@ type dateLiteral struct {
|
||||||
literalExpression
|
literalExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Date creates new date expression
|
||||||
func Date(year, month, day int) DateExpression {
|
func Date(year, month, day int) DateExpression {
|
||||||
dateLiteral := &dateLiteral{}
|
dateLiteral := &dateLiteral{}
|
||||||
|
|
||||||
|
|
@ -226,6 +235,7 @@ func (n *wrap) serialize(statement statementType, out *sqlBuilder, options ...se
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WRAP wraps list of expressions with brackets '(' and ')'
|
||||||
func WRAP(expression ...Expression) Expression {
|
func WRAP(expression ...Expression) Expression {
|
||||||
wrap := &wrap{expressions: expression}
|
wrap := &wrap{expressions: expression}
|
||||||
wrap.expressionInterfaceImpl.parent = wrap
|
wrap.expressionInterfaceImpl.parent = wrap
|
||||||
|
|
@ -245,6 +255,8 @@ func (n *rawExpression) serialize(statement statementType, out *sqlBuilder, opti
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RAW can be used for any unsupported functions, operators or expressions.
|
||||||
|
// For example: RAW("current_database()")
|
||||||
func RAW(raw string) Expression {
|
func RAW(raw string) Expression {
|
||||||
rawExp := &rawExpression{raw: raw}
|
rawExp := &rawExpression{raw: raw}
|
||||||
rawExp.expressionInterfaceImpl.parent = rawExp
|
rawExp.expressionInterfaceImpl.parent = rawExp
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ import (
|
||||||
"github.com/go-jet/jet/execution"
|
"github.com/go-jet/jet/execution"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TableLockMode is a type of possible SQL table lock
|
||||||
type TableLockMode string
|
type TableLockMode string
|
||||||
|
|
||||||
|
// Lock types for LockStatement.
|
||||||
const (
|
const (
|
||||||
LOCK_ACCESS_SHARE = "ACCESS SHARE"
|
LOCK_ACCESS_SHARE = "ACCESS SHARE"
|
||||||
LOCK_ROW_SHARE = "ROW SHARE"
|
LOCK_ROW_SHARE = "ROW SHARE"
|
||||||
|
|
@ -20,6 +22,7 @@ const (
|
||||||
LOCK_ACCESS_EXCLUSIVE = "ACCESS EXCLUSIVE"
|
LOCK_ACCESS_EXCLUSIVE = "ACCESS EXCLUSIVE"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LockStatement interface for SQL LOCK statement
|
||||||
type LockStatement interface {
|
type LockStatement interface {
|
||||||
Statement
|
Statement
|
||||||
|
|
||||||
|
|
@ -33,6 +36,7 @@ type lockStatementImpl struct {
|
||||||
nowait bool
|
nowait bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LOCK creates lock statement for list of tables.
|
||||||
func LOCK(tables ...WritableTable) LockStatement {
|
func LOCK(tables ...WritableTable) LockStatement {
|
||||||
return &lockStatementImpl{
|
return &lockStatementImpl{
|
||||||
tables: tables,
|
tables: tables,
|
||||||
|
|
@ -55,11 +59,11 @@ func (l *lockStatementImpl) DebugSql() (query string, err error) {
|
||||||
|
|
||||||
func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error) {
|
func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error) {
|
||||||
if l == nil {
|
if l == nil {
|
||||||
return "", nil, errors.New("jet: nil Statement.")
|
return "", nil, errors.New("jet: nil Statement")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(l.tables) == 0 {
|
if len(l.tables) == 0 {
|
||||||
return "", nil, errors.New("jet: There is no table selected to be locked. ")
|
return "", nil, errors.New("jet: There is no table selected to be locked")
|
||||||
}
|
}
|
||||||
|
|
||||||
out := &sqlBuilder{}
|
out := &sqlBuilder{}
|
||||||
|
|
@ -72,7 +76,7 @@ func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error)
|
||||||
out.writeString(", ")
|
out.writeString(", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := table.serialize(lock_statement, out)
|
err := table.serialize(lockStatement, out)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
|
|
@ -98,7 +102,7 @@ func (l *lockStatementImpl) Query(db execution.DB, destination interface{}) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lockStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (l *lockStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return queryContext(l, db, context, destination)
|
return queryContext(context, l, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lockStatementImpl) Exec(db execution.DB) (sql.Result, error) {
|
func (l *lockStatementImpl) Exec(db execution.DB) (sql.Result, error) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// NumericExpression is common interface for all integer and float expressions
|
||||||
type NumericExpression interface {
|
type NumericExpression interface {
|
||||||
Expression
|
Expression
|
||||||
numericExpression
|
numericExpression
|
||||||
|
|
|
||||||
22
operators.go
22
operators.go
|
|
@ -4,17 +4,19 @@ import "errors"
|
||||||
|
|
||||||
//----------- Logical operators ---------------//
|
//----------- Logical operators ---------------//
|
||||||
|
|
||||||
// Returns negation of bool expression expr
|
// NOT returns negation of bool expression result
|
||||||
func NOT(exp BoolExpression) BoolExpression {
|
func NOT(exp BoolExpression) BoolExpression {
|
||||||
return newPrefixBoolOperator(exp, "NOT")
|
return newPrefixBoolOperator(exp, "NOT")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BIT_NOT inverts every bit in integer expression result
|
||||||
func BIT_NOT(expr IntegerExpression) IntegerExpression {
|
func BIT_NOT(expr IntegerExpression) IntegerExpression {
|
||||||
return newPrefixIntegerOperator(expr, "~")
|
return newPrefixIntegerOperator(expr, "~")
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------- Comparison operators ---------------//
|
//----------- Comparison operators ---------------//
|
||||||
|
|
||||||
|
// EXISTS checks for existence of the rows in subQuery
|
||||||
func EXISTS(subQuery SelectStatement) BoolExpression {
|
func EXISTS(subQuery SelectStatement) BoolExpression {
|
||||||
return newPrefixBoolOperator(subQuery, "EXISTS")
|
return newPrefixBoolOperator(subQuery, "EXISTS")
|
||||||
}
|
}
|
||||||
|
|
@ -59,12 +61,13 @@ func gtEq(lhs, rhs Expression) BoolExpression {
|
||||||
|
|
||||||
// --------------- CASE operator -------------------//
|
// --------------- CASE operator -------------------//
|
||||||
|
|
||||||
type CaseOperatorExpression interface {
|
// CaseOperator is interface for SQL case operator
|
||||||
|
type CaseOperator interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
WHEN(condition Expression) CaseOperatorExpression
|
WHEN(condition Expression) CaseOperator
|
||||||
THEN(then Expression) CaseOperatorExpression
|
THEN(then Expression) CaseOperator
|
||||||
ELSE(els Expression) CaseOperatorExpression
|
ELSE(els Expression) CaseOperator
|
||||||
}
|
}
|
||||||
|
|
||||||
type caseOperatorImpl struct {
|
type caseOperatorImpl struct {
|
||||||
|
|
@ -76,7 +79,8 @@ type caseOperatorImpl struct {
|
||||||
els Expression
|
els Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
func CASE(expression ...Expression) CaseOperatorExpression {
|
// CASE create CASE operator with optional list of expressions
|
||||||
|
func CASE(expression ...Expression) CaseOperator {
|
||||||
caseExp := &caseOperatorImpl{}
|
caseExp := &caseOperatorImpl{}
|
||||||
|
|
||||||
if len(expression) > 0 {
|
if len(expression) > 0 {
|
||||||
|
|
@ -88,17 +92,17 @@ func CASE(expression ...Expression) CaseOperatorExpression {
|
||||||
return caseExp
|
return caseExp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *caseOperatorImpl) WHEN(when Expression) CaseOperatorExpression {
|
func (c *caseOperatorImpl) WHEN(when Expression) CaseOperator {
|
||||||
c.when = append(c.when, when)
|
c.when = append(c.when, when)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *caseOperatorImpl) THEN(then Expression) CaseOperatorExpression {
|
func (c *caseOperatorImpl) THEN(then Expression) CaseOperator {
|
||||||
c.then = append(c.then, then)
|
c.then = append(c.then, then)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *caseOperatorImpl) ELSE(els Expression) CaseOperatorExpression {
|
func (c *caseOperatorImpl) ELSE(els Expression) CaseOperator {
|
||||||
c.els = els
|
c.els = els
|
||||||
|
|
||||||
return c
|
return c
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import "testing"
|
||||||
func TestOperatorNOT(t *testing.T) {
|
func TestOperatorNOT(t *testing.T) {
|
||||||
notExpression := NOT(Int(2).EQ(Int(1)))
|
notExpression := NOT(Int(2).EQ(Int(1)))
|
||||||
|
|
||||||
|
assertClauseSerialize(t, NOT(table1ColBool), "NOT table1.col_bool")
|
||||||
assertClauseSerialize(t, notExpression, "NOT ($1 = $2)", int64(2), int64(1))
|
assertClauseSerialize(t, notExpression, "NOT ($1 = $2)", int64(2), int64(1))
|
||||||
assertProjectionSerialize(t, notExpression.AS("alias_not_expression"), `NOT ($1 = $2) AS "alias_not_expression"`, int64(2), int64(1))
|
assertProjectionSerialize(t, notExpression.AS("alias_not_expression"), `NOT ($1 = $2) AS "alias_not_expression"`, int64(2), int64(1))
|
||||||
assertClauseSerialize(t, notExpression.AND(Int(4).EQ(Int(5))), `(NOT ($1 = $2) AND ($3 = $4))`, int64(2), int64(1), int64(4), int64(5))
|
assertClauseSerialize(t, notExpression.AND(Int(4).EQ(Int(5))), `(NOT ($1 = $2) AND ($3 = $4))`, int64(2), int64(1), int64(4), int64(5))
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ package jet
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
type OrderByClause interface {
|
// OrderByClause
|
||||||
|
type orderByClause interface {
|
||||||
serializeForOrderBy(statement statementType, out *sqlBuilder) error
|
serializeForOrderBy(statement statementType, out *sqlBuilder) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -13,7 +14,7 @@ type orderByClauseImpl struct {
|
||||||
|
|
||||||
func (o *orderByClauseImpl) serializeForOrderBy(statement statementType, out *sqlBuilder) error {
|
func (o *orderByClauseImpl) serializeForOrderBy(statement statementType, out *sqlBuilder) error {
|
||||||
if o.expression == nil {
|
if o.expression == nil {
|
||||||
return errors.New("jet: nil orderBy by clause.")
|
return errors.New("jet: nil orderBy by clause")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := o.expression.serializeForOrderBy(statement, out); err != nil {
|
if err := o.expression.serializeForOrderBy(statement, out); err != nil {
|
||||||
|
|
@ -29,6 +30,6 @@ func (o *orderByClauseImpl) serializeForOrderBy(statement statementType, out *sq
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOrderByClause(expression Expression, ascent bool) OrderByClause {
|
func newOrderByClause(expression Expression, ascent bool) orderByClause {
|
||||||
return &orderByClauseImpl{expression: expression, ascent: ascent}
|
return &orderByClauseImpl{expression: expression, ascent: ascent}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@ package jet
|
||||||
|
|
||||||
type projection interface {
|
type projection interface {
|
||||||
serializeForProjection(statement statementType, out *sqlBuilder) error
|
serializeForProjection(statement statementType, out *sqlBuilder) error
|
||||||
from(subQuery ExpressionTable) projection
|
from(subQuery SelectTable) projection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectionList is a redefined type, so that ProjectionList can be used as a projection.
|
||||||
type ProjectionList []projection
|
type ProjectionList []projection
|
||||||
|
|
||||||
func (cl ProjectionList) from(subQuery ExpressionTable) projection {
|
func (cl ProjectionList) from(subQuery SelectTable) projection {
|
||||||
newProjectionList := ProjectionList{}
|
newProjectionList := ProjectionList{}
|
||||||
|
|
||||||
for _, projection := range cl {
|
for _, projection := range cl {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/go-jet/jet/execution"
|
"github.com/go-jet/jet/execution"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Select statements lock types
|
||||||
var (
|
var (
|
||||||
UPDATE = newLock("UPDATE")
|
UPDATE = newLock("UPDATE")
|
||||||
NO_KEY_UPDATE = newLock("NO KEY UPDATE")
|
NO_KEY_UPDATE = newLock("NO KEY UPDATE")
|
||||||
|
|
@ -14,6 +15,7 @@ var (
|
||||||
KEY_SHARE = newLock("KEY SHARE")
|
KEY_SHARE = newLock("KEY SHARE")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SelectStatement is interface for SQL SELECT statements
|
||||||
type SelectStatement interface {
|
type SelectStatement interface {
|
||||||
Statement
|
Statement
|
||||||
Expression
|
Expression
|
||||||
|
|
@ -23,7 +25,7 @@ type SelectStatement interface {
|
||||||
WHERE(expression BoolExpression) SelectStatement
|
WHERE(expression BoolExpression) SelectStatement
|
||||||
GROUP_BY(groupByClauses ...groupByClause) SelectStatement
|
GROUP_BY(groupByClauses ...groupByClause) SelectStatement
|
||||||
HAVING(boolExpression BoolExpression) SelectStatement
|
HAVING(boolExpression BoolExpression) SelectStatement
|
||||||
ORDER_BY(orderByClauses ...OrderByClause) SelectStatement
|
ORDER_BY(orderByClauses ...orderByClause) SelectStatement
|
||||||
LIMIT(limit int64) SelectStatement
|
LIMIT(limit int64) SelectStatement
|
||||||
OFFSET(offset int64) SelectStatement
|
OFFSET(offset int64) SelectStatement
|
||||||
FOR(lock SelectLock) SelectStatement
|
FOR(lock SelectLock) SelectStatement
|
||||||
|
|
@ -35,11 +37,12 @@ type SelectStatement interface {
|
||||||
EXCEPT(rhs SelectStatement) SelectStatement
|
EXCEPT(rhs SelectStatement) SelectStatement
|
||||||
EXCEPT_ALL(rhs SelectStatement) SelectStatement
|
EXCEPT_ALL(rhs SelectStatement) SelectStatement
|
||||||
|
|
||||||
AsTable(alias string) ExpressionTable
|
AsTable(alias string) SelectTable
|
||||||
|
|
||||||
projections() []projection
|
projections() []projection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//SELECT creates new SelectStatement with list of projections
|
||||||
func SELECT(projection1 projection, projections ...projection) SelectStatement {
|
func SELECT(projection1 projection, projections ...projection) SelectStatement {
|
||||||
return newSelectStatement(nil, append([]projection{projection1}, projections...))
|
return newSelectStatement(nil, append([]projection{projection1}, projections...))
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +58,7 @@ type selectStatementImpl struct {
|
||||||
groupBy []groupByClause
|
groupBy []groupByClause
|
||||||
having BoolExpression
|
having BoolExpression
|
||||||
|
|
||||||
orderBy []OrderByClause
|
orderBy []orderByClause
|
||||||
limit, offset int64
|
limit, offset int64
|
||||||
|
|
||||||
lockFor SelectLock
|
lockFor SelectLock
|
||||||
|
|
@ -81,8 +84,8 @@ func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
|
||||||
return s.parent
|
return s.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) AsTable(alias string) ExpressionTable {
|
func (s *selectStatementImpl) AsTable(alias string) SelectTable {
|
||||||
return newExpressionTable(s.parent, alias, s.parent.projections())
|
return newSelectTable(s.parent, alias)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) WHERE(expression BoolExpression) SelectStatement {
|
func (s *selectStatementImpl) WHERE(expression BoolExpression) SelectStatement {
|
||||||
|
|
@ -100,7 +103,7 @@ func (s *selectStatementImpl) HAVING(expression BoolExpression) SelectStatement
|
||||||
return s.parent
|
return s.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) ORDER_BY(clauses ...OrderByClause) SelectStatement {
|
func (s *selectStatementImpl) ORDER_BY(clauses ...orderByClause) SelectStatement {
|
||||||
s.orderBy = clauses
|
s.orderBy = clauses
|
||||||
return s.parent
|
return s.parent
|
||||||
}
|
}
|
||||||
|
|
@ -189,20 +192,20 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
return errors.New("jet: no column selected for projection")
|
return errors.New("jet: no column selected for projection")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := out.writeProjections(select_statement, s.projectionList)
|
err := out.writeProjections(selectStatement, s.projectionList)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.table != nil {
|
if s.table != nil {
|
||||||
if err := out.writeFrom(select_statement, s.table); err != nil {
|
if err := out.writeFrom(selectStatement, s.table); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.where != nil {
|
if s.where != nil {
|
||||||
err := out.writeWhere(select_statement, s.where)
|
err := out.writeWhere(selectStatement, s.where)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -210,7 +213,7 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.groupBy != nil && len(s.groupBy) > 0 {
|
if s.groupBy != nil && len(s.groupBy) > 0 {
|
||||||
err := out.writeGroupBy(select_statement, s.groupBy)
|
err := out.writeGroupBy(selectStatement, s.groupBy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -218,7 +221,7 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.having != nil {
|
if s.having != nil {
|
||||||
err := out.writeHaving(select_statement, s.having)
|
err := out.writeHaving(selectStatement, s.having)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -226,7 +229,7 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.orderBy != nil {
|
if s.orderBy != nil {
|
||||||
err := out.writeOrderBy(select_statement, s.orderBy)
|
err := out.writeOrderBy(selectStatement, s.orderBy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -236,19 +239,19 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
if s.limit >= 0 {
|
if s.limit >= 0 {
|
||||||
out.newLine()
|
out.newLine()
|
||||||
out.writeString("LIMIT")
|
out.writeString("LIMIT")
|
||||||
out.insertPreparedArgument(s.limit)
|
out.insertParametrizedArgument(s.limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.offset >= 0 {
|
if s.offset >= 0 {
|
||||||
out.newLine()
|
out.newLine()
|
||||||
out.writeString("OFFSET")
|
out.writeString("OFFSET")
|
||||||
out.insertPreparedArgument(s.offset)
|
out.insertParametrizedArgument(s.offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.lockFor != nil {
|
if s.lockFor != nil {
|
||||||
out.newLine()
|
out.newLine()
|
||||||
out.writeString("FOR")
|
out.writeString("FOR")
|
||||||
err := s.lockFor.serialize(select_statement, out)
|
err := s.lockFor.serialize(selectStatement, out)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -281,7 +284,7 @@ func (s *selectStatementImpl) Query(db execution.DB, destination interface{}) er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (s *selectStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return queryContext(s.parent, db, context, destination)
|
return queryContext(context, s.parent, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (s *selectStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
|
|
@ -292,8 +295,7 @@ func (s *selectStatementImpl) ExecContext(db execution.DB, context context.Conte
|
||||||
return execContext(s.parent, db, context)
|
return execContext(s.parent, db, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectLock
|
// SelectLock is interface for SELECT statement locks
|
||||||
|
|
||||||
type SelectLock interface {
|
type SelectLock interface {
|
||||||
clause
|
clause
|
||||||
|
|
||||||
|
|
|
||||||
63
select_table.go
Normal file
63
select_table.go
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package jet
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
// SelectTable is interface for SELECT sub-queries
|
||||||
|
type SelectTable interface {
|
||||||
|
ReadableTable
|
||||||
|
|
||||||
|
Alias() string
|
||||||
|
|
||||||
|
AllColumns() ProjectionList
|
||||||
|
}
|
||||||
|
|
||||||
|
type selectTableImpl struct {
|
||||||
|
readableTableInterfaceImpl
|
||||||
|
selectStmt SelectStatement
|
||||||
|
alias string
|
||||||
|
|
||||||
|
projections []projection
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSelectTable(selectStmt SelectStatement, alias string) SelectTable {
|
||||||
|
expTable := &selectTableImpl{selectStmt: selectStmt, alias: alias}
|
||||||
|
|
||||||
|
expTable.readableTableInterfaceImpl.parent = expTable
|
||||||
|
|
||||||
|
for _, projection := range selectStmt.projections() {
|
||||||
|
newProjection := projection.from(expTable)
|
||||||
|
|
||||||
|
expTable.projections = append(expTable.projections, newProjection)
|
||||||
|
}
|
||||||
|
|
||||||
|
return expTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *selectTableImpl) Alias() string {
|
||||||
|
return s.alias
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *selectTableImpl) columns() []column {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *selectTableImpl) AllColumns() ProjectionList {
|
||||||
|
return s.projections
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *selectTableImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
|
||||||
|
if s == nil {
|
||||||
|
return errors.New("jet: Expression table is nil. ")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.selectStmt.serialize(statement, out)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
out.writeString("AS")
|
||||||
|
out.writeIdentifier(s.alias)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -4,28 +4,40 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UNION effectively appends the result of sub-queries(select statements) into single query.
|
||||||
|
// It eliminates duplicate rows from its result.
|
||||||
func UNION(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
func UNION(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||||
return newSetStatementImpl(union, false, toSelectList(lhs, rhs, selects...))
|
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 SelectStatement, selects ...SelectStatement) SelectStatement {
|
func UNION_ALL(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||||
return newSetStatementImpl(union, true, toSelectList(lhs, rhs, selects...))
|
return newSetStatementImpl(union, true, toSelectList(lhs, rhs, selects...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// INTERSECT returns all rows that are in query results.
|
||||||
|
// It eliminates duplicate rows from its result.
|
||||||
func INTERSECT(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
func INTERSECT(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||||
return newSetStatementImpl(intersect, false, toSelectList(lhs, rhs, selects...))
|
return newSetStatementImpl(intersect, false, toSelectList(lhs, rhs, selects...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// INTERSECT_ALL returns all rows that are in query results.
|
||||||
|
// It does not eliminates duplicate rows from its result.
|
||||||
func INTERSECT_ALL(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
func INTERSECT_ALL(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||||
return newSetStatementImpl(intersect, true, toSelectList(lhs, rhs, selects...))
|
return newSetStatementImpl(intersect, true, toSelectList(lhs, rhs, selects...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func EXCEPT(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
// EXCEPT returns all rows that are in the result of query lhs but not in the result of query rhs.
|
||||||
return newSetStatementImpl(except, false, toSelectList(lhs, rhs, selects...))
|
// It eliminates duplicate rows from its result.
|
||||||
|
func EXCEPT(lhs, rhs SelectStatement) SelectStatement {
|
||||||
|
return newSetStatementImpl(except, false, toSelectList(lhs, rhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func EXCEPT_ALL(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
// EXCEPT_ALL returns all rows that are in the result of query lhs but not in the result of query rhs.
|
||||||
return newSetStatementImpl(except, true, toSelectList(lhs, rhs, selects...))
|
// It does not eliminates duplicate rows from its result.
|
||||||
|
func EXCEPT_ALL(lhs, rhs SelectStatement) SelectStatement {
|
||||||
|
return newSetStatementImpl(except, true, toSelectList(lhs, rhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func toSelectList(lhs, rhs SelectStatement, selects ...SelectStatement) []SelectStatement {
|
func toSelectList(lhs, rhs SelectStatement, selects ...SelectStatement) []SelectStatement {
|
||||||
|
|
@ -102,7 +114,7 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.selects) < 2 {
|
if len(s.selects) < 2 {
|
||||||
return errors.New("jet: UNION Statement must have at least two SELECT statements.")
|
return errors.New("jet: UNION Statement must have at least two SELECT statements")
|
||||||
}
|
}
|
||||||
|
|
||||||
out.newLine()
|
out.newLine()
|
||||||
|
|
@ -124,7 +136,7 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
return errors.New("jet: select statement is nil")
|
return errors.New("jet: select statement is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := selectStmt.serialize(set_statement, out)
|
err := selectStmt.serialize(setStatement, out)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -136,7 +148,7 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
out.writeString(")")
|
out.writeString(")")
|
||||||
|
|
||||||
if s.orderBy != nil {
|
if s.orderBy != nil {
|
||||||
err := out.writeOrderBy(set_statement, s.orderBy)
|
err := out.writeOrderBy(setStatement, s.orderBy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -145,13 +157,13 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
|
||||||
if s.limit >= 0 {
|
if s.limit >= 0 {
|
||||||
out.newLine()
|
out.newLine()
|
||||||
out.writeString("LIMIT")
|
out.writeString("LIMIT")
|
||||||
out.insertPreparedArgument(s.limit)
|
out.insertParametrizedArgument(s.limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.offset >= 0 {
|
if s.offset >= 0 {
|
||||||
out.newLine()
|
out.newLine()
|
||||||
out.writeString("OFFSET")
|
out.writeString("OFFSET")
|
||||||
out.insertPreparedArgument(s.offset)
|
out.insertParametrizedArgument(s.offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUnionTwoSelect(t *testing.T) {
|
func TestUnionTwoSelect(t *testing.T) {
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
SELECT table1.col1 AS "table1.col1"
|
SELECT table1.col1 AS "table1.col1"
|
||||||
|
|
@ -27,8 +27,8 @@ func TestUnionTwoSelect(t *testing.T) {
|
||||||
|
|
||||||
unionStmt2 := UNION(table1.SELECT(table1Col1), table2.SELECT(table2Col3))
|
unionStmt2 := UNION(table1.SELECT(table1Col1), table2.SELECT(table2Col3))
|
||||||
|
|
||||||
assertStatement(t, unionStmt1, expectedSql)
|
assertStatement(t, unionStmt1, expectedSQL)
|
||||||
assertStatement(t, unionStmt2, expectedSql)
|
assertStatement(t, unionStmt2, expectedSQL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnionNilSelect(t *testing.T) {
|
func TestUnionNilSelect(t *testing.T) {
|
||||||
|
|
@ -49,7 +49,7 @@ func TestUnionThreeSelect1(t *testing.T) {
|
||||||
table3.SELECT(table3Col1),
|
table3.SELECT(table3Col1),
|
||||||
)
|
)
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
(
|
(
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
@ -71,7 +71,7 @@ func TestUnionThreeSelect1(t *testing.T) {
|
||||||
);
|
);
|
||||||
`
|
`
|
||||||
|
|
||||||
assertStatement(t, unionStmt1, expectedSql)
|
assertStatement(t, unionStmt1, expectedSQL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnionThreeSelect2(t *testing.T) {
|
func TestUnionThreeSelect2(t *testing.T) {
|
||||||
|
|
@ -82,7 +82,7 @@ func TestUnionThreeSelect2(t *testing.T) {
|
||||||
table3.SELECT(table3Col1),
|
table3.SELECT(table3Col1),
|
||||||
)
|
)
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
SELECT table1.col1 AS "table1.col1"
|
SELECT table1.col1 AS "table1.col1"
|
||||||
|
|
@ -101,7 +101,7 @@ func TestUnionThreeSelect2(t *testing.T) {
|
||||||
);
|
);
|
||||||
`
|
`
|
||||||
|
|
||||||
assertStatement(t, unionStmt2, expectedSql)
|
assertStatement(t, unionStmt2, expectedSQL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnionWithOrderBy(t *testing.T) {
|
func TestUnionWithOrderBy(t *testing.T) {
|
||||||
|
|
@ -155,7 +155,7 @@ OFFSET $2;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnionInUnion(t *testing.T) {
|
func TestUnionInUnion(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
SELECT table2.col3 AS "table2.col3",
|
SELECT table2.col3 AS "table2.col3",
|
||||||
|
|
@ -182,7 +182,7 @@ func TestUnionInUnion(t *testing.T) {
|
||||||
UNION_ALL(table1.SELECT(table1Col1), table2.SELECT(table2Col3)),
|
UNION_ALL(table1.SELECT(table1Col1), table2.SELECT(table2Col3)),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertStatement(t, query, expectedSql)
|
assertStatement(t, query, expectedSQL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnionALL(t *testing.T) {
|
func TestUnionALL(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//Statement is common interface for all statements(SELECT, INSERT, UPDATE, DELETE, LOCK)
|
||||||
type Statement interface {
|
type Statement interface {
|
||||||
// Sql returns parametrized sql query with list of arguments.
|
// Sql returns parametrized sql query with list of arguments.
|
||||||
// err is returned if statement is not composed correctly
|
// err is returned if statement is not composed correctly
|
||||||
|
|
@ -37,14 +38,14 @@ func debugSql(statement Statement) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
debugSqlQuery := sqlQuery
|
debugSQLQuery := sqlQuery
|
||||||
|
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
argPlaceholder := "$" + strconv.Itoa(i+1)
|
argPlaceholder := "$" + strconv.Itoa(i+1)
|
||||||
debugSqlQuery = strings.Replace(debugSqlQuery, argPlaceholder, ArgToString(arg), 1)
|
debugSQLQuery = strings.Replace(debugSQLQuery, argPlaceholder, argToString(arg), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return debugSqlQuery, nil
|
return debugSQLQuery, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func query(statement Statement, db execution.DB, destination interface{}) error {
|
func query(statement Statement, db execution.DB, destination interface{}) error {
|
||||||
|
|
@ -57,7 +58,7 @@ func query(statement Statement, db execution.DB, destination interface{}) error
|
||||||
return execution.Query(db, context.Background(), query, args, destination)
|
return execution.Query(db, context.Background(), query, args, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryContext(statement Statement, db execution.DB, context context.Context, destination interface{}) error {
|
func queryContext(context context.Context, statement Statement, db execution.DB, destination interface{}) error {
|
||||||
query, args, err := statement.Sql()
|
query, args, err := statement.Sql()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// StringExpression interface
|
||||||
type StringExpression interface {
|
type StringExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
|
|
@ -108,6 +109,9 @@ func newStringExpressionWrap(expression Expression) StringExpression {
|
||||||
return &stringExpressionWrap
|
return &stringExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StringExp is string expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as string expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func StringExp(expression Expression) StringExpression {
|
func StringExp(expression Expression) StringExpression {
|
||||||
return newStringExpressionWrap(expression)
|
return newStringExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
table.go
14
table.go
|
|
@ -36,18 +36,21 @@ type writableTable interface {
|
||||||
LOCK() LockStatement
|
LOCK() LockStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadableTable interface
|
||||||
type ReadableTable interface {
|
type ReadableTable interface {
|
||||||
table
|
table
|
||||||
readableTable
|
readableTable
|
||||||
clause
|
clause
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WritableTable interface
|
||||||
type WritableTable interface {
|
type WritableTable interface {
|
||||||
table
|
table
|
||||||
writableTable
|
writableTable
|
||||||
clause
|
clause
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Table interface
|
||||||
type Table interface {
|
type Table interface {
|
||||||
table
|
table
|
||||||
readableTable
|
readableTable
|
||||||
|
|
@ -110,6 +113,7 @@ func (w *writableTableInterfaceImpl) LOCK() LockStatement {
|
||||||
return LOCK(w.parent)
|
return LOCK(w.parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTable creates new table with schema name, table name and list of columns
|
||||||
func NewTable(schemaName, name string, columns ...Column) Table {
|
func NewTable(schemaName, name string, columns ...Column) Table {
|
||||||
|
|
||||||
t := &tableImpl{
|
t := &tableImpl{
|
||||||
|
|
@ -196,20 +200,20 @@ type joinTable struct {
|
||||||
|
|
||||||
lhs ReadableTable
|
lhs ReadableTable
|
||||||
rhs ReadableTable
|
rhs ReadableTable
|
||||||
join_type joinType
|
joinType joinType
|
||||||
onCondition BoolExpression
|
onCondition BoolExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
func newJoinTable(
|
func newJoinTable(
|
||||||
lhs ReadableTable,
|
lhs ReadableTable,
|
||||||
rhs ReadableTable,
|
rhs ReadableTable,
|
||||||
join_type joinType,
|
joinType joinType,
|
||||||
onCondition BoolExpression) ReadableTable {
|
onCondition BoolExpression) ReadableTable {
|
||||||
|
|
||||||
joinTable := &joinTable{
|
joinTable := &joinTable{
|
||||||
lhs: lhs,
|
lhs: lhs,
|
||||||
rhs: rhs,
|
rhs: rhs,
|
||||||
join_type: join_type,
|
joinType: joinType,
|
||||||
onCondition: onCondition,
|
onCondition: onCondition,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,7 +249,7 @@ func (t *joinTable) serialize(statement statementType, out *sqlBuilder, options
|
||||||
|
|
||||||
out.newLine()
|
out.newLine()
|
||||||
|
|
||||||
switch t.join_type {
|
switch t.joinType {
|
||||||
case innerJoin:
|
case innerJoin:
|
||||||
out.writeString("INNER JOIN")
|
out.writeString("INNER JOIN")
|
||||||
case leftJoin:
|
case leftJoin:
|
||||||
|
|
@ -266,7 +270,7 @@ func (t *joinTable) serialize(statement statementType, out *sqlBuilder, options
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.onCondition == nil && t.join_type != crossJoin {
|
if t.onCondition == nil && t.joinType != crossJoin {
|
||||||
return errors.New("jet: join condition is nil")
|
return errors.New("jet: join condition is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ func TestFloatOperators(t *testing.T) {
|
||||||
CEIL(AllTypes.Real),
|
CEIL(AllTypes.Real),
|
||||||
FLOOR(AllTypes.Real),
|
FLOOR(AllTypes.Real),
|
||||||
ROUND(AllTypes.Decimal),
|
ROUND(AllTypes.Decimal),
|
||||||
ROUND(AllTypes.Decimal, Int(3)).AS("round"),
|
ROUND(AllTypes.Decimal, AllTypes.Integer).AS("round"),
|
||||||
SIGN(AllTypes.Real),
|
SIGN(AllTypes.Real),
|
||||||
TRUNC(AllTypes.Decimal),
|
TRUNC(AllTypes.Decimal),
|
||||||
TRUNC(AllTypes.Decimal, Int(1)),
|
TRUNC(AllTypes.Decimal, Int(1)),
|
||||||
|
|
@ -361,7 +361,7 @@ func TestSubQueryColumnReference(t *testing.T) {
|
||||||
args []interface{}
|
args []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
subQueries := map[ExpressionTable]expected{}
|
subQueries := map[SelectTable]expected{}
|
||||||
|
|
||||||
selectSubQuery := AllTypes.SELECT(
|
selectSubQuery := AllTypes.SELECT(
|
||||||
AllTypes.Boolean,
|
AllTypes.Boolean,
|
||||||
|
|
@ -378,7 +378,7 @@ func TestSubQueryColumnReference(t *testing.T) {
|
||||||
LIMIT(2).
|
LIMIT(2).
|
||||||
AsTable("subQuery")
|
AsTable("subQuery")
|
||||||
|
|
||||||
var selectExpectedSql = ` (
|
var selectexpectedSQL = ` (
|
||||||
SELECT all_types.boolean AS "all_types.boolean",
|
SELECT all_types.boolean AS "all_types.boolean",
|
||||||
all_types.integer AS "all_types.integer",
|
all_types.integer AS "all_types.integer",
|
||||||
all_types.real AS "all_types.real",
|
all_types.real AS "all_types.real",
|
||||||
|
|
@ -424,7 +424,7 @@ func TestSubQueryColumnReference(t *testing.T) {
|
||||||
).
|
).
|
||||||
AsTable("subQuery")
|
AsTable("subQuery")
|
||||||
|
|
||||||
unionExpectedSql := `
|
unionexpectedSQL := `
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
SELECT all_types.boolean AS "all_types.boolean",
|
SELECT all_types.boolean AS "all_types.boolean",
|
||||||
|
|
@ -458,8 +458,8 @@ func TestSubQueryColumnReference(t *testing.T) {
|
||||||
)
|
)
|
||||||
) AS "subQuery"`
|
) AS "subQuery"`
|
||||||
|
|
||||||
subQueries[selectSubQuery] = expected{sql: selectExpectedSql, args: []interface{}{int64(2)}}
|
subQueries[selectSubQuery] = expected{sql: selectexpectedSQL, args: []interface{}{int64(2)}}
|
||||||
subQueries[unionSubQuery] = expected{sql: unionExpectedSql, args: []interface{}{int64(1), int64(1), int64(1)}}
|
subQueries[unionSubQuery] = expected{sql: unionexpectedSQL, args: []interface{}{int64(1), int64(1), int64(1)}}
|
||||||
|
|
||||||
for subQuery, expected := range subQueries {
|
for subQuery, expected := range subQueries {
|
||||||
boolColumn := AllTypes.Boolean.From(subQuery)
|
boolColumn := AllTypes.Boolean.From(subQuery)
|
||||||
|
|
@ -487,7 +487,7 @@ func TestSubQueryColumnReference(t *testing.T) {
|
||||||
).
|
).
|
||||||
FROM(subQuery)
|
FROM(subQuery)
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
SELECT "subQuery"."all_types.boolean" AS "all_types.boolean",
|
SELECT "subQuery"."all_types.boolean" AS "all_types.boolean",
|
||||||
"subQuery"."all_types.integer" AS "all_types.integer",
|
"subQuery"."all_types.integer" AS "all_types.integer",
|
||||||
"subQuery"."all_types.real" AS "all_types.real",
|
"subQuery"."all_types.real" AS "all_types.real",
|
||||||
|
|
@ -500,7 +500,7 @@ SELECT "subQuery"."all_types.boolean" AS "all_types.boolean",
|
||||||
"subQuery"."aliasedColumn" AS "aliasedColumn"
|
"subQuery"."aliasedColumn" AS "aliasedColumn"
|
||||||
FROM`
|
FROM`
|
||||||
|
|
||||||
assertStatementSql(t, stmt1, expectedSql+expected.sql+";\n", expected.args...)
|
assertStatementSql(t, stmt1, expectedSQL+expected.sql+";\n", expected.args...)
|
||||||
|
|
||||||
dest1 := []model.AllTypes{}
|
dest1 := []model.AllTypes{}
|
||||||
err := stmt1.Query(db, &dest1)
|
err := stmt1.Query(db, &dest1)
|
||||||
|
|
@ -523,7 +523,7 @@ FROM`
|
||||||
|
|
||||||
//fmt.Println(stmt2.DebugSql())
|
//fmt.Println(stmt2.DebugSql())
|
||||||
|
|
||||||
assertStatementSql(t, stmt2, expectedSql+expected.sql+";\n", expected.args...)
|
assertStatementSql(t, stmt2, expectedSQL+expected.sql+";\n", expected.args...)
|
||||||
|
|
||||||
dest2 := []model.AllTypes{}
|
dest2 := []model.AllTypes{}
|
||||||
err = stmt2.Query(db, &dest2)
|
err = stmt2.Query(db, &dest2)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
func TestDeleteWithWhere(t *testing.T) {
|
func TestDeleteWithWhere(t *testing.T) {
|
||||||
initForDeleteTest(t)
|
initForDeleteTest(t)
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
DELETE FROM test_sample.link
|
DELETE FROM test_sample.link
|
||||||
WHERE link.name IN ('Gmail', 'Outlook');
|
WHERE link.name IN ('Gmail', 'Outlook');
|
||||||
`
|
`
|
||||||
|
|
@ -19,14 +19,14 @@ WHERE link.name IN ('Gmail', 'Outlook');
|
||||||
DELETE().
|
DELETE().
|
||||||
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
|
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
|
||||||
|
|
||||||
assertStatementSql(t, deleteStmt, expectedSql, "Gmail", "Outlook")
|
assertStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook")
|
||||||
assertExec(t, deleteStmt, 2)
|
assertExec(t, deleteStmt, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteWithWhereAndReturning(t *testing.T) {
|
func TestDeleteWithWhereAndReturning(t *testing.T) {
|
||||||
initForDeleteTest(t)
|
initForDeleteTest(t)
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
DELETE FROM test_sample.link
|
DELETE FROM test_sample.link
|
||||||
WHERE link.name IN ('Gmail', 'Outlook')
|
WHERE link.name IN ('Gmail', 'Outlook')
|
||||||
RETURNING link.id AS "link.id",
|
RETURNING link.id AS "link.id",
|
||||||
|
|
@ -39,7 +39,7 @@ RETURNING link.id AS "link.id",
|
||||||
WHERE(Link.Name.IN(String("Gmail"), String("Outlook"))).
|
WHERE(Link.Name.IN(String("Gmail"), String("Outlook"))).
|
||||||
RETURNING(Link.AllColumns)
|
RETURNING(Link.AllColumns)
|
||||||
|
|
||||||
assertStatementSql(t, deleteStmt, expectedSql, "Gmail", "Outlook")
|
assertStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook")
|
||||||
|
|
||||||
dest := []model.Link{}
|
dest := []model.Link{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
func TestInsertValues(t *testing.T) {
|
func TestInsertValues(t *testing.T) {
|
||||||
cleanUpLinkTable(t)
|
cleanUpLinkTable(t)
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
INSERT INTO test_sample.link (id, url, name, description) VALUES
|
INSERT INTO test_sample.link (id, url, name, description) VALUES
|
||||||
(100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT),
|
(100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT),
|
||||||
(101, 'http://www.google.com', 'Google', DEFAULT),
|
(101, 'http://www.google.com', 'Google', DEFAULT),
|
||||||
|
|
@ -28,7 +28,7 @@ RETURNING link.id AS "link.id",
|
||||||
VALUES(102, "http://www.yahoo.com", "Yahoo", nil).
|
VALUES(102, "http://www.yahoo.com", "Yahoo", nil).
|
||||||
RETURNING(Link.AllColumns)
|
RETURNING(Link.AllColumns)
|
||||||
|
|
||||||
assertStatementSql(t, insertQuery, expectedSql,
|
assertStatementSql(t, insertQuery, expectedSQL,
|
||||||
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
||||||
101, "http://www.google.com", "Google",
|
101, "http://www.google.com", "Google",
|
||||||
102, "http://www.yahoo.com", "Yahoo", nil)
|
102, "http://www.yahoo.com", "Yahoo", nil)
|
||||||
|
|
@ -74,7 +74,7 @@ RETURNING link.id AS "link.id",
|
||||||
func TestInsertEmptyColumnList(t *testing.T) {
|
func TestInsertEmptyColumnList(t *testing.T) {
|
||||||
cleanUpLinkTable(t)
|
cleanUpLinkTable(t)
|
||||||
|
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
INSERT INTO test_sample.link VALUES
|
INSERT INTO test_sample.link VALUES
|
||||||
(100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT);
|
(100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT);
|
||||||
`
|
`
|
||||||
|
|
@ -82,7 +82,7 @@ INSERT INTO test_sample.link VALUES
|
||||||
stmt := Link.INSERT().
|
stmt := Link.INSERT().
|
||||||
VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT)
|
VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT)
|
||||||
|
|
||||||
assertStatementSql(t, stmt, expectedSql,
|
assertStatementSql(t, stmt, expectedSQL,
|
||||||
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial")
|
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial")
|
||||||
|
|
||||||
assertExec(t, stmt, 1)
|
assertExec(t, stmt, 1)
|
||||||
|
|
@ -90,7 +90,7 @@ INSERT INTO test_sample.link VALUES
|
||||||
|
|
||||||
func TestInsertModelObject(t *testing.T) {
|
func TestInsertModelObject(t *testing.T) {
|
||||||
cleanUpLinkTable(t)
|
cleanUpLinkTable(t)
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
INSERT INTO test_sample.link (url, name) VALUES
|
INSERT INTO test_sample.link (url, name) VALUES
|
||||||
('http://www.duckduckgo.com', 'Duck Duck go');
|
('http://www.duckduckgo.com', 'Duck Duck go');
|
||||||
`
|
`
|
||||||
|
|
@ -104,7 +104,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
||||||
INSERT(Link.URL, Link.Name).
|
INSERT(Link.URL, Link.Name).
|
||||||
MODEL(linkData)
|
MODEL(linkData)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, "http://www.duckduckgo.com", "Duck Duck go")
|
assertStatementSql(t, query, expectedSQL, "http://www.duckduckgo.com", "Duck Duck go")
|
||||||
|
|
||||||
result, err := query.Exec(db)
|
result, err := query.Exec(db)
|
||||||
|
|
||||||
|
|
@ -116,7 +116,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertModelsObject(t *testing.T) {
|
func TestInsertModelsObject(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
INSERT INTO test_sample.link (url, name) VALUES
|
INSERT INTO test_sample.link (url, name) VALUES
|
||||||
('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial'),
|
('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial'),
|
||||||
('http://www.google.com', 'Google'),
|
('http://www.google.com', 'Google'),
|
||||||
|
|
@ -142,7 +142,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
||||||
INSERT(Link.URL, Link.Name).
|
INSERT(Link.URL, Link.Name).
|
||||||
MODELS([]model.Link{tutorial, google, yahoo})
|
MODELS([]model.Link{tutorial, google, yahoo})
|
||||||
|
|
||||||
assertStatementSql(t, stmt, expectedSql,
|
assertStatementSql(t, stmt, expectedSQL,
|
||||||
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
||||||
"http://www.google.com", "Google",
|
"http://www.google.com", "Google",
|
||||||
"http://www.yahoo.com", "Yahoo")
|
"http://www.yahoo.com", "Yahoo")
|
||||||
|
|
@ -151,7 +151,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertUsingMutableColumns(t *testing.T) {
|
func TestInsertUsingMutableColumns(t *testing.T) {
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
INSERT INTO test_sample.link (url, name, description) VALUES
|
INSERT INTO test_sample.link (url, name, description) VALUES
|
||||||
('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT),
|
('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT),
|
||||||
('http://www.google.com', 'Google', NULL),
|
('http://www.google.com', 'Google', NULL),
|
||||||
|
|
@ -175,7 +175,7 @@ INSERT INTO test_sample.link (url, name, description) VALUES
|
||||||
MODEL(google).
|
MODEL(google).
|
||||||
MODELS([]model.Link{google, yahoo})
|
MODELS([]model.Link{google, yahoo})
|
||||||
|
|
||||||
assertStatementSql(t, stmt, expectedSql,
|
assertStatementSql(t, stmt, expectedSQL,
|
||||||
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
||||||
"http://www.google.com", "Google", nil,
|
"http://www.google.com", "Google", nil,
|
||||||
"http://www.google.com", "Google", nil,
|
"http://www.google.com", "Google", nil,
|
||||||
|
|
@ -190,7 +190,7 @@ func TestInsertQuery(t *testing.T) {
|
||||||
Exec(db)
|
Exec(db)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
INSERT INTO test_sample.link (url, name) (
|
INSERT INTO test_sample.link (url, name) (
|
||||||
SELECT link.url AS "link.url",
|
SELECT link.url AS "link.url",
|
||||||
link.name AS "link.name"
|
link.name AS "link.name"
|
||||||
|
|
@ -212,7 +212,7 @@ RETURNING link.id AS "link.id",
|
||||||
).
|
).
|
||||||
RETURNING(Link.AllColumns)
|
RETURNING(Link.AllColumns)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, int64(0))
|
assertStatementSql(t, query, expectedSQL, int64(0))
|
||||||
|
|
||||||
dest := []model.Link{}
|
dest := []model.Link{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ FROM test_sample.person;
|
||||||
|
|
||||||
func TestSelecSelfJoin1(t *testing.T) {
|
func TestSelecSelfJoin1(t *testing.T) {
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
SELECT employee.employee_id AS "employee.employee_id",
|
SELECT employee.employee_id AS "employee.employee_id",
|
||||||
employee.first_name AS "employee.first_name",
|
employee.first_name AS "employee.first_name",
|
||||||
employee.last_name AS "employee.last_name",
|
employee.last_name AS "employee.last_name",
|
||||||
|
|
@ -97,7 +97,7 @@ ORDER BY employee.employee_id;
|
||||||
).
|
).
|
||||||
ORDER_BY(Employee.EmployeeID)
|
ORDER_BY(Employee.EmployeeID)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql)
|
assertStatementSql(t, query, expectedSQL)
|
||||||
|
|
||||||
type Manager model.Employee
|
type Manager model.Employee
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSelect_ScanToStruct(t *testing.T) {
|
func TestSelect_ScanToStruct(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
|
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
|
||||||
actor.first_name AS "actor.first_name",
|
actor.first_name AS "actor.first_name",
|
||||||
actor.last_name AS "actor.last_name",
|
actor.last_name AS "actor.last_name",
|
||||||
|
|
@ -24,7 +24,7 @@ WHERE actor.actor_id = 1;
|
||||||
DISTINCT().
|
DISTINCT().
|
||||||
WHERE(Actor.ActorID.EQ(Int(1)))
|
WHERE(Actor.ActorID.EQ(Int(1)))
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, int64(1))
|
assertStatementSql(t, query, expectedSQL, int64(1))
|
||||||
|
|
||||||
actor := model.Actor{}
|
actor := model.Actor{}
|
||||||
err := query.Query(db, &actor)
|
err := query.Query(db, &actor)
|
||||||
|
|
@ -42,7 +42,7 @@ WHERE actor.actor_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClassicSelect(t *testing.T) {
|
func TestClassicSelect(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT payment.payment_id AS "payment.payment_id",
|
SELECT payment.payment_id AS "payment.payment_id",
|
||||||
payment.customer_id AS "payment.customer_id",
|
payment.customer_id AS "payment.customer_id",
|
||||||
payment.staff_id AS "payment.staff_id",
|
payment.staff_id AS "payment.staff_id",
|
||||||
|
|
@ -74,7 +74,7 @@ LIMIT 30;
|
||||||
ORDER_BY(Payment.PaymentID.ASC()).
|
ORDER_BY(Payment.PaymentID.ASC()).
|
||||||
LIMIT(30)
|
LIMIT(30)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, int64(30))
|
assertStatementSql(t, query, expectedSQL, int64(30))
|
||||||
|
|
||||||
dest := []model.Payment{}
|
dest := []model.Payment{}
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@ LIMIT 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelect_ScanToSlice(t *testing.T) {
|
func TestSelect_ScanToSlice(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT customer.customer_id AS "customer.customer_id",
|
SELECT customer.customer_id AS "customer.customer_id",
|
||||||
customer.store_id AS "customer.store_id",
|
customer.store_id AS "customer.store_id",
|
||||||
customer.first_name AS "customer.first_name",
|
customer.first_name AS "customer.first_name",
|
||||||
|
|
@ -103,7 +103,7 @@ ORDER BY customer.customer_id ASC;
|
||||||
|
|
||||||
query := Customer.SELECT(Customer.AllColumns).ORDER_BY(Customer.CustomerID.ASC())
|
query := Customer.SELECT(Customer.AllColumns).ORDER_BY(Customer.CustomerID.ASC())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql)
|
assertStatementSql(t, query, expectedSQL)
|
||||||
|
|
||||||
err := query.Query(db, &customers)
|
err := query.Query(db, &customers)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
@ -116,7 +116,7 @@ ORDER BY customer.customer_id ASC;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectAndUnionInProjection(t *testing.T) {
|
func TestSelectAndUnionInProjection(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT payment.payment_id AS "payment.payment_id",
|
SELECT payment.payment_id AS "payment.payment_id",
|
||||||
(
|
(
|
||||||
SELECT customer.customer_id AS "customer.customer_id"
|
SELECT customer.customer_id AS "customer.customer_id"
|
||||||
|
|
@ -156,12 +156,12 @@ LIMIT 12;
|
||||||
).
|
).
|
||||||
LIMIT(12)
|
LIMIT(12)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, int64(1), int64(1), int64(10), int64(1), int64(2), int64(1), int64(12))
|
assertStatementSql(t, query, expectedSQL, int64(1), int64(1), int64(10), int64(1), int64(2), int64(1), int64(12))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJoinQueryStruct(t *testing.T) {
|
func TestJoinQueryStruct(t *testing.T) {
|
||||||
|
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT film_actor.actor_id AS "film_actor.actor_id",
|
SELECT film_actor.actor_id AS "film_actor.actor_id",
|
||||||
film_actor.film_id AS "film_actor.film_id",
|
film_actor.film_id AS "film_actor.film_id",
|
||||||
film_actor.last_update AS "film_actor.last_update",
|
film_actor.last_update AS "film_actor.last_update",
|
||||||
|
|
@ -224,7 +224,7 @@ LIMIT 1000;
|
||||||
ORDER_BY(Film.FilmID.ASC()).
|
ORDER_BY(Film.FilmID.ASC()).
|
||||||
LIMIT(1000)
|
LIMIT(1000)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, int64(1000))
|
assertStatementSql(t, query, expectedSQL, int64(1000))
|
||||||
|
|
||||||
var languageActorFilm []struct {
|
var languageActorFilm []struct {
|
||||||
model.Language
|
model.Language
|
||||||
|
|
@ -253,7 +253,7 @@ LIMIT 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJoinQuerySlice(t *testing.T) {
|
func TestJoinQuerySlice(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT language.language_id AS "language.language_id",
|
SELECT language.language_id AS "language.language_id",
|
||||||
language.name AS "language.name",
|
language.name AS "language.name",
|
||||||
language.last_update AS "language.last_update",
|
language.last_update AS "language.last_update",
|
||||||
|
|
@ -290,7 +290,7 @@ LIMIT 15;
|
||||||
WHERE(Film.Rating.EQ(enum.MpaaRating.Nc17)).
|
WHERE(Film.Rating.EQ(enum.MpaaRating.Nc17)).
|
||||||
LIMIT(15)
|
LIMIT(15)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, int64(15))
|
assertStatementSql(t, query, expectedSQL, int64(15))
|
||||||
|
|
||||||
err := query.Query(db, &filmsPerLanguage)
|
err := query.Query(db, &filmsPerLanguage)
|
||||||
|
|
||||||
|
|
@ -657,7 +657,7 @@ func TestSelectOrderByAscDesc(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectFullJoin(t *testing.T) {
|
func TestSelectFullJoin(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT customer.customer_id AS "customer.customer_id",
|
SELECT customer.customer_id AS "customer.customer_id",
|
||||||
customer.store_id AS "customer.store_id",
|
customer.store_id AS "customer.store_id",
|
||||||
customer.first_name AS "customer.first_name",
|
customer.first_name AS "customer.first_name",
|
||||||
|
|
@ -685,7 +685,7 @@ ORDER BY customer.customer_id ASC;
|
||||||
SELECT(Customer.AllColumns, Address.AllColumns).
|
SELECT(Customer.AllColumns, Address.AllColumns).
|
||||||
ORDER_BY(Customer.CustomerID.ASC())
|
ORDER_BY(Customer.CustomerID.ASC())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql)
|
assertStatementSql(t, query, expectedSQL)
|
||||||
|
|
||||||
allCustomersAndAddress := []struct {
|
allCustomersAndAddress := []struct {
|
||||||
Address *model.Address
|
Address *model.Address
|
||||||
|
|
@ -708,7 +708,7 @@ ORDER BY customer.customer_id ASC;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectFullCrossJoin(t *testing.T) {
|
func TestSelectFullCrossJoin(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT customer.customer_id AS "customer.customer_id",
|
SELECT customer.customer_id AS "customer.customer_id",
|
||||||
customer.store_id AS "customer.store_id",
|
customer.store_id AS "customer.store_id",
|
||||||
customer.first_name AS "customer.first_name",
|
customer.first_name AS "customer.first_name",
|
||||||
|
|
@ -738,7 +738,7 @@ LIMIT 1000;
|
||||||
ORDER_BY(Customer.CustomerID.ASC()).
|
ORDER_BY(Customer.CustomerID.ASC()).
|
||||||
LIMIT(1000)
|
LIMIT(1000)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, int64(1000))
|
assertStatementSql(t, query, expectedSQL, int64(1000))
|
||||||
|
|
||||||
var customerAddresCrosJoined []struct {
|
var customerAddresCrosJoined []struct {
|
||||||
model.Customer
|
model.Customer
|
||||||
|
|
@ -753,7 +753,7 @@ LIMIT 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectSelfJoin(t *testing.T) {
|
func TestSelectSelfJoin(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT f1.film_id AS "f1.film_id",
|
SELECT f1.film_id AS "f1.film_id",
|
||||||
f1.title AS "f1.title",
|
f1.title AS "f1.title",
|
||||||
f1.description AS "f1.description",
|
f1.description AS "f1.description",
|
||||||
|
|
@ -793,7 +793,7 @@ ORDER BY f1.film_id ASC;
|
||||||
SELECT(f1.AllColumns, f2.AllColumns).
|
SELECT(f1.AllColumns, f2.AllColumns).
|
||||||
ORDER_BY(f1.FilmID.ASC())
|
ORDER_BY(f1.FilmID.ASC())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql)
|
assertStatementSql(t, query, expectedSQL)
|
||||||
|
|
||||||
type F1 model.Film
|
type F1 model.Film
|
||||||
type F2 model.Film
|
type F2 model.Film
|
||||||
|
|
@ -813,7 +813,7 @@ ORDER BY f1.film_id ASC;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectAliasColumn(t *testing.T) {
|
func TestSelectAliasColumn(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT f1.title AS "thesame_length_films.title1",
|
SELECT f1.title AS "thesame_length_films.title1",
|
||||||
f2.title AS "thesame_length_films.title2",
|
f2.title AS "thesame_length_films.title2",
|
||||||
f1.length AS "thesame_length_films.length"
|
f1.length AS "thesame_length_films.length"
|
||||||
|
|
@ -835,7 +835,7 @@ LIMIT 1000;
|
||||||
ORDER_BY(f1.Length.ASC(), f1.Title.ASC(), f2.Title.ASC()).
|
ORDER_BY(f1.Length.ASC(), f1.Title.ASC(), f2.Title.ASC()).
|
||||||
LIMIT(1000)
|
LIMIT(1000)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, int64(1000))
|
assertStatementSql(t, query, expectedSQL, int64(1000))
|
||||||
|
|
||||||
type thesameLengthFilms struct {
|
type thesameLengthFilms struct {
|
||||||
Title1 string
|
Title1 string
|
||||||
|
|
@ -928,7 +928,7 @@ FROM dvds.film;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectQueryScalar(t *testing.T) {
|
func TestSelectQueryScalar(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT film.film_id AS "film.film_id",
|
SELECT film.film_id AS "film.film_id",
|
||||||
film.title AS "film.title",
|
film.title AS "film.title",
|
||||||
film.description AS "film.description",
|
film.description AS "film.description",
|
||||||
|
|
@ -960,7 +960,7 @@ ORDER BY film.film_id ASC;
|
||||||
WHERE(Film.RentalRate.EQ(maxFilmRentalRate)).
|
WHERE(Film.RentalRate.EQ(maxFilmRentalRate)).
|
||||||
ORDER_BY(Film.FilmID.ASC())
|
ORDER_BY(Film.FilmID.ASC())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql)
|
assertStatementSql(t, query, expectedSQL)
|
||||||
|
|
||||||
maxRentalRateFilms := []model.Film{}
|
maxRentalRateFilms := []model.Film{}
|
||||||
err := query.Query(db, &maxRentalRateFilms)
|
err := query.Query(db, &maxRentalRateFilms)
|
||||||
|
|
@ -989,7 +989,7 @@ ORDER BY film.film_id ASC;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectGroupByHaving(t *testing.T) {
|
func TestSelectGroupByHaving(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT payment.customer_id AS "customer_payment_sum.customer_id",
|
SELECT payment.customer_id AS "customer_payment_sum.customer_id",
|
||||||
SUM(payment.amount) AS "customer_payment_sum.amount_sum",
|
SUM(payment.amount) AS "customer_payment_sum.amount_sum",
|
||||||
AVG(payment.amount) AS "customer_payment_sum.amount_avg",
|
AVG(payment.amount) AS "customer_payment_sum.amount_avg",
|
||||||
|
|
@ -1018,7 +1018,7 @@ ORDER BY SUM(payment.amount) ASC;
|
||||||
SUMf(Payment.Amount).GT(Float(100)),
|
SUMf(Payment.Amount).GT(Float(100)),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertStatementSql(t, customersPaymentQuery, expectedSql, float64(100))
|
assertStatementSql(t, customersPaymentQuery, expectedSQL, float64(100))
|
||||||
|
|
||||||
type CustomerPaymentSum struct {
|
type CustomerPaymentSum struct {
|
||||||
CustomerID int16
|
CustomerID int16
|
||||||
|
|
@ -1047,7 +1047,7 @@ ORDER BY SUM(payment.amount) ASC;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectGroupBy2(t *testing.T) {
|
func TestSelectGroupBy2(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT customer.customer_id AS "customer.customer_id",
|
SELECT customer.customer_id AS "customer.customer_id",
|
||||||
customer.store_id AS "customer.store_id",
|
customer.store_id AS "customer.store_id",
|
||||||
customer.first_name AS "customer.first_name",
|
customer.first_name AS "customer.first_name",
|
||||||
|
|
@ -1088,7 +1088,7 @@ ORDER BY customer_payment_sum."amount_sum" ASC;
|
||||||
).
|
).
|
||||||
ORDER_BY(amountSum.ASC())
|
ORDER_BY(amountSum.ASC())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql)
|
assertStatementSql(t, query, expectedSQL)
|
||||||
|
|
||||||
type CustomerWithAmounts struct {
|
type CustomerWithAmounts struct {
|
||||||
Customer *model.Customer
|
Customer *model.Customer
|
||||||
|
|
@ -1157,7 +1157,7 @@ func TestSelectStaff(t *testing.T) {
|
||||||
|
|
||||||
func TestSelectTimeColumns(t *testing.T) {
|
func TestSelectTimeColumns(t *testing.T) {
|
||||||
|
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT payment.payment_id AS "payment.payment_id",
|
SELECT payment.payment_id AS "payment.payment_id",
|
||||||
payment.customer_id AS "payment.customer_id",
|
payment.customer_id AS "payment.customer_id",
|
||||||
payment.staff_id AS "payment.staff_id",
|
payment.staff_id AS "payment.staff_id",
|
||||||
|
|
@ -1173,7 +1173,7 @@ ORDER BY payment.payment_date ASC;
|
||||||
WHERE(Payment.PaymentDate.LT(Timestamp(2007, 02, 14, 22, 16, 01, 0))).
|
WHERE(Payment.PaymentDate.LT(Timestamp(2007, 02, 14, 22, 16, 01, 0))).
|
||||||
ORDER_BY(Payment.PaymentDate.ASC())
|
ORDER_BY(Payment.PaymentDate.ASC())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, "2007-02-14 22:16:01.000")
|
assertStatementSql(t, query, expectedSQL, "2007-02-14 22:16:01.000")
|
||||||
|
|
||||||
payments := []model.Payment{}
|
payments := []model.Payment{}
|
||||||
|
|
||||||
|
|
@ -1260,8 +1260,8 @@ func TestAllSetOperators(t *testing.T) {
|
||||||
UNION_ALL,
|
UNION_ALL,
|
||||||
INTERSECT,
|
INTERSECT,
|
||||||
INTERSECT_ALL,
|
INTERSECT_ALL,
|
||||||
EXCEPT,
|
//EXCEPT,
|
||||||
EXCEPT_ALL,
|
//EXCEPT_ALL,
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedDestLen := []int{
|
expectedDestLen := []int{
|
||||||
|
|
@ -1316,7 +1316,7 @@ LIMIT 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLockTable(t *testing.T) {
|
func TestLockTable(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
LOCK TABLE dvds.address IN`
|
LOCK TABLE dvds.address IN`
|
||||||
|
|
||||||
var testData = []TableLockMode{
|
var testData = []TableLockMode{
|
||||||
|
|
@ -1333,7 +1333,7 @@ LOCK TABLE dvds.address IN`
|
||||||
for _, lockMode := range testData {
|
for _, lockMode := range testData {
|
||||||
query := Address.LOCK().IN(lockMode)
|
query := Address.LOCK().IN(lockMode)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql+" "+string(lockMode)+" MODE;\n")
|
assertStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE;\n")
|
||||||
|
|
||||||
tx, _ := db.Begin()
|
tx, _ := db.Begin()
|
||||||
|
|
||||||
|
|
@ -1349,7 +1349,7 @@ LOCK TABLE dvds.address IN`
|
||||||
for _, lockMode := range testData {
|
for _, lockMode := range testData {
|
||||||
query := Address.LOCK().IN(lockMode).NOWAIT()
|
query := Address.LOCK().IN(lockMode).NOWAIT()
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql+" "+string(lockMode)+" MODE NOWAIT;\n")
|
assertStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE NOWAIT;\n")
|
||||||
|
|
||||||
tx, _ := db.Begin()
|
tx, _ := db.Begin()
|
||||||
|
|
||||||
|
|
@ -1373,7 +1373,7 @@ func getRowLockTestData() map[SelectLock]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRowLock(t *testing.T) {
|
func TestRowLock(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM dvds.address
|
FROM dvds.address
|
||||||
LIMIT 3
|
LIMIT 3
|
||||||
|
|
@ -1385,7 +1385,7 @@ FOR`
|
||||||
for lockType, lockTypeStr := range getRowLockTestData() {
|
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||||
query.FOR(lockType)
|
query.FOR(lockType)
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql+" "+lockTypeStr+";\n", int64(3))
|
assertStatementSql(t, query, expectedSQL+" "+lockTypeStr+";\n", int64(3))
|
||||||
|
|
||||||
tx, _ := db.Begin()
|
tx, _ := db.Begin()
|
||||||
|
|
||||||
|
|
@ -1401,7 +1401,7 @@ FOR`
|
||||||
for lockType, lockTypeStr := range getRowLockTestData() {
|
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||||
query.FOR(lockType.NOWAIT())
|
query.FOR(lockType.NOWAIT())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql+" "+lockTypeStr+" NOWAIT;\n", int64(3))
|
assertStatementSql(t, query, expectedSQL+" "+lockTypeStr+" NOWAIT;\n", int64(3))
|
||||||
|
|
||||||
tx, _ := db.Begin()
|
tx, _ := db.Begin()
|
||||||
|
|
||||||
|
|
@ -1417,7 +1417,7 @@ FOR`
|
||||||
for lockType, lockTypeStr := range getRowLockTestData() {
|
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||||
query.FOR(lockType.SKIP_LOCKED())
|
query.FOR(lockType.SKIP_LOCKED())
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql+" "+lockTypeStr+" SKIP LOCKED;\n", int64(3))
|
assertStatementSql(t, query, expectedSQL+" "+lockTypeStr+" SKIP LOCKED;\n", int64(3))
|
||||||
|
|
||||||
tx, _ := db.Begin()
|
tx, _ := db.Begin()
|
||||||
|
|
||||||
|
|
@ -1433,7 +1433,7 @@ FOR`
|
||||||
|
|
||||||
func TestQuickStart(t *testing.T) {
|
func TestQuickStart(t *testing.T) {
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
SELECT actor.actor_id AS "actor.actor_id",
|
SELECT actor.actor_id AS "actor.actor_id",
|
||||||
actor.first_name AS "actor.first_name",
|
actor.first_name AS "actor.first_name",
|
||||||
actor.last_name AS "actor.last_name",
|
actor.last_name AS "actor.last_name",
|
||||||
|
|
@ -1488,7 +1488,7 @@ ORDER BY actor.actor_id ASC, film.film_id ASC;
|
||||||
Film.FilmID.ASC(),
|
Film.FilmID.ASC(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertStatementSql(t, stmt, expectedSql, "English", "Action", int64(180))
|
assertStatementSql(t, stmt, expectedSQL, "English", "Action", int64(180))
|
||||||
|
|
||||||
var dest []struct {
|
var dest []struct {
|
||||||
model.Actor
|
model.Actor
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ func TestUpdateValues(t *testing.T) {
|
||||||
SET("Bong", "http://bong.com").
|
SET("Bong", "http://bong.com").
|
||||||
WHERE(Link.Name.EQ(String("Bing")))
|
WHERE(Link.Name.EQ(String("Bing")))
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
UPDATE test_sample.link
|
UPDATE test_sample.link
|
||||||
SET (name, url) = ('Bong', 'http://bong.com')
|
SET (name, url) = ('Bong', 'http://bong.com')
|
||||||
WHERE link.name = 'Bing';
|
WHERE link.name = 'Bing';
|
||||||
`
|
`
|
||||||
assertStatementSql(t, query, expectedSql, "Bong", "http://bong.com", "Bing")
|
assertStatementSql(t, query, expectedSQL, "Bong", "http://bong.com", "Bing")
|
||||||
|
|
||||||
assertExec(t, query, 1)
|
assertExec(t, query, 1)
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ func TestUpdateWithSubQueries(t *testing.T) {
|
||||||
).
|
).
|
||||||
WHERE(Link.Name.EQ(String("Bing")))
|
WHERE(Link.Name.EQ(String("Bing")))
|
||||||
|
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
UPDATE test_sample.link
|
UPDATE test_sample.link
|
||||||
SET (name, url) = ((
|
SET (name, url) = ((
|
||||||
SELECT 'Bong'
|
SELECT 'Bong'
|
||||||
|
|
@ -66,7 +66,7 @@ SET (name, url) = ((
|
||||||
WHERE link.name = 'Bing';
|
WHERE link.name = 'Bing';
|
||||||
`
|
`
|
||||||
|
|
||||||
assertStatementSql(t, query, expectedSql, "Bong", "Bing", "Bing")
|
assertStatementSql(t, query, expectedSQL, "Bong", "Bing", "Bing")
|
||||||
|
|
||||||
assertExec(t, query, 1)
|
assertExec(t, query, 1)
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +74,7 @@ WHERE link.name = 'Bing';
|
||||||
func TestUpdateAndReturning(t *testing.T) {
|
func TestUpdateAndReturning(t *testing.T) {
|
||||||
setupLinkTableForUpdateTest(t)
|
setupLinkTableForUpdateTest(t)
|
||||||
|
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
UPDATE test_sample.link
|
UPDATE test_sample.link
|
||||||
SET (name, url) = ('DuckDuckGo', 'http://www.duckduckgo.com')
|
SET (name, url) = ('DuckDuckGo', 'http://www.duckduckgo.com')
|
||||||
WHERE link.name = 'Ask'
|
WHERE link.name = 'Ask'
|
||||||
|
|
@ -90,7 +90,7 @@ RETURNING link.id AS "link.id",
|
||||||
WHERE(Link.Name.EQ(String("Ask"))).
|
WHERE(Link.Name.EQ(String("Ask"))).
|
||||||
RETURNING(Link.AllColumns)
|
RETURNING(Link.AllColumns)
|
||||||
|
|
||||||
assertStatementSql(t, stmt, expectedSql, "DuckDuckGo", "http://www.duckduckgo.com", "Ask")
|
assertStatementSql(t, stmt, expectedSQL, "DuckDuckGo", "http://www.duckduckgo.com", "Ask")
|
||||||
|
|
||||||
links := []model.Link{}
|
links := []model.Link{}
|
||||||
|
|
||||||
|
|
@ -112,7 +112,7 @@ func TestUpdateWithSelect(t *testing.T) {
|
||||||
).
|
).
|
||||||
WHERE(Link.ID.EQ(Int(0)))
|
WHERE(Link.ID.EQ(Int(0)))
|
||||||
|
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
UPDATE test_sample.link
|
UPDATE test_sample.link
|
||||||
SET (id, url, name, description) = (
|
SET (id, url, name, description) = (
|
||||||
SELECT link.id AS "link.id",
|
SELECT link.id AS "link.id",
|
||||||
|
|
@ -124,7 +124,7 @@ SET (id, url, name, description) = (
|
||||||
)
|
)
|
||||||
WHERE link.id = 0;
|
WHERE link.id = 0;
|
||||||
`
|
`
|
||||||
assertStatementSql(t, stmt, expectedSql, int64(0), int64(0))
|
assertStatementSql(t, stmt, expectedSQL, int64(0), int64(0))
|
||||||
|
|
||||||
assertExec(t, stmt, 1)
|
assertExec(t, stmt, 1)
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +139,7 @@ func TestUpdateWithInvalidSelect(t *testing.T) {
|
||||||
).
|
).
|
||||||
WHERE(Link.ID.EQ(Int(0)))
|
WHERE(Link.ID.EQ(Int(0)))
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
UPDATE test_sample.link
|
UPDATE test_sample.link
|
||||||
SET (id, url, name, description) = (
|
SET (id, url, name, description) = (
|
||||||
SELECT link.id AS "link.id",
|
SELECT link.id AS "link.id",
|
||||||
|
|
@ -149,7 +149,7 @@ SET (id, url, name, description) = (
|
||||||
)
|
)
|
||||||
WHERE link.id = 0;
|
WHERE link.id = 0;
|
||||||
`
|
`
|
||||||
assertStatementSql(t, stmt, expectedSql, int64(0), int64(0))
|
assertStatementSql(t, stmt, expectedSQL, int64(0), int64(0))
|
||||||
|
|
||||||
assertExecErr(t, stmt, "pq: number of columns does not match number of values")
|
assertExecErr(t, stmt, "pq: number of columns does not match number of values")
|
||||||
}
|
}
|
||||||
|
|
@ -168,12 +168,12 @@ func TestUpdateWithModelData(t *testing.T) {
|
||||||
MODEL(link).
|
MODEL(link).
|
||||||
WHERE(Link.ID.EQ(Int(int64(link.ID))))
|
WHERE(Link.ID.EQ(Int(int64(link.ID))))
|
||||||
|
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
UPDATE test_sample.link
|
UPDATE test_sample.link
|
||||||
SET (id, url, name, description) = (201, 'http://www.duckduckgo.com', 'DuckDuckGo', NULL)
|
SET (id, url, name, description) = (201, 'http://www.duckduckgo.com', 'DuckDuckGo', NULL)
|
||||||
WHERE link.id = 201;
|
WHERE link.id = 201;
|
||||||
`
|
`
|
||||||
assertStatementSql(t, stmt, expectedSql, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201))
|
assertStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201))
|
||||||
|
|
||||||
assertExec(t, stmt, 1)
|
assertExec(t, stmt, 1)
|
||||||
}
|
}
|
||||||
|
|
@ -195,12 +195,12 @@ func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
|
||||||
MODEL(link).
|
MODEL(link).
|
||||||
WHERE(Link.ID.EQ(Int(int64(link.ID))))
|
WHERE(Link.ID.EQ(Int(int64(link.ID))))
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
UPDATE test_sample.link
|
UPDATE test_sample.link
|
||||||
SET (description, name, url) = (NULL, 'DuckDuckGo', 'http://www.duckduckgo.com')
|
SET (description, name, url) = (NULL, 'DuckDuckGo', 'http://www.duckduckgo.com')
|
||||||
WHERE link.id = 201;
|
WHERE link.id = 201;
|
||||||
`
|
`
|
||||||
assertStatementSql(t, stmt, expectedSql, nil, "DuckDuckGo", "http://www.duckduckgo.com", int64(201))
|
assertStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int64(201))
|
||||||
|
|
||||||
assertExec(t, stmt, 1)
|
assertExec(t, stmt, 1)
|
||||||
}
|
}
|
||||||
|
|
@ -231,12 +231,12 @@ func TestUpdateWithInvalidModelData(t *testing.T) {
|
||||||
MODEL(link).
|
MODEL(link).
|
||||||
WHERE(Link.ID.EQ(Int(int64(link.Ident))))
|
WHERE(Link.ID.EQ(Int(int64(link.Ident))))
|
||||||
|
|
||||||
var expectedSql = `
|
var expectedSQL = `
|
||||||
UPDATE test_sample.link
|
UPDATE test_sample.link
|
||||||
SET (id, url, name, description, rel) = ('http://www.duckduckgo.com', 'DuckDuckGo', NULL, NULL)
|
SET (id, url, name, description, rel) = ('http://www.duckduckgo.com', 'DuckDuckGo', NULL, NULL)
|
||||||
WHERE link.id = 201;
|
WHERE link.id = 201;
|
||||||
`
|
`
|
||||||
assertStatementSql(t, stmt, expectedSql, "http://www.duckduckgo.com", "DuckDuckGo", nil, nil, int64(201))
|
assertStatementSql(t, stmt, expectedSQL, "http://www.duckduckgo.com", "DuckDuckGo", nil, nil, int64(201))
|
||||||
|
|
||||||
assertExecErr(t, stmt, "pq: number of columns does not match number of values")
|
assertExecErr(t, stmt, "pq: number of columns does not match number of values")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// TimeExpression interface
|
||||||
type TimeExpression interface {
|
type TimeExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
|
|
@ -68,10 +69,6 @@ func newPrefixTimeExpression(operator string, expression Expression) TimeExpress
|
||||||
return &timeExpr
|
return &timeExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
func INTERVAL(interval string) Expression {
|
|
||||||
return newPrefixTimeExpression("INTERVAL", literal(interval))
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------//
|
//---------------------------------------------------//
|
||||||
|
|
||||||
type timeExpressionWrapper struct {
|
type timeExpressionWrapper struct {
|
||||||
|
|
@ -85,6 +82,9 @@ func newTimeExpressionWrap(expression Expression) TimeExpression {
|
||||||
return &timeExpressionWrap
|
return &timeExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimeExp is time expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as time expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func TimeExp(expression Expression) TimeExpression {
|
func TimeExp(expression Expression) TimeExpression {
|
||||||
return newTimeExpressionWrap(expression)
|
return newTimeExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// TimestampExpression interface
|
||||||
type TimestampExpression interface {
|
type TimestampExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
|
|
@ -63,6 +64,9 @@ func newTimestampExpressionWrap(expression Expression) TimestampExpression {
|
||||||
return ×tampExpressionWrap
|
return ×tampExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimestampExp is timestamp expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as timestamp expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func TimestampExp(expression Expression) TimestampExpression {
|
func TimestampExp(expression Expression) TimestampExpression {
|
||||||
return newTimestampExpressionWrap(expression)
|
return newTimestampExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// TimestampzExpression interface
|
||||||
type TimestampzExpression interface {
|
type TimestampzExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
|
|
@ -63,6 +64,9 @@ func newTimestampzExpressionWrap(expression Expression) TimestampzExpression {
|
||||||
return ×tampzExpressionWrap
|
return ×tampzExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimestampzExp is timestamp with time zone expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as timestamp with time zone expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func TimestampzExp(expression Expression) TimestampzExpression {
|
func TimestampzExp(expression Expression) TimestampzExpression {
|
||||||
return newTimestampzExpressionWrap(expression)
|
return newTimestampzExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,25 @@
|
||||||
package jet
|
package jet
|
||||||
|
|
||||||
|
// TimezExpression interface 'time with time zone'
|
||||||
type TimezExpression interface {
|
type TimezExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
|
//EQ
|
||||||
EQ(rhs TimezExpression) BoolExpression
|
EQ(rhs TimezExpression) BoolExpression
|
||||||
|
//NOT_EQ
|
||||||
NOT_EQ(rhs TimezExpression) BoolExpression
|
NOT_EQ(rhs TimezExpression) BoolExpression
|
||||||
|
//IS_DISTINCT_FROM
|
||||||
IS_DISTINCT_FROM(rhs TimezExpression) BoolExpression
|
IS_DISTINCT_FROM(rhs TimezExpression) BoolExpression
|
||||||
|
//IS_NOT_DISTINCT_FROM
|
||||||
IS_NOT_DISTINCT_FROM(rhs TimezExpression) BoolExpression
|
IS_NOT_DISTINCT_FROM(rhs TimezExpression) BoolExpression
|
||||||
|
|
||||||
|
//LT
|
||||||
LT(rhs TimezExpression) BoolExpression
|
LT(rhs TimezExpression) BoolExpression
|
||||||
|
//LT_EQ
|
||||||
LT_EQ(rhs TimezExpression) BoolExpression
|
LT_EQ(rhs TimezExpression) BoolExpression
|
||||||
|
//GT
|
||||||
GT(rhs TimezExpression) BoolExpression
|
GT(rhs TimezExpression) BoolExpression
|
||||||
|
//GT_EQ
|
||||||
GT_EQ(rhs TimezExpression) BoolExpression
|
GT_EQ(rhs TimezExpression) BoolExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +90,9 @@ func newTimezExpressionWrap(expression Expression) TimezExpression {
|
||||||
return &timezExpressionWrap
|
return &timezExpressionWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimezExp is time with time zone expression wrapper around arbitrary expression.
|
||||||
|
// Allows go compiler to see any expression as time with time zone expression.
|
||||||
|
// Does not add sql cast to generated sql builder output.
|
||||||
func TimezExp(expression Expression) TimezExpression {
|
func TimezExp(expression Expression) TimezExpression {
|
||||||
return newTimezExpressionWrap(expression)
|
return newTimezExpressionWrap(expression)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/go-jet/jet/execution"
|
"github.com/go-jet/jet/execution"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UpdateStatement is interface of SQL UPDATE statement
|
||||||
type UpdateStatement interface {
|
type UpdateStatement interface {
|
||||||
Statement
|
Statement
|
||||||
|
|
||||||
|
|
@ -65,7 +66,7 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
return "", nil, errors.New("jet: table to update is nil")
|
return "", nil, errors.New("jet: table to update is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = u.table.serialize(update_statement, out); err != nil {
|
if err = u.table.serialize(updateStatement, out); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +101,7 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
out.writeString("(")
|
out.writeString("(")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = serializeClauseList(update_statement, u.row, out)
|
err = serializeClauseList(updateStatement, u.row, out)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -114,11 +115,11 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
return "", nil, errors.New("jet: WHERE clause not set")
|
return "", nil, errors.New("jet: WHERE clause not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = out.writeWhere(update_statement, u.where); err != nil {
|
if err = out.writeWhere(updateStatement, u.where); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = out.writeReturning(update_statement, u.returning); err != nil {
|
if err = out.writeReturning(updateStatement, u.returning); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,7 +136,7 @@ func (u *updateStatementImpl) Query(db execution.DB, destination interface{}) er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
func (u *updateStatementImpl) QueryContext(db execution.DB, context context.Context, destination interface{}) error {
|
||||||
return queryContext(u, db, context, destination)
|
return queryContext(context, u, db, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
func (u *updateStatementImpl) Exec(db execution.DB) (res sql.Result, err error) {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUpdateWithOneValue(t *testing.T) {
|
func TestUpdateWithOneValue(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
UPDATE db.table1
|
UPDATE db.table1
|
||||||
SET col_int = $1
|
SET col_int = $1
|
||||||
WHERE table1.col_int >= $2;
|
WHERE table1.col_int >= $2;
|
||||||
|
|
@ -14,11 +14,11 @@ WHERE table1.col_int >= $2;
|
||||||
SET(1).
|
SET(1).
|
||||||
WHERE(table1ColInt.GT_EQ(Int(33)))
|
WHERE(table1ColInt.GT_EQ(Int(33)))
|
||||||
|
|
||||||
assertStatement(t, stmt, expectedSql, 1, int64(33))
|
assertStatement(t, stmt, expectedSQL, 1, int64(33))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateWithValues(t *testing.T) {
|
func TestUpdateWithValues(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
UPDATE db.table1
|
UPDATE db.table1
|
||||||
SET (col_int, col_float) = ($1, $2)
|
SET (col_int, col_float) = ($1, $2)
|
||||||
WHERE table1.col_int >= $3;
|
WHERE table1.col_int >= $3;
|
||||||
|
|
@ -27,11 +27,11 @@ WHERE table1.col_int >= $3;
|
||||||
SET(1, 22.2).
|
SET(1, 22.2).
|
||||||
WHERE(table1ColInt.GT_EQ(Int(33)))
|
WHERE(table1ColInt.GT_EQ(Int(33)))
|
||||||
|
|
||||||
assertStatement(t, stmt, expectedSql, 1, 22.2, int64(33))
|
assertStatement(t, stmt, expectedSQL, 1, 22.2, int64(33))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateOneColumnWithSelect(t *testing.T) {
|
func TestUpdateOneColumnWithSelect(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
UPDATE db.table1
|
UPDATE db.table1
|
||||||
SET col_float = (
|
SET col_float = (
|
||||||
SELECT table1.col_float AS "table1.col_float"
|
SELECT table1.col_float AS "table1.col_float"
|
||||||
|
|
@ -48,11 +48,11 @@ RETURNING table1.col1 AS "table1.col1";
|
||||||
WHERE(table1Col1.EQ(Int(2))).
|
WHERE(table1Col1.EQ(Int(2))).
|
||||||
RETURNING(table1Col1)
|
RETURNING(table1Col1)
|
||||||
|
|
||||||
assertStatement(t, stmt, expectedSql, int64(2))
|
assertStatement(t, stmt, expectedSQL, int64(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateColumnsWithSelect(t *testing.T) {
|
func TestUpdateColumnsWithSelect(t *testing.T) {
|
||||||
expectedSql := `
|
expectedSQL := `
|
||||||
UPDATE db.table1
|
UPDATE db.table1
|
||||||
SET (col1, col_float) = (
|
SET (col1, col_float) = (
|
||||||
SELECT table1.col_float AS "table1.col_float",
|
SELECT table1.col_float AS "table1.col_float",
|
||||||
|
|
@ -67,7 +67,7 @@ RETURNING table1.col1 AS "table1.col1";
|
||||||
WHERE(table1Col1.EQ(Int(2))).
|
WHERE(table1Col1.EQ(Int(2))).
|
||||||
RETURNING(table1Col1)
|
RETURNING(table1Col1)
|
||||||
|
|
||||||
assertStatement(t, stmt, expectedSql, int64(2))
|
assertStatement(t, stmt, expectedSQL, int64(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInvalidInputs(t *testing.T) {
|
func TestInvalidInputs(t *testing.T) {
|
||||||
|
|
|
||||||
10
utils.go
10
utils.go
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func serializeOrderByClauseList(statement statementType, orderByClauses []OrderByClause, out *sqlBuilder) error {
|
func serializeOrderByClauseList(statement statementType, orderByClauses []orderByClause, out *sqlBuilder) error {
|
||||||
|
|
||||||
for i, value := range orderByClauses {
|
for i, value := range orderByClauses {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
|
@ -32,7 +32,7 @@ func serializeGroupByClauseList(statement statementType, clauses []groupByClause
|
||||||
}
|
}
|
||||||
|
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return errors.New("jet: nil clause.")
|
return errors.New("jet: nil clause")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.serializeForGroupBy(statement, out); err != nil {
|
if err = c.serializeForGroupBy(statement, out); err != nil {
|
||||||
|
|
@ -51,7 +51,7 @@ func serializeClauseList(statement statementType, clauses []clause, out *sqlBuil
|
||||||
}
|
}
|
||||||
|
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return errors.New("jet: nil clause.")
|
return errors.New("jet: nil clause")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.serialize(statement, out); err != nil {
|
if err = c.serialize(statement, out); err != nil {
|
||||||
|
|
@ -131,9 +131,9 @@ func isNil(v interface{}) bool {
|
||||||
func valueToClause(value interface{}) clause {
|
func valueToClause(value interface{}) clause {
|
||||||
if clause, ok := value.(clause); ok {
|
if clause, ok := value.(clause); ok {
|
||||||
return clause
|
return clause
|
||||||
} else {
|
|
||||||
return literal(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return literal(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unwindRowFromModel(columns []column, data interface{}) []clause {
|
func unwindRowFromModel(columns []column, data interface{}) []clause {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ var table3 = NewTable(
|
||||||
|
|
||||||
func assertClauseSerialize(t *testing.T, clause clause, query string, args ...interface{}) {
|
func assertClauseSerialize(t *testing.T, clause clause, query string, args ...interface{}) {
|
||||||
out := sqlBuilder{}
|
out := sqlBuilder{}
|
||||||
err := clause.serialize(select_statement, &out)
|
err := clause.serialize(selectStatement, &out)
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ func assertClauseSerialize(t *testing.T, clause clause, query string, args ...in
|
||||||
|
|
||||||
func assertClauseSerializeErr(t *testing.T, clause clause, errString string) {
|
func assertClauseSerializeErr(t *testing.T, clause clause, errString string) {
|
||||||
out := sqlBuilder{}
|
out := sqlBuilder{}
|
||||||
err := clause.serialize(select_statement, &out)
|
err := clause.serialize(selectStatement, &out)
|
||||||
|
|
||||||
//fmt.Println(out.buff.String())
|
//fmt.Println(out.buff.String())
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
|
|
@ -72,7 +72,7 @@ func assertClauseSerializeErr(t *testing.T, clause clause, errString string) {
|
||||||
|
|
||||||
func assertProjectionSerialize(t *testing.T, projection projection, query string, args ...interface{}) {
|
func assertProjectionSerialize(t *testing.T, projection projection, query string, args ...interface{}) {
|
||||||
out := sqlBuilder{}
|
out := sqlBuilder{}
|
||||||
err := projection.serializeForProjection(select_statement, &out)
|
err := projection.serializeForProjection(selectStatement, &out)
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue